@astrosheep/keiyaku 0.1.87 → 1.0.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 (158) hide show
  1. package/README.md +12 -22
  2. package/build/.tsbuildinfo +1 -1
  3. package/build/agents/effective-policy.js +32 -0
  4. package/build/agents/harness/event-channel.js +178 -0
  5. package/build/agents/harness/execution-handle.js +117 -0
  6. package/build/agents/harness/index.js +622 -0
  7. package/build/agents/harness/pump.js +152 -0
  8. package/build/agents/harness/runtime.js +68 -0
  9. package/build/agents/index.js +104 -213
  10. package/build/agents/opencode-sdk.js +12 -18
  11. package/build/agents/providers/claude-agent-sdk.js +529 -0
  12. package/build/agents/providers/codex-app-server.js +656 -0
  13. package/build/agents/providers/codex-sdk.js +193 -0
  14. package/build/agents/providers/opencode-sdk.js +257 -0
  15. package/build/agents/providers/pi.js +345 -0
  16. package/build/agents/selector.js +15 -6
  17. package/build/agents/session.js +29 -0
  18. package/build/agents/types.js +5 -11
  19. package/build/cli/commands/akuma.js +79 -0
  20. package/build/cli/completion.js +71 -0
  21. package/build/cli/draft-artifact.js +50 -0
  22. package/build/cli/flags.js +96 -0
  23. package/build/cli/help.js +108 -0
  24. package/build/cli/index.js +204 -912
  25. package/build/cli/parse.js +280 -0
  26. package/build/cli/render/arc.js +63 -0
  27. package/build/{responses/tool-errors.js → cli/render/errors.js} +15 -16
  28. package/build/cli/render/format.js +199 -0
  29. package/build/cli/render/misc.js +40 -0
  30. package/build/cli/render/petition.js +32 -0
  31. package/build/{responses → cli/render}/response-style.js +4 -4
  32. package/build/cli/render/shared.js +122 -0
  33. package/build/cli/render/status.js +69 -0
  34. package/build/cli/render/summon.js +17 -0
  35. package/build/cli/render/tell.js +11 -0
  36. package/build/cli/skills-install.js +237 -0
  37. package/build/cli/subagent-guard.js +6 -3
  38. package/build/config/akuma-loader.js +268 -0
  39. package/build/config/env-keys.js +0 -10
  40. package/build/config/{schema.js → env.js} +117 -23
  41. package/build/config/settings.js +137 -260
  42. package/build/core/amend.js +120 -0
  43. package/build/core/arc.js +225 -0
  44. package/build/core/atomic-publish.js +64 -0
  45. package/build/core/bind.js +281 -0
  46. package/build/core/claim.js +360 -0
  47. package/build/core/command-io.js +174 -0
  48. package/build/core/context.js +108 -0
  49. package/build/core/contract.js +14 -0
  50. package/build/core/draft.js +82 -0
  51. package/build/core/entry.js +203 -0
  52. package/build/core/forfeit.js +60 -0
  53. package/build/core/hints.js +108 -0
  54. package/build/core/ids.js +70 -0
  55. package/build/core/ledger.js +117 -0
  56. package/build/core/log.js +24 -0
  57. package/build/{protocol → core}/markdown/parser.js +68 -0
  58. package/build/{protocol → core}/markdown/sections.js +2 -28
  59. package/build/core/markdown/titles.js +9 -0
  60. package/build/{tools/petition/claim-gates.js → core/petition-claim-gates.js} +43 -29
  61. package/build/core/petition-claim.js +116 -0
  62. package/build/core/petition-forfeit.js +39 -0
  63. package/build/{tools/round/head-guard.js → core/petition-head-guard.js} +2 -2
  64. package/build/core/petition-run.js +81 -0
  65. package/build/core/petition.js +96 -0
  66. package/build/core/places.js +82 -0
  67. package/build/core/projection-core.js +541 -0
  68. package/build/core/projection-mint.js +79 -0
  69. package/build/core/projection-status.js +179 -0
  70. package/build/core/projection-wake.js +252 -0
  71. package/build/core/queue.js +73 -0
  72. package/build/core/ref-log.js +94 -0
  73. package/build/core/registry.js +96 -0
  74. package/build/core/render.js +326 -0
  75. package/build/core/renew.js +195 -0
  76. package/build/core/scope.js +163 -0
  77. package/build/core/seal.js +195 -0
  78. package/build/core/status.js +476 -0
  79. package/build/{tools/summon/persist.js → core/summon-persist.js} +10 -9
  80. package/build/core/summon.js +377 -0
  81. package/build/{protocol/response-history.js → core/transcripts.js} +83 -39
  82. package/build/core/verdict.js +96 -0
  83. package/build/core/worktree-path.js +134 -0
  84. package/build/flow-error.js +80 -4
  85. package/build/generated/version.js +1 -1
  86. package/build/git/branches.js +8 -9
  87. package/build/git/core.js +1 -1
  88. package/build/git/diff/pathspec.js +2 -3
  89. package/build/git/diff/preview.js +7 -2
  90. package/build/git/diff/read.js +4 -3
  91. package/build/git/staging.js +1 -1
  92. package/build/index.js +12 -6
  93. package/build/keiyaku.js +17 -13
  94. package/build/telemetry/debug-log.js +1 -1
  95. package/package.json +16 -9
  96. package/skills/keiyaku/SKILL.md +16 -13
  97. package/build/agents/claude-agent-sdk-exec.js +0 -352
  98. package/build/agents/codex-cli-exec.js +0 -237
  99. package/build/agents/codex-sdk-exec.js +0 -291
  100. package/build/agents/gemini-cli-core-exec.js +0 -499
  101. package/build/agents/opencode-exec.js +0 -297
  102. package/build/agents/process-runner.js +0 -239
  103. package/build/agents/progress-reporter.js +0 -137
  104. package/build/agents/round-runner.js +0 -53
  105. package/build/config/apply-argument-descriptions.js +0 -16
  106. package/build/config/architect-hints.js +0 -374
  107. package/build/config/base-rules.js +0 -23
  108. package/build/config/config.js +0 -50
  109. package/build/config/dotenv.js +0 -61
  110. package/build/config/keiyaku-home.js +0 -9
  111. package/build/config/path-utils.js +0 -11
  112. package/build/config/render-template.js +0 -8
  113. package/build/git/diff/filter.js +0 -67
  114. package/build/git/keiyaku-state.js +0 -58
  115. package/build/git/snapshot.js +0 -41
  116. package/build/git/stash.js +0 -62
  117. package/build/protocol/bind-draft.js +0 -195
  118. package/build/protocol/draft-artifacts.js +0 -99
  119. package/build/protocol/file-guards.js +0 -24
  120. package/build/protocol/keiyaku-draft.js +0 -168
  121. package/build/protocol/ledger.js +0 -374
  122. package/build/protocol/markdown/index.js +0 -14
  123. package/build/protocol/markdown/normalization.js +0 -71
  124. package/build/protocol/markdown/render.js +0 -68
  125. package/build/protocol/oath.js +0 -36
  126. package/build/protocol/render-keiyaku.js +0 -37
  127. package/build/protocol/review.js +0 -1
  128. package/build/protocol/status-previews.js +0 -68
  129. package/build/responses/responses.js +0 -515
  130. package/build/tools/amend/index.js +0 -18
  131. package/build/tools/amend/run.js +0 -44
  132. package/build/tools/bind/index.js +0 -44
  133. package/build/tools/bind/run.js +0 -237
  134. package/build/tools/contracts.js +0 -1
  135. package/build/tools/create-handler.js +0 -31
  136. package/build/tools/help.js +0 -9
  137. package/build/tools/petition/claim.js +0 -174
  138. package/build/tools/petition/forfeit.js +0 -100
  139. package/build/tools/petition/index.js +0 -83
  140. package/build/tools/petition/run.js +0 -66
  141. package/build/tools/round/guidance.js +0 -7
  142. package/build/tools/round/prompt.js +0 -70
  143. package/build/tools/round/report.js +0 -153
  144. package/build/tools/round/worktree.js +0 -55
  145. package/build/tools/round-close/index.js +0 -19
  146. package/build/tools/round-close/run.js +0 -98
  147. package/build/tools/round-open/index.js +0 -20
  148. package/build/tools/round-open/run.js +0 -77
  149. package/build/tools/schema.js +0 -69
  150. package/build/tools/status/index.js +0 -16
  151. package/build/tools/status/read.js +0 -155
  152. package/build/tools/summon/index.js +0 -27
  153. package/build/tools/summon/run.js +0 -80
  154. /package/build/{config/toml.js → agents/harness/events.js} +0 -0
  155. /package/build/{git/diff/contracts.js → cli/render/types.js} +0 -0
  156. /package/build/{protocol/bind-input.js → cli/types.js} +0 -0
  157. /package/build/{protocol → core}/markdown/lex.js +0 -0
  158. /package/build/{protocol → core}/markdown/types.js +0 -0
