@lucascouts/claude-agent-tui 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.
Files changed (112) hide show
  1. package/LICENSE +191 -0
  2. package/NOTICE +14 -0
  3. package/README.md +50 -0
  4. package/dist/acp-agent.d.ts +594 -0
  5. package/dist/acp-agent.d.ts.map +1 -0
  6. package/dist/acp-agent.js +2139 -0
  7. package/dist/ansi-mirror.d.ts +42 -0
  8. package/dist/ansi-mirror.d.ts.map +1 -0
  9. package/dist/ansi-mirror.js +61 -0
  10. package/dist/besteffort.d.ts +44 -0
  11. package/dist/besteffort.d.ts.map +1 -0
  12. package/dist/besteffort.js +100 -0
  13. package/dist/billing/entrypoint-guard.d.ts +97 -0
  14. package/dist/billing/entrypoint-guard.d.ts.map +1 -0
  15. package/dist/billing/entrypoint-guard.js +166 -0
  16. package/dist/claude-path.d.ts +12 -0
  17. package/dist/claude-path.d.ts.map +1 -0
  18. package/dist/claude-path.js +61 -0
  19. package/dist/diff-enriched-reader.d.ts +41 -0
  20. package/dist/diff-enriched-reader.d.ts.map +1 -0
  21. package/dist/diff-enriched-reader.js +106 -0
  22. package/dist/diff-source.d.ts +104 -0
  23. package/dist/diff-source.d.ts.map +1 -0
  24. package/dist/diff-source.js +164 -0
  25. package/dist/end-of-turn.d.ts +172 -0
  26. package/dist/end-of-turn.d.ts.map +1 -0
  27. package/dist/end-of-turn.js +415 -0
  28. package/dist/engine-lifecycle.d.ts +222 -0
  29. package/dist/engine-lifecycle.d.ts.map +1 -0
  30. package/dist/engine-lifecycle.js +236 -0
  31. package/dist/engine-pty.d.ts +143 -0
  32. package/dist/engine-pty.d.ts.map +1 -0
  33. package/dist/engine-pty.js +222 -0
  34. package/dist/engine-watcher.d.ts +83 -0
  35. package/dist/engine-watcher.d.ts.map +1 -0
  36. package/dist/engine-watcher.js +173 -0
  37. package/dist/engine.d.ts +30 -0
  38. package/dist/engine.d.ts.map +1 -0
  39. package/dist/engine.js +34 -0
  40. package/dist/event-switch.d.ts +164 -0
  41. package/dist/event-switch.d.ts.map +1 -0
  42. package/dist/event-switch.js +206 -0
  43. package/dist/gate/port.d.ts +38 -0
  44. package/dist/gate/port.d.ts.map +1 -0
  45. package/dist/gate/port.js +126 -0
  46. package/dist/gate/settings-writer.d.ts +130 -0
  47. package/dist/gate/settings-writer.d.ts.map +1 -0
  48. package/dist/gate/settings-writer.js +349 -0
  49. package/dist/index.d.ts +3 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +106 -0
  52. package/dist/jsonl.d.ts +267 -0
  53. package/dist/jsonl.d.ts.map +1 -0
  54. package/dist/jsonl.js +527 -0
  55. package/dist/lib.d.ts +6 -0
  56. package/dist/lib.d.ts.map +1 -0
  57. package/dist/lib.js +5 -0
  58. package/dist/linearize.d.ts +219 -0
  59. package/dist/linearize.d.ts.map +1 -0
  60. package/dist/linearize.js +444 -0
  61. package/dist/live-diff-env.d.ts +7 -0
  62. package/dist/live-diff-env.d.ts.map +1 -0
  63. package/dist/live-diff-env.js +18 -0
  64. package/dist/live-subagent-env.d.ts +7 -0
  65. package/dist/live-subagent-env.d.ts.map +1 -0
  66. package/dist/live-subagent-env.js +19 -0
  67. package/dist/permissions/allow-inject.d.ts +67 -0
  68. package/dist/permissions/allow-inject.d.ts.map +1 -0
  69. package/dist/permissions/allow-inject.js +85 -0
  70. package/dist/permissions/deny.d.ts +60 -0
  71. package/dist/permissions/deny.d.ts.map +1 -0
  72. package/dist/permissions/deny.js +81 -0
  73. package/dist/permissions/gate-wiring.d.ts +112 -0
  74. package/dist/permissions/gate-wiring.d.ts.map +1 -0
  75. package/dist/permissions/gate-wiring.js +350 -0
  76. package/dist/permissions/hook-server.d.ts +72 -0
  77. package/dist/permissions/hook-server.d.ts.map +1 -0
  78. package/dist/permissions/hook-server.js +179 -0
  79. package/dist/permissions/permission-mode.d.ts +67 -0
  80. package/dist/permissions/permission-mode.d.ts.map +1 -0
  81. package/dist/permissions/permission-mode.js +100 -0
  82. package/dist/permissions/request-permission.d.ts +102 -0
  83. package/dist/permissions/request-permission.d.ts.map +1 -0
  84. package/dist/permissions/request-permission.js +124 -0
  85. package/dist/settings.d.ts +68 -0
  86. package/dist/settings.d.ts.map +1 -0
  87. package/dist/settings.js +182 -0
  88. package/dist/stop-reason-map.d.ts +17 -0
  89. package/dist/stop-reason-map.d.ts.map +1 -0
  90. package/dist/stop-reason-map.js +33 -0
  91. package/dist/subagent-source.d.ts +63 -0
  92. package/dist/subagent-source.d.ts.map +1 -0
  93. package/dist/subagent-source.js +132 -0
  94. package/dist/subagent-watcher.d.ts +40 -0
  95. package/dist/subagent-watcher.d.ts.map +1 -0
  96. package/dist/subagent-watcher.js +108 -0
  97. package/dist/tools.d.ts +119 -0
  98. package/dist/tools.d.ts.map +1 -0
  99. package/dist/tools.js +729 -0
  100. package/dist/usage-env.d.ts +7 -0
  101. package/dist/usage-env.d.ts.map +1 -0
  102. package/dist/usage-env.js +16 -0
  103. package/dist/usage.d.ts +54 -0
  104. package/dist/usage.d.ts.map +1 -0
  105. package/dist/usage.js +53 -0
  106. package/dist/utils.d.ts +16 -0
  107. package/dist/utils.d.ts.map +1 -0
  108. package/dist/utils.js +83 -0
  109. package/dist/zed-register.d.ts +26 -0
  110. package/dist/zed-register.d.ts.map +1 -0
  111. package/dist/zed-register.js +106 -0
  112. package/package.json +79 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-enriched-reader.d.ts","sourceRoot":"","sources":["../src/diff-enriched-reader.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EAAE,WAAW,EAAkB,MAAM,qBAAqB,CAAC;AAEvE;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAiBzE;AAED,mGAAmG;AACnG,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,cAAc,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;IACjD;;;;OAIG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;CAC3C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,WAAW,EACjB,IAAI,GAAE,yBAA8B,GACnC,WAAW,CAoCb"}
