DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

andrewhmir /

andrewhmir/dsh-plan-review

Verified

Inline plan review for the DeepSeek Harness Web GUI: full plan rendered in the composer with highlight-to-comment before you approve.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@23633a9d

@andrewhmir/dsh-plan-review — read the whole plan before you approve it

An unofficial community plugin for DeepSeek Harness (DSH). Repository: https://github.com/andrewhmir/dsh-plan-review. It removes one specific piece of friction in the superpowers workflow:

The agent asks you to approve a plan. The question card shows path: C:\ws\.superpowers\plans\feature.md and two buttons — so you open the markdown file by hand just to find out what you are approving.

With this plugin installed, that question takes over the composer and renders the complete plan inline, with Accept plan / Revise plan at the top and highlight → comment on any passage. You decide with the plan on screen.

What it does

property behavior
trigger an ask_user_question request whose single question header starts with [plan-review]
presentation composer takeover: sticky decision header, full plan markdown, scrollable body, comment rail
plan source path: <absolute .md> on the question's first line, read through the plugin's own host route; without a path, the question text itself is the plan
comments select text in the plan → Add comment; each comment anchors to the quoted passage, is editable/deletable, and can be located again
accept answers with the question's own accept label; refused while comments or an overall note exist, so feedback is never silently dropped
revise sends {decision, comments, note} back in the answer's custom field; refuses locally when there is no feedback yet
drafts comments and the overall note are kept in this browser tab's session storage, so closing and reopening the review does not lose them; answering clears the draft
fallback unreadable plan or an unclaimed question shows the shipped card / an inline error; the review stays answerable
keyboard Ctrl/Cmd+Enter accepts; Escape clears a pending comment selection
dismissal Close dismisses the review without answering (same as the shipped card's discuss action)
locale panel chrome is English; package metadata ships en + zh

Requirements

  • DSH >= 0.2.1-rc.2 with the Web GUI (dsh web).
  • The superpowers workflow's superpowers-ui skill (installed under $DSH_HOME/skills/) emits the [plan-review] protocol this plugin renders.
  • Node.js 22 or newer only for the tests and the client build; the plugin itself runs inside the harness process.

Install

The package is a DSH bundle: it declares dsh.bundle.patch and one client+host plugin row (id: plan-review). Install it into the profile you run, then restart dsh web.

From a plugin market

Enable DSH's custom plugin market, add a community index that lists this package (the repository carries the dsh-plugin GitHub topic so indexes can discover it), and install @andrewhmir/dsh-plan-review from the Discover tab.

With the agent

plugin_manager install_bundle  target: @andrewhmir/dsh-plan-review@0.1.0

From a local checkout

plugin_manager install_bundle  target: /absolute/path/to/dsh-plan-review

After installing

Restart dsh web. The running process holds its pre-install module graph; a restart loads the new host half and the client bundle. Then confirm the composition:

dsh --profile web --dump-config

Expected: exit code 0 and a row id: plan-review / name: @andrewhmir/dsh-plan-review with no not found, unknown key, or cannot resolve lines.

How it works

  • Claim. The plugin's client half registers into the conversation.composer chain slot at priority: -20 — ahead of the shipped question composer (0), the approval panel (1) and the subagent read-only composer (-10). Its selector returns a claim only for a single generic question whose header starts with [plan-review]; every other interaction gets null, so the shipped card is untouched. (A question must carry at most two options and not be multi-select; anything else also falls back.)
  • Protocol. The question text is path: <absolute markdown file> on line one, followed by the review heading. Without a path: line the whole text is the plan. The option labels are the authority for the decision buttons; accept-like and revise-like labels are matched by pattern and sent back verbatim.
  • Host half. GET /plan-review/file?path=… (loopback-only, read-only) reads the plan as UTF-8. Reads are confined to the profile's registered workspace roots plus the sandbox policy's workspaceRoot; binary extensions, oversized files, and paths outside those roots are refused with stable error codes. GET /plan-review/ping is the liveness probe.
  • Rendering. The plan markdown is rendered by the plugin's own renderer (src/client/markdown.mjs): ATX headings, paragraphs, fenced code, inline code, bold/italic/strikethrough, links (http/https/mailto/#/relative only), ordered and unordered lists, blockquotes, GFM tables, and rules. Raw HTML is shown as text. Nothing is fetched from the network, and rendering does not depend on a module-table primitive the shell might not expose.
  • Comments. Highlighting is anchored by the quoted text plus character offsets over the rendered document; offsets are repaired against the document as it renders, so a re-render never leaves a comment pointing at the wrong passage. Anchored comments are painted with the browser's CSS Custom Highlight API, so the markdown renderer's DOM is never mutated. A comment whose quote disappeared is marked passage not found but keeps its note.
  • Answers. Accept sends { id, selected: [<accept label>] }. Revise needs at least one comment or an overall note, then sends { id, selected: [], custom: "{\"decision\":…,\"comments\":[{\"quote\":…,\"note\":…}],\"note\":…}" } — the shape the superpowers-ui skill documents. The panel only renders; it never edits plan files.

The protocol (agent-facing)

{
  "id": "plan-review",
  "header": "[plan-review]",
  "question": "path: C:\\ws\\.superpowers\\plans\\feature.md\nReview the plan below.",
  "options": [
    { "label": "Accept plan", "description": "Start executing the plan as written." },
    { "label": "Revise plan", "description": "Incorporate my comments and show me the updated plan." }
  ]
}

Answers arrive in the ask_user_question result. A plain decision is selected: ["Accept plan"]. A comment-bearing decision instead has selected: [] and custom holding {"decision": "<label>", "comments": [{"quote": "<passage>", "note": "<what to change>"}], "note": "<overall note>"}. note is this plugin's additive field for an overall remark (the skill documents decision + comments); a body that had to be shortened to fit one tool result also carries "truncated": true. Locate each quoted passage in the plan file, apply every note (never drop one), rewrite the plan, and ask again.

The plugin refuses to send an accept answer while comments or an overall note exist: a label decision has no field for them, so it asks for Request changes (or for the comments to be deleted) instead.

Configure

The plugin row accepts one optional value; it is read without a Config schema:

- insert:
    - id: plan-review
      name: '@andrewhmir/dsh-plan-review'
      config:
        maxPlanBytes: 2000000   # read cap for one plan file (default 2 MB)

Known limitations

  • The [plan-review] protocol only. The harness's native plan-mode review (exit_plan_mode, architect preset) is a separate, shipped surface and is deliberately not touched — this plugin exists to render superpowers plan files.
  • Plan files must live under a workspace root. A plan outside every registered root is refused by design (the error names the path so it can be fixed). The route only serves markdown/text plan files (.md, .markdown, .mdown, .mkd, .mdx, .txt), never arbitrary workspace files.
  • Drafts are per browser tab. Comments survive closing and reopening the review in the same tab (sessionStorage); they are not synced to another tab or device, and answering the review clears them.
  • Malformed answers are capped. The encoded answer stays under the profile's tool-result pruner budget; if it had to shrink, the payload says "truncated": true so the agent can ask rather than silently missing notes.
  • English panel copy. Package metadata is bilingual; in-panel strings are English in this version.
  • Web GUI only. The host route is generic, but the takeover and comments are Web-client features.
  • The composer is occupied while reviewing. That is the same seat the shipped question card takes; dismissing the review returns the composer.
  • Quote-based anchoring. A comment is tied to the exact text the user selected; if a plan is rewritten mid-review (it is not, by this plugin), the comment shows passage not found.
  • A future host protocol change can shadow this plugin. Claiming depends on the documented conversation.composer chain and the [plan-review] header; if a future harness ships its own renderer for that header, its composer entry may win.

Compatibility

engines.dsh declares >=0.2.1-rc.2. The composer chain, the question answer wire schema, the loopback web route and the seeded React module were implemented against the 0.2.1-rc.2 packages on this machine and are covered by a unit/integration suite with fake React, fake storage and fake fetch (no live browser is driven by the tests). Plan rendering is self-contained and does not depend on the shell's markdown primitive. Live install + smoke-test evidence is recorded in MOUNT.md once performed.

Verify

From this directory:

node --test "test/*.test.mjs"
node tools/build-client.mjs --check
node --check client.js

In a confined Windows sandbox the test runner's child-process spawn is blocked; run node --test --test-isolation=none "test/*.test.mjs" there instead.

Development

node tools/build-client.mjs         # regenerate client.js from src/client/*.mjs
node tools/build-client.mjs --check # fail when client.js is stale
node --test "test/*.test.mjs"

client.js is a generated classic script that registers itself with the harness's module loader under the package name. Source modules under src/client/ are plain ESM with relative .mjs imports only; the host half lives in src/host/ and is injected with webServer (optional workspaceRegistry / sandboxPolicy).

After editing only the client half, the harness's client HMR stat-polls the built bundle and hot-swaps it in the open page. Host-half edits need a dsh web restart.

Independence and license

This is an unofficial community plugin, not affiliated with DeepSeek. It is an independent implementation of the inline plan-review idea for the superpowers protocol; its predecessor on this machine was the private dsh-superpowers-ui plugin (0.1.x API, retired in the 0.2.x upgrade). Upstream DSH does not accept external pull requests at the moment, so distribution is a standalone package; the repository carries the dsh-plugin topic so community plugin indexes can discover it.

MIT. See LICENSE.

—/ 5

No ratings yet

Verified DSH bundle

Commit 23633a9d2591

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout