zcode-acp-server 0.1.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/LICENSE +201 -0
- package/README.md +167 -0
- package/README.zh-CN.md +163 -0
- package/dist/backend/client.d.ts +103 -0
- package/dist/backend/client.d.ts.map +1 -0
- package/dist/backend/client.js +344 -0
- package/dist/backend/client.js.map +1 -0
- package/dist/backend/credentials.d.ts +31 -0
- package/dist/backend/credentials.d.ts.map +1 -0
- package/dist/backend/credentials.js +93 -0
- package/dist/backend/credentials.js.map +1 -0
- package/dist/backend/index.d.ts +7 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +6 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/listener.d.ts +63 -0
- package/dist/backend/listener.d.ts.map +1 -0
- package/dist/backend/listener.js +138 -0
- package/dist/backend/listener.js.map +1 -0
- package/dist/backend/resolve.d.ts +11 -0
- package/dist/backend/resolve.d.ts.map +1 -0
- package/dist/backend/resolve.js +116 -0
- package/dist/backend/resolve.js.map +1 -0
- package/dist/backend/types.d.ts +164 -0
- package/dist/backend/types.d.ts.map +1 -0
- package/dist/backend/types.js +15 -0
- package/dist/backend/types.js.map +1 -0
- package/dist/config/model-cache.d.ts +20 -0
- package/dist/config/model-cache.d.ts.map +1 -0
- package/dist/config/model-cache.js +62 -0
- package/dist/config/model-cache.js.map +1 -0
- package/dist/config/options.d.ts +36 -0
- package/dist/config/options.d.ts.map +1 -0
- package/dist/config/options.js +171 -0
- package/dist/config/options.js.map +1 -0
- package/dist/config/runtime-model.d.ts +33 -0
- package/dist/config/runtime-model.d.ts.map +1 -0
- package/dist/config/runtime-model.js +96 -0
- package/dist/config/runtime-model.js.map +1 -0
- package/dist/handlers/dispatch.d.ts +15 -0
- package/dist/handlers/dispatch.d.ts.map +1 -0
- package/dist/handlers/dispatch.js +183 -0
- package/dist/handlers/dispatch.js.map +1 -0
- package/dist/handlers/extensions.d.ts +43 -0
- package/dist/handlers/extensions.d.ts.map +1 -0
- package/dist/handlers/extensions.js +310 -0
- package/dist/handlers/extensions.js.map +1 -0
- package/dist/handlers/io.d.ts +40 -0
- package/dist/handlers/io.d.ts.map +1 -0
- package/dist/handlers/io.js +55 -0
- package/dist/handlers/io.js.map +1 -0
- package/dist/handlers/server-requests.d.ts +34 -0
- package/dist/handlers/server-requests.d.ts.map +1 -0
- package/dist/handlers/server-requests.js +357 -0
- package/dist/handlers/server-requests.js.map +1 -0
- package/dist/handlers/session.d.ts +46 -0
- package/dist/handlers/session.d.ts.map +1 -0
- package/dist/handlers/session.js +738 -0
- package/dist/handlers/session.js.map +1 -0
- package/dist/handlers/slash.d.ts +16 -0
- package/dist/handlers/slash.d.ts.map +1 -0
- package/dist/handlers/slash.js +107 -0
- package/dist/handlers/slash.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction/adapter.d.ts +136 -0
- package/dist/interaction/adapter.d.ts.map +1 -0
- package/dist/interaction/adapter.js +353 -0
- package/dist/interaction/adapter.js.map +1 -0
- package/dist/server.d.ts +73 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +97 -0
- package/dist/server.js.map +1 -0
- package/dist/tasks-index.d.ts +39 -0
- package/dist/tasks-index.d.ts.map +1 -0
- package/dist/tasks-index.js +152 -0
- package/dist/tasks-index.js.map +1 -0
- package/dist/translators/event-translator.d.ts +40 -0
- package/dist/translators/event-translator.d.ts.map +1 -0
- package/dist/translators/event-translator.js +214 -0
- package/dist/translators/event-translator.js.map +1 -0
- package/dist/translators/index.d.ts +6 -0
- package/dist/translators/index.d.ts.map +1 -0
- package/dist/translators/index.js +5 -0
- package/dist/translators/index.js.map +1 -0
- package/dist/translators/projection-differ.d.ts +48 -0
- package/dist/translators/projection-differ.d.ts.map +1 -0
- package/dist/translators/projection-differ.js +239 -0
- package/dist/translators/projection-differ.js.map +1 -0
- package/dist/translators/tool-helpers.d.ts +60 -0
- package/dist/translators/tool-helpers.d.ts.map +1 -0
- package/dist/translators/tool-helpers.js +308 -0
- package/dist/translators/tool-helpers.js.map +1 -0
- package/dist/translators/types.d.ts +58 -0
- package/dist/translators/types.d.ts.map +1 -0
- package/dist/translators/types.js +27 -0
- package/dist/translators/types.js.map +1 -0
- package/dist/utils.d.ts +111 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +110 -0
- package/dist/utils.js.map +1 -0
- package/docs/ARCHITECTURE.md +299 -0
- package/docs/DEVELOPMENT.md +193 -0
- package/docs/PROTOCOL.md +649 -0
- package/docs/TROUBLESHOOTING.md +251 -0
- package/package.json +66 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ZCode subprocess client: spawn, read-loop multiplexer, async request/response.
|
|
3
|
+
*
|
|
4
|
+
* The ZCode app-server is launched as a subprocess (`zcode app-server --stdio`)
|
|
5
|
+
* speaking line-delimited JSON over stdio. A single async read loop demultiplexes
|
|
6
|
+
* inbound messages into three channels:
|
|
7
|
+
* - responses (id, no method) → resolve the matching pending request promise
|
|
8
|
+
* - server→client requests (id + method, id not pending) → server-request queue
|
|
9
|
+
* - notifications (no id):
|
|
10
|
+
* - `session/event` → routed to the registered session listener
|
|
11
|
+
* - anything else → general notification queue
|
|
12
|
+
*
|
|
13
|
+
* Process-group isolation: the subprocess is its own process-group leader
|
|
14
|
+
* (`detached: true`) so `close()` can kill the whole tree (zcode + its model
|
|
15
|
+
* workers) with `process.kill(-pid)` and leave no orphans.
|
|
16
|
+
*/
|
|
17
|
+
import { spawn } from "node:child_process";
|
|
18
|
+
import { createInterface } from "node:readline";
|
|
19
|
+
import process from "node:process";
|
|
20
|
+
import { log, warn } from "../utils.js";
|
|
21
|
+
export class ZcodeBackend {
|
|
22
|
+
proc;
|
|
23
|
+
pending = new Map();
|
|
24
|
+
serverRequests = [];
|
|
25
|
+
listeners = new Map();
|
|
26
|
+
readerDead = false;
|
|
27
|
+
/** Monotonic id for fire-and-forget sends (send()). Uses a high range to
|
|
28
|
+
* avoid collisions with the server's request ids (low range). */
|
|
29
|
+
sendIdCounter = 1_000_000_000;
|
|
30
|
+
/** Watchdog process that kills the zcode group if this bridge dies (SIGKILL). */
|
|
31
|
+
watchdog = null;
|
|
32
|
+
constructor(argv, env) {
|
|
33
|
+
this.proc = spawn(argv[0], argv.slice(1), {
|
|
34
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
35
|
+
env,
|
|
36
|
+
detached: true, // own process group → kill(-pid) reaps the whole tree
|
|
37
|
+
});
|
|
38
|
+
// Node stream write errors (EPIPE on a closed stdin) are emitted as async
|
|
39
|
+
// 'error' events, NOT thrown synchronously — without a listener the process
|
|
40
|
+
// crashes with an unhandled 'error' event. Catch them here and mark the
|
|
41
|
+
// reader dead so the rest of the bridge stops talking to a gone backend.
|
|
42
|
+
this.proc.stdin?.on("error", (err) => {
|
|
43
|
+
this.readerDead = true;
|
|
44
|
+
warn(`backend: stdin error: ${err.message}`);
|
|
45
|
+
});
|
|
46
|
+
this.startReader();
|
|
47
|
+
this.startWatchdog();
|
|
48
|
+
log(`backend: started zcode app-server (pid=${this.proc.pid})`);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Spawn a tiny detached watchdog that kills the zcode process group if this
|
|
52
|
+
* bridge process disappears.
|
|
53
|
+
*
|
|
54
|
+
* The detached/kill(-pid) cleanup in `close()` only runs when the bridge
|
|
55
|
+
* exits cleanly enough for the signal handlers to fire (SIGTERM/SIGINT/etc).
|
|
56
|
+
* If the bridge is SIGKILLed (Zed force-kill on reconnect, crash, OOM), the
|
|
57
|
+
* handler never runs and the zcode subprocess group is orphaned. The
|
|
58
|
+
* watchdog closes that gap: it polls the bridge pid every 2s and, once the
|
|
59
|
+
* bridge is gone, sends SIGKILL to the zcode process group, then exits.
|
|
60
|
+
*
|
|
61
|
+
* The watchdog is its own process-group leader (detached) and `unref`'d, so
|
|
62
|
+
* it never holds the event loop open and is not part of the zcode group it
|
|
63
|
+
* kills. It self-terminates as soon as the zcode process exits, so a normal
|
|
64
|
+
* shutdown leaves no lingering watchdog.
|
|
65
|
+
*/
|
|
66
|
+
startWatchdog() {
|
|
67
|
+
const bridgePid = process.pid;
|
|
68
|
+
const zcodePid = this.proc.pid;
|
|
69
|
+
if (!bridgePid || !zcodePid)
|
|
70
|
+
return;
|
|
71
|
+
// Inline script: poll bridge liveness, kill zcode group on bridge death.
|
|
72
|
+
const script = `
|
|
73
|
+
const bridgePid = ${bridgePid};
|
|
74
|
+
const zcodePid = ${zcodePid};
|
|
75
|
+
const tick = () => {
|
|
76
|
+
// Bridge gone? → reap the whole zcode process group, then exit.
|
|
77
|
+
try { process.kill(bridgePid, 0); }
|
|
78
|
+
catch {
|
|
79
|
+
try { process.kill(-zcodePid, 'SIGKILL'); } catch {}
|
|
80
|
+
process.exit(0);
|
|
81
|
+
}
|
|
82
|
+
// zcode already exited? → watchdog has no job left.
|
|
83
|
+
try { process.kill(-zcodePid, 0); }
|
|
84
|
+
catch { process.exit(0); }
|
|
85
|
+
};
|
|
86
|
+
setInterval(tick, 2000);
|
|
87
|
+
tick();
|
|
88
|
+
`;
|
|
89
|
+
this.watchdog = spawn(process.execPath, ["-e", script], {
|
|
90
|
+
stdio: "ignore",
|
|
91
|
+
detached: true, // own process group, not part of the zcode group
|
|
92
|
+
});
|
|
93
|
+
this.watchdog.unref();
|
|
94
|
+
}
|
|
95
|
+
// ---------- read loop ----------
|
|
96
|
+
startReader() {
|
|
97
|
+
const stdout = this.proc.stdout;
|
|
98
|
+
if (!stdout) {
|
|
99
|
+
this.markReaderDead("no stdout");
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const rl = createInterface({ input: stdout });
|
|
103
|
+
rl.on("line", (line) => {
|
|
104
|
+
const trimmed = line.trim();
|
|
105
|
+
if (!trimmed)
|
|
106
|
+
return;
|
|
107
|
+
let msg;
|
|
108
|
+
try {
|
|
109
|
+
msg = JSON.parse(trimmed);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return; // unparseable line: ignore
|
|
113
|
+
}
|
|
114
|
+
this.route(msg);
|
|
115
|
+
});
|
|
116
|
+
rl.on("close", () => this.markReaderDead("stdout closed"));
|
|
117
|
+
}
|
|
118
|
+
route(msg) {
|
|
119
|
+
const method = msg.method;
|
|
120
|
+
const id = msg.id;
|
|
121
|
+
if (id !== undefined && method === undefined) {
|
|
122
|
+
// Response (id, no method) → resolve pending request.
|
|
123
|
+
this.resolvePending(id, msg);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (id !== undefined && method !== undefined) {
|
|
127
|
+
// id + method: our pending response wins the race; else it's a server→client request.
|
|
128
|
+
if (this.pending.has(id)) {
|
|
129
|
+
this.resolvePending(id, msg);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
this.serverRequests.push({
|
|
133
|
+
id,
|
|
134
|
+
method,
|
|
135
|
+
params: (msg.params ?? {}),
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (method !== undefined) {
|
|
141
|
+
// Notification.
|
|
142
|
+
if (method === "session/event") {
|
|
143
|
+
const ev = (msg.params ?? {});
|
|
144
|
+
const sid = ev.sessionId;
|
|
145
|
+
const listener = sid ? this.listeners.get(sid) : undefined;
|
|
146
|
+
listener?.handleEvent(ev);
|
|
147
|
+
}
|
|
148
|
+
// Other notifications are currently ignored (state.updated, etc.).
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
resolvePending(id, resp) {
|
|
152
|
+
const p = this.pending.get(id);
|
|
153
|
+
if (!p)
|
|
154
|
+
return;
|
|
155
|
+
clearTimeout(p.timer);
|
|
156
|
+
this.pending.delete(id);
|
|
157
|
+
p.resolve(resp);
|
|
158
|
+
}
|
|
159
|
+
markReaderDead(reason) {
|
|
160
|
+
if (this.readerDead)
|
|
161
|
+
return;
|
|
162
|
+
this.readerDead = true;
|
|
163
|
+
warn(`backend: reader exited (${reason})`);
|
|
164
|
+
for (const [, p] of this.pending) {
|
|
165
|
+
clearTimeout(p.timer);
|
|
166
|
+
p.resolve({
|
|
167
|
+
id: 0,
|
|
168
|
+
error: { message: "zcode backend reader exited (backend dead)" },
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
this.pending.clear();
|
|
172
|
+
}
|
|
173
|
+
// ---------- listeners / server requests ----------
|
|
174
|
+
registerEventListener(zcodeSid, listener) {
|
|
175
|
+
this.listeners.set(zcodeSid, listener);
|
|
176
|
+
}
|
|
177
|
+
unregisterEventListener(zcodeSid) {
|
|
178
|
+
this.listeners.delete(zcodeSid);
|
|
179
|
+
}
|
|
180
|
+
/** Non-blocking drain of pending server→client requests. */
|
|
181
|
+
pollServerRequests() {
|
|
182
|
+
if (this.serverRequests.length === 0)
|
|
183
|
+
return [];
|
|
184
|
+
return this.serverRequests.splice(0, this.serverRequests.length);
|
|
185
|
+
}
|
|
186
|
+
/** Reply to a zcode server→client request with a result (id + result). */
|
|
187
|
+
sendReply(id, result) {
|
|
188
|
+
const stdin = this.proc.stdin;
|
|
189
|
+
if (!stdin || stdin.destroyed) {
|
|
190
|
+
warn("backend: sendReply dropped (stdin closed)");
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
// Write errors (EPIPE) are delivered via the stdin 'error' listener
|
|
194
|
+
// installed in the constructor (synchronous try/catch cannot catch them);
|
|
195
|
+
// no try/catch needed here.
|
|
196
|
+
stdin.write(JSON.stringify({ id, result }) + "\n");
|
|
197
|
+
}
|
|
198
|
+
/** Reply to a zcode server→client request with an error. */
|
|
199
|
+
sendError(id, code, message) {
|
|
200
|
+
const stdin = this.proc.stdin;
|
|
201
|
+
if (!stdin || stdin.destroyed) {
|
|
202
|
+
warn("backend: sendError dropped (stdin closed)");
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
stdin.write(JSON.stringify({ id, error: { code, message } }) + "\n");
|
|
206
|
+
}
|
|
207
|
+
// ---------- send / request ----------
|
|
208
|
+
/** Fire-and-forget notification to ZCode (no id, no response). */
|
|
209
|
+
notify(method, params) {
|
|
210
|
+
const stdin = this.proc.stdin;
|
|
211
|
+
if (!stdin || stdin.destroyed) {
|
|
212
|
+
warn("backend: notify dropped (stdin closed)");
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
stdin.write(JSON.stringify({ method, params }) + "\n");
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Send a message with an id but WITHOUT registering a pending response
|
|
219
|
+
* (fire-and-forget). Mirrors Python's `_backend.send({"id": ..., ...})` for
|
|
220
|
+
* `session/stop`: some backends route by id presence, so carrying an id is
|
|
221
|
+
* more robust than a bare notify. If the backend replies, the reader's
|
|
222
|
+
* `resolvePending` finds no pending entry and safely discards it.
|
|
223
|
+
*/
|
|
224
|
+
send(method, params) {
|
|
225
|
+
const stdin = this.proc.stdin;
|
|
226
|
+
if (!stdin || stdin.destroyed) {
|
|
227
|
+
warn("backend: send dropped (stdin closed)");
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const id = this.sendIdCounter++;
|
|
231
|
+
stdin.write(JSON.stringify({ id, method, params: params ?? {} }) + "\n");
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Synchronous request/response: register a pending promise, send, await.
|
|
235
|
+
* Other notifications arriving during the wait are routed async by the
|
|
236
|
+
* reader loop (they don't get swallowed).
|
|
237
|
+
*
|
|
238
|
+
* Returns `{error}` on dead backend, broken pipe, or timeout — never throws.
|
|
239
|
+
*/
|
|
240
|
+
async request(id, method, params, timeoutMs = 30000) {
|
|
241
|
+
if (this.readerDead) {
|
|
242
|
+
return { id, error: { message: "zcode backend reader exited (backend dead)" } };
|
|
243
|
+
}
|
|
244
|
+
const promise = new Promise((resolve) => {
|
|
245
|
+
const timer = setTimeout(() => {
|
|
246
|
+
if (this.pending.delete(id)) {
|
|
247
|
+
resolve({ id, error: { message: "timeout" } });
|
|
248
|
+
}
|
|
249
|
+
}, timeoutMs);
|
|
250
|
+
this.pending.set(id, { resolve, timer });
|
|
251
|
+
});
|
|
252
|
+
try {
|
|
253
|
+
const stdin = this.proc.stdin;
|
|
254
|
+
if (!stdin || stdin.destroyed)
|
|
255
|
+
throw new Error("stdin closed");
|
|
256
|
+
stdin.write(JSON.stringify({ id, method, params: params ?? {} }) + "\n");
|
|
257
|
+
}
|
|
258
|
+
catch (e) {
|
|
259
|
+
this.pending.delete(id);
|
|
260
|
+
this.readerDead = true;
|
|
261
|
+
return {
|
|
262
|
+
id,
|
|
263
|
+
error: {
|
|
264
|
+
message: `zcode backend pipe broken: ${e instanceof Error ? e.message : String(e)}`,
|
|
265
|
+
},
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
return promise;
|
|
269
|
+
}
|
|
270
|
+
// ---------- lifecycle ----------
|
|
271
|
+
/**
|
|
272
|
+
* Kill the whole zcode process group and wait for it to die.
|
|
273
|
+
*
|
|
274
|
+
* SIGTERM → wait up to 3s → SIGKILL if still alive. Mirrors the Python
|
|
275
|
+
* `os.killpg` + `proc.wait(3)` + SIGKILL escalation. Note `proc.killed` is
|
|
276
|
+
* NOT set by `process.kill(-pid)` (group signal), so we track liveness via
|
|
277
|
+
* `exitCode === null` instead. Async so the caller can `await` a full reap
|
|
278
|
+
* before the parent exits (an unref'd timer could be skipped on fast exit,
|
|
279
|
+
* leaving orphans).
|
|
280
|
+
*/
|
|
281
|
+
async close() {
|
|
282
|
+
const proc = this.proc;
|
|
283
|
+
if (!proc.pid)
|
|
284
|
+
return;
|
|
285
|
+
try {
|
|
286
|
+
// Already exited?
|
|
287
|
+
if (proc.exitCode !== null || proc.signalCode)
|
|
288
|
+
return;
|
|
289
|
+
try {
|
|
290
|
+
process.kill(-proc.pid, "SIGTERM");
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
return; // group already gone
|
|
294
|
+
}
|
|
295
|
+
// Wait up to 3s for a clean exit.
|
|
296
|
+
const exited = await new Promise((resolve) => {
|
|
297
|
+
let timer;
|
|
298
|
+
const done = () => {
|
|
299
|
+
clearTimeout(timer); // don't let the timeout keep the event loop alive
|
|
300
|
+
resolve(true);
|
|
301
|
+
};
|
|
302
|
+
proc.once("exit", done);
|
|
303
|
+
timer = setTimeout(() => {
|
|
304
|
+
proc.removeListener("exit", done);
|
|
305
|
+
resolve(false);
|
|
306
|
+
}, 3000);
|
|
307
|
+
});
|
|
308
|
+
if (exited)
|
|
309
|
+
return;
|
|
310
|
+
// Still alive → SIGKILL the whole group.
|
|
311
|
+
try {
|
|
312
|
+
if (proc.pid && proc.exitCode === null)
|
|
313
|
+
process.kill(-proc.pid, "SIGKILL");
|
|
314
|
+
}
|
|
315
|
+
catch {
|
|
316
|
+
// already gone
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
finally {
|
|
320
|
+
// Stop the watchdog — it would self-exit on its next tick once the zcode
|
|
321
|
+
// group is gone, but killing it here avoids the up-to-2s delay.
|
|
322
|
+
this.killWatchdog();
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
/** Terminate the watchdog process if it is still running. */
|
|
326
|
+
killWatchdog() {
|
|
327
|
+
const wd = this.watchdog;
|
|
328
|
+
if (!wd)
|
|
329
|
+
return;
|
|
330
|
+
this.watchdog = null;
|
|
331
|
+
if (wd.pid && wd.exitCode === null) {
|
|
332
|
+
try {
|
|
333
|
+
process.kill(wd.pid, "SIGTERM");
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
// already gone
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
get isDead() {
|
|
341
|
+
return this.readerDead;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/backend/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ZCode credential and environment handling.
|
|
3
|
+
*
|
|
4
|
+
* Vendored from the reference Python implementation so this package stays
|
|
5
|
+
* self-contained. The ZCode desktop app stores provider credentials in
|
|
6
|
+
* `~/.zcode/v2/config.json`; GUI-launched processes don't inherit shell env
|
|
7
|
+
* vars, so we read the config and inject the active provider's settings into
|
|
8
|
+
* the subprocess environment.
|
|
9
|
+
*/
|
|
10
|
+
/** Credentials extracted from the active provider. */
|
|
11
|
+
export interface ZcodeCredentials {
|
|
12
|
+
ZCODE_MODEL?: string;
|
|
13
|
+
ZCODE_BASE_URL?: string;
|
|
14
|
+
ANTHROPIC_API_KEY?: string;
|
|
15
|
+
}
|
|
16
|
+
/** Read the active provider's credentials from config.json. Best-effort. */
|
|
17
|
+
export declare function loadZcodeCredentials(): ZcodeCredentials;
|
|
18
|
+
/**
|
|
19
|
+
* Merge process.env with config credentials.
|
|
20
|
+
*
|
|
21
|
+
* Explicit non-empty env vars override config (so `ZCODE_MODEL=foo` works as a
|
|
22
|
+
* temporary override). Empty-string env vars are treated as unset so they
|
|
23
|
+
* don't clobber the config value.
|
|
24
|
+
*
|
|
25
|
+
* Also self-heals a stale `ZCODE_BASE_URL`: if the env value is the endpoint
|
|
26
|
+
* of a *different* provider in config (a leftover from switching plans in the
|
|
27
|
+
* App), revert to the enabled provider's URL. User-defined custom endpoints
|
|
28
|
+
* are respected.
|
|
29
|
+
*/
|
|
30
|
+
export declare function mergeEnvWithCreds(creds: ZcodeCredentials): NodeJS.ProcessEnv;
|
|
31
|
+
//# sourceMappingURL=credentials.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/backend/credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAkBH,sDAAsD;AACtD,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,4EAA4E;AAC5E,wBAAgB,oBAAoB,IAAI,gBAAgB,CAoBvD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAAC,UAAU,CAuB5E"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ZCode credential and environment handling.
|
|
3
|
+
*
|
|
4
|
+
* Vendored from the reference Python implementation so this package stays
|
|
5
|
+
* self-contained. The ZCode desktop app stores provider credentials in
|
|
6
|
+
* `~/.zcode/v2/config.json`; GUI-launched processes don't inherit shell env
|
|
7
|
+
* vars, so we read the config and inject the active provider's settings into
|
|
8
|
+
* the subprocess environment.
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync } from "node:fs";
|
|
11
|
+
import process from "node:process";
|
|
12
|
+
import { log, ZCODE_CREDS_PATH } from "../utils.js";
|
|
13
|
+
/** Read the active provider's credentials from config.json. Best-effort. */
|
|
14
|
+
export function loadZcodeCredentials() {
|
|
15
|
+
try {
|
|
16
|
+
const cfg = JSON.parse(readFileSync(ZCODE_CREDS_PATH, "utf8"));
|
|
17
|
+
for (const [, p] of Object.entries(cfg.provider ?? {})) {
|
|
18
|
+
if (p?.enabled) {
|
|
19
|
+
const opts = p.options ?? {};
|
|
20
|
+
const models = p.models ?? {};
|
|
21
|
+
return {
|
|
22
|
+
ZCODE_MODEL: Object.keys(models)[0] ?? "GLM-5.2",
|
|
23
|
+
ZCODE_BASE_URL: opts.baseURL ?? "",
|
|
24
|
+
ANTHROPIC_API_KEY: opts.apiKey ?? "",
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
log(`credentials: failed to read ${ZCODE_CREDS_PATH}: ${e instanceof Error ? e.message : String(e)}`);
|
|
31
|
+
}
|
|
32
|
+
return {};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Merge process.env with config credentials.
|
|
36
|
+
*
|
|
37
|
+
* Explicit non-empty env vars override config (so `ZCODE_MODEL=foo` works as a
|
|
38
|
+
* temporary override). Empty-string env vars are treated as unset so they
|
|
39
|
+
* don't clobber the config value.
|
|
40
|
+
*
|
|
41
|
+
* Also self-heals a stale `ZCODE_BASE_URL`: if the env value is the endpoint
|
|
42
|
+
* of a *different* provider in config (a leftover from switching plans in the
|
|
43
|
+
* App), revert to the enabled provider's URL. User-defined custom endpoints
|
|
44
|
+
* are respected.
|
|
45
|
+
*/
|
|
46
|
+
export function mergeEnvWithCreds(creds) {
|
|
47
|
+
const merged = { ...process.env, ...creds };
|
|
48
|
+
for (const k of ["ZCODE_MODEL", "ZCODE_BASE_URL", "ANTHROPIC_API_KEY"]) {
|
|
49
|
+
const v = process.env[k];
|
|
50
|
+
if (v)
|
|
51
|
+
merged[k] = v;
|
|
52
|
+
}
|
|
53
|
+
// Stale-baseURL self-heal.
|
|
54
|
+
const envBu = process.env.ZCODE_BASE_URL ?? "";
|
|
55
|
+
const configBu = creds.ZCODE_BASE_URL ?? "";
|
|
56
|
+
if (envBu && configBu && envBu !== configBu) {
|
|
57
|
+
const allHosts = collectProviderHosts();
|
|
58
|
+
const envHost = hostOf(envBu);
|
|
59
|
+
const configHost = hostOf(configBu);
|
|
60
|
+
if (envHost && configHost && envHost !== configHost && allHosts.has(envHost)) {
|
|
61
|
+
merged.ZCODE_BASE_URL = configBu;
|
|
62
|
+
log(`credentials: ZCODE_BASE_URL stale-host detected (env='${envBu}' is another ` +
|
|
63
|
+
`provider's endpoint); reverted to config='${configBu}'.`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return merged;
|
|
67
|
+
}
|
|
68
|
+
function collectProviderHosts() {
|
|
69
|
+
const hosts = new Set();
|
|
70
|
+
try {
|
|
71
|
+
const cfg = JSON.parse(readFileSync(ZCODE_CREDS_PATH, "utf8"));
|
|
72
|
+
for (const p of Object.values(cfg.provider ?? {})) {
|
|
73
|
+
const bu = p?.options?.baseURL ?? "";
|
|
74
|
+
const h = hostOf(bu);
|
|
75
|
+
if (h)
|
|
76
|
+
hosts.add(h);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// ignore — stale detection just degrades gracefully
|
|
81
|
+
}
|
|
82
|
+
return hosts;
|
|
83
|
+
}
|
|
84
|
+
function hostOf(url) {
|
|
85
|
+
try {
|
|
86
|
+
const u = new URL(url);
|
|
87
|
+
return `${u.protocol}//${u.host}`;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/backend/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Backend layer barrel: ZCode subprocess client + listener + resolve + credentials. */
|
|
2
|
+
export { ZcodeBackend, type ServerRequest, type EventListener } from "./client.js";
|
|
3
|
+
export { EventStreamListener, TurnMonitor, type NextId } from "./listener.js";
|
|
4
|
+
export { resolveZcodeCommand } from "./resolve.js";
|
|
5
|
+
export { loadZcodeCredentials, mergeEnvWithCreds, type ZcodeCredentials } from "./credentials.js";
|
|
6
|
+
export type { ZcodeRequest, ZcodeNotification, ZcodeResponse, ZcodeInbound, ZcodeSessionInfo, ZcodeCreateResult, ZcodeSessionListItem, ZcodeListResult, ZcodeEvent, ZcodeEventType, ZcodeSubscribeResult, ZcodeSnapshot, ZcodeProjection, ZcodeMessage, ZcodeMessagePart, ZcodeMessagesResult, ZcodeReadResult, ZcodeInteractionPermissionParams, ZcodeInteractionUserInputParams, ZcodeInteractionResponse, } from "./types.js";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"AAAA,wFAAwF;AAExF,OAAO,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAClG,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,UAAU,EACV,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,gCAAgC,EAChC,+BAA+B,EAC/B,wBAAwB,GACzB,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Backend layer barrel: ZCode subprocess client + listener + resolve + credentials. */
|
|
2
|
+
export { ZcodeBackend } from "./client.js";
|
|
3
|
+
export { EventStreamListener, TurnMonitor } from "./listener.js";
|
|
4
|
+
export { resolveZcodeCommand } from "./resolve.js";
|
|
5
|
+
export { loadZcodeCredentials, mergeEnvWithCreds } from "./credentials.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/backend/index.ts"],"names":[],"mappings":"AAAA,wFAAwF;AAExF,OAAO,EAAE,YAAY,EAA0C,MAAM,aAAa,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAe,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAyB,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event-stream listener and turn monitor.
|
|
3
|
+
*
|
|
4
|
+
* `EventStreamListener` subscribes to ZCode's `session/subscribe` event push
|
|
5
|
+
* (deliveryKind `desktop-continuous`) and queues `session/event` notifications
|
|
6
|
+
* for the turn loop to consume. It tracks a `lastSeq` watermark and can
|
|
7
|
+
* resubscribe from it to recover missed events after a stall.
|
|
8
|
+
*
|
|
9
|
+
* `TurnMonitor` is the legacy snapshot path: a one-shot `session/read` that
|
|
10
|
+
* returns the authoritative projection. Used for stall reconciliation and
|
|
11
|
+
* lock-release probing.
|
|
12
|
+
*/
|
|
13
|
+
import type { ZcodeBackend } from "./client.js";
|
|
14
|
+
import type { ZcodeEvent, ZcodeProjection, ZcodeSnapshot } from "./types.js";
|
|
15
|
+
/** ID generator function (the server's `_next_id`). */
|
|
16
|
+
export type NextId = () => number;
|
|
17
|
+
export declare class EventStreamListener {
|
|
18
|
+
private readonly backend;
|
|
19
|
+
readonly sid: string;
|
|
20
|
+
/** High-watermark of consumed event sequence numbers. */
|
|
21
|
+
lastSeq: number;
|
|
22
|
+
subscribed: boolean;
|
|
23
|
+
private readonly queue;
|
|
24
|
+
private readonly waiters;
|
|
25
|
+
constructor(backend: ZcodeBackend, zcodeSid: string);
|
|
26
|
+
/**
|
|
27
|
+
* Subscribe and capture the initial snapshot + eventSeq watermark.
|
|
28
|
+
*
|
|
29
|
+
* Returns the snapshot (with projection/messages) or null on failure. ZCode
|
|
30
|
+
* CLI 0.14.8+ always supports this; null means an old/ broken backend and
|
|
31
|
+
* the caller should surface an error (polling fallback was removed).
|
|
32
|
+
*/
|
|
33
|
+
subscribe(nextId: NextId): Promise<ZcodeSnapshot | null>;
|
|
34
|
+
/** Called by the backend reader when a `session/event` arrives. */
|
|
35
|
+
handleEvent(event: ZcodeEvent): void;
|
|
36
|
+
/**
|
|
37
|
+
* Wait for the next event, resolving once one arrives or `timeoutMs` elapses
|
|
38
|
+
* (resolves null on timeout). Events arriving with no active waiter are
|
|
39
|
+
* queued. A timed-out waiter is marked `done` so a later event skips it
|
|
40
|
+
* instead of being silently dropped on a settled promise.
|
|
41
|
+
*/
|
|
42
|
+
pollEvent(timeoutMs?: number): Promise<ZcodeEvent | null>;
|
|
43
|
+
/**
|
|
44
|
+
* Stall recovery: resubscribe from `lastSeq` so the server replays missed
|
|
45
|
+
* events. Failure is logged but non-fatal — the caller degrades to polling.
|
|
46
|
+
* The snapshot (if returned despite `includeSnapshot:false`) is intentionally
|
|
47
|
+
* not consumed; resubscribe only refreshes the watermark + resumes the push.
|
|
48
|
+
*/
|
|
49
|
+
resubscribe(nextId: NextId): Promise<boolean>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Legacy snapshot path: a single `session/read` returning the authoritative
|
|
53
|
+
* projection. Used in stall reconciliation and lock-release probing.
|
|
54
|
+
*/
|
|
55
|
+
export declare class TurnMonitor {
|
|
56
|
+
private readonly backend;
|
|
57
|
+
private readonly zcodeSid;
|
|
58
|
+
private readonly nextId;
|
|
59
|
+
constructor(backend: ZcodeBackend, zcodeSid: string, nextId: NextId);
|
|
60
|
+
/** Returns the projection snapshot, or null on error. */
|
|
61
|
+
pollOnce(): Promise<ZcodeProjection | null>;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=listener.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../../src/backend/listener.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,aAAa,EAAwB,MAAM,YAAY,CAAC;AAEnG,uDAAuD;AACvD,MAAM,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC;AAUlC,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,OAAO,SAAK;IACZ,UAAU,UAAS;IACnB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoB;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;gBAE5B,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM;IAKnD;;;;;;OAMG;IACG,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAqB9D,mEAAmE;IACnE,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAepC;;;;;OAKG;IACH,SAAS,CAAC,SAAS,SAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAoBtD;;;;;OAKG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAqBpD;AAED;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAMnE,yDAAyD;IACnD,QAAQ,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;CAWlD"}
|