@lucascouts/claude-agent-tui 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/acp-agent.d.ts +187 -13
  2. package/dist/acp-agent.d.ts.map +1 -1
  3. package/dist/acp-agent.js +448 -60
  4. package/dist/agent-catalog.d.ts +96 -0
  5. package/dist/agent-catalog.d.ts.map +1 -0
  6. package/dist/agent-catalog.js +287 -0
  7. package/dist/claude-path.d.ts.map +1 -1
  8. package/dist/claude-path.js +6 -0
  9. package/dist/end-of-turn.d.ts +6 -0
  10. package/dist/end-of-turn.d.ts.map +1 -1
  11. package/dist/end-of-turn.js +8 -1
  12. package/dist/engine-lifecycle.d.ts +66 -1
  13. package/dist/engine-lifecycle.d.ts.map +1 -1
  14. package/dist/engine-lifecycle.js +43 -4
  15. package/dist/engine-pty.d.ts +70 -2
  16. package/dist/engine-pty.d.ts.map +1 -1
  17. package/dist/engine-pty.js +80 -6
  18. package/dist/gate/settings-writer.d.ts +34 -3
  19. package/dist/gate/settings-writer.d.ts.map +1 -1
  20. package/dist/gate/settings-writer.js +62 -7
  21. package/dist/image-input.d.ts +31 -0
  22. package/dist/image-input.d.ts.map +1 -0
  23. package/dist/image-input.js +79 -0
  24. package/dist/image-vision-smoke.d.ts +52 -0
  25. package/dist/image-vision-smoke.d.ts.map +1 -0
  26. package/dist/image-vision-smoke.js +111 -0
  27. package/dist/index.js +6 -0
  28. package/dist/mcp-config-writer.d.ts +61 -0
  29. package/dist/mcp-config-writer.d.ts.map +1 -0
  30. package/dist/mcp-config-writer.js +172 -0
  31. package/dist/model-catalog.d.ts +29 -2
  32. package/dist/model-catalog.d.ts.map +1 -1
  33. package/dist/model-catalog.js +50 -10
  34. package/dist/permissions/gate-wiring.d.ts +13 -1
  35. package/dist/permissions/gate-wiring.d.ts.map +1 -1
  36. package/dist/permissions/gate-wiring.js +158 -40
  37. package/dist/permissions/hook-server.d.ts +15 -0
  38. package/dist/permissions/hook-server.d.ts.map +1 -1
  39. package/dist/permissions/hook-server.js +30 -1
  40. package/dist/permissions/request-permission.d.ts +9 -0
  41. package/dist/permissions/request-permission.d.ts.map +1 -1
  42. package/dist/permissions/request-permission.js +20 -5
  43. package/dist/settings.d.ts.map +1 -1
  44. package/dist/settings.js +9 -0
  45. package/dist/tools.d.ts +10 -2
  46. package/dist/tools.d.ts.map +1 -1
  47. package/dist/tools.js +5 -1
  48. package/dist/usage.d.ts +3 -0
  49. package/dist/usage.d.ts.map +1 -1
  50. package/dist/usage.js +9 -5
  51. package/package.json +8 -8
