zcode-acp-server 0.44.4 → 0.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +2 -3
  2. package/README.zh-CN.md +2 -4
  3. package/dist/backend/client.d.ts +11 -0
  4. package/dist/backend/client.d.ts.map +1 -1
  5. package/dist/backend/client.js +21 -0
  6. package/dist/backend/client.js.map +1 -1
  7. package/dist/backend/credentials.d.ts +19 -5
  8. package/dist/backend/credentials.d.ts.map +1 -1
  9. package/dist/backend/credentials.js +15 -46
  10. package/dist/backend/credentials.js.map +1 -1
  11. package/dist/backend/listener.d.ts +7 -3
  12. package/dist/backend/listener.d.ts.map +1 -1
  13. package/dist/backend/listener.js +20 -4
  14. package/dist/backend/listener.js.map +1 -1
  15. package/dist/backend/types.d.ts +6 -0
  16. package/dist/backend/types.d.ts.map +1 -1
  17. package/dist/code-fingerprint.json +1 -1
  18. package/dist/config/auto-compact.d.ts.map +1 -1
  19. package/dist/config/auto-compact.js +5 -0
  20. package/dist/config/auto-compact.js.map +1 -1
  21. package/dist/config/mcp-discovery.d.ts +19 -0
  22. package/dist/config/mcp-discovery.d.ts.map +1 -1
  23. package/dist/config/mcp-discovery.js +26 -0
  24. package/dist/config/mcp-discovery.js.map +1 -1
  25. package/dist/handlers/dispatch.d.ts.map +1 -1
  26. package/dist/handlers/dispatch.js +33 -0
  27. package/dist/handlers/dispatch.js.map +1 -1
  28. package/dist/handlers/extensions.d.ts +13 -11
  29. package/dist/handlers/extensions.d.ts.map +1 -1
  30. package/dist/handlers/extensions.js +58 -36
  31. package/dist/handlers/extensions.js.map +1 -1
  32. package/dist/handlers/session.d.ts.map +1 -1
  33. package/dist/handlers/session.js +115 -17
  34. package/dist/handlers/session.js.map +1 -1
  35. package/dist/handlers/slash.d.ts +3 -1
  36. package/dist/handlers/slash.d.ts.map +1 -1
  37. package/dist/handlers/slash.js +68 -6
  38. package/dist/handlers/slash.js.map +1 -1
  39. package/dist/i18n.d.ts +16 -0
  40. package/dist/i18n.d.ts.map +1 -1
  41. package/dist/i18n.js +20 -0
  42. package/dist/i18n.js.map +1 -1
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +4 -2
  45. package/dist/index.js.map +1 -1
  46. package/dist/quota/client.js +2 -2
  47. package/dist/quota/client.js.map +1 -1
  48. package/dist/server.d.ts +24 -0
  49. package/dist/server.d.ts.map +1 -1
  50. package/dist/server.js +31 -0
  51. package/dist/server.js.map +1 -1
  52. package/dist/translators/event-translator.d.ts +9 -1
  53. package/dist/translators/event-translator.d.ts.map +1 -1
  54. package/dist/translators/event-translator.js +37 -1
  55. package/dist/translators/event-translator.js.map +1 -1
  56. package/dist/translators/types.d.ts +16 -1
  57. package/dist/translators/types.d.ts.map +1 -1
  58. package/dist/translators/types.js.map +1 -1
  59. package/docs/BACKLOG.md +286 -102
  60. package/docs/TROUBLESHOOTING.md +1 -1
  61. package/docs/agents/domain.md +4 -2
  62. package/package.json +1 -1
package/docs/BACKLOG.md CHANGED
@@ -8,17 +8,41 @@ Last audited against **app-server 0.16.5 bundled in ZCode desktop 3.12.3**
8
8
  the app version, not the CLI string, dates a bundle). Method names were
9
9
  extracted from the `zcode.cjs` method-name enum (`session/create` → 65
10
10
  entries) and the v4 enum; event types from the zod event-envelope union.
