zcode-acp-server 0.23.0 → 0.25.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.
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/quota/format.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/quota/format.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Quota dock refresher (ADR-0021) — keeps the Martty TUI's resident quota line
3
+ * up to date.
4
+ *
5
+ * A lazy process-wide singleton: started on first martty session activity, it
6
+ * refreshes every 60s and on every forceRefresh() (wired at turn end). Each
7
+ * successful refresh stores the formatted string on `server.quotaDock` and
8
+ * pushes a `config_option_update` (full options array — martty's subscribe is
9
+ * full-replace semantics) to the martty connections only.
10
+ *
11
+ * Cross-process sharing is hub-first: when the remote hub is reachable, its
12
+ * cached /api/quota/dock endpoint serves the string (~500ms budget); any
13
+ * failure falls back silently to a direct queryQuota() — the fallback is the
14
+ * normal path for local-only users (the hub is opt-in and idle-exits).
15
+ */
16
+ import type { ZcodeAcpServer } from "../server.js";
17
+ /** Interval between background refreshes. */
18
+ export declare const QUOTA_REFRESH_INTERVAL_MS = 60000;
19
+ /**
20
+ * Start the refresher (idempotent). No-op unless a martty client has been
21
+ * seen — editor-only setups never poll the quota API in the background.
22
+ */
23
+ export declare function startQuotaRefresher(server: ZcodeAcpServer): void;
24
+ /** Best-effort immediate refresh (called at every turn end). Never rejects. */
25
+ export declare function forceRefreshQuota(): Promise<void>;
26
+ /** Stop and forget the singleton (test helper). */
27
+ export declare function resetQuotaRefresherForTest(): void;
28
+ /** Hub-first dock string, falling back to a direct query. */
29
+ export declare function fetchDockText(env?: NodeJS.ProcessEnv): Promise<string | null>;
30
+ //# sourceMappingURL=live.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../../src/quota/live.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAOH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAKnD,6CAA6C;AAC7C,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAahD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAUhE;AAED,+EAA+E;AAC/E,wBAAgB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAGjD;AAED,mDAAmD;AACnD,wBAAgB,0BAA0B,IAAI,IAAI,CAGjD;AAuBD,6DAA6D;AAC7D,wBAAsB,aAAa,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAkBhG"}
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Quota dock refresher (ADR-0021) — keeps the Martty TUI's resident quota line
3
+ * up to date.
4
+ *
5
+ * A lazy process-wide singleton: started on first martty session activity, it
6
+ * refreshes every 60s and on every forceRefresh() (wired at turn end). Each
7
+ * successful refresh stores the formatted string on `server.quotaDock` and
8
+ * pushes a `config_option_update` (full options array — martty's subscribe is
9
+ * full-replace semantics) to the martty connections only.
10
+ *
11
+ * Cross-process sharing is hub-first: when the remote hub is reachable, its
12
+ * cached /api/quota/dock endpoint serves the string (~500ms budget); any
13
+ * failure falls back silently to a direct queryQuota() — the fallback is the
14
+ * normal path for local-only users (the hub is opt-in and idle-exits).
15
+ */
16
+ import { buildConfigOptions } from "../config/options.js";
17
+ import { parseRemoteConfig } from "../remote/config.js";
18
+ import { log, warn } from "../utils.js";
19
+ import { enqueueSessionSend } from "../handlers/io.js";
20
+ import { formatQuotaDock } from "./format.js";
21
+ import { queryQuota } from "./index.js";
22
+ /** Interval between background refreshes. */
23
+ export const QUOTA_REFRESH_INTERVAL_MS = 60_000;
24
+ /** Budget for the hub-first lookup before falling back to a direct query. */
25
+ const HUB_TIMEOUT_MS = 500;
26
+ let state = null;
27
+ /**
28
+ * Start the refresher (idempotent). No-op unless a martty client has been
29
+ * seen — editor-only setups never poll the quota API in the background.
30
+ */
31
+ export function startQuotaRefresher(server) {
32
+ if (state || !server.marttyClientSeen)
33
+ return;
34
+ const entry = {
35
+ server,
36
+ timer: setInterval(() => void refresh(entry), QUOTA_REFRESH_INTERVAL_MS),
37
+ inFlight: null,
38
+ };
39
+ entry.timer.unref?.();
40
+ state = entry;
41
+ void refresh(entry);
42
+ }
43
+ /** Best-effort immediate refresh (called at every turn end). Never rejects. */
44
+ export function forceRefreshQuota() {
45
+ if (!state)
46
+ return Promise.resolve();
47
+ return refresh(state);
48
+ }
49
+ /** Stop and forget the singleton (test helper). */
50
+ export function resetQuotaRefresherForTest() {
51
+ if (state)
52
+ clearInterval(state.timer);
53
+ state = null;
54
+ }
55
+ async function refresh(entry) {
56
+ if (entry.inFlight)
57
+ return entry.inFlight;
58
+ entry.inFlight = runRefresh(entry.server)
59
+ .catch((e) => {
60
+ log(`quota-dock: refresh failed (${e instanceof Error ? e.message : String(e)})`);
61
+ })
62
+ .finally(() => {
63
+ entry.inFlight = null;
64
+ });
65
+ return entry.inFlight;
66
+ }
67
+ async function runRefresh(server) {
68
+ const text = await fetchDockText();
69
+ const prev = server.quotaDock;
70
+ server.quotaDock = text;
71
+ // ADR-0021: on failure/no-data the dock hides — no update is emitted.
72
+ if (text === null || text === prev)
73
+ return;
74
+ await emitQuotaOptions(server);
75
+ }
76
+ /** Hub-first dock string, falling back to a direct query. */
77
+ export async function fetchDockText(env = process.env) {
78
+ const remote = parseRemoteConfig(env);
79
+ if (remote) {
80
+ try {
81
+ const resp = await fetch(`http://${remote.hubHost}:${remote.hubPort}/api/quota/dock`, {
82
+ headers: { Authorization: `Bearer ${remote.token}` },
83
+ signal: AbortSignal.timeout(HUB_TIMEOUT_MS),
84
+ });
85
+ if (resp.ok) {
86
+ const body = (await resp.json());
87
+ if (body.formatted === null)
88
+ return null;
89
+ if (typeof body.formatted === "string")
90
+ return body.formatted;
91
+ }
92
+ }
93
+ catch {
94
+ // hub absent/restarting — silent fallback below
95
+ }
96
+ }
97
+ return formatQuotaDock(await queryQuota());
98
+ }
99
+ /**
100
+ * Push a `config_option_update` carrying the full options array (quota
101
+ * included) to every martty connection, for every live session alias. Other
102
+ * clients are untouched — the quota option is martty-only by contract.
103
+ */
104
+ async function emitQuotaOptions(server) {
105
+ if (server.marttyConnectionRoots.size === 0)
106
+ return;
107
+ const targets = server.clients
108
+ .snapshot()
109
+ .filter((cx) => server.marttyConnectionRoots.has(connectionRootOf(cx)));
110
+ if (targets.length === 0)
111
+ return;
112
+ // Build the options once per zcode session (aliases share the same list).
113
+ const byZcodeSid = new Map();
114
+ const emitFor = async (acpSid) => {
115
+ const zcodeSid = server.resolveSid(acpSid) ?? null;
116
+ let options = byZcodeSid.get(zcodeSid);
117
+ if (!options) {
118
+ // All targets are martty connections by construction — any target's
119
+ // root unlocks the quota pseudo-option for the shared options array.
120
+ options = await buildConfigOptions(server, zcodeSid, connectionRootOf(targets[0]));
121
+ byZcodeSid.set(zcodeSid, options);
122
+ }
123
+ await enqueueSessionSend(acpSid, async () => {
124
+ const results = await Promise.allSettled(targets.map((cx) => cx.notify("session/update", {
125
+ sessionId: acpSid,
126
+ update: { sessionUpdate: "config_option_update", configOptions: options },
127
+ })));
128
+ for (const r of results) {
129
+ if (r.status === "rejected") {
130
+ warn(`quota-dock: config_option_update failed on one client: ` +
131
+ `${r.reason instanceof Error ? r.reason.message : String(r.reason)}`);
132
+ }
133
+ }
134
+ });
135
+ };
136
+ const acpSids = [...server.sessionMap.keys(), ...server.pendingSessions.keys()];
137
+ for (const acpSid of acpSids)
138
+ await emitFor(acpSid);
139
+ }
140
+ /** clientConnectionRoot equivalent for a raw ClientLike (see utils.ts). */
141
+ function connectionRootOf(cx) {
142
+ return cx.connectionContext;
143
+ }
144
+ //# sourceMappingURL=live.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live.js","sourceRoot":"","sources":["../../src/quota/live.ts"],"names":[],"mappings":"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"}
@@ -127,8 +127,30 @@ export declare function resolveTerminalLaunch(env: NodeJS.ProcessEnv, prefs?: Te
127
127
  * values are single-quoted.
128
128
  */
129
129
  export declare function terminalTuiScript(cwd: string, cliJs: string, env: NodeJS.ProcessEnv): string;
130
+ /**
131
+ * Write the throwaway .command script for a terminal TUI incubation.
132
+ *
133
+ * Preferred location: `<workspace>/.zcode/tmp/tui-XXXX.command`. Terminal apps
134
+ * bind the new tab's project root to the script's PARENT directory (Warp's
135
+ * open_file opens a session in the file's dir before executing it), so a
136
+ * tmpdir script leaves the tab bound to a throwaway directory — the in-script
137
+ * `cd` only moves the shell cwd and never re-binds the terminal project, which
138
+ * blinds diff/git panels. Any failure writing there (read-only workspace,
139
+ * permissions, …) falls back to the historical mkdtemp(tmpdir()) path.
140
+ */
141
+ export declare function writeTuiScript(workspace: string, cliJs: string, env: NodeJS.ProcessEnv): string;
130
142
  /** Reset the quota cache (test helper). */
131
143
  export declare function resetQuotaCacheForTest(): void;
144
+ /** Reset the dock cache (test helper). */
145
+ export declare function resetDockCacheForTest(): void;
146
+ /**
147
+ * Tab-title sanitizer: the value is printf'd into the terminal as an OSC
148
+ * payload, so control characters (an ESC inside a model-generated summary
149
+ * would inject terminal sequences) become spaces, whitespace collapses, and
150
+ * the length caps at what a tab can usefully show. Empty/non-string →
151
+ * undefined (the caller falls back to the project name).
152
+ */
153
+ export declare function sanitizeTabTitle(v: unknown): string | undefined;
132
154
  /**
133
155
  * Start the hub. Resolves once listening; rejects on bind failure (including
134
156
  * EADDRINUSE when another hub already owns the port).
@@ -1 +1 @@
1
- {"version":3,"file":"hub-server.d.ts","sourceRoot":"","sources":["../../src/remote/hub-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAwB9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAM9D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB;;;;OAIG;IACH,SAAS,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAClB,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;QACvB,sFAAsF;QACtF,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC;KACvB,KAAK,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAsID,sEAAsE;AACtE,MAAM,MAAM,cAAc;AACxB;uEACuE;AACrE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AACpC,6EAA6E;GAC3E;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE;AAClC;kEACkE;GAChE;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE;AACtD;;;;kEAIkE;GAChE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AA2BrD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,KAAK,GAAE,aAAwC,GAC9C;IACD,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAUA;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAc5F;AA6JD,2CAA2C;AAC3C,wBAAgB,sBAAsB,IAAI,IAAI,CAG7C;AA4JD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CA60B9F"}
1
+ {"version":3,"file":"hub-server.d.ts","sourceRoot":"","sources":["../../src/remote/hub-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAS,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAiC9D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAQ9D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB;;;;OAIG;IACH,SAAS,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACrD;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAClB,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;QACvB,sFAAsF;QACtF,IAAI,EAAE,KAAK,GAAG,OAAO,CAAC;KACvB,KAAK,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAsID,sEAAsE;AACtE,MAAM,MAAM,cAAc;AACxB;uEACuE;AACrE;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AACpC,6EAA6E;GAC3E;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE;AAClC;kEACkE;GAChE;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE;AACtD;;;;kEAIkE;GAChE;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AA2BrD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,KAAK,GAAE,aAAwC,GAC9C;IACD,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAUA;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAqB5F;AAKD;;;;;;;;;;GAUG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CA+B/F;AA2JD,2CAA2C;AAC3C,wBAAgB,sBAAsB,IAAI,IAAI,CAG7C;AAsBD,0CAA0C;AAC1C,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAmCD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAQ/D;AAyID;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CA83B9F"}
@@ -24,7 +24,7 @@
24
24
  */
25
25
  import { spawn } from "node:child_process";
26
26
  import { createHash, randomUUID, timingSafeEqual } from "node:crypto";
27
- import { chmodSync, mkdtempSync, realpathSync, writeFileSync } from "node:fs";
27
+ import { chmodSync, mkdirSync, mkdtempSync, readdirSync, realpathSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
28
28
  import { readdir, readFile, stat } from "node:fs/promises";
29
29
  import { createServer, get as httpGet, request as httpRequest, } from "node:http";
30
30
  import { EventEmitter } from "node:events";
@@ -38,6 +38,8 @@ import { AGENT_INFO, compareVersions, log, warn } from "../utils.js";
38
38
  import { remoteTerminalPrefs } from "./config.js";
39
39
  import { accountUsageStats } from "../handlers/account.js";
40
40
  import { BOOT_RESUME_TRIGGER } from "../handlers/session.js";
41
+ import { formatQuotaDock } from "../quota/format.js";
42
+ import { queryQuota } from "../quota/index.js";
41
43
  import { listKnownWorkspaces } from "../tasks-index.js";
42
44
  const HEARTBEAT_TIMEOUT_MS = 30_000;
43
45
  const IDLE_EXIT_MS = 10 * 60_000;
@@ -199,10 +201,64 @@ export function terminalTuiScript(cwd, cliJs, env) {
199
201
  `# Hub-incubated TUI session (ADR-0016): closing this window ends the bridge.`,
200
202
  `cd ${shQuote(cwd)} || exit 1`,
201
203
  ...exports,
204
+ // OSC 0 names the tab after the conversation — without it terminals show
205
+ // the running process ("node"). printf reads the \033/\007 escapes from
206
+ // the format string; %s keeps the value itself shell-safe. martty never
207
+ // sets a terminal title, so this survives until the window closes.
208
+ ...(env.ZCODE_ACP_TAB_TITLE !== undefined
209
+ ? [`printf '\\033]0;%s\\007' "$ZCODE_ACP_TAB_TITLE"`]
210
+ : []),
202
211
  `exec ${shQuote(process.execPath)} ${shQuote(cliJs)}`,
203
212
  "",
204
213
  ].join("\n");
205
214
  }
215
+ /** Stale TUI scripts older than this are swept on the next incubation. */
216
+ const TUI_SCRIPT_MAX_AGE_MS = 60 * 60 * 1000;
217
+ /**
218
+ * Write the throwaway .command script for a terminal TUI incubation.
219
+ *
220
+ * Preferred location: `<workspace>/.zcode/tmp/tui-XXXX.command`. Terminal apps
221
+ * bind the new tab's project root to the script's PARENT directory (Warp's
222
+ * open_file opens a session in the file's dir before executing it), so a
223
+ * tmpdir script leaves the tab bound to a throwaway directory — the in-script
224
+ * `cd` only moves the shell cwd and never re-binds the terminal project, which
225
+ * blinds diff/git panels. Any failure writing there (read-only workspace,
226
+ * permissions, …) falls back to the historical mkdtemp(tmpdir()) path.
227
+ */
228
+ export function writeTuiScript(workspace, cliJs, env) {
229
+ const contents = terminalTuiScript(workspace, cliJs, env);
230
+ const dir = path.join(workspace, ".zcode", "tmp");
231
+ try {
232
+ mkdirSync(dir, { recursive: true });
233
+ // Best-effort sweep of stale scripts (>1h old): an unlinked-but-running
234
+ // script keeps executing on unix, and a fresh one may back a live
235
+ // incubation, so only clearly-stale files go.
236
+ const cutoff = Date.now() - TUI_SCRIPT_MAX_AGE_MS;
237
+ for (const entry of readdirSync(dir)) {
238
+ if (!entry.startsWith("tui-") || !entry.endsWith(".command"))
239
+ continue;
240
+ const stale = path.join(dir, entry);
241
+ try {
242
+ if (statSync(stale).mtimeMs < cutoff)
243
+ unlinkSync(stale);
244
+ }
245
+ catch {
246
+ // best-effort — a racing removal must not abort the incubation
247
+ }
248
+ }
249
+ const script = path.join(dir, `tui-${randomUUID().slice(0, 8)}.command`);
250
+ writeFileSync(script, contents, { mode: 0o700 });
251
+ chmodSync(script, 0o700);
252
+ return script;
253
+ }
254
+ catch (e) {
255
+ warn(`hub: cannot place the TUI script in ${dir} (${e instanceof Error ? e.message : String(e)}) — using the system tmpdir`);
256
+ }
257
+ const fallback = path.join(mkdtempSync(path.join(tmpdir(), "zcode-acp-term-")), "tui.command");
258
+ writeFileSync(fallback, contents, { mode: 0o700 });
259
+ chmodSync(fallback, 0o700);
260
+ return fallback;
261
+ }
206
262
  /**
207
263
  * Spawn session-create as a VISIBLE interactive TUI (ADR-0016): write a
208
264
  * throwaway .command script (`cd <project> && exec node cli.js`) and hand it
@@ -226,9 +282,7 @@ async function spawnTerminalTui(opts) {
226
282
  if (!remoteTerminalPrefs(process.env).enabled)
227
283
  return null;
228
284
  const cliJs = fileURLToPath(new URL("../cli.js", import.meta.url));
229
- const script = path.join(mkdtempSync(path.join(tmpdir(), "zcode-acp-term-")), "tui.command");
230
- writeFileSync(script, terminalTuiScript(opts.cwd, cliJs, opts.env), { mode: 0o700 });
231
- chmodSync(script, 0o700);
285
+ const script = writeTuiScript(opts.cwd, cliJs, opts.env);
232
286
  const { launch, warning } = resolveTerminalLaunch(process.env);
233
287
  if (warning)
234
288
  warn(`hub: ${warning}`);
@@ -354,6 +408,28 @@ export function resetQuotaCacheForTest() {
354
408
  quotaCache = null;
355
409
  quotaInflight = null;
356
410
  }
411
+ /**
412
+ * Cached dock string for GET /api/quota/dock (ADR-0021) — the compact one-line
413
+ * quota format consumed by the Martty TUI refresher. Shorter TTL than
414
+ * /api/quota (15s): the dock is resident UI, freshness beats upstream load.
415
+ * `formatted: null` (no data) is cached too, so a credentials-less machine
416
+ * does not hammer the API on every 60s refresh.
417
+ */
418
+ const DOCK_TTL_MS = 15_000;
419
+ let dockCache = null;
420
+ function getQuotaDock() {
421
+ if (dockCache && Date.now() - dockCache.at < DOCK_TTL_MS) {
422
+ return Promise.resolve({ formatted: dockCache.formatted, fetchedAt: dockCache.at });
423
+ }
424
+ return queryQuota().then((result) => {
425
+ dockCache = { formatted: formatQuotaDock(result), at: Date.now() };
426
+ return { formatted: dockCache.formatted, fetchedAt: dockCache.at };
427
+ });
428
+ }
429
+ /** Reset the dock cache (test helper). */
430
+ export function resetDockCacheForTest() {
431
+ dockCache = null;
432
+ }
357
433
  /**
358
434
  * TCP-probe a bridge's loopback endpoint. Loopback refusals are instant, so
359
435
  * the timeout only guards pathological cases; a bare connect+destroy is
@@ -381,6 +457,36 @@ const MAX_SESSION_LIST_BYTES = 4 * 1024 * 1024;
381
457
  * gives its own query 15s).
382
458
  */
383
459
  const SESSION_LIST_TIMEOUT_MS = 12_000;
460
+ /** Best-effort budget for the resume tab-title lookup — the window must
461
+ * never wait on a slow bridge (the 12s list budget is for listings, not
462
+ * for cosmetics). */
463
+ const TITLE_LOOKUP_BUDGET_MS = 2_000;
464
+ /**
465
+ * Tab-title sanitizer: the value is printf'd into the terminal as an OSC
466
+ * payload, so control characters (an ESC inside a model-generated summary
467
+ * would inject terminal sequences) become spaces, whitespace collapses, and
468
+ * the length caps at what a tab can usefully show. Empty/non-string →
469
+ * undefined (the caller falls back to the project name).
470
+ */
471
+ export function sanitizeTabTitle(v) {
472
+ if (typeof v !== "string")
473
+ return undefined;
474
+ const clean = v
475
+ .replace(/[\p{Cc}]/gu, " ")
476
+ .replace(/\s+/g, " ")
477
+ .trim()
478
+ .slice(0, 80);
479
+ return clean.length > 0 ? clean : undefined;
480
+ }
481
+ /** Resolve with undefined after `ms` — for best-effort lookups that must not
482
+ * stall their caller; the losing promise settles into the void (its own
483
+ * rejection is the caller's `.catch`, never unhandled). */
484
+ function withTimeout(p, ms) {
485
+ const timeout = new Promise((resolve) => {
486
+ setTimeout(() => resolve(undefined), ms).unref?.();
487
+ });
488
+ return Promise.race([p, timeout]);
489
+ }
384
490
  /**
385
491
  * Fetch a bridge's GET /sessions payload (ADR-0015), forwarding the
386
492
  * pagination query ("?limit=..&before=.."). Resolves with the parsed JSON;
@@ -537,7 +643,7 @@ export function startHub(options) {
537
643
  * requested session (ADR-0017), "serve" the detached headless bridge
538
644
  * (background listing, ADR-0015).
539
645
  */
540
- const incubateServe = async (workspacePath, kind, sessionId) => {
646
+ const incubateServe = async (workspacePath, kind, sessionId, tabTitle) => {
541
647
  // Async spawn failures (ENOENT — the dir vanished between the whitelist
542
648
  // check and the spawn) arrive as an 'error' event with exitCode still
543
649
  // null; without this flag the poll burns the full budget.
@@ -578,6 +684,14 @@ export function startHub(options) {
578
684
  // Must ride the env verbatim — martty reads it once at process start.
579
685
  env.DSH_TUI_AUTOPROMPT = BOOT_RESUME_TRIGGER;
580
686
  }
687
+ if (kind !== "serve") {
688
+ // Tab title (both visible-terminal kinds): a resume carries the
689
+ // conversation's title when the hub resolved it; session-create and a
690
+ // failed lookup fall back to the project name. Rides the env —
691
+ // terminalTuiScript turns it into an OSC 0 before exec'ing the CLI
692
+ // (terminals otherwise name the tab after the process, "node").
693
+ env.ZCODE_ACP_TAB_TITLE = tabTitle ?? path.basename(workspacePath);
694
+ }
581
695
  try {
582
696
  // Resume shares session-create's visible-terminal surface (and its
583
697
  // detached-serve fallback for headless machines); only a background
@@ -639,14 +753,14 @@ export function startHub(options) {
639
753
  * key carries the session id, so resumes of different sessions each get
640
754
  * their own window.
641
755
  */
642
- const joinIncubation = (workspacePath, kind, sessionId) => {
756
+ const joinIncubation = (workspacePath, kind, sessionId, tabTitle) => {
643
757
  const mapKey = kind === "resume" ? `${workspacePath}\u0000resume\u0000${sessionId ?? ""}` : workspacePath;
644
758
  const inflight = serveIncubations.get(mapKey);
645
759
  if (inflight && (inflight.kind === kind || kind === "serve")) {
646
760
  log(`hub: joining the incubating serve bridge for ${workspacePath}`);
647
761
  return inflight.promise;
648
762
  }
649
- const promise = incubateServe(workspacePath, kind, sessionId);
763
+ const promise = incubateServe(workspacePath, kind, sessionId, tabTitle);
650
764
  serveIncubations.set(mapKey, { kind, promise });
651
765
  // Drop the entry once settled (identity-checked — a newer incubation may
652
766
  // already have replaced it). The catch keeps the DERIVED promise handled;
@@ -829,6 +943,26 @@ export function startHub(options) {
829
943
  }
830
944
  return;
831
945
  }
946
+ // GET /api/quota/dock — the compact quota-dock string for the TUI
947
+ // refresher (ADR-0021). Account-level like /api/quota; hub-side cache is
948
+ // the only caching layer, so clients must not store stale copies.
949
+ if (url.pathname === "/api/quota/dock" && req.method === "GET") {
950
+ if (!authorized(req, url, token)) {
951
+ res.writeHead(401, { "Content-Type": "text/plain" });
952
+ res.end("unauthorized");
953
+ return;
954
+ }
955
+ try {
956
+ const { formatted, fetchedAt } = await getQuotaDock();
957
+ res.writeHead(200, { "Content-Type": "application/json", "Cache-Control": "no-store" });
958
+ res.end(JSON.stringify({ formatted, fetchedAt }));
959
+ }
960
+ catch {
961
+ res.writeHead(502, { "Content-Type": "text/plain" });
962
+ res.end("quota query failed");
963
+ }
964
+ return;
965
+ }
832
966
  // GET /api/projects — the machine's known-project list (remote
833
967
  // session-create, ADR-0014). Sourced from the App's tasks index: every
834
968
  // workspace that ever ran a session. The list gates POST /api/instances
@@ -984,13 +1118,26 @@ export function startHub(options) {
984
1118
  return;
985
1119
  }
986
1120
  if (resumeSid) {
1121
+ // Tab title, best-effort: the App browsed this conversation through
1122
+ // the serve bridge's /sessions history, which is normally still live
1123
+ // and still holds the title. Every miss (no live instance, id beyond
1124
+ // the page, slow fetch) falls back to the project name inside
1125
+ // incubateServe — the window must never wait on this lookup.
1126
+ let tabTitle;
1127
+ const titleSource = findServeInstance(workspacePath);
1128
+ if (titleSource) {
1129
+ const row = await withTimeout(fetchBridgeSessions(titleSource.port, "?limit=200")
1130
+ .then((payload) => (payload.sessions ?? []).find((s) => s.sessionId === resumeSid))
1131
+ .catch(() => undefined), TITLE_LOOKUP_BUDGET_MS);
1132
+ tabTitle = sanitizeTabTitle(row?.title);
1133
+ }
987
1134
  // Resume never reuses the live serve bridge: the window IS the
988
1135
  // feature, and the answer must be the NEW instance so the attaching
989
1136
  // client and the terminal share one bridge (and one backend process)
990
1137
  // for the session. A bogus id still opens the window — the TUI
991
1138
  // shows the load failure and falls back to a fresh session, the same
992
1139
  // honesty as a window that dies early (ADR-0016 §4).
993
- const incubation = joinIncubation(workspacePath, "resume", resumeSid);
1140
+ const incubation = joinIncubation(workspacePath, "resume", resumeSid, tabTitle);
994
1141
  try {
995
1142
  const out = await incubation;
996
1143
  res.writeHead(200, { "Content-Type": "application/json" });