@@ -0,0 +1,106 @@
1
+ // Story 043 / Task 1.1 (R1.1, R1.2, R1.3, R4.2) — the diff-enriched reduced-shape reader.
2
+ //
3
+ // PROBLEM. `getSessionMessages` returns the REDUCED shape (6 fields; see the
4
+ // getsessionmessages-reduced-shape follow-up): it does NOT carry the per-type `toolUseResult` that the
5
+ // story-021/026 Edit/Write diff block reads off `turn.message.toolUseResult` (acp-agent.ts:1461). With
6
+ // the PTY engine the PostToolUse hook that once produced diffs is GONE, so a live pump over the reduced
7
+ // shape renders no diff — the diff silently no-ops.
8
+ //
9
+ // SOLUTION (REUSE-faithful, billing-free). WRAP the base reader and HYDRATE each returned message's
10
+ // `toolUseResult` from the raw JSONL transcript, matched by `uuid`:
11
+ // - ordering / identity stay the base reader's (the SDK is the single parser; we add ONE key);
12
+ // - the raw read is a pure `fs` read of the transcript located via `findTranscript(sessionId)` — NO
13
+ // SDK call, so NO token billing (R4.2);
14
+ // - a message whose raw record has no `toolUseResult` is returned UNCHANGED — we NEVER fabricate a
15
+ // patch (R1.2 / R4.2);
16
+ // - any failure to locate / read / parse the transcript falls back to the plain reduced messages so
17
+ // the diff degrades to the existing graceful no-op and the pump NEVER crashes (R1.3).
18
+ //
19
+ // DEVIATION (recorded in .draft/deviations.yaml, task 1.1/2.2). design.md sketched
20
+ // `createDiffEnrichedReader(session.transcriptPath, base)`, but `session.transcriptPath` does not exist
21
+ // (neither SessionState nor StartedEngine expose it) and `this.getMessages` is AGENT-level (shared
22
+ // across sessions). So the reader derives the path itself from the `sessionId` it already receives via
23
+ // `findTranscript(sessionId)[0]` — keeping the wiring agent-level (one `this.getMessages` covers both
24
+ // pumpUpdates and replaySessionHistory), multi-session safe, and correct on the story-028 fresh path
25
+ // (the path resolves at use-time, when the transcript already exists).
26
+ //
27
+ // node: builtins + the in-fork jsonl glob only — no new runtime dep, no lib.ts export (frozen surface).
28
+ import { readFileSync } from "node:fs";
29
+ import { findTranscript as defaultFindTranscript } from "./jsonl.js";
30
+ /**
31
+ * Build a `uuid → toolUseResult` index from raw JSONL transcript lines.
32
+ *
33
+ * Only records that ARE plain objects carrying BOTH a string `uuid` AND a defined `toolUseResult`
34
+ * enter the map — a record without a `toolUseResult` is intentionally absent so the matching message is
35
+ * returned unchanged (R1.2). Empty/whitespace lines and malformed JSON are skipped silently (robustness:
36
+ * a torn or partially-written final line must never throw and abort the hydration).
37
+ *
38
+ * @param rawLines the transcript's newline-split lines (READ-ONLY; never mutated).
39
+ * @returns a map from message uuid to its raw `toolUseResult` value (possibly empty).
40
+ */
41
+ export function toolUseResultMap(rawLines) {
42
+ const map = new Map();
43
+ for (const line of rawLines) {
44
+ if (line.trim() === "")
45
+ continue; // skip blank lines (e.g. the trailing newline split)
46
+ let rec;
47
+ try {
48
+ rec = JSON.parse(line);
49
+ }
50
+ catch {
51
+ continue; // malformed / partially-written line — skip silently, never throw
52
+ }
53
+ if (rec === null || typeof rec !== "object")
54
+ continue;
55
+ const { uuid, toolUseResult } = rec;
56
+ if (typeof uuid === "string" && toolUseResult !== undefined) {
57
+ map.set(uuid, toolUseResult);
58
+ }
59
+ }
60
+ return map;
61
+ }
62
+ /**
63
+ * Wrap a base `getSessionMessages`-shaped reader so each returned message gains its `toolUseResult`
64
+ * from the raw transcript, matched by `uuid`. This is PURE hydration: ordering and identity come from
65
+ * `base`; only the top-level `toolUseResult` key is added (exactly where the diff block reads it,
66
+ * `turn.message.toolUseResult`). Billing-free — the only extra cost is one `fs` read of the transcript
67
+ * located from the `sessionId` (R4.2). On ANY locate/read/parse failure, or when no record carries a
68
+ * `toolUseResult`, the plain reduced messages are returned unchanged (R1.3) and NO patch is fabricated.
69
+ *
70
+ * @param base the underlying reader (the SDK `getSessionMessages`, or an injected stub).
71
+ * @param opts injectable {@link DiffEnrichedReaderOptions} seams (defaults are production behaviour).
72
+ * @returns a {@link GetMessages} that yields the base messages with `toolUseResult` hydrated by uuid.
73
+ */
74
+ export function createDiffEnrichedReader(base, opts = {}) {
75
+ const findTranscript = opts.findTranscript ?? defaultFindTranscript;
76
+ const readRawLines = opts.readRawLines ?? ((path) => readFileSync(path, "utf8").split("\n"));
77
+ return async (sessionId, readerOpts) => {
78
+ // base is the single source of order/identity (and the only billed reader) — invoked exactly once.
79
+ const reduced = await base(sessionId, readerOpts);
80
+ // Locate the transcript from the sessionId. A throw OR an empty glob → no raw source: return the
81
+ // reduced messages unchanged (R1.3; no fabrication, R4.2).
82
+ let path;
83
+ try {
84
+ path = findTranscript(sessionId)[0];
85
+ }
86
+ catch {
87
+ return reduced;
88
+ }
89
+ if (!path)
90
+ return reduced;
91
+ // Read the raw transcript. A read failure must NEVER crash the pump → fall back to reduced (R1.3).
92
+ let raw;
93
+ try {
94
+ raw = readRawLines(path);
95
+ }
96
+ catch {
97
+ return reduced;
98
+ }
99
+ const map = toolUseResultMap(raw);
100
+ if (map.size === 0)
101
+ return reduced; // nothing to hydrate → reduced unchanged
102
+ // Attach the matched toolUseResult as a top-level key; unmatched messages pass through UNCHANGED
103
+ // (they never gain a `toolUseResult` key — R1.2 / R4.2).
104
+ return reduced.map((m) => typeof m.uuid === "string" && map.has(m.uuid) ? { ...m, toolUseResult: map.get(m.uuid) } : m);
105
+ };
106
+ }
@@ -0,0 +1,104 @@
1
+ import type { ToolCallContent } from "@agentclientprotocol/sdk";
2
+ /** A single diff hunk — the unit the reused `toolUpdateFromDiffToolResponse` reads `lines` from. */
3
+ export interface Hunk {
4
+ readonly oldStart: number;
5
+ readonly oldLines: number;
6
+ readonly newStart: number;
7
+ readonly newLines: number;
8
+ readonly lines: readonly string[];
9
+ }
10
+ /**
11
+ * The classification of a `toolUseResult` as a diff source, discriminated by `kind`.
12
+ *
13
+ * - `not-a-diff-source` — the payload carries none of the diff-source fields and cannot
14
+ * reconstruct a diff (Task 1.1; e.g. a `file-history-snapshot`).
15
+ * - `edit` — an Edit (`type:update`): carries `filePath`, the pre-edit `originalFile`, and the
16
+ * `structuredPatch` hunks fed VERBATIM to the reused translator.
17
+ * - `write` — a Write (`type:create`): carries `filePath` and the new-file `content` (its
18
+ * structuredPatch is empty; the renderable hunk is synthesised in {@link toDiffToolResponse}).
19
+ * - `unsupported` — a diff-bearing payload whose shape could not be verified (skip-and-logged).
20
+ */
21
+ export type DiffSource = {
22
+ readonly kind: "not-a-diff-source";
23
+ } | {
24
+ readonly kind: "edit";
25
+ readonly filePath: string;
26
+ readonly originalFile: string;
27
+ readonly structuredPatch: readonly Hunk[];
28
+ } | {
29
+ readonly kind: "write";
30
+ readonly filePath: string;
31
+ readonly content: string;
32
+ } | {
33
+ readonly kind: "unsupported";
34
+ readonly tool?: string;
35
+ };
36
+ /** The source shape consumed by the reused `toolUpdateFromDiffToolResponse` (tools.ts). */
37
+ export interface DiffToolResponseInput {
38
+ readonly filePath: string;
39
+ readonly structuredPatch: readonly Hunk[];
40
+ }
41
+ /**
42
+ * Classify a `user` event's `toolUseResult` as a diff source.
43
+ *
44
+ * Returns, in order: `not-a-diff-source` when `toolUseResult` is not a non-null object, or holds NONE
45
+ * of the diff-source fields (`structuredPatch` array / `content` / `originalFile`) AND its tool name
46
+ * is not diff-bearing (Task 1.1; e.g. a `file-history-snapshot`, name `undefined`); `unsupported`
47
+ * (skip-and-logged) when a diff-bearing tool name (Task 3.2 — `MultiEdit`/`NotebookEdit`/`mcp__…`)
48
+ * carries an unmappable shape; `edit` for an Edit (`name === "Edit"`, or a non-empty `structuredPatch`
49
+ * paired with a string `originalFile` — so a recognised MultiEdit shape maps here too), carrying
50
+ * `{filePath, originalFile, structuredPatch}`; `write` for a Write (`name === "Write"`, or an EMPTY
51
+ * `structuredPatch` paired with a string `content`), carrying `{filePath, content}`; and `unsupported`
52
+ * (skip-and-logged) for a diff-bearing payload whose required field is missing or the wrong type.
53
+ * NEVER throws; NEVER emits a half-built edit/write with an undefined field; NEVER aborts the pipeline.
54
+ *
55
+ * @param name - The originating tool name (`Edit`, `Write`, …), or `undefined` when unknown.
56
+ * @param toolUseResult - The raw `toolUseResult` value to inspect (READ-ONLY, never mutated).
57
+ * @returns A {@link DiffSource}.
58
+ */
59
+ export declare function classifyDiffSource(name: string | undefined, toolUseResult: unknown): DiffSource;
60
+ /**
61
+ * Assemble the `{filePath, structuredPatch}` input consumed by the reused
62
+ * `toolUpdateFromDiffToolResponse` (tools.ts) — the only thing this module produces for rendering.
63
+ *
64
+ * - `edit` — pass the hunks through VERBATIM (same array reference): `{filePath, structuredPatch}`.
65
+ * - `write` — normalise to a single synthetic all-additions hunk (see {@link syntheticAdditionHunk})
66
+ * so the reused translator emits `oldText:null` / newText=`content`.
67
+ * - `unsupported` / `not-a-diff-source` — not renderable; returns `null`.
68
+ *
69
+ * This module does NOT call `toolUpdateFromDiffToolResponse` and does NOT hand-build diff content —
70
+ * the caller (the tests now; story 023 later) feeds this input to the reused translator.
71
+ *
72
+ * @param source - A {@link DiffSource} from {@link classifyDiffSource}.
73
+ * @returns The reused translator's input, or `null` when `source` is not renderable.
74
+ */
75
+ export declare function toDiffToolResponse(source: DiffSource): DiffToolResponseInput | null;
76
+ /**
77
+ * The §7 `tool_call_update` envelope carrying rendered diff content, attached to an OPEN tool call.
78
+ *
79
+ * It updates an already-open tool call (the story 019 seam keyed by `toolCallId`); it does NOT open a
80
+ * new one. `content` is the diff content rendered by the reused `toolUpdateFromDiffToolResponse`.
81
+ */
82
+ export interface DiffToolCallUpdate {
83
+ readonly sessionUpdate: "tool_call_update";
84
+ readonly toolCallId: string;
85
+ readonly content: ToolCallContent[];
86
+ }
87
+ /**
88
+ * Render a classified diff source into a §7 `tool_call_update` (Task 3.1, R4.1/R4.2).
89
+ *
90
+ * Feeds {@link toDiffToolResponse}'s `{filePath, structuredPatch}` input to the REUSED, unmodified
91
+ * `toolUpdateFromDiffToolResponse` (tools.ts §3) — the ONLY place this module calls the reused
92
+ * translator — and wraps the rendered hunks in the envelope attached to the OPEN `toolCallId` (story
93
+ * 019 seam; this does not open a new tool call). The reused translator dictates oldText/newText
94
+ * (Decision A): for an Edit the JSONL `structuredPatch` is fed VERBATIM (shim: none); for a Write the
95
+ * synthetic all-additions hunk is supplied by {@link toDiffToolResponse} (the empty structuredPatch is
96
+ * not accepted verbatim), so the new file renders with `oldText:null`.
97
+ *
98
+ * @param source - A {@link DiffSource} from {@link classifyDiffSource}.
99
+ * @param toolCallId - The OPEN tool call id the diff content attaches to.
100
+ * @returns The `tool_call_update` envelope, or `null` when `source` is not renderable or yields no
101
+ * diff content (an unsupported/not-a-diff-source source, or a translation with no `content`).
102
+ */
103
+ export declare function diffToolCallUpdate(source: DiffSource, toolCallId: string): DiffToolCallUpdate | null;
104
+ //# sourceMappingURL=diff-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-source.d.ts","sourceRoot":"","sources":["../src/diff-source.ts"],"names":[],"mappings":"AAgEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAGhE,oGAAoG;AACpG,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAA;CAAE,GACtC;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,eAAe,EAAE,SAAS,IAAI,EAAE,CAAC;CAC3C,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC/E;IAAE,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7D,2FAA2F;AAC3F,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,eAAe,EAAE,SAAS,IAAI,EAAE,CAAC;CAC3C;AAsCD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,aAAa,EAAE,OAAO,GAAG,UAAU,CAiD/F;AAoBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,qBAAqB,GAAG,IAAI,CAanF;AAED;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,aAAa,EAAE,kBAAkB,CAAC;IAC3C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,eAAe,EAAE,CAAC;CACrC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,MAAM,GACjB,kBAAkB,GAAG,IAAI,CAU3B"}
@@ -0,0 +1,164 @@
1
+ import { toolUpdateFromDiffToolResponse } from "./tools.js";
2
+ /** The not-a-diff-source result is a singleton — it carries no payload, so it can be shared. */
3
+ const NOT_A_DIFF_SOURCE = { kind: "not-a-diff-source" };
4
+ /** True when `value` is a non-null object (the only shape that can hold diff-source fields). */
5
+ function isObject(value) {
6
+ return typeof value === "object" && value !== null;
7
+ }
8
+ /** True when `value` is a string — the type both `originalFile` and `content` must have to be usable. */
9
+ function isString(value) {
10
+ return typeof value === "string";
11
+ }
12
+ /** The explicit diff-producing tool names (besides the `mcp__` prefix, handled in {@link isDiffBearingName}). */
13
+ const DIFF_BEARING_NAMES = new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
14
+ /**
15
+ * True when `name` denotes a diff-producing tool (Task 3.2). A contentless payload from such a tool is
16
+ * skip-and-logged drift telemetry (`unsupported`), whereas a contentless payload with NO diff-bearing
17
+ * name (e.g. a `file-history-snapshot`, name `undefined`) stays the silent `not-a-diff-source` (Task
18
+ * 1.1). The set is {@link DIFF_BEARING_NAMES} plus any MCP tool (`mcp__…`); never assume a fixed set.
19
+ */
20
+ function isDiffBearingName(name) {
21
+ return name !== undefined && (DIFF_BEARING_NAMES.has(name) || name.startsWith("mcp__"));
22
+ }
23
+ /**
24
+ * Skip-and-log seam (§6, consistent with event-switch.ts): a diff-bearing payload whose shape could
25
+ * not be verified is logged to STDERR — NEVER stdout, which carries the ACP stream — and degraded to
26
+ * `unsupported`. Returning the discriminated result keeps every caller a single tolerant expression.
27
+ */
28
+ function skipAndLog(name, reason) {
29
+ console.error(`[diff-source] skipping ${name ?? "<unknown tool>"}: ${reason}`);
30
+ return { kind: "unsupported", tool: name };
31
+ }
32
+ /**
33
+ * Classify a `user` event's `toolUseResult` as a diff source.
34
+ *
35
+ * Returns, in order: `not-a-diff-source` when `toolUseResult` is not a non-null object, or holds NONE
36
+ * of the diff-source fields (`structuredPatch` array / `content` / `originalFile`) AND its tool name
37
+ * is not diff-bearing (Task 1.1; e.g. a `file-history-snapshot`, name `undefined`); `unsupported`
38
+ * (skip-and-logged) when a diff-bearing tool name (Task 3.2 — `MultiEdit`/`NotebookEdit`/`mcp__…`)
39
+ * carries an unmappable shape; `edit` for an Edit (`name === "Edit"`, or a non-empty `structuredPatch`
40
+ * paired with a string `originalFile` — so a recognised MultiEdit shape maps here too), carrying
41
+ * `{filePath, originalFile, structuredPatch}`; `write` for a Write (`name === "Write"`, or an EMPTY
42
+ * `structuredPatch` paired with a string `content`), carrying `{filePath, content}`; and `unsupported`
43
+ * (skip-and-logged) for a diff-bearing payload whose required field is missing or the wrong type.
44
+ * NEVER throws; NEVER emits a half-built edit/write with an undefined field; NEVER aborts the pipeline.
45
+ *
46
+ * @param name - The originating tool name (`Edit`, `Write`, …), or `undefined` when unknown.
47
+ * @param toolUseResult - The raw `toolUseResult` value to inspect (READ-ONLY, never mutated).
48
+ * @returns A {@link DiffSource}.
49
+ */
50
+ export function classifyDiffSource(name, toolUseResult) {
51
+ if (!isObject(toolUseResult)) {
52
+ return NOT_A_DIFF_SOURCE;
53
+ }
54
+ const structuredPatch = toolUseResult.structuredPatch;
55
+ const hasStructuredPatch = Array.isArray(structuredPatch);
56
+ const hasContent = "content" in toolUseResult;
57
+ const hasOriginalFile = "originalFile" in toolUseResult;
58
+ // No diff-source field is present. A diff-bearing tool name (Task 3.2 — MultiEdit/NotebookEdit/MCP)
59
+ // means a tool that SHOULD have produced a patch shipped one we cannot map: detect + log it as drift
60
+ // telemetry and degrade to `unsupported`. A payload with no diff-bearing name (e.g. a
61
+ // `file-history-snapshot`, name `undefined`) is the silent `not-a-diff-source` (Task 1.1).
62
+ if (!hasStructuredPatch && !hasContent && !hasOriginalFile) {
63
+ return isDiffBearingName(name)
64
+ ? skipAndLog(name, "diff-bearing tool produced no usable structuredPatch/originalFile/content")
65
+ : NOT_A_DIFF_SOURCE;
66
+ }
67
+ const filePath = toolUseResult.filePath;
68
+ const originalFile = toolUseResult.originalFile;
69
+ const content = toolUseResult.content;
70
+ // Edit (`type:update`): an explicit Edit name, OR a non-empty structuredPatch alongside a string
71
+ // `originalFile`. The hunks reconstruct the diff; without `originalFile` (or without a usable
72
+ // filePath/patch) the Edit shape is unverified and skipped — never a half-built edit.
73
+ const looksLikeEdit = name === "Edit" || (hasStructuredPatch && structuredPatch.length > 0 && isString(originalFile));
74
+ if (looksLikeEdit) {
75
+ if (!isString(filePath) || !isString(originalFile) || !hasStructuredPatch) {
76
+ return skipAndLog(name, "Edit is missing filePath, originalFile, or structuredPatch");
77
+ }
78
+ return { kind: "edit", filePath, originalFile, structuredPatch: structuredPatch };
79
+ }
80
+ // Write (`type:create`): an explicit Write name, OR an EMPTY structuredPatch alongside a string
81
+ // `content`. The new-file body lives in `content`; without it there is nothing to render — skip.
82
+ const looksLikeWrite = name === "Write" || (hasStructuredPatch && structuredPatch.length === 0 && isString(content));
83
+ if (looksLikeWrite) {
84
+ if (!isString(filePath) || !isString(content)) {
85
+ return skipAndLog(name, "Write is missing filePath or content");
86
+ }
87
+ return { kind: "write", filePath, content };
88
+ }
89
+ // A diff-source field IS present but the shape matched neither a verifiable Edit nor Write.
90
+ return skipAndLog(name, "diff-bearing payload of an unverified shape");
91
+ }
92
+ /**
93
+ * Build one synthetic all-additions hunk from a new file's `content` (Decision A, D3).
94
+ *
95
+ * Every line of `content` is prefixed `+`, so the reused translator — which reads only the hunk
96
+ * `lines` — collects NO `-`/context lines and therefore yields `oldText:null` (literal null) and
97
+ * newText=`content`. The hunk header marks the whole body as added: oldStart/oldLines 0/0, newStart 1.
98
+ */
99
+ function syntheticAdditionHunk(content) {
100
+ const lines = content.split("\n");
101
+ return {
102
+ oldStart: 0,
103
+ oldLines: 0,
104
+ newStart: 1,
105
+ newLines: lines.length,
106
+ lines: lines.map((line) => "+" + line),
107
+ };
108
+ }
109
+ /**
110
+ * Assemble the `{filePath, structuredPatch}` input consumed by the reused
111
+ * `toolUpdateFromDiffToolResponse` (tools.ts) — the only thing this module produces for rendering.
112
+ *
113
+ * - `edit` — pass the hunks through VERBATIM (same array reference): `{filePath, structuredPatch}`.
114
+ * - `write` — normalise to a single synthetic all-additions hunk (see {@link syntheticAdditionHunk})
115
+ * so the reused translator emits `oldText:null` / newText=`content`.
116
+ * - `unsupported` / `not-a-diff-source` — not renderable; returns `null`.
117
+ *
118
+ * This module does NOT call `toolUpdateFromDiffToolResponse` and does NOT hand-build diff content —
119
+ * the caller (the tests now; story 023 later) feeds this input to the reused translator.
120
+ *
121
+ * @param source - A {@link DiffSource} from {@link classifyDiffSource}.
122
+ * @returns The reused translator's input, or `null` when `source` is not renderable.
123
+ */
124
+ export function toDiffToolResponse(source) {
125
+ switch (source.kind) {
126
+ case "edit":
127
+ return { filePath: source.filePath, structuredPatch: source.structuredPatch };
128
+ case "write":
129
+ return {
130
+ filePath: source.filePath,
131
+ structuredPatch: [syntheticAdditionHunk(source.content)],
132
+ };
133
+ case "unsupported":
134
+ case "not-a-diff-source":
135
+ return null;
136
+ }
137
+ }
138
+ /**
139
+ * Render a classified diff source into a §7 `tool_call_update` (Task 3.1, R4.1/R4.2).
140
+ *
141
+ * Feeds {@link toDiffToolResponse}'s `{filePath, structuredPatch}` input to the REUSED, unmodified
142
+ * `toolUpdateFromDiffToolResponse` (tools.ts §3) — the ONLY place this module calls the reused
143
+ * translator — and wraps the rendered hunks in the envelope attached to the OPEN `toolCallId` (story
144
+ * 019 seam; this does not open a new tool call). The reused translator dictates oldText/newText
145
+ * (Decision A): for an Edit the JSONL `structuredPatch` is fed VERBATIM (shim: none); for a Write the
146
+ * synthetic all-additions hunk is supplied by {@link toDiffToolResponse} (the empty structuredPatch is
147
+ * not accepted verbatim), so the new file renders with `oldText:null`.
148
+ *
149
+ * @param source - A {@link DiffSource} from {@link classifyDiffSource}.
150
+ * @param toolCallId - The OPEN tool call id the diff content attaches to.
151
+ * @returns The `tool_call_update` envelope, or `null` when `source` is not renderable or yields no
152
+ * diff content (an unsupported/not-a-diff-source source, or a translation with no `content`).
153
+ */
154
+ export function diffToolCallUpdate(source, toolCallId) {
155
+ const input = toDiffToolResponse(source);
156
+ if (input === null) {
157
+ return null;
158
+ }
159
+ const { content } = toolUpdateFromDiffToolResponse(input);
160
+ if (content === undefined || content.length === 0) {
161
+ return null;
162
+ }
163
+ return { sessionUpdate: "tool_call_update", toolCallId, content };
164
+ }
@@ -0,0 +1,172 @@
1
+ import type { PromptResponse } from "@agentclientprotocol/sdk";
2
+ import { TURN_WATCHDOG_MS } from "./linearize.js";
3
+ import { FILE_DISCOVERY_WATCHDOG_MS } from "./jsonl.js";
4
+ import { type StopReasonLogger } from "./stop-reason-map.js";
5
+ export { TURN_WATCHDOG_MS, FILE_DISCOVERY_WATCHDOG_MS };
6
+ /**
7
+ * Default STALL window (ms): the watchdog trips only after this much transcript silence while a
8
+ * turn is in flight. Generous on purpose — a long text block or tool run writes nothing for tens of
9
+ * seconds; the watchdog exists to fail a DEAD turn loudly (R5.2), not to cap a slow one.
10
+ */
11
+ export declare const TURN_STALL_WATCHDOG_MS = 120000;
12
+ /** Env var overriding the default stall window per process (positive integer ms). */
13
+ export declare const TURN_WATCHDOG_ENV = "FORK_TURN_WATCHDOG_MS";
14
+ /**
15
+ * The TERMINAL `message.stop_reason` values (E3 augmented predicate, Binding decision 2). An
16
+ * `assistant` event whose stop_reason is one of these is an end-of-turn boundary CANDIDATE; a
17
+ * `tool_use` pause (or `null`) is mid-turn and NOT a boundary. Typed `ReadonlySet` so the set
18
+ * cannot drift at a call site.
19
+ */
20
+ export declare const TERMINAL_STOP_REASONS: ReadonlySet<string>;
21
+ /**
22
+ * The minimal structural shape the predicate reads off a story-015/016 typed `JsonlEvent` (only
23
+ * `.type` and `.message` are inspected). Kept structural — and every field `unknown` — so the
24
+ * predicate stays defensive: it never assumes a fixed `.type` set and never throws on a string-or-
25
+ * array `message.content` (§6 tolerant parser, R1.2/R3 forward-compat).
26
+ */
27
+ export interface StopReasonEvent {
28
+ readonly type?: unknown;
29
+ readonly message?: unknown;
30
+ /** Sidechain (subagent) back-pointer, SDK snake_case — non-null marks a sidechain row (R4.1). */
31
+ readonly parent_tool_use_id?: unknown;
32
+ /** Sidechain back-pointer, story-015 typed alias — read alongside the snake_case form (R4.1). */
33
+ readonly parentToolUseId?: unknown;
34
+ }
35
+ /**
36
+ * The E3 augmented predicate (Binding decision 2): is `event` an `assistant` event whose
37
+ * `message.stop_reason` is a TERMINAL value? Reads everything defensively — a non-`assistant`
38
+ * `.type`, a missing/string `message`, or a `null`/`undefined`/`tool_use` stop_reason all yield
39
+ * `false`. Pure and total: never throws.
40
+ *
41
+ * Story 041 (R4.1): a SIDECHAIN row (non-null `parent_tool_use_id`) is EXCLUDED — its terminal stop
42
+ * is the subagent's own turn ending and must never end the parent turn.
43
+ */
44
+ export declare function isTerminalStop(event: StopReasonEvent | null | undefined): boolean;
45
+ /**
46
+ * The LAST event in `events` satisfying {@link isTerminalStop} — the single per-turn boundary
47
+ * candidate (E3 picks the LAST terminal `assistant`, so a turn that streamed several assistant
48
+ * blocks collapses to one boundary). Returns `undefined` when no event is terminal (e.g. a
49
+ * `tool_use`-only turn still in flight). Pure; never throws on an unknown `.type` or string content.
50
+ */
51
+ export declare function findTerminalCandidate<E extends StopReasonEvent>(events: readonly E[]): E | undefined;
52
+ /**
53
+ * The Δt quiescence window (ms) — E3 binding decision 2: the SMALLEST zero-false-positive window
54
+ * (Δt sweep, experiments/DECISION.md). A terminal candidate is confirmed only after Δt of silence
55
+ * with no further user/assistant write. Consumed VERBATIM from E3 — NOT re-derived here.
56
+ */
57
+ export declare const DELTA_T_MS = 200;
58
+ /**
59
+ * Injectable timer seam: schedule `fn` after `ms`, returning a cancel function. The detector takes
60
+ * it as an option so tests drive a deterministic fake clock (mirrors `bindEndOfTurnReparse`); the
61
+ * default wraps `setTimeout`/`clearTimeout`.
62
+ */
63
+ export type DetectorSchedule = (fn: () => void, ms: number) => () => void;
64
+ /** Diagnostics carried by a {@link TurnTimeoutError} — the last-seen event and the elapsed window. */
65
+ export interface TurnTimeoutDiagnostics {
66
+ /** The turn-watchdog window that elapsed (ms). */
67
+ readonly elapsedMs: number;
68
+ /** The `.type` of the last event the detector saw before the watchdog tripped, if any. */
69
+ readonly lastEventType?: string;
70
+ /** The `message.stop_reason` of that last event, if any. */
71
+ readonly lastStopReason?: string;
72
+ /** The session whose turn stalled, if known. */
73
+ readonly sessionId?: string;
74
+ }
75
+ /**
76
+ * Typed error surfaced when no end-of-turn is detected within the 5583 ms turn watchdog (R5.2). It
77
+ * carries the elapsed window plus last-seen-event diagnostics so the §5 stall is observable for R2
78
+ * runtime telemetry instead of hanging the ACP protocol silently.
79
+ */
80
+ export declare class TurnTimeoutError extends Error {
81
+ readonly elapsedMs: number;
82
+ readonly lastEventType?: string;
83
+ readonly lastStopReason?: string;
84
+ readonly sessionId?: string;
85
+ constructor(diag: TurnTimeoutDiagnostics);
86
+ }
87
+ /** Options for {@link createEndOfTurnDetector}. */
88
+ export interface EndOfTurnDetectorOptions {
89
+ /** Invoked exactly once per confirmed turn boundary, with the terminal candidate event. */
90
+ onEndOfTurn: (boundary: StopReasonEvent) => void;
91
+ /** Invoked when the turn watchdog trips before any end-of-turn (R5.2). */
92
+ onTurnTimeout?: (error: TurnTimeoutError) => void;
93
+ /** Timer seam (default wraps setTimeout). */
94
+ schedule?: DetectorSchedule;
95
+ /** Δt quiescence window (ms); defaults to {@link DELTA_T_MS}. */
96
+ deltaTMs?: number;
97
+ /**
98
+ * STALL window (ms): silence tolerated between observed events while a turn is in flight.
99
+ * Defaults to the {@link TURN_WATCHDOG_ENV} env override when valid, else
100
+ * {@link TURN_STALL_WATCHDOG_MS}. Pass {@link TURN_WATCHDOG_MS} explicitly for the E3 cap.
101
+ */
102
+ watchdogMs?: number;
103
+ /** The session whose turns this detector watches — carried in {@link TurnTimeoutError}. */
104
+ sessionId?: string;
105
+ /** Telemetry sink for a stalled turn (R2). The timeout is also surfaced via `onTurnTimeout`. */
106
+ logger?: {
107
+ error: (...args: unknown[]) => void;
108
+ };
109
+ }
110
+ /** Handle returned by {@link createEndOfTurnDetector}. */
111
+ export interface EndOfTurnDetector {
112
+ /** Arm the turn watchdog — call when a turn becomes in-flight (the prompt loop, story 023). */
113
+ beginTurn(): void;
114
+ /** Feed the next watched event, in arrival order. */
115
+ observe(event: StopReasonEvent): void;
116
+ /**
117
+ * Liveness-only kick (story 044, Option B): re-arm the stall watchdog iff a turn is in flight (the
118
+ * watchdog is armed). Registers NO event, touches NO boundary/openTaskIds/diagnostics state — it is
119
+ * purely "the turn is still alive". Called by the sub-agent watcher on observed sub-agent progress
120
+ * so a silent main chain with an active sub-agent never trips the watchdog (R1.2). No-op when
121
+ * stopped, cancelled, or not armed (replay/load never starts a stall clock).
122
+ */
123
+ noteActivity(): void;
124
+ /**
125
+ * Cancel seam (the Degrau-2 story 030 calls this): set the single-resolution latch and clear both
126
+ * the Δt timer and the turn watchdog, so the detector cannot also fire an end-of-turn for this turn
127
+ * (no double-resolve, R3.4). Read-only — it does NOT resolve the ACP session/prompt here.
128
+ */
129
+ markCancelled(): void;
130
+ /** Tear down: cancel any armed timer and suppress further signals. Idempotent. */
131
+ stop(): void;
132
+ }
133
+ /**
134
+ * The end-of-turn detector: feed it the linearized turn events via {@link EndOfTurnDetector.observe}
135
+ * and it emits exactly one end-of-turn per turn. A terminal candidate (Task 1) arms a Δt timer; the
136
+ * boundary is confirmed on Δt quiescence (here) or immediately on a queued follow-up write (Task 2.2).
137
+ * A `fired` latch keyed on the boundary uuid prevents the same terminal event from firing twice.
138
+ */
139
+ export declare function createEndOfTurnDetector(opts: EndOfTurnDetectorOptions): EndOfTurnDetector;
140
+ /** Options for {@link createTurnResolver} — forwarded to the underlying detector. */
141
+ export interface TurnResolverOptions {
142
+ schedule?: DetectorSchedule;
143
+ sessionId?: string;
144
+ logger?: StopReasonLogger;
145
+ deltaTMs?: number;
146
+ watchdogMs?: number;
147
+ }
148
+ /** A detector paired with the awaitable {@link PromptResponse} the prompt() loop returns. */
149
+ export interface TurnResolver {
150
+ /** Feed events here (and arm the turn via `beginTurn`). */
151
+ detector: EndOfTurnDetector;
152
+ /** Settles once: resolves with the mapped PromptResponse, or rejects with a TurnTimeoutError. */
153
+ promise: Promise<PromptResponse>;
154
+ /**
155
+ * Story 031 (R2.1, R2.2, R3.1) — claim the story-024 single-resolution latch to resolve the
156
+ * prompt as `{ stopReason: "cancelled" }`, then call `detector.markCancelled()` to clear its Δt +
157
+ * watchdog. A no-op if the turn already settled (the latch is the arbiter): a racing detector
158
+ * boundary, a watchdog trip, or a second `cancel()` cannot produce a second resolution. This is
159
+ * story-031 wiring that CALLS the latch — it does NOT re-implement it.
160
+ */
161
+ cancel(): void;
162
+ }
163
+ /**
164
+ * Wrap the end-of-turn detector in the awaitable the rewritten `prompt()` loop (story 023) returns
165
+ * (R2). The promise stays pending across every mid-turn event and settles EXACTLY ONCE — resolving
166
+ * with `{ stopReason: mapStopReason(boundary.message.stop_reason) }` on the confirmed boundary, or
167
+ * rejecting with the surfaced {@link TurnTimeoutError} on a watchdog trip. A single-resolution latch
168
+ * makes a detector/watchdog/cancel race settle the prompt exactly once (and stops the detector so a
169
+ * late boundary cannot produce a second settlement).
170
+ */
171
+ export declare function createTurnResolver(opts?: TurnResolverOptions): TurnResolver;
172
+ //# sourceMappingURL=end-of-turn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"end-of-turn.d.ts","sourceRoot":"","sources":["../src/end-of-turn.ts"],"names":[],"mappings":"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"}