@@ -0,0 +1,52 @@
1
+ /**
2
+ * The claude version where `@<path>` → Read-vision was PROVEN to work (story 058 research).
3
+ *
4
+ * WHY this exact anchor: on claude 2.1.170 a `@path` image prompt did NOT vision-encode the picture —
5
+ * the TUI did not turn it into a Read the model could see (story 030). On claude 2.1.195 it DOES: the
6
+ * two-arm proof (a blue vs a green image under the same uuid filename, each described correctly) showed
7
+ * `@path` → Read vision-encodes. So 2.1.195 is the earliest version we are willing to call "confirmed";
8
+ * anything below is treated as unconfirmed and warned about.
9
+ */
10
+ export declare const VISION_CONFIRMED_CLAUDE_VERSION = "2.1.195";
11
+ /** The verdict {@link imageVisionSmoke} returns. Observability only — there is NO capability toggle here. */
12
+ export interface VisionSmokeResult {
13
+ /** True iff the running `claude` version is one we have CONFIRMED vision-encodes `@image` via Read. */
14
+ confirmed: boolean;
15
+ /**
16
+ * Human-readable one-liner. On `confirmed=true` it is a positive note. On `confirmed=false` it is the
17
+ * fail-loud WARNING text and NAMES the detected version (or "undetected") plus the confirmed anchor
18
+ * (mirrors drift-checks.ts's "name the offending value" habit).
19
+ */
20
+ detail: string;
21
+ }
22
+ /**
23
+ * Compare two `x.y.z` semver strings: `true` iff `a >= b` componentwise (major, then minor, then patch).
24
+ *
25
+ * Splits on `.`, parses the three leading numeric components; a missing/non-numeric component counts as
26
+ * `0` (so `"2.1"` reads as `2.1.0`). Private to this module — exported only so the unit test can pin the
27
+ * ordering directly. Pure.
28
+ */
29
+ export declare function versionGte(a: string, b: string): boolean;
30
+ /**
31
+ * PURE verdict: is the running `claude` `version` one we have CONFIRMED vision-encodes `@image` via Read?
32
+ *
33
+ * `confirmed: true` IFF `version` is a parseable leading `x.y.z` that is `>= {@link
34
+ * VISION_CONFIRMED_CLAUDE_VERSION}`. In that case `detail` is a positive one-liner.
35
+ *
36
+ * Otherwise (`null` / `undefined` / unparseable, OR a parseable version BELOW the anchor) `confirmed:
37
+ * false` and `detail` is the fail-loud WARNING text — it NAMES the detected version (or "undetected")
38
+ * and the confirmed anchor, and states that the image is NOT blocked (R3.1). No I/O; depends only on
39
+ * its argument.
40
+ */
41
+ export declare function imageVisionSmoke(version: string | null | undefined): VisionSmokeResult;
42
+ /**
43
+ * Best-effort fail-loud reporter: compute {@link imageVisionSmoke} and, WHEN unconfirmed, log the
44
+ * verdict's `detail` EXACTLY ONCE via `log` with an `[image-vision]` prefix (mirrors claude-path.ts's
45
+ * reportVersionDrift `[claude-path] …` style). Returns the verdict.
46
+ *
47
+ * Logs NOTHING on a confirmed version (a confirmed `claude` is the expected case — no news is good news,
48
+ * matching reportVersionDrift which is silent when there is no drift). NEVER blocks and NEVER throws out
49
+ * of the caller's intent — it is pure aside from the single conditional `log` call (R3.1, R3.2).
50
+ */
51
+ export declare function reportImageVisionSmoke(version: string | null | undefined, log?: (...args: unknown[]) => void): VisionSmokeResult;
52
+ //# sourceMappingURL=image-vision-smoke.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-vision-smoke.d.ts","sourceRoot":"","sources":["../src/image-vision-smoke.ts"],"names":[],"mappings":"AA8BA;;;;;;;;GAQG;AACH,eAAO,MAAM,+BAA+B,YAAY,CAAC;AAEzD,6GAA6G;AAC7G,MAAM,WAAW,iBAAiB;IAChC,uGAAuG;IACvG,SAAS,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAWxD;AAcD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,iBAAiB,CAiBtF;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAClC,GAAG,GAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAoB,GAChD,iBAAiB,CAMnB"}
@@ -0,0 +1,111 @@
1
+ // === Story 058 / Task 3.1 (R3.1, R3.2) — version-aware image-vision smoke (pure verdict + fail-loud) ==
2
+ //
3
+ // The whole "image input via @path" feature rests on a VERSION-FRAGILE claude behavior: a prompt
4
+ // containing `@<path>` makes the native TUI invoke the Read tool, and Read vision-encodes the image so
5
+ // the model can see it. This was PROVEN on claude 2.1.195 (story 058 research — two-arm proof: a blue
6
+ // image vs a green image under the same filename, each correctly described). It did NOT work on claude
7
+ // 2.1.170 (story 030): there, `@path` did not vision-encode, so an image prompt silently dropped its
8
+ // picture.
9
+ //
10
+ // Because the behavior is version-fragile, this module makes a too-old / unknown `claude` LOUD instead
11
+ // of silently dropping the image. It mirrors story 049's drift discipline:
12
+ // - the VERDICT is PURE (no I/O — like src/drift-checks.ts's `{surface, ok, detail}` checks), and
13
+ // - the REPORTER is best-effort + fail-loud one-liner (like src/claude-path.ts's reportVersionDrift,
14
+ // `[claude-path] …`); here the prefix is `[image-vision]`.
15
+ //
16
+ // CRITICAL — OBSERVABILITY ONLY, NEVER A GATE (R3.1): this smoke NEVER blocks the prompt and NEVER
17
+ // touches `promptCapabilities.image`, which stays literally `image: true` (acp-agent.ts:1413),
18
+ // UNCONDITIONALLY. The verdict's only output is `{confirmed, detail}` — there is deliberately NO field
19
+ // or return shape here that could disable a capability. A too-old `claude` produces a WARNING, not a
20
+ // degraded capability: the image still rides the @path delivery; we just warn that this `claude` is not
21
+ // a version we have confirmed vision-encodes it.
22
+ //
23
+ // LIMITATION (documented honestly): this is an OFFLINE `>= anchor` version-gate. It catches too-old and
24
+ // undetected/unparseable versions, but it CANNOT catch a *future regression* — a hypothetical 2.1.300
25
+ // that re-breaks @path-vision would still parse as `>= 2.1.195` and report confirmed. Catching a future
26
+ // regression needs the LIVE smoke (opt-in — story 058 R4 probe: actually send @image and check the
27
+ // model saw it), which this offline gate intentionally does NOT implement.
28
+ //
29
+ // node:test runner: `node --experimental-strip-types --test test/image-vision-smoke.test.ts`
30
+ /**
31
+ * The claude version where `@<path>` → Read-vision was PROVEN to work (story 058 research).
32
+ *
33
+ * WHY this exact anchor: on claude 2.1.170 a `@path` image prompt did NOT vision-encode the picture —
34
+ * the TUI did not turn it into a Read the model could see (story 030). On claude 2.1.195 it DOES: the
35
+ * two-arm proof (a blue vs a green image under the same uuid filename, each described correctly) showed
36
+ * `@path` → Read vision-encodes. So 2.1.195 is the earliest version we are willing to call "confirmed";
37
+ * anything below is treated as unconfirmed and warned about.
38
+ */
39
+ export const VISION_CONFIRMED_CLAUDE_VERSION = "2.1.195";
40
+ /**
41
+ * Compare two `x.y.z` semver strings: `true` iff `a >= b` componentwise (major, then minor, then patch).
42
+ *
43
+ * Splits on `.`, parses the three leading numeric components; a missing/non-numeric component counts as
44
+ * `0` (so `"2.1"` reads as `2.1.0`). Private to this module — exported only so the unit test can pin the
45
+ * ordering directly. Pure.
46
+ */
47
+ export function versionGte(a, b) {
48
+ const partsA = a.split(".");
49
+ const partsB = b.split(".");
50
+ for (let i = 0; i < 3; i++) {
51
+ const na = toComponent(partsA[i]);
52
+ const nb = toComponent(partsB[i]);
53
+ if (na !== nb) {
54
+ return na > nb;
55
+ }
56
+ }
57
+ return true; // all three components equal → a >= b holds
58
+ }
59
+ /** Parse one semver component to a non-negative integer; missing / non-numeric → 0. */
60
+ function toComponent(part) {
61
+ if (part === undefined) {
62
+ return 0;
63
+ }
64
+ const n = Number.parseInt(part, 10);
65
+ return Number.isNaN(n) ? 0 : n;
66
+ }
67
+ /** Matches a leading `x.y.z` triple — same shape parseClaudeVersion extracts (claude-path.ts:58). */
68
+ const SEMVER_RE = /^(\d+\.\d+\.\d+)/;
69
+ /**
70
+ * PURE verdict: is the running `claude` `version` one we have CONFIRMED vision-encodes `@image` via Read?
71
+ *
72
+ * `confirmed: true` IFF `version` is a parseable leading `x.y.z` that is `>= {@link
73
+ * VISION_CONFIRMED_CLAUDE_VERSION}`. In that case `detail` is a positive one-liner.
74
+ *
75
+ * Otherwise (`null` / `undefined` / unparseable, OR a parseable version BELOW the anchor) `confirmed:
76
+ * false` and `detail` is the fail-loud WARNING text — it NAMES the detected version (or "undetected")
77
+ * and the confirmed anchor, and states that the image is NOT blocked (R3.1). No I/O; depends only on
78
+ * its argument.
79
+ */
80
+ export function imageVisionSmoke(version) {
81
+ const parsed = typeof version === "string" ? SEMVER_RE.exec(version) : null;
82
+ if (parsed && versionGte(parsed[1], VISION_CONFIRMED_CLAUDE_VERSION)) {
83
+ return {
84
+ confirmed: true,
85
+ detail: `claude ${parsed[1]} >= ${VISION_CONFIRMED_CLAUDE_VERSION} — @image is confirmed to vision-encode via Read`,
86
+ };
87
+ }
88
+ const named = parsed ? parsed[1] : "undetected";
89
+ return {
90
+ confirmed: false,
91
+ detail: `@image vision-encoding is UNCONFIRMED on this claude (detected ${named}; confirmed at ` +
92
+ `${VISION_CONFIRMED_CLAUDE_VERSION}+). Sending images anyway — image input is NOT blocked — but ` +
93
+ `if the picture is ignored, upgrade claude to ${VISION_CONFIRMED_CLAUDE_VERSION} or newer`,
94
+ };
95
+ }
96
+ /**
97
+ * Best-effort fail-loud reporter: compute {@link imageVisionSmoke} and, WHEN unconfirmed, log the
98
+ * verdict's `detail` EXACTLY ONCE via `log` with an `[image-vision]` prefix (mirrors claude-path.ts's
99
+ * reportVersionDrift `[claude-path] …` style). Returns the verdict.
100
+ *
101
+ * Logs NOTHING on a confirmed version (a confirmed `claude` is the expected case — no news is good news,
102
+ * matching reportVersionDrift which is silent when there is no drift). NEVER blocks and NEVER throws out
103
+ * of the caller's intent — it is pure aside from the single conditional `log` call (R3.1, R3.2).
104
+ */
105
+ export function reportImageVisionSmoke(version, log = console.error) {
106
+ const result = imageVisionSmoke(version);
107
+ if (!result.confirmed) {
108
+ log(`[image-vision] ${result.detail}`);
109
+ }
110
+ return result;
111
+ }
package/dist/index.js CHANGED
@@ -88,6 +88,12 @@ else {
88
88
  // (src/live-subagent-env.ts) so the truth table is unit-checkable; threaded through
89
89
  // runAcp → AgentDeps → the agent.
90
90
  const liveSubagentWatch = liveSubagentWatchEnabled();
91
+ // Story 056 / Task 7 (R3.5): enable the live agent-discovery probe in PRODUCTION only. The probe
92
+ // (agent-catalog.ts) spawns `claude --agent <sentinel>` once per createSession to read `claude`'s
93
+ // canonical persona list (enabled plugins + built-ins) for the 4th `agent` selector. Gated opt-in so
94
+ // the unit suite — which imports modules directly without this flag — stays on the hermetic glob
95
+ // fallback and never spawns the real binary. `??=` keeps a user opt-out (`FORK_AGENT_PROBE=0`).
96
+ process.env.FORK_AGENT_PROBE ??= "1";
91
97
  const { connection, agent } = runAcp({ usageUpdate, gate, liveDiff, liveSubagentWatch });
92
98
  async function shutdown() {
93
99
  await agent.dispose().catch((err) => {
@@ -0,0 +1,61 @@
1
+ import type { McpServer } from "@agentclientprotocol/sdk";
2
+ /**
3
+ * A single entry under claude's `--mcp-config` `mcpServers` map. A discriminated union over the
4
+ * transport claude understands:
5
+ * - http/sse → `{ type, url, headers? }` (headers as a plain `{ [name]: value }` object)
6
+ * - stdio → `{ command, args?, env? }` (NO `type` — claude infers stdio from `command`)
7
+ * ACP-transport servers have no `--mcp-config` equivalent and are dropped before this shape.
8
+ */
9
+ export type ClaudeMcpEntry = {
10
+ type: "http" | "sse";
11
+ url: string;
12
+ headers?: Record<string, string>;
13
+ } | {
14
+ command: string;
15
+ args?: string[];
16
+ env?: Record<string, string>;
17
+ };
18
+ /** The full claude `--mcp-config` document: a name-keyed map of {@link ClaudeMcpEntry}. */
19
+ export interface ClaudeMcpConfig {
20
+ mcpServers: Record<string, ClaudeMcpEntry>;
21
+ }
22
+ /**
23
+ * Translate the ACP `McpServer[]` union into claude's `--mcp-config` `{ mcpServers: { … } }` shape
24
+ * (R2.1). PURE and total — never throws; empty/undefined input yields `{ mcpServers: {} }`.
25
+ *
26
+ * Discriminator (per the ACP schema): `type === "http"|"sse"|"acp"` selects that transport; a server
27
+ * with NO `type` field is the bare stdio variant. Per-transport mapping:
28
+ * - http / sse → `{ type, url, headers? }`; `headers` is OMITTED when the ACP array is empty.
29
+ * - stdio → `{ command, args?, env? }`; `args` and `env` are each OMITTED when empty; NO `type`.
30
+ * - acp → DROPPED (ACP-channel transport has no `--mcp-config` equivalent); a one-line note
31
+ * is emitted to stderr (no url/headers/env — R2.3).
32
+ *
33
+ * Duplicate names collapse onto the same key (last wins) — claude's map is name-keyed, so this matches
34
+ * how claude itself would resolve a repeated server name.
35
+ *
36
+ * @param servers the ACP-declared MCP servers, or `undefined`/`[]` when the client declared none.
37
+ * @returns the claude `--mcp-config` document (possibly with an empty `mcpServers`).
38
+ */
39
+ export declare function translateMcpServers(servers: readonly McpServer[] | undefined): ClaudeMcpConfig;
40
+ /**
41
+ * DURABLY write `config` to a fresh uuid-namespaced scratch file under the OS temp dir with mode
42
+ * `0600`, and RETURN its absolute path (R2.1, R2.3). The file is `JSON.stringify(config, null, 2)`
43
+ * plus a trailing newline. The caller passes the returned path to `claude --mcp-config <path>` and
44
+ * is responsible for removing it on teardown via {@link removeMcpScratch}.
45
+ *
46
+ * The file may carry MCP auth headers/env (secrets), so it is created owner-only (0600) and is NEVER
47
+ * logged here (R2.3).
48
+ *
49
+ * @param config the document from {@link translateMcpServers}.
50
+ * @returns the absolute path of the written scratch file.
51
+ * @throws {Error} if the durable write fails — the partial temp is cleaned up first (no residue).
52
+ */
53
+ export declare function writeMcpScratch(config: ClaudeMcpConfig): Promise<string>;
54
+ /**
55
+ * Idempotently remove a scratch file written by {@link writeMcpScratch} (R2.3 teardown). Uses
56
+ * `fs.rm(filePath, { force: true })`, so a missing/already-removed path is a no-op and NEVER throws.
57
+ *
58
+ * @param filePath the path returned by {@link writeMcpScratch}.
59
+ */
60
+ export declare function removeMcpScratch(filePath: string): Promise<void>;
61
+ //# sourceMappingURL=mcp-config-writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-config-writer.d.ts","sourceRoot":"","sources":["../src/mcp-config-writer.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,SAAS,EAA2B,MAAM,0BAA0B,CAAC;AAEnF;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GACvE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,CAAC;AAEvE,2FAA2F;AAC3F,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CAC5C;AAWD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,GAAG,eAAe,CA2C9F;AAqDD;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAK9E;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtE"}
@@ -0,0 +1,172 @@
1
+ // Story 057 / Task 2.1 — translate ACP MCP servers → claude `--mcp-config` JSON + scratch-file seam.
2
+ //
3
+ // The fork spawns the real `claude` TUI; claude consumes externally-declared MCP servers via a
4
+ // `--mcp-config <file.json>` flag (a `{ mcpServers: { <name>: { … } } }` document). The Zed client,
5
+ // however, declares its MCP servers over ACP as a `McpServer[]` array (a discriminated union). This
6
+ // module is the standalone, OFFLINE-testable translation + scratch-file seam between the two:
7
+ //
8
+ // translateMcpServers(servers) → ClaudeMcpConfig (PURE — array → claude `{mcpServers:{…}}` shape)
9
+ // writeMcpScratch(config) → Promise<string> (DURABLE 0600 write → returns the scratch path)
10
+ // removeMcpScratch(path) → Promise<void> (idempotent unlink on teardown)
11
+ //
12
+ // It owns NO engine wiring — the before-spawn `--mcp-config` plumbing into acp-agent.ts/the engine is
13
+ // a separate Task (2.2/2.3). The scratch-JSON discipline (temp-file → fsync → atomic rename, with a
14
+ // guaranteed 0600 mode) mirrors `gate/settings-writer.ts`'s private `durableWrite`; that pattern is
15
+ // copied here rather than imported (it is not exported there).
16
+ //
17
+ // SECRETS (R2.3): the scratch file may carry MCP auth headers / env / URLs. Its mode is forced to
18
+ // `0600` (owner-only) and it is removable on teardown. The config object, headers, env, and url are
19
+ // NEVER logged — the ONLY log this module emits is a one-line note when an `acp`-transport server is
20
+ // dropped, and that note carries no secret-bearing field.
21
+ import * as fs from "node:fs/promises";
22
+ import * as path from "node:path";
23
+ import * as os from "node:os";
24
+ import { randomUUID } from "node:crypto";
25
+ /** Convert an ACP `{name,value}[]` list into a plain `{ [name]: value }` object. */
26
+ function pairsToObject(pairs) {
27
+ const out = {};
28
+ for (const { name, value } of pairs) {
29
+ out[name] = value;
30
+ }
31
+ return out;
32
+ }
33
+ /**
34
+ * Translate the ACP `McpServer[]` union into claude's `--mcp-config` `{ mcpServers: { … } }` shape
35
+ * (R2.1). PURE and total — never throws; empty/undefined input yields `{ mcpServers: {} }`.
36
+ *
37
+ * Discriminator (per the ACP schema): `type === "http"|"sse"|"acp"` selects that transport; a server
38
+ * with NO `type` field is the bare stdio variant. Per-transport mapping:
39
+ * - http / sse → `{ type, url, headers? }`; `headers` is OMITTED when the ACP array is empty.
40
+ * - stdio → `{ command, args?, env? }`; `args` and `env` are each OMITTED when empty; NO `type`.
41
+ * - acp → DROPPED (ACP-channel transport has no `--mcp-config` equivalent); a one-line note
42
+ * is emitted to stderr (no url/headers/env — R2.3).
43
+ *
44
+ * Duplicate names collapse onto the same key (last wins) — claude's map is name-keyed, so this matches
45
+ * how claude itself would resolve a repeated server name.
46
+ *
47
+ * @param servers the ACP-declared MCP servers, or `undefined`/`[]` when the client declared none.
48
+ * @returns the claude `--mcp-config` document (possibly with an empty `mcpServers`).
49
+ */
50
+ export function translateMcpServers(servers) {
51
+ const mcpServers = {};
52
+ if (!servers) {
53
+ return { mcpServers };
54
+ }
55
+ for (const server of servers) {
56
+ // The ACP union is NOT a uniform discriminated union: http/sse/acp carry a `type` tag, but the
57
+ // stdio variant has NO `type` field at all. So a `"type" in server` guard (not `server.type`)
58
+ // first splits the tagged members from the bare stdio variant; within the tagged set, `type`
59
+ // then selects http/sse vs acp.
60
+ if ("type" in server) {
61
+ if (server.type === "http" || server.type === "sse") {
62
+ const entry = { type: server.type, url: server.url };
63
+ if (server.headers.length > 0) {
64
+ entry.headers = pairsToObject(server.headers);
65
+ }
66
+ mcpServers[server.name] = entry;
67
+ }
68
+ else {
69
+ // type === "acp": ACP-transport servers ride the ACP channel (mcp/connect…); claude's
70
+ // --mcp-config cannot express them, so drop. Log ONLY the (non-secret) name — never
71
+ // id/url/headers/env (R2.3).
72
+ console.error(`[mcp-config-writer] dropping ACP-transport MCP server ${JSON.stringify(server.name)}: ` +
73
+ `no --mcp-config equivalent (ACP-channel transport is not supported by the claude CLI).`);
74
+ }
75
+ continue;
76
+ }
77
+ // No `type` field → the bare stdio variant: `{ command, args, env }`. NO `type` is emitted
78
+ // (claude infers stdio from `command`); empty `args`/`env` are omitted.
79
+ const entry = { command: server.command };
80
+ if (server.args.length > 0) {
81
+ entry.args = [...server.args];
82
+ }
83
+ if (server.env.length > 0) {
84
+ entry.env = pairsToObject(server.env);
85
+ }
86
+ mcpServers[server.name] = entry;
87
+ }
88
+ return { mcpServers };
89
+ }
90
+ /**
91
+ * Durably write `text` to `filePath` with mode `0600` via a temp-file → fsync → atomic `rename` so a
92
+ * reader (claude on startup) never observes a partial file. The 0600 mode is GUARANTEED twice: the
93
+ * temp is created with `mode: 0o600`, and `chmod(0o600)` is re-applied after the rename so a permissive
94
+ * umask cannot loosen it. On any failure the partial temp is removed before the error propagates.
95
+ *
96
+ * Mirrors `gate/settings-writer.ts`'s private `durableWrite` (copied — that helper is not exported),
97
+ * with the added 0600 guarantee this scratch file requires (R2.3).
98
+ */
99
+ async function durableWrite0600(filePath, text) {
100
+ const dir = path.dirname(filePath);
101
+ const tmp = path.join(dir, `.${path.basename(filePath)}.fork-tmp-${process.pid}-${Date.now()}`);
102
+ let handle = null;
103
+ try {
104
+ // Create the temp owner-only from the outset so its bytes are never world-readable, even briefly.
105
+ handle = await fs.open(tmp, "w", 0o600);
106
+ await handle.writeFile(text, "utf8");
107
+ await handle.sync(); // flush the file's own bytes to disk before the rename
108
+ await handle.close();
109
+ handle = null;
110
+ await fs.rename(tmp, filePath); // atomic swap into place
111
+ // Re-assert 0600 AFTER the rename so the active umask cannot have loosened the open() mode.
112
+ await fs.chmod(filePath, 0o600);
113
+ // Best-effort fsync of the directory entry so the rename itself is durable.
114
+ try {
115
+ const dirHandle = await fs.open(dir, "r");
116
+ try {
117
+ await dirHandle.sync();
118
+ }
119
+ finally {
120
+ await dirHandle.close();
121
+ }
122
+ }
123
+ catch {
124
+ // Some platforms reject O_RDONLY dir fsync; the file fsync above is the load-bearing one.
125
+ }
126
+ }
127
+ catch (err) {
128
+ if (handle !== null) {
129
+ try {
130
+ await handle.close();
131
+ }
132
+ catch {
133
+ // ignore
134
+ }
135
+ }
136
+ try {
137
+ await fs.rm(tmp, { force: true });
138
+ }
139
+ catch {
140
+ // ignore — nothing durable to clean
141
+ }
142
+ throw err;
143
+ }
144
+ }
145
+ /**
146
+ * DURABLY write `config` to a fresh uuid-namespaced scratch file under the OS temp dir with mode
147
+ * `0600`, and RETURN its absolute path (R2.1, R2.3). The file is `JSON.stringify(config, null, 2)`
148
+ * plus a trailing newline. The caller passes the returned path to `claude --mcp-config <path>` and
149
+ * is responsible for removing it on teardown via {@link removeMcpScratch}.
150
+ *
151
+ * The file may carry MCP auth headers/env (secrets), so it is created owner-only (0600) and is NEVER
152
+ * logged here (R2.3).
153
+ *
154
+ * @param config the document from {@link translateMcpServers}.
155
+ * @returns the absolute path of the written scratch file.
156
+ * @throws {Error} if the durable write fails — the partial temp is cleaned up first (no residue).
157
+ */
158
+ export async function writeMcpScratch(config) {
159
+ const filePath = path.join(os.tmpdir(), `fork-acp-mcp-${randomUUID()}.json`);
160
+ const text = `${JSON.stringify(config, null, 2)}\n`;
161
+ await durableWrite0600(filePath, text);
162
+ return filePath;
163
+ }
164
+ /**
165
+ * Idempotently remove a scratch file written by {@link writeMcpScratch} (R2.3 teardown). Uses
166
+ * `fs.rm(filePath, { force: true })`, so a missing/already-removed path is a no-op and NEVER throws.
167
+ *
168
+ * @param filePath the path returned by {@link writeMcpScratch}.
169
+ */
170
+ export async function removeMcpScratch(filePath) {
171
+ await fs.rm(filePath, { force: true });
172
+ }
@@ -1,9 +1,36 @@
1
1
  import type { ModelInfo } from "@anthropic-ai/claude-agent-sdk";
2
+ /**
3
+ * Effort levels offered for reasoning-capable models — the SDK's `supportedEffortLevels` vocabulary.
4
+ * Story 060: exported so the ultracode guard test can assert membership stays the five real levels
5
+ * (it must NEVER contain {@link ULTRACODE_EFFORT}; the real `--effort` enum is exactly this set).
6
+ */
7
+ export declare const REASONING_EFFORT_LEVELS: NonNullable<ModelInfo["supportedEffortLevels"]>;
8
+ /**
9
+ * Story 060 — the "ultracode" pseudo-level sentinel for the effort selector. NOT a real `--effort`
10
+ * value (claude 2.1.195 rejects `--effort ultracode`; the enum stays {@link REASONING_EFFORT_LEVELS}).
11
+ * Selecting it maps to `--effort xhigh` PLUS activating the ultracode keyword-trigger for the session
12
+ * (story 060 Task 3). Kept OUT of REASONING_EFFORT_LEVELS so no real-effort code path ever emits it.
13
+ */
14
+ export declare const ULTRACODE_EFFORT = "ultracode";
15
+ /** The real effort level the ultracode pseudo-level maps to (its documented effort component). */
16
+ export declare const ULTRACODE_EFFORT_LEVEL = "xhigh";
17
+ /** Selector label — makes clear it is xhigh + orchestration, NOT a duplicate of the plain `xhigh` entry. */
18
+ export declare const ULTRACODE_EFFORT_LABEL = "ultracode (xhigh + orchestration)";
2
19
  /**
3
20
  * The static curated catalog advertised to the Zed Agent Panel's `model` selector. Each `value` is a
4
21
  * `claude` TUI alias accepted by `/model <alias>` (live) and `--model <alias>` (spawn). `default` is
5
- * first and is the safe fallback. Effort-capable models (`sonnet`, `opus`) carry the metadata that
6
- * surfaces the effort selector; `default`/`haiku`/`opusplan` advertise no effort levels.
22
+ * first and is the safe fallback.
23
+ *
24
+ * ORDER + membership mirror the ORIGINAL's `/model` picker, LIVE-VERIFIED against 2.1.195 (PTY probe):
25
+ * `Default (recommended)`, `Opus`, `Sonnet`, `Sonnet (1M context)`, `Haiku`. The original gets this
26
+ * from the SDK `supportedModels()` the fork cut, so we curate it statically. The 1M alias is literally
27
+ * `sonnet[1m]` (`/model sonnet[1m]` accepted; `sonnet-1m` → "not found"). `opusplan` is a fork-only
28
+ * EXTRA (a real `claude` plan-mode preset the original does not list) kept as the trailing entry.
29
+ *
30
+ * Effort-capable models (`default`/`opus`/`sonnet`/`sonnet[1m]`) carry `supportsEffort` +
31
+ * `supportedEffortLevels`; `haiku`/`opusplan` advertise none. `supportsAutoMode: true` on the same four
32
+ * surfaces the `auto` permission mode (a model classifier) — the original drops `auto` on `haiku`
33
+ * (the SDK signal `reconcileModeFromTranscript` clamps), so haiku/opusplan omit it.
7
34
  */
8
35
  export declare const MODEL_CATALOG: ModelInfo[];
9
36
  /** The safe fallback entry, kept as a named export so callers can seed/anchor on it without a lookup. */
@@ -1 +1 @@
1
- {"version":3,"file":"model-catalog.d.ts","sourceRoot":"","sources":["../src/model-catalog.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAShE;;;;;GAKG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,EA8BpC,CAAC;AAEF,yGAAyG;AACzG,eAAO,MAAM,kBAAkB,EAAE,SAA4B,CAAC"}
1
+ {"version":3,"file":"model-catalog.d.ts","sourceRoot":"","sources":["../src/model-catalog.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAEhE;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,EAAE,WAAW,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAMnF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,cAAc,CAAC;AAE5C,kGAAkG;AAClG,eAAO,MAAM,sBAAsB,UAAU,CAAC;AAE9C,4GAA4G;AAC5G,eAAO,MAAM,sBAAsB,sCAAsC,CAAC;AAE1E;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,EA6CpC,CAAC;AAEF,yGAAyG;AACzG,eAAO,MAAM,kBAAkB,EAAE,SAA4B,CAAC"}
@@ -1,20 +1,58 @@
1
- /** Effort levels offered for reasoning-capable models — the SDK's `supportedEffortLevels` vocabulary. */
2
- const REASONING_EFFORT_LEVELS = [
1
+ /**
2
+ * Effort levels offered for reasoning-capable models — the SDK's `supportedEffortLevels` vocabulary.
3
+ * Story 060: exported so the ultracode guard test can assert membership stays the five real levels
4
+ * (it must NEVER contain {@link ULTRACODE_EFFORT}; the real `--effort` enum is exactly this set).
5
+ */
6
+ export const REASONING_EFFORT_LEVELS = [
3
7
  "low",
4
8
  "medium",
5
9
  "high",
10
+ "xhigh",
11
+ "max",
6
12
  ];
13
+ /**
14
+ * Story 060 — the "ultracode" pseudo-level sentinel for the effort selector. NOT a real `--effort`
15
+ * value (claude 2.1.195 rejects `--effort ultracode`; the enum stays {@link REASONING_EFFORT_LEVELS}).
16
+ * Selecting it maps to `--effort xhigh` PLUS activating the ultracode keyword-trigger for the session
17
+ * (story 060 Task 3). Kept OUT of REASONING_EFFORT_LEVELS so no real-effort code path ever emits it.
18
+ */
19
+ export const ULTRACODE_EFFORT = "ultracode";
20
+ /** The real effort level the ultracode pseudo-level maps to (its documented effort component). */
21
+ export const ULTRACODE_EFFORT_LEVEL = "xhigh";
22
+ /** Selector label — makes clear it is xhigh + orchestration, NOT a duplicate of the plain `xhigh` entry. */
23
+ export const ULTRACODE_EFFORT_LABEL = "ultracode (xhigh + orchestration)";
7
24
  /**
8
25
  * The static curated catalog advertised to the Zed Agent Panel's `model` selector. Each `value` is a
9
26
  * `claude` TUI alias accepted by `/model <alias>` (live) and `--model <alias>` (spawn). `default` is
10
- * first and is the safe fallback. Effort-capable models (`sonnet`, `opus`) carry the metadata that
11
- * surfaces the effort selector; `default`/`haiku`/`opusplan` advertise no effort levels.
27
+ * first and is the safe fallback.
28
+ *
29
+ * ORDER + membership mirror the ORIGINAL's `/model` picker, LIVE-VERIFIED against 2.1.195 (PTY probe):
30
+ * `Default (recommended)`, `Opus`, `Sonnet`, `Sonnet (1M context)`, `Haiku`. The original gets this
31
+ * from the SDK `supportedModels()` the fork cut, so we curate it statically. The 1M alias is literally
32
+ * `sonnet[1m]` (`/model sonnet[1m]` accepted; `sonnet-1m` → "not found"). `opusplan` is a fork-only
33
+ * EXTRA (a real `claude` plan-mode preset the original does not list) kept as the trailing entry.
34
+ *
35
+ * Effort-capable models (`default`/`opus`/`sonnet`/`sonnet[1m]`) carry `supportsEffort` +
36
+ * `supportedEffortLevels`; `haiku`/`opusplan` advertise none. `supportsAutoMode: true` on the same four
37
+ * surfaces the `auto` permission mode (a model classifier) — the original drops `auto` on `haiku`
38
+ * (the SDK signal `reconcileModeFromTranscript` clamps), so haiku/opusplan omit it.
12
39
  */
13
40
  export const MODEL_CATALOG = [
14
41
  {
15
42
  value: "default",
16
- displayName: "Default",
17
- description: "Use the model the claude TUI is configured with (safe fallback).",
43
+ displayName: "Default (recommended)",
44
+ description: "Use the model the claude TUI is configured with (safe fallback); supports reasoning effort.",
45
+ supportsEffort: true,
46
+ supportedEffortLevels: REASONING_EFFORT_LEVELS,
47
+ supportsAutoMode: true,
48
+ },
49
+ {
50
+ value: "opus",
51
+ displayName: "Opus",
52
+ description: "Claude Opus — highest capability; supports reasoning effort.",
53
+ supportsEffort: true,
54
+ supportedEffortLevels: REASONING_EFFORT_LEVELS,
55
+ supportsAutoMode: true,
18
56
  },
19
57
  {
20
58
  value: "sonnet",
@@ -22,13 +60,15 @@ export const MODEL_CATALOG = [
22
60
  description: "Claude Sonnet — balanced speed and capability; supports reasoning effort.",
23
61
  supportsEffort: true,
24
62
  supportedEffortLevels: REASONING_EFFORT_LEVELS,
63
+ supportsAutoMode: true,
25
64
  },
26
65
  {
27
- value: "opus",
28
- displayName: "Opus",
29
- description: "Claude Opus highest capability; supports reasoning effort.",
66
+ value: "sonnet[1m]",
67
+ displayName: "Sonnet (1M context)",
68
+ description: "Claude Sonnet with a 1M-token context window; draws from usage credits; supports reasoning effort.",
30
69
  supportsEffort: true,
31
70
  supportedEffortLevels: REASONING_EFFORT_LEVELS,
71
+ supportsAutoMode: true,
32
72
  },
33
73
  {
34
74
  value: "haiku",
@@ -38,7 +78,7 @@ export const MODEL_CATALOG = [
38
78
  {
39
79
  value: "opusplan",
40
80
  displayName: "Opus Plan",
41
- description: "Opus while planning, Sonnet for execution (plan-mode workflow).",
81
+ description: "Opus while planning, Sonnet for execution (plan-mode workflow; fork extra).",
42
82
  },
43
83
  ];
44
84
  /** The safe fallback entry, kept as a named export so callers can seed/anchor on it without a lookup. */
@@ -34,6 +34,13 @@ export declare const DEFAULT_CORRELATION_POLL_MS = 50;
34
34
  * fail-closed timeout deny. Tracked separately from the poll interval (the poll is 10-50ms; nudging on
35
35
  * every poll would hammer the pump) — a nudge fires only once ~250ms has elapsed since the last one. */
36
36
  export declare const DEFAULT_CORRELATION_RENUDGE_MS = 250;
37
+ /**
38
+ * FIX(watchdog-permission): while a permission dialog is pending the claude is BLOCKED and writes
39
+ * nothing to the JSONL, so the end-of-turn watchdog (120s of silence) would mistake a long human
40
+ * decision for a dead turn. Re-arm it every this-many ms via the bound `noteActivity` for as long as
41
+ * the dialog is open. Must stay well under TURN_STALL_WATCHDOG_MS (120_000).
42
+ */
43
+ export declare const DEFAULT_PERMISSION_HEARTBEAT_MS = 30000;
37
44
  /** Default window for the native prompt to APPEAR after an allow decision (#52822 sweep, ms).
38
45
  * If no marker renders within it, allow-suppression held (the 2.1.161 case) — nothing to clear. */
39
46
  export declare const DEFAULT_PROMPT_APPEAR_MS = 1500;
@@ -99,6 +106,9 @@ export type ResolveSubagentRelay = (innerToolUseId: string) => SubagentRelay | u
99
106
  export interface SessionGate {
100
107
  /** The verified-free loopback port the hook server bound (== the port in the scratch hook URL). */
101
108
  port: number;
109
+ /** Story 055 (R1.3) — the per-session secret token bound into the hook URL after the marker path.
110
+ * The hook-server rejects any PreToolUse POST that does not present `${marker}/<token>`. */
111
+ readonly token: string;
102
112
  /** Absolute path of the per-session scratch settings file (hand to the spawn as `--settings`). */
103
113
  settingsPath: string;
104
114
  /** The per-session `tool_use.id` correlation map. The live pump REGISTERS every JSONL `tool_use`
@@ -116,7 +126,9 @@ export interface SessionGate {
116
126
  * relay a KNOWN subagent tool's dialog under its parent Task id (R1/R2), or to fail LOUD (R4) on
117
127
  * an orphan / uncorrelatable subagent. A main-chain tool (no resolver entry) is unchanged (U1).
118
128
  */
119
- bindSession(sessionId: string, nudge?: () => void, resolveSubagentRelay?: ResolveSubagentRelay): void;
129
+ bindSession(sessionId: string, nudge?: () => void, resolveSubagentRelay?: ResolveSubagentRelay,
130
+ /** FIX(watchdog-permission) — re-arms the end-of-turn watchdog while a permission dialog is open. */
131
+ noteActivity?: () => void): void;
120
132
  /** Bind the live PTY: stores the raw writer for the allow keystroke and (when the PTY exposes
121
133
  * `onData`) attaches the recent-output tap feeding the native-prompt probe. */
122
134
  bindPty(pty: GatePty): void;
@@ -1 +1 @@
1
- {"version":3,"file":"gate-wiring.d.ts","sourceRoot":"","sources":["../../src/permissions/gate-wiring.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gate-wiring.d.ts","sourceRoot":"","sources":["../../src/permissions/gate-wiring.ts"],"names":[],"mappings":"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"}