npm.io
0.1.11 • Published 4h ago

@guillaumemeyer/dsh-plan-approval

Licence
MIT
Version
0.1.11
Deps
0
Size
32 kB
Vulns
0
Weekly
0

DeepSeek Harness Enhanced Plan Mode

A fullscreen, enhanced plan mode for DeepSeek Harness (DSH).

It replaces the small in-chat plan review card with a full-screen review surface so large plans are readable and navigable. It renders automatically when the agent presents a plan (exit_plan_mode) and rides the existing planMode / userQuestions review contract.

Features

  • Fullscreen review in the frame-wide shell.overlay layer, at 90vw × 90vh.
  • Line navigation (vim-style): j/k move line-by-line, gg jump to top, G (Shift+g) jump to bottom, with a straight left highlight on the cursor line that auto-scrolls.
  • Inline search: / opens a search bar; matching lines highlight live, Enter cycles to the next match and Shift+Enter to the previous, Esc closes (n/N also work once the overlay re-takes focus).
  • Inline comments: c (or clicking a line) drops a comment anchored to that line, shown as an inline chip. Comments are integrated into the plan:
    • On request changes (s) they're serialized into the feedback answer so the agent revises the plan with them.
    • On approval (a) the plan is approved and plan mode exits; the merged plan (comments included) is what's copied with y. Comments are not attached to an approval — use s (request changes) to send them back for revision.
  • Actions: a approve · s request changes · y copy plan · q quit plan.
  • A bottom status line lists every keyboard shortcut.

Install (into a DSH deployment)

This is a dsh.client browser plugin, so it must be installed and mounted where DSH composes its web surface (host/web composition), then the host restarted so the client-modules node half produces the bundle.

  1. Install the package into the DSH deployment's web app:

    npm i @guillaumemeyer/dsh-plan-approval
  2. Find the web-surface (browser roster) composition. This is the cordis.yml / cordis.patch.yml in the DSH web app that lists the other browser roster rows (ui-plan, ui-user-questions, ui-tool, …). (The shipped @deepseek-ai/dsh-web-app cordis.patch.yml is the reference for this "browser plugin roster" section.)

  3. Add one row to that roster:

    - id: ui-plan-approval
      name: '@guillaumemeyer/dsh-plan-approval'
  4. Restart the DSH host. The @deepseek-ai/dsh-client-modules node half re-scans loader entries for packages declaring dsh.client, bundles /plugins/@guillaumemeyer/dsh-plan-approval/client.js, and the browser loads it. (With a pnpm run dev:web watcher, the bundle is rebuilt automatically without a restart; in a production/built deployment a host restart is required.)

The row must live in the web-surface dsh.client roster (a dsh.client platform: "web" package). Placing it in an agent preset or a non-web composition will not be scanned into window.__DSH_BOOT__.

Verify it's mounted

After restart, the package's browser bundle is served under /plugins/@guillaumemeyer/dsh-plan-approval/client.js, and the plugin appears in the shell.overlay slot.

Use it from DSH

  1. Enter plan mode — switch the agent into plan mode (the /plan command or the session's plan control) and ask it to plan.
  2. Present a plan — when the agent has the plan, it calls exit_plan_mode with the plan markdown. The full-screen review overlay opens automatically.
  3. Review the plan:
    • Navigate: j/k move the cursor line, gg jump to top, G (Shift+g) jump to bottom; the plan auto-scrolls to follow the cursor.
    • Search: / opens the search bar — type to highlight matches, Enter to the next match, Shift+Enter to the previous, Esc to close.
    • Comment: c (or click any line) anchors an inline comment to that line; type it and press Enter to add (Esc to cancel). Comments show as inline chips.
    • Copy: y copies the plan, including any inline comments (the merged plan).
  4. Decide:
    • a approve the plan.
    • s request changes — the feedback box opens; submit your requested changes (plus any inline comments) → the agent keeps planning and revises the plan.
    • q quit plan — cancel the review and go talk instead.

The status line at the bottom shows every shortcut: a approve · s changes · c comment · y copy · q quit · j/k move · gg/G ends · / search.

Keyboard shortcuts
Key Action
a Approve the plan
s Request changes (opens feedback box; Enter submits)
c Add an inline comment at the current line (Enter add, Esc cancel)
y Copy the plan (merged with comments)
q Quit / cancel the plan review
j / k Move the cursor down / up one line
gg Jump to top
G (Shift+g) Jump to bottom
/ Open search (type to highlight; Enter next, Shift+Enter prev, Esc close)
Esc Close the search/comment box, otherwise quit

How the review answers map

The underlying exit_plan_mode review is binary (approve vs. keep-planning). This plugin keeps that contract and layers comments onto it:

  • a (approve) always sends the plain approve answer ({ selected: [approve] }), so the host leaves plan mode and the plan is carried out from the next step — whether or not there are inline comments. Attaching the comments as custom on an approval would make an unpatched host treat the approval as "keep planning" (keeping the session in plan mode instead of switching to execution), so the approve path deliberately keeps the answer clean.
  • s (request changes) sends the typed feedback plus the inline comments as the custom answer → the host keeps planning, and the agent revises the plan with your comments. This is the path to use when you want your comments considered.
  • The merged plan (plan + inline comments) is still available to copy with y.

Host change: approve-with-notes (optional)

The shipped @deepseek-ai/dsh-plan-mode tool treats any custom value on the review answer as "keep planning". The plugin's approve path keeps that contract by sending a plain approval, so an approval always leaves plan mode and starts execution. If you additionally want inline comments auto-attached to an approval, re-enable the custom field in approve() (client.js) and patch the host's exit_plan_mode to accept it:

// before: if (... || item.custom !== void 0) { /* keep planning */ }
if (item?.selected.length !== 1 || item.selected[0] !== APPROVE_LABEL) { /* keep planning */ }
// after pendingIntents.set(...):
const notes = item?.custom;
return { approved: true, ...(notes ? { notes } : {}) };

And allow notes in the tool's output.schema (optional notes: { type: "string" }), plus include it in the result render so the model sees the comments after approval. This requires a host restart to take effect, and is a change to a shipped package that an upgrade would overwrite — ideally upstream it.

Publishing updates

To publish a new version, ensure a local .env (untracked) holds your npm token, then:

cp .env.example .env   # once: edit to add NPM_TOKEN=...
npm run release        # runs publish:check (preversion), bumps patch, publishes to npm
  • The token is read from .env and referenced by the committed .npmrc via ${NPM_TOKEN}, so it is never tracked.
  • preversion runs node --check client.js && npm pack --dry-run automatically before the version bump.
  • The script is named release because publish is a reserved npm lifecycle name: npm auto-runs a publish script during npm publish. Naming it publish made npm publish re-run the script, bumping and publishing a version on every loop.

Notes

  • Client-only browser plugin; the node half (index.js) is an empty apply.
  • Package is published with publishConfig.access: "public"; .npmignore discards repo/dev cruft.

License

MIT