zcode-acp-server 0.1.0 → 0.3.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.
- package/README.md +192 -9
- package/README.zh-CN.md +143 -8
- package/dist/backend/client.d.ts +12 -4
- package/dist/backend/client.d.ts.map +1 -1
- package/dist/backend/client.js +72 -7
- package/dist/backend/client.js.map +1 -1
- package/dist/backend/credentials.d.ts.map +1 -1
- package/dist/backend/credentials.js +2 -1
- package/dist/backend/credentials.js.map +1 -1
- package/dist/backend/listener.d.ts +12 -4
- package/dist/backend/listener.d.ts.map +1 -1
- package/dist/backend/listener.js +68 -12
- package/dist/backend/listener.js.map +1 -1
- package/dist/backend/types.d.ts +1 -1
- package/dist/backend/types.d.ts.map +1 -1
- package/dist/bin/hub.d.ts +16 -0
- package/dist/bin/hub.d.ts.map +1 -0
- package/dist/bin/hub.js +41 -0
- package/dist/bin/hub.js.map +1 -0
- package/dist/bin/quota.d.ts +54 -0
- package/dist/bin/quota.d.ts.map +1 -0
- package/dist/bin/quota.js +333 -0
- package/dist/bin/quota.js.map +1 -0
- package/dist/config/auto-compact.d.ts +23 -0
- package/dist/config/auto-compact.d.ts.map +1 -0
- package/dist/config/auto-compact.js +67 -0
- package/dist/config/auto-compact.js.map +1 -0
- package/dist/config/mcp-discovery.d.ts +34 -0
- package/dist/config/mcp-discovery.d.ts.map +1 -0
- package/dist/config/mcp-discovery.js +153 -0
- package/dist/config/mcp-discovery.js.map +1 -0
- package/dist/config/model-cache.d.ts +12 -1
- package/dist/config/model-cache.d.ts.map +1 -1
- package/dist/config/model-cache.js +30 -8
- package/dist/config/model-cache.js.map +1 -1
- package/dist/config/options.d.ts +87 -9
- package/dist/config/options.d.ts.map +1 -1
- package/dist/config/options.js +248 -45
- package/dist/config/options.js.map +1 -1
- package/dist/config/plugin-commands.d.ts +24 -0
- package/dist/config/plugin-commands.d.ts.map +1 -0
- package/dist/config/plugin-commands.js +107 -0
- package/dist/config/plugin-commands.js.map +1 -0
- package/dist/config/provider-registry.d.ts +60 -0
- package/dist/config/provider-registry.d.ts.map +1 -0
- package/dist/config/provider-registry.js +128 -0
- package/dist/config/provider-registry.js.map +1 -0
- package/dist/config/runtime-model.d.ts +54 -18
- package/dist/config/runtime-model.d.ts.map +1 -1
- package/dist/config/runtime-model.js +105 -61
- package/dist/config/runtime-model.js.map +1 -1
- package/dist/config/skill-discovery.d.ts +35 -0
- package/dist/config/skill-discovery.d.ts.map +1 -0
- package/dist/config/skill-discovery.js +188 -0
- package/dist/config/skill-discovery.js.map +1 -0
- package/dist/handlers/account.d.ts +43 -0
- package/dist/handlers/account.d.ts.map +1 -0
- package/dist/handlers/account.js +59 -0
- package/dist/handlers/account.js.map +1 -0
- package/dist/handlers/background-tasks.d.ts +72 -0
- package/dist/handlers/background-tasks.d.ts.map +1 -0
- package/dist/handlers/background-tasks.js +330 -0
- package/dist/handlers/background-tasks.js.map +1 -0
- package/dist/handlers/dispatch.d.ts.map +1 -1
- package/dist/handlers/dispatch.js +134 -22
- package/dist/handlers/dispatch.js.map +1 -1
- package/dist/handlers/extensions.d.ts +15 -0
- package/dist/handlers/extensions.d.ts.map +1 -1
- package/dist/handlers/extensions.js +43 -27
- package/dist/handlers/extensions.js.map +1 -1
- package/dist/handlers/io.d.ts +31 -3
- package/dist/handlers/io.d.ts.map +1 -1
- package/dist/handlers/io.js +108 -9
- package/dist/handlers/io.js.map +1 -1
- package/dist/handlers/replay.d.ts +79 -0
- package/dist/handlers/replay.d.ts.map +1 -0
- package/dist/handlers/replay.js +252 -0
- package/dist/handlers/replay.js.map +1 -0
- package/dist/handlers/server-requests.d.ts +20 -4
- package/dist/handlers/server-requests.d.ts.map +1 -1
- package/dist/handlers/server-requests.js +293 -63
- package/dist/handlers/server-requests.js.map +1 -1
- package/dist/handlers/session.d.ts +113 -10
- package/dist/handlers/session.d.ts.map +1 -1
- package/dist/handlers/session.js +932 -277
- package/dist/handlers/session.js.map +1 -1
- package/dist/handlers/slash.d.ts +37 -1
- package/dist/handlers/slash.d.ts.map +1 -1
- package/dist/handlers/slash.js +143 -8
- package/dist/handlers/slash.js.map +1 -1
- package/dist/index.js +76 -12
- package/dist/index.js.map +1 -1
- package/dist/interaction/adapter.d.ts +19 -33
- package/dist/interaction/adapter.d.ts.map +1 -1
- package/dist/interaction/adapter.js +80 -79
- package/dist/interaction/adapter.js.map +1 -1
- package/dist/lazy-sessions.d.ts +35 -0
- package/dist/lazy-sessions.d.ts.map +1 -0
- package/dist/lazy-sessions.js +98 -0
- package/dist/lazy-sessions.js.map +1 -0
- package/dist/quota/cache.d.ts +18 -0
- package/dist/quota/cache.d.ts.map +1 -0
- package/dist/quota/cache.js +32 -0
- package/dist/quota/cache.js.map +1 -0
- package/dist/quota/client.d.ts +30 -0
- package/dist/quota/client.d.ts.map +1 -0
- package/dist/quota/client.js +57 -0
- package/dist/quota/client.js.map +1 -0
- package/dist/quota/color.d.ts +58 -0
- package/dist/quota/color.d.ts.map +1 -0
- package/dist/quota/color.js +95 -0
- package/dist/quota/color.js.map +1 -0
- package/dist/quota/combined.d.ts +66 -0
- package/dist/quota/combined.d.ts.map +1 -0
- package/dist/quota/combined.js +179 -0
- package/dist/quota/combined.js.map +1 -0
- package/dist/quota/format.d.ts +105 -0
- package/dist/quota/format.d.ts.map +1 -0
- package/dist/quota/format.js +219 -0
- package/dist/quota/format.js.map +1 -0
- package/dist/quota/index.d.ts +23 -0
- package/dist/quota/index.d.ts.map +1 -0
- package/dist/quota/index.js +42 -0
- package/dist/quota/index.js.map +1 -0
- package/dist/quota/opencode-go/cache.d.ts +17 -0
- package/dist/quota/opencode-go/cache.d.ts.map +1 -0
- package/dist/quota/opencode-go/cache.js +31 -0
- package/dist/quota/opencode-go/cache.js.map +1 -0
- package/dist/quota/opencode-go/client.d.ts +28 -0
- package/dist/quota/opencode-go/client.d.ts.map +1 -0
- package/dist/quota/opencode-go/client.js +48 -0
- package/dist/quota/opencode-go/client.js.map +1 -0
- package/dist/quota/opencode-go/config.d.ts +37 -0
- package/dist/quota/opencode-go/config.d.ts.map +1 -0
- package/dist/quota/opencode-go/config.js +58 -0
- package/dist/quota/opencode-go/config.js.map +1 -0
- package/dist/quota/opencode-go/format.d.ts +36 -0
- package/dist/quota/opencode-go/format.d.ts.map +1 -0
- package/dist/quota/opencode-go/format.js +87 -0
- package/dist/quota/opencode-go/format.js.map +1 -0
- package/dist/quota/opencode-go/index.d.ts +30 -0
- package/dist/quota/opencode-go/index.d.ts.map +1 -0
- package/dist/quota/opencode-go/index.js +108 -0
- package/dist/quota/opencode-go/index.js.map +1 -0
- package/dist/quota/opencode-go/parse.d.ts +41 -0
- package/dist/quota/opencode-go/parse.d.ts.map +1 -0
- package/dist/quota/opencode-go/parse.js +75 -0
- package/dist/quota/opencode-go/parse.js.map +1 -0
- package/dist/quota/opencode-go/types.d.ts +48 -0
- package/dist/quota/opencode-go/types.d.ts.map +1 -0
- package/dist/quota/opencode-go/types.js +11 -0
- package/dist/quota/opencode-go/types.js.map +1 -0
- package/dist/quota/parse.d.ts +33 -0
- package/dist/quota/parse.d.ts.map +1 -0
- package/dist/quota/parse.js +200 -0
- package/dist/quota/parse.js.map +1 -0
- package/dist/quota/types.d.ts +72 -0
- package/dist/quota/types.d.ts.map +1 -0
- package/dist/quota/types.js +10 -0
- package/dist/quota/types.js.map +1 -0
- package/dist/remote/broadcast.d.ts +47 -0
- package/dist/remote/broadcast.d.ts.map +1 -0
- package/dist/remote/broadcast.js +121 -0
- package/dist/remote/broadcast.js.map +1 -0
- package/dist/remote/config.d.ts +32 -0
- package/dist/remote/config.d.ts.map +1 -0
- package/dist/remote/config.js +65 -0
- package/dist/remote/config.js.map +1 -0
- package/dist/remote/endpoint.d.ts +30 -0
- package/dist/remote/endpoint.d.ts.map +1 -0
- package/dist/remote/endpoint.js +213 -0
- package/dist/remote/endpoint.js.map +1 -0
- package/dist/remote/hub-server.d.ts +41 -0
- package/dist/remote/hub-server.d.ts.map +1 -0
- package/dist/remote/hub-server.js +346 -0
- package/dist/remote/hub-server.js.map +1 -0
- package/dist/server.d.ts +139 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +179 -4
- package/dist/server.js.map +1 -1
- package/dist/tasks-index.d.ts +14 -4
- package/dist/tasks-index.d.ts.map +1 -1
- package/dist/tasks-index.js +145 -46
- package/dist/tasks-index.js.map +1 -1
- package/dist/translators/event-translator.d.ts +33 -0
- package/dist/translators/event-translator.d.ts.map +1 -1
- package/dist/translators/event-translator.js +101 -0
- package/dist/translators/event-translator.js.map +1 -1
- package/dist/translators/index.d.ts +1 -1
- package/dist/translators/index.d.ts.map +1 -1
- package/dist/translators/index.js +1 -1
- package/dist/translators/index.js.map +1 -1
- package/dist/translators/projection-differ.d.ts +8 -0
- package/dist/translators/projection-differ.d.ts.map +1 -1
- package/dist/translators/projection-differ.js +19 -9
- package/dist/translators/projection-differ.js.map +1 -1
- package/dist/translators/tool-helpers.d.ts +28 -0
- package/dist/translators/tool-helpers.d.ts.map +1 -1
- package/dist/translators/tool-helpers.js +104 -0
- package/dist/translators/tool-helpers.js.map +1 -1
- package/dist/translators/types.d.ts +38 -1
- package/dist/translators/types.d.ts.map +1 -1
- package/dist/translators/types.js.map +1 -1
- package/dist/utils.d.ts +36 -7
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +69 -5
- package/dist/utils.js.map +1 -1
- package/docs/ARCHITECTURE.md +130 -40
- package/docs/BACKLOG.md +59 -0
- package/docs/DEVELOPMENT.md +31 -0
- package/docs/PROTOCOL.md +328 -23
- package/docs/REMOTE-CLIENTS.md +260 -0
- package/docs/REPLAY-GUIDE.md +131 -0
- package/docs/TROUBLESHOOTING.md +131 -14
- package/docs/adr/0001-bridge-lifetime-follows-primary-client.md +14 -0
- package/docs/adr/0002-stateless-hub-over-per-bridge-acp-endpoints.md +23 -0
- package/docs/adr/0003-tail-replay-meta-and-cursor-pagination.md +40 -0
- package/docs/agents/domain.md +51 -0
- package/docs/agents/issue-tracker.md +22 -0
- package/docs/agents/triage-labels.md +15 -0
- package/docs/proposals/0001-tail-session-replay.md +136 -0
- package/docs/proposals/0002-plan-quota-usage.md +81 -0
- package/package.json +10 -6
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -14,7 +14,7 @@ application-client (Zed / JetBrains)
|
|
|
14
14
|
|
|
|
15
15
|
v
|
|
16
16
|
zcode-acp-server (stdio JSON-RPC ACP)
|
|
17
|
-
|-- handlers/ session, extensions, dispatch, server-requests, io, slash
|
|
17
|
+
|-- handlers/ session, extensions, dispatch, server-requests, io, slash, account
|
|
18
18
|
|-- translators/ event-translator, projection-differ, tool-helpers
|
|
19
19
|
|-- interaction/ adapter
|
|
20
20
|
|-- config/ options, runtime-model, model-cache
|
|
@@ -25,18 +25,58 @@ zcode-acp-server (stdio JSON-RPC ACP)
|
|
|
25
25
|
zcode app-server --stdio (line-delimited JSON)
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
## ACP Handshake
|
|
29
|
+
|
|
30
|
+
The `initialize` request (`server.ts`) negotiates the protocol version and
|
|
31
|
+
declares the agent's shape to the editor:
|
|
32
|
+
|
|
33
|
+
- **`protocolVersion`** — pinned to `PROTOCOL_VERSION` (currently 1).
|
|
34
|
+
- **`agentInfo`** — name/title/version from `AGENT_INFO` in `utils.ts`.
|
|
35
|
+
- **`agentCapabilities`** — `loadSession`, plus `sessionCapabilities.list /
|
|
36
|
+
resume / fork`. The prompt capabilities (image/audio/embeddedContext) and
|
|
37
|
+
MCP capabilities are all off.
|
|
38
|
+
- **`authMethods`** — a single agent-type entry (`zcode-credentials`). The
|
|
39
|
+
bridge reads the GLM API key itself from `~/.zcode/v2/config.json` and
|
|
40
|
+
forwards it to the ZCode subprocess via `ANTHROPIC_API_KEY`; the editor
|
|
41
|
+
never supplies credentials. Omitting the `type` field defaults to `"agent"`,
|
|
42
|
+
which the ACP registry's auth-check accepts as "agent self-handles auth".
|
|
43
|
+
|
|
44
|
+
`initialize` does **not** spawn the backend, and neither does `session/new`:
|
|
45
|
+
the backend is lazily created on the first backend RPC — for a fresh session
|
|
46
|
+
that is the first `session/create` at its first use (prompt / config change /
|
|
47
|
+
extension method). This keeps the handshake succeeding even in an environment
|
|
48
|
+
without `~/.zcode/v2/config.json` (e.g. the registry CI runs `initialize` with
|
|
49
|
+
an isolated `HOME`).
|
|
50
|
+
|
|
51
|
+
Client capabilities advertised at `initialize` are recorded on the server
|
|
52
|
+
(`clientCapabilities`) and drive later behaviour: `supportsElicitationForm()`
|
|
53
|
+
gates form-based elicitation, and `supportsTerminalOutput()` gates Zed's Bash
|
|
54
|
+
terminal UI.
|
|
55
|
+
|
|
28
56
|
## Core Data Flow
|
|
29
57
|
|
|
30
58
|
### 1. Session lifecycle
|
|
31
59
|
|
|
32
60
|
```
|
|
33
|
-
session/new → session
|
|
61
|
+
session/new → placeholder id (backend session NOT created yet)
|
|
62
|
+
|
|
|
63
|
+
first use: prompt / set_config_option / extension method
|
|
64
|
+
|
|
|
65
|
+
session/create → register EventListener
|
|
34
66
|
|
|
|
35
67
|
prompt request → session/send → EventTranslator translates → dispatchEvent
|
|
36
68
|
| |
|
|
37
69
|
end_turn / cancelled session/update notification
|
|
38
70
|
```
|
|
39
71
|
|
|
72
|
+
Sessions are materialized lazily (`ensureRealSession`): an editor startup that
|
|
73
|
+
never sends a message leaves no empty session in the backend or the App's task
|
|
74
|
+
index. The placeholder → backend-session mapping is persisted to
|
|
75
|
+
`~/.zcode/v2/acp-lazy-sessions.json` (`src/lazy-sessions.ts`), so a `session/
|
|
76
|
+
resume` / `session/load` of a placeholder from a previous bridge lifetime still
|
|
77
|
+
resolves: with a recorded backend id the real session is resumed, without one a
|
|
78
|
+
fresh (empty) session is materialized — never "Session not found".
|
|
79
|
+
|
|
40
80
|
### 2. Event stream subscription
|
|
41
81
|
|
|
42
82
|
```
|
|
@@ -52,11 +92,13 @@ pollEvent() consumes → EventTranslator.translate()
|
|
|
52
92
|
### 3. Dual-path event handling
|
|
53
93
|
|
|
54
94
|
#### Real-time path (EventTranslator)
|
|
95
|
+
|
|
55
96
|
- Listens to zcode `session/event` pushes
|
|
56
97
|
- Translates each event to an ACP `session/update` in real time
|
|
57
98
|
- Maintains `seenToolIds` to avoid duplicates
|
|
58
99
|
|
|
59
100
|
#### Snapshot path (ProjectionDiffer)
|
|
101
|
+
|
|
60
102
|
- On turn completion, builds a snapshot from `session/messages` + `session/read`
|
|
61
103
|
- Diffs two snapshots to produce new events (PlanUpdate / TextDelta / ToolCallNew, etc.)
|
|
62
104
|
- Used for turn-completion triage and stall recovery
|
|
@@ -82,6 +124,7 @@ Key: **`seenToolIds` synchronization**
|
|
|
82
124
|
|
|
83
125
|
In `session.ts:629`, after the event path finishes processing, the state is
|
|
84
126
|
synced to the differ:
|
|
127
|
+
|
|
85
128
|
```typescript
|
|
86
129
|
for (const seenId of translator.seenToolIds) {
|
|
87
130
|
differ.markToolSeen(seenId);
|
|
@@ -92,49 +135,96 @@ This ensures the snapshot diff does not re-emit tools already handled by the
|
|
|
92
135
|
event path, preventing Bash terminal output from being overwritten by a
|
|
93
136
|
content-less ToolCallNew.
|
|
94
137
|
|
|
138
|
+
## Data & Privacy
|
|
139
|
+
|
|
140
|
+
**No telemetry, no analytics, no third-party network calls.** The server is a
|
|
141
|
+
local relay: prompts, code, and tool outputs pass through process memory on
|
|
142
|
+
their way between the editor and the ZCode subprocess, but reach the GLM cloud
|
|
143
|
+
API only because the ZCode backend itself sends them for inference.
|
|
144
|
+
|
|
145
|
+
| Concern | Detail |
|
|
146
|
+
| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
147
|
+
| Network | One outbound request in the whole codebase — `src/quota/client.ts` GET to the quota API, Bearer token only, no body |
|
|
148
|
+
| Credentials | API key from `~/.zcode/v2/config.json` (authenticates the subprocess + quota request), never logged. OAuth handled by the ZCode subprocess, not this server |
|
|
149
|
+
| Disk | No new files. Writes only to the existing `~/.zcode/v2/tasks-index.sqlite` — syncs sessions into the ZCode app's history & search (session title + first prompt) |
|
|
150
|
+
| Logging | `log()`/`warn()` → stderr only for troubleshooting; even with `ZCODE_ACP_DEBUG=1`, no prompts/code/keys are logged |
|
|
151
|
+
|
|
95
152
|
## Module Responsibilities
|
|
96
153
|
|
|
97
154
|
### `backend/` — ZCode process communication
|
|
98
155
|
|
|
99
|
-
| File
|
|
100
|
-
|
|
101
|
-
| `client.ts`
|
|
102
|
-
| `listener.ts` | EventStreamListener (subscribe/consume the event stream) and TurnMonitor (snapshot polling)
|
|
103
|
-
| `types.ts`
|
|
156
|
+
| File | Responsibility |
|
|
157
|
+
| ------------- | ----------------------------------------------------------------------------------------------- |
|
|
158
|
+
| `client.ts` | Spawn/manage the zcode subprocess, reader-loop, request/response multiplexing, process watchdog |
|
|
159
|
+
| `listener.ts` | EventStreamListener (subscribe/consume the event stream) and TurnMonitor (snapshot polling) |
|
|
160
|
+
| `types.ts` | ZCode JSON-RPC message type definitions |
|
|
104
161
|
|
|
105
162
|
### `translators/` — Event translation
|
|
106
163
|
|
|
107
|
-
| File
|
|
108
|
-
|
|
109
|
-
| `event-translator.ts`
|
|
110
|
-
| `projection-differ.ts` | Diff two snapshots to produce InternalEvent (snapshot path)
|
|
111
|
-
| `tool-helpers.ts`
|
|
112
|
-
| `types.ts`
|
|
164
|
+
| File | Responsibility |
|
|
165
|
+
| ---------------------- | -------------------------------------------------------------------------------------------------- |
|
|
166
|
+
| `event-translator.ts` | Translate zcode events to InternalEvent (real-time path) |
|
|
167
|
+
| `projection-differ.ts` | Diff two snapshots to produce InternalEvent (snapshot path) |
|
|
168
|
+
| `tool-helpers.ts` | Tool-related pure functions: title generation, output rendering, diff parsing, location extraction |
|
|
169
|
+
| `types.ts` | InternalEvent union type and plan entry builders |
|
|
113
170
|
|
|
114
171
|
### `handlers/` — ACP method handling
|
|
115
172
|
|
|
116
|
-
| File
|
|
117
|
-
|
|
118
|
-
| `session.ts`
|
|
119
|
-
| `extensions.ts`
|
|
120
|
-
| `dispatch.ts`
|
|
121
|
-
| `
|
|
122
|
-
| `
|
|
123
|
-
| `
|
|
173
|
+
| File | Responsibility |
|
|
174
|
+
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
175
|
+
| `session.ts` | session/new/list/resume/load/prompt/set_config_option/cancel |
|
|
176
|
+
| `extensions.ts` | fork/rewind/rewindCascade/goal/compact/steer/cancelBackgroundTask/setModel/setMode/setThoughtLevel |
|
|
177
|
+
| `dispatch.ts` | dispatchEvent single exit point: InternalEvent → ACP session/update |
|
|
178
|
+
| `background-tasks.ts` | Session-scoped `BackgroundTaskListener` — forwards background sub-agent status (`session.updated` taskId) + completion-notification turns to the client OUTSIDE request handlers (lives across prompts) |
|
|
179
|
+
| `server-requests.ts` | Handle zcode interaction/* requests (tool auth, ExitPlanMode, AskUserQuestion), protocol negotiation routing |
|
|
180
|
+
| `io.ts` | ACP notification helpers (including `sendAvailableCommandsDeferred` deferred notification) |
|
|
181
|
+
| `slash.ts` | Interception of `/`-prefixed commands (/compact /goal /fork /rewind /steer /model /mode /thought); non-advertised `/x` prompts are neutralized into plain text (`neutralizeSlashText`) |
|
|
182
|
+
| `account.ts` | `account/usage_stats` — account-level plan quota for remote clients (Proposal 0002; quota pipeline + graceful error) |
|
|
124
183
|
|
|
125
184
|
### `interaction/` — Interaction bridging
|
|
126
185
|
|
|
127
|
-
| File
|
|
128
|
-
|
|
186
|
+
| File | Responsibility |
|
|
187
|
+
| ------------ | ------------------------------------------------------------------------------------------------ |
|
|
129
188
|
| `adapter.ts` | Conversion adapter from zcode interaction requests to ACP (requestPermission + elicitation form) |
|
|
130
189
|
|
|
131
190
|
### `config/` — Configuration management
|
|
132
191
|
|
|
133
|
-
| File
|
|
134
|
-
|
|
135
|
-
| `options.ts`
|
|
136
|
-
| `runtime-model.ts` | runtimeModel overlay construction and application
|
|
137
|
-
| `model-cache.ts`
|
|
192
|
+
| File | Responsibility |
|
|
193
|
+
| ------------------ | -------------------------------------------------------------- |
|
|
194
|
+
| `options.ts` | configOptions / modes construction, set_config_option dispatch |
|
|
195
|
+
| `runtime-model.ts` | runtimeModel overlay construction and application |
|
|
196
|
+
| `model-cache.ts` | Model ID cache and usage initialization |
|
|
197
|
+
|
|
198
|
+
### `remote/` — Remote access (opt-in via `ZCODE_ACP_REMOTE=1`)
|
|
199
|
+
|
|
200
|
+
| File | Responsibility |
|
|
201
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
202
|
+
| `broadcast.ts` | ClientRegistry + broadcast proxy: notify fans out to all clients; request is first-response-wins with loser `$/cancel_request` |
|
|
203
|
+
| `config.ts` | ENV parsing (gate, mandatory token, hub/bridge ports) |
|
|
204
|
+
| `endpoint.ts` | Loopback ACP endpoint (SDK AcpServer transport, port auto-increment) + hub registration/heartbeat |
|
|
205
|
+
| `hub-server.ts` | The hub singleton: token auth, instance discovery, byte-level WS proxying, heartbeat pruning, on-demand `?probe=1` liveness, idle exit, version self-upgrade |
|
|
206
|
+
|
|
207
|
+
When enabled, the same `AgentApp` serves the stdio editor and a loopback
|
|
208
|
+
WebSocket endpoint. Every connection (editor or remote) joins the broadcast
|
|
209
|
+
registry via `trackConnections`, so one turn's notifications reach all clients
|
|
210
|
+
regardless of who prompted. The bridge registers itself with the machine-level
|
|
211
|
+
`zcode-acp-hub` (`bin/hub.ts`), which is the only public entry point and holds
|
|
212
|
+
no session state (see `docs/adr/0002`). The bridge's lifetime still follows the
|
|
213
|
+
stdio client (ADR-0001); the listener is `unref()`'d so remote clients alone
|
|
214
|
+
never keep the process alive.
|
|
215
|
+
|
|
216
|
+
Hub upgrades are self-managing: each heartbeat carries the bridge's package
|
|
217
|
+
version, and a hub that sees a NEWER bridge replies `{ok, restarting}`, exits,
|
|
218
|
+
and is re-spawned by that bridge from its own (upgraded) `dist/` within a few
|
|
219
|
+
seconds. Equal, older, or absent versions never trigger a restart — downgrades
|
|
220
|
+
and mixed-version fleets are fine. Without this handshake a long-lived hub
|
|
221
|
+
would keep running pre-upgrade code until its 10-minute idle exit.
|
|
222
|
+
|
|
223
|
+
Discovery liveness has two layers: the heartbeat TTL (30s, pruned every 5s)
|
|
224
|
+
drops bridges that stopped registering — the fallback for hard kills — and
|
|
225
|
+
`GET /api/instances?probe=1` actively TCP-probes each registered loopback port
|
|
226
|
+
on demand, so a client refresh gets an immediately-honest list with no
|
|
227
|
+
background probing cost.
|
|
138
228
|
|
|
139
229
|
## Key State Machines
|
|
140
230
|
|
|
@@ -222,12 +312,12 @@ mirroring the Python bridge's `_pending_post_notifs` queue +
|
|
|
222
312
|
The session mode can change through four entry points, all of which must
|
|
223
313
|
notify the editor UI:
|
|
224
314
|
|
|
225
|
-
| Trigger
|
|
226
|
-
|
|
227
|
-
| `session/setMode` request
|
|
228
|
-
| `session/set_config_option` (mode)
|
|
229
|
-
| `/mode` slash command
|
|
230
|
-
| In-turn `EnterPlanMode`/`ExitPlanMode` | reconciled at turn completion
|
|
315
|
+
| Trigger | Path | Notifies UI |
|
|
316
|
+
| -------------------------------------- | -------------------------------------------------------------- | :---------: |
|
|
317
|
+
| `session/setMode` request | `extensions.ts:setMode` | yes |
|
|
318
|
+
| `session/set_config_option` (mode) | `session.ts:setConfigOptionHandler` → `emitConfigOptionUpdate` | yes |
|
|
319
|
+
| `/mode` slash command | `slash.ts` → `emitConfigOptionUpdate` | yes |
|
|
320
|
+
| In-turn `EnterPlanMode`/`ExitPlanMode` | reconciled at turn completion | yes |
|
|
231
321
|
|
|
232
322
|
The in-turn path bypasses the bridge entirely, so `prompt()` runs
|
|
233
323
|
`emitModeIfChanged` (`session.ts`) at turn completion: it re-reads the
|
|
@@ -277,12 +367,12 @@ zcode process exits, so a normal shutdown leaves no lingering watchdog.
|
|
|
277
367
|
|
|
278
368
|
### Why a dual path?
|
|
279
369
|
|
|
280
|
-
| Scenario
|
|
281
|
-
|
|
282
|
-
| Normal streaming
|
|
283
|
-
| Lost events
|
|
284
|
-
| Deduplication
|
|
285
|
-
| Turn-completion triage | Not triggered
|
|
370
|
+
| Scenario | Real-time path | Snapshot path |
|
|
371
|
+
| ---------------------- | -------------- | ------------------------------- |
|
|
372
|
+
| Normal streaming | Low latency | Must wait for turn end |
|
|
373
|
+
| Lost events | Loses data | Recovers from snapshot |
|
|
374
|
+
| Deduplication | seenToolIds | seenMessageIds + markToolSeen() |
|
|
375
|
+
| Turn-completion triage | Not triggered | PlanUpdate / usage_update |
|
|
286
376
|
|
|
287
377
|
### Why no polling fallback?
|
|
288
378
|
|
package/docs/BACKLOG.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Protocol Backlog
|
|
2
|
+
|
|
3
|
+
Backend RPC methods and event types exposed by the ZCode CLI (`zcode app-server`)
|
|
4
|
+
that are **not yet wired into the bridge**, tracked for potential future support.
|
|
5
|
+
|
|
6
|
+
Last audited against **app-server 0.15.2** (bundled in ZCode desktop 3.4.2,
|
|
7
|
+
2026-07-22). Method names were extracted from the bundled `zcode.cjs`.
|
|
8
|
+
|
|
9
|
+
## Candidate methods (optional enhancements)
|
|
10
|
+
|
|
11
|
+
These are available in the backend but have no ACP-side counterpart yet. Pick
|
|
12
|
+
them up when a concrete ACP/editor need appears.
|
|
13
|
+
|
|
14
|
+
| Method | Purpose | Current bridge behavior |
|
|
15
|
+
|--------|---------|-------------------------|
|
|
16
|
+
| `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 |
|
|
17
|
+
| `session/events` | Pull-mode event history (complement to `session/subscribe`) | Not used; could support event replay/gap-fill |
|
|
18
|
+
| `session/usage` | Per-session token usage | Context bar uses `session.updated` usage payload instead |
|
|
19
|
+
| `session/close` | Explicitly close a session (vs `session/stop` which ends a turn) | Not used; sessions close on process exit |
|
|
20
|
+
|
|
21
|
+
### New event types (undocumented in PROTOCOL.md)
|
|
22
|
+
|
|
23
|
+
| Event | Status field | Notes |
|
|
24
|
+
|-------|--------------|-------|
|
|
25
|
+
| `turn.steerQueued` | — | Emitted when a `session/steer` is queued behind a running turn. Enhances steer UI feedback |
|
|
26
|
+
| `turn.steerDrained` | — | Emitted when queued steer instructions are drained into the turn |
|
|
27
|
+
| `turn.terminal` | `status: success \| interrupted \| failed`, `resultType?`, `durationMs`, `...usage` | Terminal turn lifecycle event; currently the bridge relies on `turn.completed`/`turn.failed` |
|
|
28
|
+
|
|
29
|
+
## Not planned (client/config layer)
|
|
30
|
+
|
|
31
|
+
These methods belong to the desktop client or workspace configuration layer and
|
|
32
|
+
have no ACP equivalent. Listed for completeness only — the bridge does not
|
|
33
|
+
intend to surface them.
|
|
34
|
+
|
|
35
|
+
`automation/create`, `automation/list`, `automation/delete` (scheduled tasks),
|
|
36
|
+
`usage/stats` (token analytics; the account-level plan quota it does NOT cover
|
|
37
|
+
is exposed via the bridge's own `account/usage_stats` — see Proposal 0002),
|
|
38
|
+
`workspace/readState`, `workspace/upsertModelProvider`,
|
|
39
|
+
`workspace/removeModelProvider`, `workspace/updateProviderRegistry`,
|
|
40
|
+
`workspace/setDefaultModel`, `workspace/setDefaultThoughtLevel`,
|
|
41
|
+
`workspace/setDefaultMode`, `workspace/generateText`, `mcp/list`,
|
|
42
|
+
`plugins/list`, `plugins/setEnabled`, `plugins/overview`, `plugins/describe`,
|
|
43
|
+
`plugins/marketplace/*`.
|
|
44
|
+
|
|
45
|
+
## Verification method
|
|
46
|
+
|
|
47
|
+
The bundled CLI is minified, so a literal `grep "session/rewind"` returns 0
|
|
48
|
+
hits even when the method is fully supported — method names are split across
|
|
49
|
+
variable references. To audit reliably:
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
cd /Applications/ZCode.app/Contents/Resources/glm
|
|
53
|
+
# Full RPC enum: search for the method-dispatch table (Key:"ns/name" pairs)
|
|
54
|
+
python3 -c "import re; ..." # see commit that added this file
|
|
55
|
+
# Word-level presence is more reliable for verifying a method still exists:
|
|
56
|
+
grep -oiF "rewind" zcode.cjs | wc -l # 357 → definitely present
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Never conclude a method was removed from a single string-literal search.
|
package/docs/DEVELOPMENT.md
CHANGED
|
@@ -90,6 +90,32 @@ describe("backend", () => {
|
|
|
90
90
|
});
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
+
### Method 4: Remote access (hub + endpoint)
|
|
94
|
+
|
|
95
|
+
Run the bridge with the remote env vars on scratch ports (keep stdin open —
|
|
96
|
+
the bridge exits when its stdio client disconnects):
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
ZCODE_ACP_REMOTE=1 \
|
|
100
|
+
ZCODE_ACP_REMOTE_TOKEN=dev-token \
|
|
101
|
+
ZCODE_ACP_HUB_PORT=18377 \
|
|
102
|
+
ZCODE_ACP_REMOTE_PORT=18378 \
|
|
103
|
+
ZCODE_ACP_DEBUG=1 \
|
|
104
|
+
tail -f /dev/null | node dist/index.js
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The first bridge spawns `dist/bin/hub.js` on its own. Verify discovery:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
curl -H "Authorization: Bearer dev-token" http://127.0.0.1:18377/api/instances
|
|
111
|
+
curl -H "Authorization: Bearer dev-token" "http://127.0.0.1:18377/api/instances?probe=1"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Integration tests live in `tests/hub.test.ts` (hub API, probe, proxy, idle
|
|
115
|
+
exit) and `tests/remote-endpoint.test.ts` (registration + end-to-end proxied
|
|
116
|
+
initialize). The remote features are opt-in and self-contained — remote
|
|
117
|
+
failures warn and disable remote only, so stdio testing works without them.
|
|
118
|
+
|
|
93
119
|
## Debugging Tips
|
|
94
120
|
|
|
95
121
|
### Enable verbose logging
|
|
@@ -117,6 +143,11 @@ cat ~/.zcode/v2/config.json
|
|
|
117
143
|
# confirm a provider is enabled and has models
|
|
118
144
|
```
|
|
119
145
|
|
|
146
|
+
The bridge reads the GLM API key from this file and forwards it to the ZCode
|
|
147
|
+
subprocess — no editor-side API key or environment variable is required. If
|
|
148
|
+
`config.json` is missing or no provider is enabled, install and log into the
|
|
149
|
+
ZCode desktop app so it writes a valid file.
|
|
150
|
+
|
|
120
151
|
### Test session/subscribe
|
|
121
152
|
|
|
122
153
|
```bash
|