# Changelog

## 0.8.0
- **Renamed to `dsh-claude-delegate`.** The package no longer shares the upstream name: `package.json`, the bundled `cordis.patch.yml` wiring, the SDK client identifier and the client bundle's `window.__ModuleLoader__.load({ id })` (which is derived from the package name, and asserted at build time) all follow. Install with `dsh plugin --profile <name> add dsh-claude-delegate`; an existing install of the old name has to be removed first, because DSH resolves a plugin row by package name.
- **This is a derivative work, and the README now says so.** Upstream is [zhangjunjesse/dsh-claude-code](https://github.com/zhangjunjesse/dsh-claude-code) (published to npm only up to 0.1.2); this fork continues from its 0.6.0. The README was rewritten around that fact with a "where it came from" table of what changed (DSH 0.2 adaptation, the live shell channel, the monitor panel, `resume`, runtime-registered skill, quota removal, safe bundle defaults), and it no longer documents the harness's own `subagent_claude_code` path.
- **The panel keeps its job rows across a tab switch.** Switching the conversation tab unmounts the view: the harness roster does not necessarily re-push settled jobs on re-subscribe, and the plugin's own tracker poll swallowed its RPC failure, so the tab strip could come back empty. The merged rows are now written into the same module-level panel cache as the event buffers and used to seed the next mount, a failing list RPC reports its reason in the panel instead of being discarded, and the empty state prints `row sources: roster N · tracker M` so the broken source is identifiable.

## 0.7.1
- **Background delegations work on DSH 0.2.** `run_in_background: true` failed immediately with `session "[object Object]" has no live agent (background job owner must be live)` — and since the Claude Code panel's job rows ride that same seam, the tab stayed empty. In DSH 0.2 the jobs seam resolves a spec's owner through `agents.get(owner)` and stores the live Agent, so `jobs.start()` now receives the owning session's **id** (`exec.agent.id`) instead of the Agent object; the tracker's `ownerSessionId` is written from the same value. Foreground delegation was never affected.
- **Background job output reaches the model again.** DSH 0.2 stores a producer's final text in `outcome.result` (0.1.x used `output`) and streams only what the producer passes to `handle.append()` into the ring behind `job_output`; the plugin used neither, so a finished background delegation read back as "(no new output)". It now forwards live deltas through `handle.append()` and reports the settled `result` for text the live stream did not already deliver (the seam concatenates the two, so re-sending would duplicate it). The monitor panel was never affected — it reads the plugin's own buffer offsets.
- **The panel lists delegations again on DSH 0.2.** 0.2 replaced the client session store's `jobsBySession` mirror with a first-class `jobs` client service, so the row list was permanently empty — and because the mirror simply came back `undefined`, the panel showed no error at all. The client half now reads the roster from `ctx.jobs` (looked up rather than injected, so a 0.1.x client without that service still loads) and holds its stream open with `watchRows(sessionId)`; a client with neither source falls back to the plugin's own tracker list.
- **The panel is live while a delegation runs.** Rows are merged from the `jobs` service, the 0.1.x mirror and the plugin's own tracker list instead of using the first non-empty source, so a job is listed — and its 1s output/event polling starts — within one poll of `startBackgroundJob`, not when it settles. Text is streamed too: the host mirrors the SDK's partial text deltas into the event stream (the finished block only carries whatever the deltas missed) and adjacent text events merge into one node, so a long answer grows in place the way the conversation view does.
- **A running tool no longer looks frozen.** The CLI's `tool_progress` messages (tool id, name, elapsed seconds) are mirrored into the event stream and ticked on the tool card, so a Bash call that takes minutes reads `⏳ 运行中 1m20s…` while it works; and while the job itself is live, any card whose result has not arrived shows the indicator even if no heartbeat came. The `[tool] …` markers the plugin writes into the text stream are excluded from the settled-result dedupe as well: they never appear in `outcome.output`, so counting them made `job_output` re-send the whole answer once the job settled.
- **`resume` is usable now.** The host had always captured the SDK's `session_id` and accepted a `resume` argument, but the tool's rendered text printed only `(turns / cost / tokens)`, so the model never saw the handle and every "continue this delegation" silently started from zero. The rendered result now ends with `session: <id> — pass it back as resume`, and a background job appends the same line to the seam ring when it settles, because `job_output` is the only channel the model reads a background run back through.
- **The panel also lists official `subagent` jobs.** Dispatch can go through the harness's own provider (`subagent_claude_code`) instead of this plugin; those runs are ordinary background jobs, so they were invisible here. Rows are now merged from both kinds (`claude-code` + `subagent`), our own RPCs are skipped for rows we did not run, and a foreign row renders through the harness `jobs.observe(sessionId, jobId)` tail (with its gap/error notices) and is stopped through `jobs.kill`.
- **Removed every quota feature.** At the user's request the `claude_code_usage` tool, the panel's usage bar, its `claudeCode/usage` RPC and the whole `src/usage.ts` module are gone: quota appears neither in the model's toolbelt nor in the UI. `renderUsage()`, the wire types and the host-side memo went with them, and the client bundle dropped from 91 KB to 73 KB.
- **Long commands stream their own output now (`mcp__dsh__shell`).** The Agent SDK has no tool-output frame at all — its message union carries `tool_progress` heartbeats and a `tool_result` only once the command finished (`SDKLocalCommandOutputMessage` is local slash-command output), because the CLI keeps the Bash pipes to itself. So the plugin now owns an in-process MCP shell: the delegate's system prompt routes commands expected to run past ~20 seconds through it, every line is mirrored into the event stream the panel renders (`▶ 实时输出`, stderr tinted, `$ command` / `exit 0 · 12.3s` as meta lines), and the output deliberately stays out of the model's `job_output` stream. It decodes UTF-8 with a GBK fallback (Chinese Windows), kills the whole process tree on timeout (`taskkill /T /F` on Windows), resolves the same Git Bash the CLI uses (never the `WindowsApps` WSL stub), and keeps built-in Bash available for short or stateful commands, since a fresh child process cannot preserve `cd`/`export`. `shellChannelOnly: true` denies Bash for 100% coverage at the cost of that state.
- **The delegation skill is merged and ships with the plugin.** The author's own `claude-delegation-brief` skill (brief template, three pre-dispatch checks, outputSchema skeleton, post-return acceptance) is folded into the plugin's runtime-registered `claude-code-delegation` skill, together with this plugin's operational facts (parameters, explicit `cwd`, background jobs, panel, two-level timeouts) and a section on how it differs from the official `subagent_claude_code` path. Installing the plugin installs the skill, so there is one copy instead of two that drift.

## 0.7.0
- **Runs on the DSH 0.2 line (`0.1.0-rc.6` – `0.2.0-rc.2`).** Peer ranges are now `>=0.1.0-rc.6 <0.3.0`; dsh 0.2 refuses to load a plugin whose dsh peer range leaves out the running version, so every 0.6.0 install on DSH 0.2 failed at load time. The source typechecks (`tsc --noEmit` on both halves) and builds against the real `@deepseek-ai/dsh-*@0.2.0-rc.2` type packages with zero errors; the emitted host JS is byte-identical to 0.6.0's.
- **The bundled `cordis.patch.yml` now ships safe, machine-independent defaults.** It no longer carries the author's dev-machine `proxy: http://127.0.0.1:7897` (a proxy pointing at a port with no service makes every delegation fail with `ECONNREFUSED` / `API Error: Connection refused`) nor `permissionMode: bypassPermissions` + `allowDangerouslySkipPermissions: true` (a delegated Claude with no permission checks at all). It ships `permissionMode: acceptEdits`; add `proxy` only when this machine's outbound IP is a datacenter IP and Anthropic answers 403.
- **Dev note:** install dependencies with `npm install --legacy-peer-deps` — the pinned `@deepseek-ai/dsh-*@0.2.0-rc.2` set trips npm's strict peer resolver through `dsh-system-prompt` → `dsh-invariants`.
- Repository moved to `https://github.com/project-hy/dsh-claude-code`; the SDK client identifier now reports the real plugin version.

## 0.6.0
- **Delegation cwd defaults to the calling session's working directory.** An omitted `cwd` used to fall through to `process.cwd()` — the DSH install directory, which is almost never where the user's files are. New precedence: explicit `cwd` argument > configured `cwd` > calling session's cwd (`agent.session.meta.cwd ?? agent.options.cwd`, same resolution dsh-claude-driver uses) > `process.cwd()` as the last resort.
- **dontAsk trap documented at every surface the model reads.** Delegated sessions are headless, so `permissionMode: 'dontAsk'` silently denies every confirmation prompt and the task predictably fails unless paired with an `allowedTools` whitelist. Not hard-blocked (whitelist + deny-the-rest is a legitimate strict-sandbox pattern), but the tool schema, the config description and the delegation skill now all warn and steer to `acceptEdits`.

## 0.5.0
- **Follow-main-effort delegation default** (`followMainEffort`, default on). When the `effort` argument is omitted, the delegate thinking effort now follows the calling session's current reasoning-effort tier (read from the same `modelSelection` projection as the model — it carries `reasoningEffort` alongside `model`), instead of always `high`. Precedence: explicit `effort` argument > session tier > `effort` config fallback (`high`). Only tiers Claude Code accepts (`low/medium/high/xhigh/max`, case-insensitive) pass through; a foreign tier name from a non-Claude provider falls back to config. `EFFORT_LEVELS` moved into the dependency-free `delegate-model.ts` as the single source of truth for both the schema enum and the follow filter; `currentMainModel()` generalized to `currentMainSelection()` returning `{ model, reasoningEffort }` in one projection read.

## 0.4.1
- **Fix startup deadlock introduced in 0.4.0** (`dsh-plugin-desktop: 1 entry did not activate` / `dsh-claude-code: waiting for services: required, optional`). This host's cordis (`@deepseek-ai/cordis` 4.x) has **no optional-inject concept**: `Inject.resolve` treats every object key as a service name, so the `{ required: [...], optional: [...] }` form registered two phantom services named `required`/`optional` that never exist, and `_refresh` keeps the fiber INACTIVE while **any** injected service is missing — the plugin (and the whole tree entry) never activates. Fix: `inject` is back to the plain `['tools', 'skills']` array, and `sessionProjections` is read lazily via `ctx.get('sessionProjections')` (cordis reflect.get mixin, bypasses the inject requirement, returns `undefined` when absent). Behaviour of 0.4.0's follow-main-model default is unchanged. `scripts/test-delegate-model.mjs` now pins the regression: inject must stay the array form, must not name `sessionProjections`, and the lazy `ctx.get()` read must be present in the built artifact.

## 0.4.0
- **Follow-main-model delegation default** (`followMainModel`, default on). When the `model` argument is omitted, the delegate model is now derived from the calling session's **current** main model — fable→opus, opus→sonnet, sonnet→sonnet (user-decided policy 2026-09-16) — instead of always `sonnet`. Precedence: explicit `model` argument > mapping > `model` config fallback (which still covers non-Claude mains like deepseek, plus haiku/unknown ids). The main model is read from the durable `modelSelection` session projection (`pending ?? lastUsed`) so mid-session model switches are honoured; `agent.options.model` is only the creation-time fallback when the projection is unavailable. `sessionProjections` joins the inject list as **optional** — the plugin still loads (and falls back to `model`) in profiles without it. Applies to foreground and background delegations alike (single request-construction point). New offline test: `scripts/test-delegate-model.mjs`; the mapping lives in the dependency-free `src/delegate-model.ts` so the test imports it without the host service graph.

## 0.3.5
- **Markdown preview in the panel**: assistant text now renders as formatted Markdown (headings, bold/italic, inline code, fenced code blocks, lists, block quotes, rules and http(s) links that open in a new tab) through a zero-dependency renderer that never touches `innerHTML`, with a per-block "Raw / Preview" toggle for the source.

## 0.3.4
- **Compact usage bar**: the quota bar is now one collapsed line (`Claude Max · 20x | 5h 2% · 7d 3% | normal | Refresh`) that unfolds the 5-hour/7-day progress bars, reset times, per-model chips and cache age on click, giving the output back most of the panel's header height.
- **Task tabs instead of a side list**: delegations moved from a 260px left column to a horizontally scrolling tab strip above the output, so the Claude Code window now owns the full panel width.
- **Job detail modal**: each tab carries a `ⓘ` that opens a dialog (ESC / backdrop / button to close) with the complete task text, the model, status, start and finish times, duration, cost, turns, the copyable Claude session id and the failure reason.
- **Model passthrough**: a background delegation records the model it ran with (`TrackedJob.model` → `JobInfo.model`, `null` on the wire when absent), and the tabs get status-coloured dots — blue and breathing while running, green/red/grey once settled.

## 0.3.3
- **Usage bar in the monitor panel**: the Claude Code tab now opens with the subscription's quota on top — plan tier (`Claude Max · 20x`), 5-hour and 7-day progress bars with reset times (amber from 50%, red from 80%), a chip per per-model limit (`Fable 0%`), a normal/caution/blocked badge, cache age and a refresh button — served by a new `claudeCode/usage` remote that re-reads the claude CLI's own local cache (no quota is spent, no account identity is returned) and degrades to a retryable message when it cannot.

## 0.3.2
- **Two-stage timeout with periodic warnings**: `timeoutMs` now defaults to 2 hours (hard abort when reached). New `warnTimeoutMs` (default 1h) emits a `warning` event in the monitor panel (prominent amber banner, no abort), repeated every `warnIntervalMs` (default 30m) while the task keeps running. All three are per-call overridable (`timeoutMs` / `warnTimeoutMs` / `warnIntervalMs` tool args). The delegation skill now tells the agent to surface warnings to the user instead of force-killing.

## 0.3.1
- **Native-style panel output**: the monitor panel no longer renders a flat text stream. A background delegation now also emits a structured event stream — `text`, `thinking`, `tool_use` (with its full parameter JSON), `tool_result` and a closing `result` — and the panel renders it the way the Claude Code terminal does: assistant text as prose, thinking collapsed behind a one-line `💭` toggle, and a tool card per call (colour-coded name badge, one-line parameters that expand to pretty-printed JSON) that owns the result it produced, grouped by `tool_use_id` so parallel calls stay apart. Long payloads collapse by default (~200 chars for parameters, ~800 for results) with an inline expander, and the run ends on a `✅ 完成 · $0.13 · 12 turns · 3m20s` summary.
- Host side adds `claudeCode/readEvents(sessionId, jobId, fromOffset)` next to `readOutput`, backed by a per-job ring buffer bounded three ways — at most 2000 events, a 2 MB total budget, and a per-event cut so one huge block cannot evict the rest. Reads are absolute-offset and move no cursor, so the panel, a second window and a late reader can all follow the same job independently; a dropped head reports `truncated`. Tool results are capped at 2000 characters on the host, before they ever reach the wire.
- The existing text stream is untouched: the model's `job_output`, the panel's `readOutput` fallback and the UI cancel path (`cancelFromUi` → `killed`, model still notified) all behave exactly as in 0.3.0. Partial `text_delta` / `thinking_delta` frames stay out of the event stream — the panel paints whole blocks instead of flickering per token — and the text stream keeps carrying them for `job_output`'s live feel.

## 0.3.0
- Richer background job detail: a finished delegation now reports `$0.13 · 12 turns · 3m20s` instead of a bare status, so the harness's own job list shows cost, turns and duration inline with no UI code.
- **Claude Code monitor panel** (web): a third `conversation.view` tab next to Chat and Trajectory. It lists this session's delegations (live rows first, duration ticking), and shows the selected one in a terminal-like window — incremental live output with `[tool]` lines highlighted, pause-on-scroll auto-follow, turns/cost/duration stats, the Claude session id (copyable, usable as `resume`), and cancel.
  - Host side adds a `JobTracker` mirror and a `claudeCode` remote service (`listJobs` / `readOutput` / `cancel`), all owner-checked against the calling session.
  - Output reads use absolute offsets on the plugin's own buffer, so the panel never consumes the model's `job_output` bytes; cancelling from the UI goes through the plugin's abort path, so the job still settles as `killed` and the model still receives its completion notification.
  - Polling is bounded: one read per second, only while the tab is mounted and the selected job is running, plus one final read when it settles.
  - Ships as a second build artifact, `lib/client.js`, declared through `dsh.client` + `exports["./client"]`. Adding it to an already-installed plugin requires a DSH restart.
- **New tool `claude_code_usage`**: reads the local Claude subscription's quota — 5-hour and 7-day windows with reset times, the regular `limits[]` rows with severities, plan tier, spend and extra-usage state, plus cache age and a derived `normal` / `caution` / `blocked` advice. It reads only the claude CLI's own `~/.claude.json` cache and `claude auth status --json`; the credentials file is never opened and no account identity (email, uuid, token) is ever returned. Missing or renamed fields degrade to `null` plus a warning instead of failing.
- **New `parallel-dev` skill**: orchestration playbook for parallel development. When the user asks to develop several modules at once, the agent follows a decision tree (serial by default, worktree only for genuinely parallel same-repo work), auto-creates branches/directories, dispatches delegations per worktree via `cwd`, then integrates and cleans up. Confirmation is limited to one business-level question ("parallel or sequential?") and never surfaces git/worktree details to the user.

## 0.2.0
- Background delegations: `run_in_background: true` registers the run as a DSH job and returns `{ kind: "background", jobId }` immediately; manage it with the built-in `job_output` / `job_list` / `job_kill` tools and get a completion notification.
- Streaming output: background jobs expose Claude Code's live text (and tool-use markers) incrementally through `job_output`, backed by `includePartialMessages`.
- Better failure diagnostics: synchronous preflight for a missing `claude` executable, a bad `cwd`, and `bypassPermissions` without the `allowDangerouslySkipPermissions` switch, plus actionable mapping for authentication, billing, rate-limit/overload, 403/proxy, invalid model, budget-exceeded and stale-`resume` failures.
- New SDK capabilities: `appendSystemPrompt`, `thinkingMode` (adaptive/disabled), `maxBudgetUsd`, `outputSchema` → structured output, config-defined `subagents`, and `permissionMode: 'auto'`.
- Result now also carries `durationMs`, `numTurns` and `structuredOutput`; the rendered result appends a turns/cost/tokens stat line.

## 0.1.2
- Add `effort` (low/medium/high/xhigh/max) and `maxThinkingTokens` — config + per-call override.

## 0.1.1
- Add `dsh.bundle` manifest + `cordis.patch.yml` so the plugin installs via `dsh plugin add`.
- Ship `cordis.patch.yml` in the npm tarball.

## 0.1.0
- Initial release: `claude_code` tool over the official Claude Agent SDK.
- Built-in `claude-code-delegation` skill (Leader-Worker SOP).
- `resume` parameter for multi-turn memory across delegations.