11
- Live RPC verification of the full model-turn lifecycle was blocked by the
12
- GLM edge's captcha risk-control on headless sessions ("Captcha verification
13
- request timed out", `model_request_failed`) — the v3 background-task channel
14
- (`session.updated` with `taskId`) is confirmed UNCHANGED in 3.12.3: probe
15
- sessions still receive the same event vocabulary, and no `task.*` event types
16
- exist on the v3 stream. `task.upserted` / `task.removed` are **v4 controller
17
- frame ops** (the desktop's conversation-LIST stream — "task" = conversation,
18
- matching `tasks-index.sqlite`'s `tasks` table), `task.output` is a FILE NAME
19
- in the sub-agent output dir, and `backgroundTask.stop` is the TaskStop
20
- tool's permission id — none are v3 events. The previous audit ran against
21
- desktop 3.9.2 / same app-server 0.16.5 (2026-08-27).
11
+
12
+ **Source of truth (2026-09-21)**: ZCode open-sourced — local checkout at
13
+ `~/Develop/NoBackup/ZCode` (remote `github.com/zai-org/ZCode`; desktop 3.14.0 =
14
+ app-server `apps/zcode-cli` 0.16.9, the exact binary the bridge runs). The
15
+ protocol enum and zod schemas live unminified at
16
+ `packages/shared/src/zcode-protocol/index.ts`; the protocol server dispatch at
17
+ `apps/zcode-cli/packages/bootstrap/src/zcode-protocol/` (server.ts,
18
+ server-operations.ts); the agent runtime at `apps/zcode-cli/packages/core/`
19
+ (`packages/zcode-server-cli` is only a thin CLI shell). Prefer reading source
20
+ over the bundle-extraction method in "Verification method" (kept for released
21
+ versions newer than the checkout — pull the checkout before auditing a new
22
+ version). Full audit detail with `file:line` evidence:
23
+ `.zcode/scratch/alignment-protocol.md` (protocol surface) and
24
+ `.zcode/scratch/alignment-hacks.md` (Gotchas verification).
25
+
26
+ **3.14.0 audit (2026-09-20, app-server 0.16.9 — live-probed end to end)**: the
27
+ dynamic-workflow family (ten model tools led by `CreateWorkflow`) is OFF by
28
+ default headless and enabled per PROCESS via
29
+ `workspace/updateDynamicWorkflowPolicy` — the flag is process-global (the
30
+ `workspace` param is echoed, never used for lookup), has no persistence, and
31
+ mid-session flips do not reach live sessions. The
32
+ `session/requestRuntimePreferences` response schema is `.strict()` and cannot
33
+ carry the flag; `session/create` / `session/resume` accept a
34
+ `dynamicWorkflowEnabled` param that ORs with the global. (Source-confirmed
35
+ 2026-09-21: the in-agent gate defaults ON — only an explicit `false` removes
36
+ the tools — so the fail-closed default lives only at the protocol layer and
37
+ the per-session create param is sufficient; closing the gate also removes the
38
+ `dynamic-workflows` skill and `/workflow` command,
39
+ `core/src/tool/handlers/index.ts:177-183`, `bootstrap/src/app/create-app.ts:755-807`.)
40
+ Run observability lives OUTSIDE the `session/event` stream:
41
+ `workflow.lifecycle` (phases are exactly `actor-spawned` / `run-settled`)
42
+ arrives on `v4/telemetry/event`, and `sess_dwf-*` child sessions push their
43
+ turn/tool events on `computer-use/operation-event`. Bridge wiring (opt-in
44
+ enable + narrow observability tap) is designed in ADR-0024, not yet
45
+ implemented.
22
46
 
23
47
  ## Removed upstream in 0.16 (verified live: `-32601`)
24
48
 
@@ -28,105 +52,187 @@ desktop 3.9.2 / same app-server 0.16.5 (2026-08-27).
28
52
  | `session/rewind` | `v4/conversation/fileRewindPreview` + v4 rewind flow | Dropped the ACP extension + `/rewind` slash command |
29
53
  | `session/rewindCascade` | v4 rewind flow | Dropped the ACP extension |
30
54
 
55
+ Also absent from the 0.16.9 method enum (source-verified 2026-09-21 — bundle
56
+ audit had kept them as candidates or "not planned"): the whole
57
+ workspace-defaults/provider cluster — `workspace/readState`,
58
+ `workspace/setDefaultMode`, `workspace/setDefaultModel`,
59
+ `workspace/setDefaultThoughtLevel`, `workspace/upsertModelProvider`,
60
+ `workspace/removeModelProvider`, `workspace/updateProviderRegistry`. The only
61
+ `workspace/*` methods left: `readPresentation`, `hooks/trustGrant`,
62
+ `updateInteractionPreferences`, `updateModelIoPreferences`,
63
+ `updateOffPeakToolPolicy`, `updateDynamicWorkflowPolicy`, `generateText`,
64
+ `cancelGenerateText` (`index.ts:3597-3611`).
65
+
31
66
  `session/fork` (branch from checkpoint) is the remaining v3 alternative for
32
67
  rewind-like UX. The backend still emits `rewind.triggered` /
33
68
  `checkpoint.created` events, so a client can observe rewinds initiated
34
69
  elsewhere.
35
70
 
71
+ ## Deprecated in source (0.16.9 enum comments, wire cases kept)
72
+
73
+ The protocol enum now labels these `@deprecated` (`index.ts:3573-3645`); wire
74
+ cases remain, so calls still work, but plan for the v4 successors:
75
+
76
+ | Method | Source note | Bridge call site |
77
+ | ------------------------------ | --------------------------------------------------------------------------------------------------- | ----------------------------------- |
78
+ | `session/send` | Main path converged on v4 `sendText`; only the adapter-attachment fallback branch still consumes | the turn loop (fine until v4 lands) |
79
+ | `session/stop` | Host client method deleted (stop converged on the v4 stop command) | `stopBackendTurn` (dual-send) |
80
+ | `session/cancelBackgroundTask` | Replacement: v4 `cancelBackgroundWork` | `handlers/extensions.ts` |
81
+ | `session/fork` | Desktop host client chain deleted; v4 `forkAssistant` (via `forkSessionAtMessage`) is the successor | `handlers/extensions.ts` |
82
+ | `usage/stats` | Host consumption moved to `v4/usage/stats`; wire-compat case only | not used |
83
+ | `session/usage` | Host moved to `v4/conversation/usage`; slated for removal with `usage/stats` | candidate only |
84
+
36
85
  ## Candidate methods (optional enhancements)
37
86
 
38
87
  Available in the backend but with no ACP-side counterpart yet. Pick them up
39
- when a concrete ACP/editor need appears.
40
-
41
- | Method | Purpose | Current bridge behavior |
42
- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
43
- | `session/subagents` | Query the list of sub-agents for a session | Sub-agent info is parsed from the `Agent` tool result (`_meta.subagent`); sufficient for now |
44
- | `session/events` | Pull-mode event history (complement to `session/subscribe`) | Not used; could support event replay/gap-fill |
45
- | `session/usage` | Per-session token usage | Per-turn billing usage is now carried on the ACP `session/prompt` result (`usage` + `_meta.zcode.usage`), sourced from `turn.completed`; this RPC remains a candidate for session-cumulative reconciliation |
46
- | `workspace/hooks/trustGrant` | Server→client request: approve hook trust | Auto-errored by the unknown-request fallback (`server-requests.ts` `handleOne`) during turns; `session/send` carries a 15s timeout so nothing hangs. If hook trust ever needs real UX, map it onto ACP `session/request_permission` |
47
- | `interaction/browserList` / `interaction/browserExecute` | Server→client requests: browser automation via the client | Auto-errored by the fallback above; only meaningful once an ACP client has a browser surface |
48
- | `interaction/requestProviderRuntimeHeaders` | Server→client request: provider runtime headers | Auto-errored by the fallback above |
49
- | `interaction/requestOfficialMcpAuthHeaders` (0.16.5) | Server→client request: official MCP auth headers | Auto-errored by the fallback above |
50
- | `session/requestRuntimePreferences` (0.16.5) | Runtime preference negotiation | Wired — `backend/client.ts` auto-replies with defaults (nativeSearch/memory off, AskUserQuestion NOT auto-resolved); newer app-servers block `session/create` until it is answered |
51
- | `session/close` (0.16.5) | Actually close a backend session/runtime | Not used — remote close intentionally retires discovery only (ADR-0006, self-healing); backend runtimes idle-evict anyway |
52
- | `workspace/generateText` / `workspace/cancelGenerateText` (0.16.5) | Workspace-scoped one-shot text generation | Not used; no ACP counterpart |
53
- | `workspace/readState` (0.16.5) | Read workspace state | Not used |
54
- | `workspace/setDefaultMode` / `setDefaultModel` / `setDefaultThoughtLevel` (0.16.5) | Workspace-level defaults (bridge uses per-session setters) | Not used |
55
- | `workspace/upsertModelProvider` / `removeModelProvider` (0.16.5) | Provider registry management | Not used; bridge forwards the client's registry via `updateProviderRegistry` |
56
- | `workspace/updateInteractionPreferences` / `workspace/updateModelIoPreferences` | Client preference updates | Not used |
57
- | `skills/referenceCatalog`, `plugins/referenceCatalog`, `plugins/resolveSuggestedReference` (verified live 2026-08-27, params need `workspace.workspaceKey`) | Skill/plugin reference catalog lookup + suggested-reference resolution | Not used — the bridge reads skills and plugin commands from disk (`config/skill-discovery.ts`, `config/plugin-commands.ts`); revisit only if a client needs the backend's catalog view |
58
- | `plugins/{list,setEnabled,overview,install,uninstall,update,cancelOperation,restoreBuiltin,configure,resetConfig,validate,describe}` + `plugins/marketplace/{add,remove,update}` (3.12.3) | Full plugin management + marketplace family | Not used — **compat watchpoint**: if upstream moves plugin distribution to the marketplace, the bridge's disk-based discovery (`config/plugin-commands.ts`) may go stale |
59
- | `offPeak/{create,list}`, `workspace/updateOffPeakToolPolicy` (3.12.3) | Off-peak (discounted-hours) task family | Not used; `session/send` carries the matching `offPeakTaskId`/`offPeakRunType` params — candidate if a client wants to schedule discounted-hours runs |
60
- | `automation/{create,update,list,delete,checkTaskBinding}` (3.12.3, concrete enumeration) | Scheduled (cron) task family — served by the host over `automation/*` requests | Not planned (see below); `automation/checkTaskBinding` is new in 3.12.3 |
61
- | `process/childProcesses` (3.12.3) | List a session's child processes | Not used; potentially useful for background-task diagnostics |
62
- | `provider/testModelConnectivity` (3.12.3) | Probe a provider/model endpoint | Not used; model availability comes from the `session/create` response |
63
- | `workspace/readPresentation` (3.12.3) | Read workspace state (successor spelling — `workspace/readState` is absent from the 3.12.3 enum) | Not used |
64
- | `runtime/capabilities` + `computer-use/operation-event` (3.12.3) | Capability handshake + CUA (computer-use) operation events | Not used; only meaningful once an ACP client has a CUA surface |
65
-
66
- ### New `session/send` params (0.16+)
67
-
68
- `attachments` is already wired: ACP image content blocks are extracted
69
- (`extractAttachments`) and forwarded as `kind:"image"` entries (`localPath`
70
- for `file://` uris, `dataBase64` otherwise). The remaining fields are not
71
- forwarded:
72
-
73
- - `toolDenylist` — per-message tool deny list
74
- - `runtimeModel` — per-message model override (redundant with the bridge's
75
- `session/setModel` / config-option switching)
76
- - `browserAmbientContext` — browser context for the turn
77
- - `expectedRevision` / `expectedProviderRevision` / `expectedModelRuntimeRevision`
78
- — optimistic concurrency guards
79
- - `automationId` / `offPeakTaskId` / `offPeakRunType` — scheduled/off-peak tasks
80
-
81
- ### New event types (undocumented in PROTOCOL.md)
82
-
83
- | Event | Notes |
84
- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
85
- | `session.titleUpdated` (0.16.5) | **Wired** — `SessionTitleListener` adopts `generated`/`custom` pushes |
86
- | `message.upserted` / `message.removed` (0.16.5) | Message-granular upsert/remove; the projection differ reconciles instead |
87
- | `part.started` / `part.delta` / `part.upserted` / `part.removed` (0.16.5) | Message-PART granular streaming (the v4 conversation model on the v3 envelope) |
88
- | `permission.requested` / `permission.resolved` (0.16.5) | Interaction lifecycle OBSERVER events; the bridge serves the request methods |
89
- | `userInput.requested` / `userInput.resolved` (0.16.5) | Same, for user-input interactions |
90
- | `checkpoint.created` | Checkpoint lifecycle; pairs with `rewind.triggered` |
91
- | `rewind.triggered` | A rewind happened (e.g. initiated elsewhere) |
92
- | `rewind.started` / `rewind.failed` / `rewind.completed` (0.16.5) | Full rewind lifecycle; richer than the bare `triggered` |
93
- | `streamRecovery.updated` | Stream recovery progress — potentially useful for the replay/gap-fill path |
94
- | `turn.attachments.resolved` | Attachment resolution telemetry |
95
- | `usage.delta` | Streaming usage updates |
96
- | `turn.steerQueued` / `turn.steerDrained` | Steer lifecycle (queue/drain of steered inputs) |
97
- | `turn.terminal` | Terminal turn lifecycle; bridge relies on `turn.completed`/`turn.failed` |
98
-
99
- Complete 3.12.3 v3 event vocabulary (from the zod envelope union): the table
100
- above plus `session.created` / `session.resumed` / `session.updated` /
101
- `session.closed` / `turn.started` / `turn.completed` / `turn.failed` /
102
- `model.streaming` / `tool.updated`. Names like `task.upserted`,
103
- `turn.phase.*`, or `session.persistence.*` appear as STRINGS in the bundle
104
- but are v4 frames, telemetry labels, or persistence log events — not v3
105
- `session/event` types (see the audit note above).
88
+ when a concrete ACP/editor need appears. Ranked shortlist in
89
+ "Alignment opportunities" below.
90
+
91
+ | Method | Purpose | Current bridge behavior |
92
+ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
93
+ | `session/subagents` (`index.ts:1520-1618`) | Sub-agent states: `running{status: running\|waiting\|blocked}`, `ended{total, items[{status: success\|failed\|cancelled\|lost}], nextCursor}` | Sub-agent info is parsed from the `Agent` tool result (`_meta.subagent`); the RPC adds waiting/blocked/lost states for stuck-subagent detection (pairs with the watermark liveness logic in `runEventTurn`) |
94
+ | `session/events` (`{sessionId, afterSeq?, limit?}`, `index.ts:1667-1674`) | Pull-mode event history | Not used; gap-fill after the drain gate's close-escalation reload (re-subscribe + replay only the missed window), durable audit for `/debug` |
95
+ | `session/subscribe` `afterSeq` + `includeSnapshot` (`index.ts:1496-1513`) | Resume the event stream from a seq watermark, optionally with a full state snapshot | Not used; crash-safe resubscribe instead of full replay |
96
+ | `session/usage` / `v4/conversation/usage` | Per-session cumulative usage: input/output/reasoning/cache tokens, `modelRequestCount`, `modelErrorCount` (`index.ts:1627-1646`) | Per-turn billing usage is now carried on the ACP `session/prompt` result (`usage` + `_meta.zcode.usage`), sourced from `turn.completed`; this RPC remains a candidate for session-cumulative reconciliation (deprecated upstream, see table above) |
97
+ | `session/compact` `instructions` + `result.compact` (`index.ts:1829-1853`) | Custom compact instructions; result acks `{state: accepted\|already_running, inputId?, operationId?}` | Not forwarded — `/compact <focus>` could pass instructions; the backend's own `already_running` ack can backstop the bridge's `autoCompactInFlight` single-flight |
98
+ | `session/debug` (`index.ts:3571`, `bootstrap/src/zcode-protocol/session-debug.ts`) | Per-session debug snapshot accumulated from the live event stream | Not used; `zcode-acp` diagnostics command / `/debug` extension |
99
+ | `session/list` rich params (`sessionIds` incl. hidden, `includeArchived`, `limit`, `index.ts:1600-1609`) | Explicit identity lookup, archived sessions | Not used |
100
+ | `session/create` extras: `toolAllowlist`/`toolDenylist` (per-session tool face — could move Cron* hiding off process-wide `--disallowed-tools`), `importedHistory` (claudeCode / sharedContext+sha256 provenance), `persistence:"immediate"\|"deferred"`, `titleGenerationEnabled:false` (bridge sets its own titles), `parentSessionId` (`index.ts:1558-1580`) | Session-creation knobs | Not forwarded; `session/resume` also takes `toolAllowlist`/`toolDenylist` — a resume WITHOUT them drops the tool face on cold recovery (`index.ts:1589-1595`) |
101
+ | `mcp/list` `mode:"status"` (`index.ts:686-723`) | Status without connecting: per-server `{status, transport, toolCount, failureKind(19-value enum), authorization{authorizationUrl}}` | Not used; editor MCP health panel + OAuth start URL without new transport |
102
+ | `process/childProcesses` (3.12.3) | List a session's child processes (`{pid, serverName, mcpSource, pluginName?}`, pure memory) | Not used; potentially useful for background-task diagnostics |
103
+ | `skills/referenceCatalog`, `plugins/referenceCatalog[WithCategory]` (categorized variant new in 0.16.9) | Session-scoped FROZEN catalogs — the authoritative per-session view vs the bridge's live disk reads | Not used; fixes the stale-catalog class of bug (backend freezes discovery at session start) |
104
+ | `workspace/readPresentation` (3.12.3) | The backend's own view of workspace mode + slash-command list | Not used; cross-check the bridge's disk-based slash discovery for drift |
105
+ | `workflows/*` family (NEW 0.16.9: `list/get/updateMeta/delete/runs/move`, `index.ts:2685-2937, 3618-3625`) | Session-less management of saved dynamic workflows (`<cwd>/.zcode/workflows/`, project+global scopes), run history with `artifacts`, cross-cwd runs query | Not used; pairs with v4 commands `startSavedWorkflow` / `resumeWorkflowRun` |
106
+ | `provider/testModelConnectivity` (3.12.3) | Probe a provider/model endpoint | Not used; model availability comes from the `session/create` response |
107
+ | `runtime/capabilities` (3.12.3; returns `{independentPlanState:true}`) | Trivial capability handshake | Not used; cheap preflight for a `zcode-acp doctor` command |
108
+ | `interaction/providerRuntimeHeadersCancelled` notification (`index.ts:336, 2396-2406`) | Backend cancels a pending runtime-headers refresh (workspace/session/requestId scoped) | Not handled; drop pending answerers immediately on turn cancel instead of waiting them out |
109
+ | `workspace/generateText` / `workspace/cancelGenerateText` (0.16.5) | Workspace-scoped one-shot text generation | Not used; no ACP counterpart |
110
+ | `workspace/updateInteractionPreferences` / `workspace/updateModelIoPreferences` | Client preference updates | Not used |
111
+ | `offPeak/{create,list}`, `workspace/updateOffPeakToolPolicy` (3.12.3) | Off-peak (discounted-hours) task family | Not used; `session/send` carries the matching `offPeakTaskId`/`offPeakRunType` params — candidate if a client wants to schedule discounted-hours runs. Off-peak tools are fail-closed at the protocol layer with three unlock channels (per-session param OR'd, process policy method, `offPeakPort` injection) |
112
+ | `automation/{create,update,list,delete,checkTaskBinding}` (3.12.3) | Scheduled (cron) task family — served by the host over `automation/*` requests | Not planned (see below) |
113
+ | `plugins/{list,setEnabled,overview,install,uninstall,update,cancelOperation,restoreBuiltin,configure,resetConfig,validate,describe}` + `plugins/marketplace/{add,remove,update}` (3.12.3) | Full plugin management + marketplace family | Not used — **compat watchpoint**: if upstream moves plugin distribution to the marketplace, the bridge's disk-based discovery (`config/plugin-commands.ts`) may go stale |
114
+
115
+ ### `session/send` params (0.16.9-verified, `index.ts:1730-1768`)
116
+
117
+ Actual field list: `sessionId, modelSelection, modelExecution, inputId, queryId,
118
+ content, attachments, browserAmbientContext, expectedRevision,
119
+ expectedProviderRevision, automationId, offPeakTaskId, offPeakRunType,
120
+ toolDenylist`. Not forwarded by the bridge today:
121
+
122
+ - `modelSelection` — per-message model override `{providerId, modelId,
123
+ options:{reasoningLevel?}}` (`packages/shared/src/model-selection.ts`); the
124
+ previously-listed `runtimeModel` does NOT exist in 0.16.9 (bundle-audit
125
+ error). Enables per-turn model switching without a `session/setModel`
126
+ round-trip.
127
+ - `modelExecution` — requires `modelSelection` (superRefine); carries per-turn
128
+ credentials `requestAuth:{apiKey?, headers?}` plus sub-agent policy
129
+ (`subagents:{foregroundModel, background}`) and
130
+ `memoryExtraction:"skip"`. Complements `answerProviderRuntimeHeaders`.
131
+ - `toolDenylist` — per-message tool deny list.
132
+ - `browserAmbientContext` — browser context for the turn.
133
+ - `expectedRevision` / `expectedProviderRevision` — optimistic concurrency
134
+ guards. (`expectedModelRuntimeRevision`, previously listed, does not exist.)
135
+ - `automationId` / `offPeakTaskId` / `offPeakRunType` — scheduled/off-peak tasks.
136
+
137
+ ### Event vocabulary (0.16.9 envelope union — exactly 25 types, `index.ts:1100-1126`)
138
+
139
+ `session.created`, `session.resumed`, `session.updated`, `session.titleUpdated`,
140
+ `session.closed`, `turn.started`, `turn.steerQueued`, `turn.steerDrained`,
141
+ `turn.completed`, `turn.failed`, `message.upserted`, `message.removed`,
142
+ `part.started`, `part.delta`, `part.upserted`, `part.removed`,
143
+ `model.streaming`, `tool.updated`, `permission.requested`,
144
+ `permission.resolved`, `userInput.requested`, `userInput.resolved`,
145
+ `checkpoint.created`, `rewind.triggered`, `streamRecovery.updated`.
146
+
147
+ Notes per type (the ones with known bridge relevance):
148
+
149
+ | Event | Notes |
150
+ | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
151
+ | `session.titleUpdated` | **Wired** — `SessionTitleListener` adopts `generated`/`custom` pushes |
152
+ | `message.upserted` / `message.removed` | Message-granular upsert/remove; the projection differ reconciles instead |
153
+ | `part.started` / `part.delta` / `part.upserted` / `part.removed` | Message-PART granular streaming (the v4 conversation model on the v3 envelope) |
154
+ | `permission.requested` / `permission.resolved` | Interaction lifecycle OBSERVER events; the bridge serves the request methods |
155
+ | `userInput.requested` / `userInput.resolved` | Same, for user-input interactions |
156
+ | `checkpoint.created` / `rewind.triggered` | Checkpoint + rewind lifecycle (rewinds initiated elsewhere are observable) |
157
+ | `streamRecovery.updated` | Stream recovery progress — payload is an untyped `jsonObjectSchema` upstream; useful for the replay/gap-fill path |
158
+ | `turn.started` payload extras (`index.ts:1168-1186`) | `executionKind:"agent"\|"controlOnly"` (controlOnly = no model turn — the bridge's own boot-resume ack could be classified by this instead of text-matching), `foregroundExecutionId` (feeds the precise v4 stop), `backgroundSource`, `intent`, `originMeta` |
159
+ | `turn.steerQueued` / `turn.steerDrained` payloads (`index.ts:1191-1229`) | Queue length, `commandKind`, `delivery`, `targetTurnId`, drained `injectedMessageIds` — enough to render a proper "queued behind running turn" ACP update. Steer is only reachable via v4 delivery semantics (see Gotchas) — a steer caused by ANOTHER client on the same backend is visible here |
160
+ | `turn.completed` `resultType` + `cacheStats` (`index.ts:1230-1261`) | `resultType: success\|cancelled\|error_max_turns\|error_max_budget\|error_during_execution\|error_max_tool_calls`; `cacheStats{totalMessages, cachedMessages, lastCacheHit, cacheReadTokens?}` — rich terminal lines + cache-health visibility |
161
+ | `turn.failed` `turnPhase` (`index.ts:1262-1269`) | Failure phase string for better triage |
162
+ | `model.streaming` kinds (`index.ts:987-1014`) | 13 kinds incl. `reasoning_*` deltas — relevant if thinking streams are ever surfaced directly |
163
+ | `session.updated` with `state.updated` mutation reasons | Compact terminal state IS observable here: `session_compacted` / `session_compact_cancelled` / `session_compact_failed` (source: `server-operations.ts:2082-2119`) — the bridge can report real compact failures instead of assuming success from the RPC ack |
164
+
165
+ **Corrected 2026-09-21 (source)**: `rewind.started` / `rewind.failed` /
166
+ `rewind.completed`, `turn.attachments.resolved`, `usage.delta`, and
167
+ `turn.terminal` are NOT in the 0.16.9 union — bundle-audit false positives;
168
+ rows removed.
106
169
 
107
170
  Unknown event types fall through the translator's else-chain untranslated and
108
171
  silently — new backend events never produce noise or errors, so additions
109
172
  here are informational, not blocking.
110
173
 
174
+ Not on this stream (verified live 2026-09-20, 3.14.0): `workflow.lifecycle`
175
+ arrives on `v4/telemetry/event`, and `sess_dwf-*` workflow child sessions push
176
+ their own turn/tool events on `computer-use/operation-event`; neither is a
177
+ `session/event` type. The bridge ignores both channels today — the workflow
178
+ observability design (ADR-0024) taps them narrowly and re-attributes child
179
+ events to the parent session.
180
+
181
+ ### CLI→host notifications (bridge IS the host — currently ignored)
182
+
183
+ `startup/storageState` (DB phases checking/waiting_for_lock/migrating/
184
+ committing/ready/failed — could drive a real "backend starting" indicator;
185
+ control frames `startup/storagePath|storagePrepared|storagePathReady`),
186
+ `process/mcpTelemetry` (process_start/process_crash/session_startup/memory),
187
+ `process/mcpResourceSamples` (5-min MCP RSS/CPU), `process/toolExecResource`
188
+ (bash completion facts), `process/resourceSample`,
189
+ `plugins/operationProgress` (`index.ts:334-451, 3696-3713`).
190
+
111
191
  ## v4 protocol family (strategic)
112
192
 
113
193
  0.16 ships a parallel **v4** API used by the desktop client, alongside the v3
114
- `session/*` surface this bridge speaks:
194
+ `session/*` surface this bridge speaks. Full method table:
195
+ `packages/shared/src/zcode-protocol-v4/transport.ts:307-359` (larger than the
196
+ list below — see source for the authoritative set).
115
197
 
116
198
  `v4/connection/flow`, `v4/controller/{subscribe,resync,unsubscribe}`,
117
199
  `v4/conversation/{subscribe,resync,unsubscribe,rowsRange,plans,fileChanges,
118
- fileRewindPreview,usage,attachmentRead,attachmentStat,frame}`,
119
- `v4/attachment/{begin,chunk,commit,abort,read,previewSource}`,
120
- `v4/usage/stats`, `v4/commands/query`, `v4/command`, `v4/command_fact`,
121
- `v4/shared_context_import`, `v4/telemetry/event`,
122
- `v4/cua/permission-observation`, `v4/fork_start_failure` (the last six
123
- enumerated in the 3.12.3 refresh; `v4/cua/permission-observation` pairs with
124
- the `computer-use/operation-event` server→client notification and the
125
- `runtime/capabilities` handshake).
126
-
127
- Steer/rewind now live here. If the bridge ever needs them back, implementing
128
- the minimal v4 conversation subset (or `v4/command`) is the path; expect the
129
- v3 surface to stay in maintenance mode.
200
+ fileRewindPreview,usage,attachmentRead,attachmentStat,frame,backgroundBashOutput,
201
+ workflowRunEvents,workflowRuns,workflowRunArtifacts,workflowRunArtifactData,
202
+ workflowRunArtifactRead,workflowRunWorkspace,workflowRunNodeResult}`,
203
+ `v4/attachment/{begin,chunk,commit,abort,read,previewSource}` (≤512KiB
204
+ chunks), `v4/usage/stats`, `v4/conversation/usage`, `v4/commands/query`
205
+ (idempotency probe), `v4/command`, `v4/command_fact`,
206
+ `v4/shared_context_import`, `v4/telemetry/event`, `v4/telemetry/local-ttft`,
207
+ `v4/cua/permission-observation`, `v4/fork_start_failure`.
208
+
209
+ Topic model (`transport.ts:83-161`): subscribe with
210
+ `{topic, base:{logEpoch, seq}, visibility}` → ACK
211
+ `{subscriptionId, mode: snapshot|resume, logEpoch}`; frames are `(fromSeq,
212
+ toSeq]` deltas — the watermark/CAS vocabulary row-targeting commands require
213
+ (`baseRevision` + `baseLogEpoch`, `command.ts:293-317`).
214
+
215
+ The bridge already speaks `v4/command` (the dual stop). Its payload union
216
+ (`command.ts:43-244`) is a single-method stepping stone to
217
+ rewind/edit-turn/feedback/queue UX over ACP without implementing the v4
218
+ subscription mesh: `sendText (requestedDelivery startNow|queue|guide,
219
+ heldQueueDisposition)`, `stop (expectedForegroundExecutionId — obtainable
220
+ from `turn.started`; the CLI uses it to reject late stops that would kill a
221
+ newer unrelated execution)`, `compact`, `forkAssistant`, `applyFileRewind`,
222
+ `editUserQuery`, `retryTurn`, `setAssistantFeedback`, queue ops
223
+ (`sendQueuedNow`, `editQueueItem`, `reorderQueueItem`, `deleteQueueItem`,
224
+ `setAutoDrain`), `resolveInteraction`, `snoozeInteractionAutoResolution`,
225
+ `switchModelConfig`, `switchCollaborationMode (build|edit|plan|yolo)`,
226
+ `pauseGoal`/`resumeGoal`, `cancelBackgroundWork`, workflow ops
227
+ (`startSavedWorkflow`, `resumeWorkflowRun`, `amendWorkflowRunSettings`),
228
+ `renameSession`, `deleteSession`, `discardSharedContext`.
229
+
230
+ Hook trust is also v4 now: `respondWorkspaceHookReview` /
231
+ `toggleWorkspaceHookReviewItem` / `revokeWorkspaceHookTrust` /
232
+ `requestWorkspaceHookReview` (`command.ts:186-200`). The v3
233
+ `workspace/hooks/trustGrant` is CLI-HOSTED (host→CLI; the CLI's dispatch
234
+ handles it — `bootstrap/src/zcode-protocol/server.ts:607-625`), so the bridge
235
+ will never RECEIVE it (previous BACKLOG framing was wrong).
130
236
 
131
237
  ## Not planned (client/config layer)
132
238
 
@@ -134,16 +240,89 @@ These methods belong to the desktop client or workspace configuration layer and
134
240
  have no ACP equivalent. Listed for completeness only — the bridge does not
135
241
  intend to surface them.
136
242
 
137
- `automation/*` (scheduled tasks — the Cron* tools the backend advertises are
138
- disallowed by default via `--disallowed-tools`, opt back in with
139
- `ZCODE_ENABLE_AUTOMATION_TOOLS=1`; see #192), `usage/stats` (token analytics; the
140
- account-level plan quota it does NOT cover is exposed via the bridge's own
141
- `account/usage_stats` — see Proposal 0002), `workspace/readState`,
142
- `workspace/upsertModelProvider`, `workspace/removeModelProvider`,
143
- `workspace/updateProviderRegistry`, `workspace/setDefaultModel`,
144
- `workspace/setDefaultThoughtLevel`, `workspace/setDefaultMode`,
145
- `workspace/generateText`, `workspace/cancelGenerateText`, `mcp/list`,
146
- `plugins/*` (the bridge reads plugin commands from disk instead).
243
+ `automation/*` (scheduled tasks), `usage/stats`, `workspace/generateText`,
244
+ `workspace/cancelGenerateText`, `mcp/list` (connect mode), `plugins/*` (the
245
+ bridge reads plugin commands from disk instead).
246
+
247
+ **Automation tool gating, corrected against source (2026-09-21)**: there is NO
248
+ backend env gate — `ZCODE_ENABLE_AUTOMATION_TOOLS` exists only in the bridge
249
+ (`src/backend/resolve.ts`). The backend registers `CronCreate/CronList/
250
+ CronUpdate/CronDelete` whenever an `automationPort` is injected
251
+ (`core/src/runtime/helpers/runtime-tools.ts:66`), and the legacy protocol
252
+ server injects one for every session create
253
+ (`server-operations.ts:3370`) — so the backend ALWAYS registers them in
254
+ app-server mode. Opting out is entirely the bridge's `--disallowed-tools`
255
+ (or per-session `toolDenylist`). Bonus:
256
+ `AUTOMATION_MUTATION_TOOL_NAMES = [CronCreate, CronUpdate, CronDelete]` gets
257
+ special turn-loop treatment (`turn-loop-state.ts:23`).
258
+
259
+ ## Alignment opportunities (2026-09-21, source-verified — ranked)
260
+
261
+ Status markers updated after the 2026-09-21 implementation pass. Details and
262
+ `file:line` in `.zcode/scratch/alignment-protocol.md`.
263
+
264
+ 1. ~~**Precise ESC**~~ **WIRED (already present)** — `stopBackendTurn`
265
+ already captures `foregroundExecutionId` from `turn.started` and sends it
266
+ in the v4 stop, with a compaction guard for never-started turns; the
267
+ source pass only corrected the outdated comment.
268
+ 2. ~~**`/compact <focus>`**~~ **WIRED** — instructions forwarded (trimmed);
269
+ `already_running` ack surfaced; falls through to the same lock wait.
270
+ 3. ~~**Real compact failure reporting**~~ **WIRED** — `state.updated`
271
+ reasons (`session_compact_failed`/`_cancelled`) recorded via
272
+ `ZcodeBackend.onCompactOutcome` → `server.compactOutcomes`; compact()
273
+ reports `__compactFailed` (slash + auto-compact paths); usage refresh
274
+ suppressed on failure. Regression tests: `tests/compact-outcome.test.ts`.
275
+ Bonus fix from the same source pass: `waitForTurnIdle`'s lock probe now
276
+ matches 0.16.9's "A prompt is already running" wording (previously only
277
+ the 0.16.5 "prompt is running" substring — on 0.16.9 every probe fell to
278
+ the NON-LOCK branch and relied on the 30s grace).
279
+ 4. ~~**Drain-gate simplification**~~ **WIRED (behavior-adaptive,
280
+ 2026-09-21)** — `server.observedSendBusyReject`: once this backend
281
+ process has rejected a send with -32010 "A prompt is already running for
282
+ this session" (code AND message — -32010 is shared by unrelated errors),
283
+ the drain gate's pre-send poll (and its close-escalation) is skipped and
284
+ the send busy-retry loop is the single authority. Parity kept: one-shot
285
+ queued note on busy waits, post-accept differ re-baseline
286
+ (`sendAttempt > 1` ⇒ the abandoned turn unwound during our retries).
287
+ Backends that never showed the rejection keep the full legacy gate.
288
+ Regression tests: `tests/drain-gate-fast-path.test.ts`.
289
+ 5. ~~**`session/subagents`** + **`session/events` afterSeq**~~ **WIRED
290
+ (2026-09-21)** — sub-agent status text lines during silent phases: the
291
+ stall-reconcile probe polls `session/subagents` and surfaces roster
292
+ CHANGES as one-line `agent_message_chunk` updates (running/waiting/blocked
293
+ - a one-shot ended summary with failed/cancelled counts; best-effort,
294
+ -32601 backends are silent). Gap-fill landed via the ALREADY-WIRED
295
+ subscribe channel instead of the pull RPC: `resubscribe` consumes the
296
+ missed window the backend returns IN the subscribe response (`events`,
297
+ seq-ordered, deduped against the watermark), and the initial `subscribe`
298
+ now OMITS `afterSeq` — the old explicit `afterSeq: 0` made the backend
299
+ materialize the FULL event log into a response the bridge discarded,
300
+ every turn. `session/events` itself stays a `/debug`-only candidate.
301
+ Regression tests: `tests/subagent-status.test.ts`,
302
+ `tests/resubscribe-gap-fill.test.ts`.
303
+ 6. ~~**`mcp/list mode:"status"`**~~ **WIRED (2026-09-21)** — `/mcp` upgraded
304
+ to a live health panel (per-server `name · status · N tools ·
305
+ failureKind`, OAuth `authorizationUrl` indented beneath its server; any
306
+ RPC failure falls back to the local-discovery card). Regression tests:
307
+ `tests/mcp-health.test.ts`.
308
+ 7. ~~**Retire `session/updateRuntimeModelConfig`**~~ **DONE** — the ACP
309
+ extension method and handler were removed (absent from the 0.16.9 enum,
310
+ every call answered -32601); `setModel` + `applyModelSwitch` cover the
311
+ path on all builds.
312
+ 8. ~~**Cancel stale header answerers**~~ **DONE (minimal)** — the responder
313
+ answers at frame arrival, so nothing is ever pending;
314
+ `interaction/providerRuntimeHeadersCancelled` is now logged-and-acked
315
+ instead of silently ignored.
316
+ 9. ~~**`turn.completed` `resultType`/`cacheStats`**~~ **WIRED (2026-09-21)** —
317
+ one turn-end status line per reply (agent_message_chunk, distinct
318
+ messageId): success renders prompt-cache stats (`cache N/M messages ·
319
+ cache-read tokens`), non-success resultTypes surface verbatim as a
320
+ warning line. Regression tests: `tests/turn-info-line.test.ts`.
321
+ 10. **Per-session `toolDenylist` at create/resume** — move Cron* hiding off
322
+ process-wide `--disallowed-tools`; note a resume WITHOUT the lists drops
323
+ the tool face on cold recovery. PENDING.
324
+ 11. **v4/command channel** as the single implementation surface for
325
+ rewind/edit/feedback/queue UX later. PENDING.
147
326
 
148
327
  ## Verification method
149
328
 
@@ -168,4 +347,9 @@ EOF
168
347
  ```
169
348
 
170
349
  Never conclude a method was removed from a single string-literal search; a
171
- missing dispatch case plus a live `-32601` is the proof.
350
+ missing dispatch case plus a live `-32601` is the proof. With the open-source
351
+ checkout available, prefer reading `packages/shared/src/zcode-protocol/index.ts`
352
+
353
+ - the dispatch switch in
354
+ `apps/zcode-cli/packages/bootstrap/src/zcode-protocol/server.ts` first; fall
355
+ back to this method only for released versions newer than the checkout.
@@ -125,7 +125,7 @@ non-empty `options.apiKey` in that file. Start-plan providers stay declined
125
125
 
126
126
  2. If the file is missing or the key is stale, **install and log into the ZCode desktop app** — it writes a fresh `config.json` with a valid enabled provider. There is no manual API-key configuration in the editor.
127
127
 
128
- 3. If you need to override the key/base URL without touching `config.json`, set `ZCODE_BASE_URL` and provide the key via the provider config (see `src/backend/credentials.ts` for the merge order).
128
+ 3. There is no env override for the provider base URL: the app-server reads `ZCODE_BASE_URL` as its own service origin, so the bridge never passes one through (see `src/backend/credentials.ts`). Edit `config.json` (or the provider config in the App) instead.
129
129
 
130
130
  ### session/subscribe fails
131
131
 
@@ -4,9 +4,11 @@ How engineering skills should consume this repo's domain documentation when expl
4
4
 
5
5
  ## Before exploring, read these
6
6
 
7
- - **`CONTEXT.md`** at the repo root, or
7
+ - **`.zcode/CONTEXT.md`** (this repo's live glossary — the `.zcode/` path
8
+ supersedes the skill's default root location; the old root copy was
9
+ removed), or
8
10
  - **`CONTEXT-MAP.md`** at the repo root (if it exists) — it points to one `CONTEXT.md` per context. Read each file relevant to the current topic.
9
- - **`docs/adr/`** — read ADRs related to the area you are about to work on. In multi-context repos, also check `src/<context>/docs/adr/` for context-scoped decisions.
11
+ - **`docs/adr/`** — read ADRs related to the area you are about to work in. The series continues in `.zcode/docs/adr/` (0008+); read both when the area predates the move.
10
12
 
11
13
  If these files don't exist, **continue silently**. Don't flag the absence; don't proactively suggest creating them. The producer skill (`/grill-with-docs`) will lazily create them when terms or decisions are actually resolved.
12
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zcode-acp-server",
3
- "version": "0.44.4",
3
+ "version": "0.46.0",
4
4
  "description": "Agent Client Protocol (ACP) server bridging headless ZCode to editors like Zed and JetBrains.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",