@@ -0,0 +1,622 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { FlowError } from "../../flow-error.js";
3
+ import { StringTailBuffer } from "../string-tail-buffer.js";
4
+ import { SUBAGENT_SESSION_VERSION, subagentSessionEnvelopeSchema, } from "../session.js";
5
+ import { startClaudeAgentSdk, claudeSessionSchema, } from "../providers/claude-agent-sdk.js";
6
+ import { startCodexAppServer, codexAppServerSessionSchema, } from "../providers/codex-app-server.js";
7
+ import { startCodexSdk, codexThreadSchema, } from "../providers/codex-sdk.js";
8
+ import { startOpencode, opencodeSessionSchema, } from "../providers/opencode-sdk.js";
9
+ import { startPi, piSessionSchema, } from "../providers/pi.js";
10
+ import { SubagentFailure, } from "../types.js";
11
+ import { createEventChannel } from "./event-channel.js";
12
+ import { buildSyncCheckpointCallback, createReplayRunStartGate, markReplayCompleted, pumpSupervisor, snapshotReplayPrompt } from "./pump.js";
13
+ import { createAbortError, renderCapturedText } from "./runtime.js";
14
+ import { acquireAdmissionLock, createProjectionExecutionId, demoteSubmittedTellsForReplay, generationResultPath, listTellIds, markTellSubmitted, publishGenerationResult, publishVerdict, readAdmissionLock, readGenerationLaunch, releaseAdmissionLockOwned, touchHeartbeat } from "../../core/projection-core.js";
15
+ import { wakeProjection } from "../../core/projection-wake.js";
16
+ export function summon(terms) {
17
+ return createProjection(terms);
18
+ }
19
+ export function resume(terms) {
20
+ return createProjection(terms, terms);
21
+ }
22
+ function mintOutcome(draft) {
23
+ return draft;
24
+ }
25
+ function effectivePolicyFor(shared) {
26
+ return shared.terms.provider === "codex-sdk" ? shared.terms.effectivePolicy : undefined;
27
+ }
28
+ function createProjection(terms, resumeTerms) {
29
+ switch (terms.provider) {
30
+ case "pi":
31
+ case "claude-agent-sdk":
32
+ case "codex-app-server":
33
+ return createSteerableProjection(terms, resumeTerms);
34
+ case "codex-sdk":
35
+ case "opencode-sdk":
36
+ return createReplayProjection(terms, resumeTerms);
37
+ default:
38
+ return assertNever(terms);
39
+ }
40
+ }
41
+ function createSteerableProjection(terms, resumeTerms) {
42
+ const shared = createProjectionState(terms, resumeTerms);
43
+ const pendingTells = [];
44
+ let flushActive = false;
45
+ const flushPendingTells = async () => {
46
+ const initialEnqueue = shared.live?.enqueue;
47
+ if (flushActive || shared.terminal || !initialEnqueue)
48
+ return;
49
+ flushActive = true;
50
+ try {
51
+ while (!shared.terminal && pendingTells.length > 0) {
52
+ const enqueue = shared.live?.enqueue;
53
+ if (!enqueue)
54
+ break;
55
+ const nextTell = pendingTells.shift();
56
+ if (!nextTell)
57
+ break;
58
+ await enqueue(nextTell);
59
+ }
60
+ }
61
+ finally {
62
+ flushActive = false;
63
+ if (!shared.terminal && pendingTells.length > 0 && shared.live?.enqueue) {
64
+ void flushPendingTells();
65
+ }
66
+ }
67
+ };
68
+ shared.onLive = (live) => {
69
+ shared.live = live;
70
+ void flushPendingTells();
71
+ };
72
+ const outcome = settleProjection(shared).then((value) => finalizeProjectionLedger(shared, value));
73
+ return {
74
+ mode: "steerable",
75
+ get id() {
76
+ return shared.id;
77
+ },
78
+ get events() {
79
+ return shared.publicEvents.iterable;
80
+ },
81
+ get outcome() {
82
+ return outcome;
83
+ },
84
+ tell(tell) {
85
+ if (shared.terminal)
86
+ return;
87
+ pendingTells.push(tell);
88
+ void flushPendingTells();
89
+ },
90
+ recallTells() {
91
+ return pendingTells.splice(0, pendingTells.length);
92
+ },
93
+ dismiss() {
94
+ dismissProjection(shared);
95
+ },
96
+ };
97
+ }
98
+ function createReplayProjection(terms, resumeTerms) {
99
+ const shared = createProjectionState(terms, resumeTerms);
100
+ shared.onLive = (live) => {
101
+ shared.live = live;
102
+ };
103
+ const outcome = settleProjection(shared).then((value) => finalizeProjectionLedger(shared, value));
104
+ return {
105
+ mode: "replay",
106
+ get id() {
107
+ return shared.id;
108
+ },
109
+ get events() {
110
+ return shared.publicEvents.iterable;
111
+ },
112
+ get outcome() {
113
+ return outcome;
114
+ },
115
+ dismiss() {
116
+ dismissProjection(shared);
117
+ },
118
+ };
119
+ }
120
+ function createProjectionState(terms, resumeTerms) {
121
+ const shared = {
122
+ id: randomUUID(),
123
+ terms,
124
+ resumeTerms,
125
+ publicEvents: createEventChannel(),
126
+ lifecycleAbort: new AbortController(),
127
+ dismissed: false,
128
+ externallyAborted: false,
129
+ terminal: false,
130
+ onLive() { },
131
+ };
132
+ if (terms.signal) {
133
+ const listener = () => {
134
+ shared.externallyAborted = true;
135
+ if (!shared.lifecycleAbort.signal.aborted) {
136
+ shared.lifecycleAbort.abort(terms.signal?.reason);
137
+ }
138
+ };
139
+ terms.signal.addEventListener("abort", listener, { once: true });
140
+ if (terms.signal.aborted) {
141
+ listener();
142
+ }
143
+ }
144
+ return shared;
145
+ }
146
+ function finalizeProjectionLedger(shared, outcome) {
147
+ const directory = shared.terms.projectionDir;
148
+ const executionId = shared.terms.projectionExecutionId;
149
+ if (!directory || !executionId)
150
+ return outcome;
151
+ const now = Date.now();
152
+ publishGenerationResult(directory, {
153
+ version: 1,
154
+ executionId,
155
+ status: outcome.status,
156
+ createdAt: new Date(now).toISOString(),
157
+ session: outcome.session,
158
+ responsePath: generationResultPath(directory, executionId),
159
+ detail: outcome.status === "failed" ? outcome.error?.message : undefined,
160
+ });
161
+ // A stale/duplicate child must never replace a later generation's verdict.
162
+ if (readAdmissionLock(directory)?.executionId !== executionId)
163
+ return outcome;
164
+ const pending = ["inbox", "inflight", "submitted"].some((layer) => listTellIds(directory, layer).length > 0);
165
+ if (pending && outcome.status === "completed") {
166
+ // The resume lock is acquired by the one wake orchestrator before it releases
167
+ // this generation's admission; a crash leaves result-without-done for self-heal.
168
+ wakeProjection(directory, "sweep-wake", { handoffExecutionId: executionId });
169
+ return outcome;
170
+ }
171
+ publishVerdict(directory, outcome.status === "completed" ? "done" : outcome.status === "dismissed" ? "dismissed" : "failed", now, outcome.status === "failed" ? outcome.error?.message : undefined);
172
+ releaseAdmissionLockOwned(directory, executionId);
173
+ if (listTellIds(directory, "inbox").length > 0)
174
+ wakeProjection(directory, "sweep-wake");
175
+ return outcome;
176
+ }
177
+ function dismissProjection(shared) {
178
+ if (shared.dismissed || shared.terminal)
179
+ return;
180
+ shared.dismissed = true;
181
+ if (!shared.lifecycleAbort.signal.aborted) {
182
+ shared.lifecycleAbort.abort(createAbortError(`${shared.terms.provider} exec dismissed`));
183
+ }
184
+ requestAbort(shared.live);
185
+ }
186
+ function requestAbort(live) {
187
+ if (!live)
188
+ return;
189
+ void Promise.resolve()
190
+ .then(() => live.abort())
191
+ .catch(() => undefined);
192
+ }
193
+ async function settleProjection(shared) {
194
+ const state = {
195
+ outputBuffer: new StringTailBuffer(shared.terms.maxCaptureChars),
196
+ diagnosticsBuffer: new StringTailBuffer(shared.terms.maxCaptureChars),
197
+ warnings: [],
198
+ };
199
+ let timedOut = false;
200
+ let idleTimedOut = false;
201
+ let abortRequested = false;
202
+ const timeout = setTimeout(() => {
203
+ timedOut = true;
204
+ shared.lifecycleAbort.abort(createAbortError(`${shared.terms.provider} exec timed out`));
205
+ }, shared.terms.timeoutMs);
206
+ timeout.unref?.();
207
+ let idleTimeout;
208
+ const refreshIdleTimeout = () => {
209
+ if (idleTimeout)
210
+ clearTimeout(idleTimeout);
211
+ idleTimeout = setTimeout(() => {
212
+ idleTimedOut = true;
213
+ shared.lifecycleAbort.abort(createAbortError(`${shared.terms.provider} exec idle timed out`));
214
+ }, shared.terms.idleTimeoutMs);
215
+ idleTimeout.unref?.();
216
+ };
217
+ refreshIdleTimeout();
218
+ const requestLiveAbort = () => {
219
+ if (abortRequested)
220
+ return;
221
+ abortRequested = true;
222
+ requestAbort(shared.live);
223
+ };
224
+ shared.lifecycleAbort.signal.addEventListener("abort", requestLiveAbort, { once: true });
225
+ try {
226
+ if (shared.terms.projectionDir) {
227
+ const executionId = shared.terms.projectionExecutionId ?? createProjectionExecutionId();
228
+ const acquired = acquireAdmissionLock(shared.terms.projectionDir, process.pid, Date.now(), executionId);
229
+ if (acquired === "taken")
230
+ throw new FlowError("INTERNAL_STATE", "projection already has an active generation");
231
+ touchHeartbeat(shared.terms.projectionDir, Date.now());
232
+ demoteSubmittedTellsForReplay(shared.terms.projectionDir, executionId);
233
+ }
234
+ const launchTellFence = shared.terms.projectionDir && shared.terms.projectionExecutionId
235
+ ? readGenerationLaunch(shared.terms.projectionDir, shared.terms.projectionExecutionId).inputs.tellFence
236
+ : undefined;
237
+ const tellFence = launchTellFence === undefined
238
+ ? []
239
+ : Array.isArray(launchTellFence) && launchTellFence.every((tellId) => typeof tellId === "string")
240
+ ? launchTellFence
241
+ : (() => { throw new FlowError("INTERNAL_STATE", "generation launch has an invalid tellFence"); })();
242
+ const launchSnapshot = shared.terms.projectionDir && shared.terms.projectionExecutionId
243
+ ? snapshotReplayPrompt(shared.terms.projectionDir, shared.terms.prompt, tellFence, shared.terms.projectionExecutionId)
244
+ : undefined;
245
+ const launchTerms = launchSnapshot
246
+ ? shared.terms.provider === "codex-sdk" && launchSnapshot.effort
247
+ ? { ...shared.terms, prompt: launchSnapshot.prompt, threadOptions: { ...shared.terms.threadOptions, modelReasoningEffort: launchSnapshot.effort === "max" ? "xhigh" : launchSnapshot.effort } }
248
+ : { ...shared.terms, prompt: launchSnapshot.prompt }
249
+ : shared.terms;
250
+ const live = await startLiveProjection(launchTerms, shared.lifecycleAbort.signal, shared.resumeTerms, launchSnapshot?.tellIds);
251
+ // A constructed driver is not an SDK run acknowledgement. Tier-2 has no
252
+ // live steer surface, so the first provider event is the earliest harness
253
+ // observable start; a successful no-event completion is the only fallback.
254
+ const replayStartGate = launchSnapshot && shared.terms.provider !== "codex-app-server" && shared.terms.projectionDir && shared.terms.projectionExecutionId
255
+ ? createReplayRunStartGate(shared.terms.projectionDir, shared.terms.projectionExecutionId, launchSnapshot.tellIds)
256
+ : undefined;
257
+ shared.onLive(live);
258
+ if (shared.lifecycleAbort.signal.aborted) {
259
+ requestLiveAbort();
260
+ }
261
+ const projectionDir = shared.terms.projectionDir;
262
+ if (projectionDir) {
263
+ // Supervisor mode: pump with heartbeat, checkpoint, claim inbox, deliver tells.
264
+ await pumpSupervisor(live, projectionDir, shared.publicEvents, (event) => {
265
+ replayStartGate?.observeProviderEvent();
266
+ refreshIdleTimeout();
267
+ processEvent(state, event);
268
+ });
269
+ }
270
+ else {
271
+ // Legacy mode: direct event loop without supervisor pump.
272
+ for await (const event of live.events) {
273
+ replayStartGate?.observeProviderEvent();
274
+ shared.publicEvents.push(event);
275
+ refreshIdleTimeout();
276
+ processEvent(state, event);
277
+ }
278
+ }
279
+ const completionResult = await live.completion.then((value) => ({ ok: true, value }), (error) => ({ ok: false, error }));
280
+ const completionOutcome = completionResult.ok ? completionResult.value : undefined;
281
+ if (state.failEvent) {
282
+ return failFromFailEvent(shared, state, state.failEvent);
283
+ }
284
+ if (!completionResult.ok) {
285
+ return classifyFailure(shared, state, completionResult.error, timedOut, idleTimedOut);
286
+ }
287
+ if (shared.lifecycleAbort.signal.aborted) {
288
+ return classifyFailure(shared, state, shared.lifecycleAbort.signal.reason, timedOut, idleTimedOut);
289
+ }
290
+ if (!state.doneEvent && !completionOutcome) {
291
+ return failWithError(shared, state, {
292
+ code: "SUBAGENT_EXEC_ERROR",
293
+ message: `${shared.terms.provider} exec ended before completion`,
294
+ timeoutMs: shared.terms.timeoutMs,
295
+ exitCode: null,
296
+ }, state.finalMessageCandidate);
297
+ }
298
+ const finalMessage = state.doneEvent?.finalMessage ??
299
+ completionOutcome?.finalMessage ??
300
+ state.finalMessageCandidate ??
301
+ renderCapturedText(state.outputBuffer).trim();
302
+ const session = state.doneEvent?.session ?? completionOutcome?.session;
303
+ if (!session) {
304
+ return failWithError(shared, state, {
305
+ code: "SUBAGENT_EXEC_ERROR",
306
+ message: `${shared.terms.provider} exec ended without a session handle`,
307
+ timeoutMs: shared.terms.timeoutMs,
308
+ exitCode: null,
309
+ }, finalMessage);
310
+ }
311
+ // A provider may complete successfully without emitting any observable
312
+ // events. Its successful completion is still a real run start.
313
+ replayStartGate?.observeSuccessfulCompletion();
314
+ if (launchSnapshot && shared.terms.projectionDir && shared.terms.projectionExecutionId) {
315
+ markReplayCompleted(shared.terms.projectionDir, shared.terms.projectionExecutionId);
316
+ }
317
+ return mintOutcome({
318
+ status: "completed",
319
+ finalMessage,
320
+ output: renderCapturedText(state.outputBuffer),
321
+ diagnostics: renderCapturedText(state.diagnosticsBuffer),
322
+ session,
323
+ warnings: [...state.warnings],
324
+ ...(effectivePolicyFor(shared) ? { effectivePolicy: effectivePolicyFor(shared) } : {}),
325
+ });
326
+ }
327
+ catch (error) {
328
+ if (error instanceof FlowError) {
329
+ throw error;
330
+ }
331
+ return classifyFailure(shared, state, error, timedOut, idleTimedOut);
332
+ }
333
+ finally {
334
+ clearTimeout(timeout);
335
+ if (idleTimeout)
336
+ clearTimeout(idleTimeout);
337
+ shared.lifecycleAbort.signal.removeEventListener("abort", requestLiveAbort);
338
+ shared.terminal = true;
339
+ shared.publicEvents.close();
340
+ }
341
+ }
342
+ function processEvent(state, event) {
343
+ switch (event.type) {
344
+ case "output":
345
+ state.outputBuffer.append(`${JSON.stringify(event.value)}\n`);
346
+ return;
347
+ case "diagnostic":
348
+ state.diagnosticsBuffer.append(event.text);
349
+ return;
350
+ case "message":
351
+ state.finalMessageCandidate = event.text;
352
+ return;
353
+ case "warning":
354
+ state.warnings.push(event.warning);
355
+ return;
356
+ case "done":
357
+ state.doneEvent = event;
358
+ state.session = event.session;
359
+ if (event.finalMessage !== undefined) {
360
+ state.finalMessageCandidate = event.finalMessage;
361
+ }
362
+ return;
363
+ case "fail":
364
+ state.failEvent = event;
365
+ if (event.diagnostics) {
366
+ state.diagnosticsBuffer.append(event.diagnostics);
367
+ }
368
+ return;
369
+ }
370
+ }
371
+ function failFromFailEvent(shared, state, failEvent) {
372
+ const code = failEvent.code === "PROJECTION_STATE_ERROR" || failEvent.code === undefined
373
+ ? "SUBAGENT_EXEC_ERROR"
374
+ : failEvent.code;
375
+ const diagnostics = failEvent.code === "PROJECTION_STATE_ERROR"
376
+ ? [renderCapturedText(state.diagnosticsBuffer), "PROJECTION_STATE_ERROR"].filter(Boolean).join("\n")
377
+ : renderCapturedText(state.diagnosticsBuffer);
378
+ return failWithError(shared, state, {
379
+ code,
380
+ message: failEvent.message,
381
+ timeoutMs: shared.terms.timeoutMs,
382
+ exitCode: failEvent.exitCode ?? null,
383
+ }, state.finalMessageCandidate, failEvent.diagnostics ?? diagnostics);
384
+ }
385
+ function classifyFailure(shared, state, error, timedOut, idleTimedOut) {
386
+ if (shared.dismissed || shared.externallyAborted) {
387
+ return mintOutcome({
388
+ status: "dismissed",
389
+ finalMessage: state.finalMessageCandidate ?? "",
390
+ output: renderCapturedText(state.outputBuffer),
391
+ diagnostics: renderCapturedText(state.diagnosticsBuffer),
392
+ session: state.session ?? fallbackSession(shared),
393
+ warnings: [...state.warnings],
394
+ ...(effectivePolicyFor(shared) ? { effectivePolicy: effectivePolicyFor(shared) } : {}),
395
+ });
396
+ }
397
+ if (timedOut) {
398
+ return failWithError(shared, state, {
399
+ code: "SUBAGENT_TIMEOUT",
400
+ message: `${shared.terms.provider} exec timed out`,
401
+ timeoutMs: shared.terms.timeoutMs,
402
+ exitCode: null,
403
+ }, state.finalMessageCandidate);
404
+ }
405
+ if (idleTimedOut) {
406
+ return failWithError(shared, state, {
407
+ code: "SUBAGENT_TIMEOUT",
408
+ message: `${shared.terms.provider} exec idle timed out`,
409
+ timeoutMs: shared.terms.idleTimeoutMs,
410
+ exitCode: null,
411
+ }, state.finalMessageCandidate);
412
+ }
413
+ if (error instanceof SubagentFailure) {
414
+ return failWithError(shared, state, {
415
+ code: error.code,
416
+ message: error.message,
417
+ timeoutMs: error.timeoutMs,
418
+ exitCode: error.exitCode,
419
+ }, state.finalMessageCandidate ?? error.message, error.diagnostics || renderCapturedText(state.diagnosticsBuffer), error.output || renderCapturedText(state.outputBuffer));
420
+ }
421
+ const message = error instanceof Error ? error.message : `Unknown ${shared.terms.provider} exec error`;
422
+ appendThrownMessage(state.diagnosticsBuffer, message);
423
+ return failWithError(shared, state, {
424
+ code: "SUBAGENT_EXEC_ERROR",
425
+ message,
426
+ timeoutMs: null,
427
+ exitCode: null,
428
+ }, state.finalMessageCandidate ?? message);
429
+ }
430
+ function failWithError(shared, state, error, finalMessage, diagnostics = renderCapturedText(state.diagnosticsBuffer), output = renderCapturedText(state.outputBuffer)) {
431
+ return mintOutcome({
432
+ status: "failed",
433
+ error,
434
+ finalMessage: finalMessage ?? error.message,
435
+ output,
436
+ diagnostics,
437
+ session: state.session ?? fallbackSession(shared),
438
+ warnings: [...state.warnings],
439
+ ...(effectivePolicyFor(shared) ? { effectivePolicy: effectivePolicyFor(shared) } : {}),
440
+ });
441
+ }
442
+ function fallbackSession(shared) {
443
+ return shared.resumeTerms?.session ?? {
444
+ provider: shared.terms.provider,
445
+ version: SUBAGENT_SESSION_VERSION,
446
+ handle: null,
447
+ };
448
+ }
449
+ function appendThrownMessage(buffer, message) {
450
+ if (message.length === 0)
451
+ return;
452
+ const snapshot = buffer.snapshot().text;
453
+ if (snapshot.length > 0 && !snapshot.endsWith("\n")) {
454
+ buffer.append("\n");
455
+ }
456
+ buffer.append(message);
457
+ }
458
+ function admitResumeShape(provider, schema, session, resumePath) {
459
+ const envelopeResult = subagentSessionEnvelopeSchema.safeParse(session);
460
+ if (!envelopeResult.success) {
461
+ throw new FlowError("INVALID_RESPONSE_PATH", `Resume path file '${resumePath}' includes an invalid session envelope.`);
462
+ }
463
+ if (session.provider !== provider) {
464
+ throw new FlowError("INVALID_RESPONSE_PATH", `Resume path file '${resumePath}' was created with provider '${session.provider}', but the selected subagent resolves to '${provider}'. Cross-provider resume is not supported.`);
465
+ }
466
+ if (session.version !== SUBAGENT_SESSION_VERSION) {
467
+ throw new FlowError("INVALID_RESPONSE_PATH", `Resume path file '${resumePath}' uses unsupported session version '${session.version}' for provider '${session.provider}'.`);
468
+ }
469
+ const shapeResult = schema.safeParse(session.handle);
470
+ if (!shapeResult.success) {
471
+ throw new FlowError("INVALID_RESPONSE_PATH", `Resume path file '${resumePath}' includes an invalid session handle for provider '${session.provider}'.`);
472
+ }
473
+ return shapeResult.data;
474
+ }
475
+ async function startLiveProjection(terms, signal, resumeTerms, initialTellIds = []) {
476
+ const projectionCheckpoint = terms.projectionDir ? buildSyncCheckpointCallback(terms.projectionDir) : undefined;
477
+ let appServerInitialFencePending = terms.provider === "codex-app-server" && initialTellIds.length > 0;
478
+ const onSyncCheckpoint = terms.projectionDir
479
+ ? (control, checkpoint) => {
480
+ if (appServerInitialFencePending && terms.projectionExecutionId) {
481
+ for (const tellId of initialTellIds) {
482
+ if (listTellIds(terms.projectionDir, "inflight").includes(tellId)) {
483
+ markTellSubmitted(terms.projectionDir, tellId, { executionId: terms.projectionExecutionId, fence: checkpoint.fence });
484
+ }
485
+ }
486
+ appServerInitialFencePending = false;
487
+ return;
488
+ }
489
+ projectionCheckpoint?.(control, checkpoint);
490
+ }
491
+ : "onCheckpoint" in terms
492
+ ? terms.onCheckpoint
493
+ : undefined;
494
+ switch (terms.provider) {
495
+ case "pi": {
496
+ if (resumeTerms) {
497
+ const session = admitResumeShape("pi", piSessionSchema, resumeTerms.session, resumeTerms.resumePath);
498
+ return startPi(terms.prompt, terms.workdir, {
499
+ model: terms.model,
500
+ thinkingLevel: terms.thinkingLevel,
501
+ signal,
502
+ sessionFile: session.sessionFile,
503
+ appendSystemPromptOverride: terms.appendSystemPromptOverride,
504
+ onSyncCheckpoint,
505
+ onEvidence: terms.onEvidence,
506
+ });
507
+ }
508
+ return startPi(terms.prompt, terms.workdir, {
509
+ model: terms.model,
510
+ thinkingLevel: terms.thinkingLevel,
511
+ signal,
512
+ appendSystemPromptOverride: terms.appendSystemPromptOverride,
513
+ onSyncCheckpoint,
514
+ onEvidence: terms.onEvidence,
515
+ });
516
+ }
517
+ case "claude-agent-sdk": {
518
+ if (resumeTerms) {
519
+ const session = admitResumeShape("claude-agent-sdk", claudeSessionSchema, resumeTerms.session, resumeTerms.resumePath);
520
+ return startClaudeAgentSdk(terms.prompt, terms.workdir, {
521
+ model: terms.model,
522
+ executable: terms.executable,
523
+ effort: terms.effort,
524
+ signal,
525
+ permissionMode: terms.permissionMode,
526
+ settingSources: terms.settingSources,
527
+ systemPrompt: terms.systemPrompt,
528
+ sessionId: session.sessionId,
529
+ onSyncCheckpoint,
530
+ onEvidence: terms.onEvidence,
531
+ });
532
+ }
533
+ return startClaudeAgentSdk(terms.prompt, terms.workdir, {
534
+ model: terms.model,
535
+ executable: terms.executable,
536
+ effort: terms.effort,
537
+ signal,
538
+ permissionMode: terms.permissionMode,
539
+ settingSources: terms.settingSources,
540
+ systemPrompt: terms.systemPrompt,
541
+ onSyncCheckpoint,
542
+ onEvidence: terms.onEvidence,
543
+ });
544
+ }
545
+ case "codex-app-server": {
546
+ if (resumeTerms) {
547
+ const session = admitResumeShape("codex-app-server", codexAppServerSessionSchema, resumeTerms.session, resumeTerms.resumePath);
548
+ return startCodexAppServer(terms.prompt, terms.workdir, {
549
+ model: terms.model,
550
+ effort: terms.effort,
551
+ profile: terms.profile,
552
+ config: terms.config,
553
+ executable: terms.executable,
554
+ signal,
555
+ threadId: session.threadId,
556
+ codexHome: session.codexHome,
557
+ developerInstructions: terms.developerInstructions,
558
+ onSyncCheckpoint,
559
+ onEvidence: terms.onEvidence,
560
+ });
561
+ }
562
+ return startCodexAppServer(terms.prompt, terms.workdir, {
563
+ model: terms.model,
564
+ effort: terms.effort,
565
+ profile: terms.profile,
566
+ config: terms.config,
567
+ executable: terms.executable,
568
+ signal,
569
+ developerInstructions: terms.developerInstructions,
570
+ onSyncCheckpoint,
571
+ onEvidence: terms.onEvidence,
572
+ });
573
+ }
574
+ case "codex-sdk": {
575
+ if (resumeTerms) {
576
+ const session = admitResumeShape("codex-sdk", codexThreadSchema, resumeTerms.session, resumeTerms.resumePath);
577
+ return startCodexSdk(terms.prompt, terms.workdir, {
578
+ model: terms.model,
579
+ profile: terms.profile,
580
+ config: terms.config,
581
+ threadOptions: terms.threadOptions,
582
+ executable: terms.executable,
583
+ signal,
584
+ threadId: session.threadId,
585
+ onEvidence: terms.onEvidence,
586
+ });
587
+ }
588
+ return startCodexSdk(terms.prompt, terms.workdir, {
589
+ model: terms.model,
590
+ profile: terms.profile,
591
+ config: terms.config,
592
+ threadOptions: terms.threadOptions,
593
+ executable: terms.executable,
594
+ signal,
595
+ onEvidence: terms.onEvidence,
596
+ });
597
+ }
598
+ case "opencode-sdk": {
599
+ if (resumeTerms) {
600
+ const session = admitResumeShape("opencode-sdk", opencodeSessionSchema, resumeTerms.session, resumeTerms.resumePath);
601
+ return startOpencode(terms.prompt, terms.workdir, {
602
+ model: terms.model,
603
+ executable: terms.executable,
604
+ signal,
605
+ sessionId: session.sessionId,
606
+ onEvidence: terms.onEvidence,
607
+ });
608
+ }
609
+ return startOpencode(terms.prompt, terms.workdir, {
610
+ model: terms.model,
611
+ executable: terms.executable,
612
+ signal,
613
+ onEvidence: terms.onEvidence,
614
+ });
615
+ }
616
+ default:
617
+ return assertNever(terms);
618
+ }
619
+ }
620
+ function assertNever(_value) {
621
+ throw new Error("Unhandled provider");
622
+ }