@astrosheep/keiyaku 2.8.4 → 2.9.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 (229) hide show
  1. package/README.md +35 -15
  2. package/build/.tsbuildinfo +1 -1
  3. package/build/agents/{call-terms_v2.js → call-terms.js} +12 -8
  4. package/build/agents/harness/control-types.js +1 -0
  5. package/build/agents/harness/execution-handle.js +23 -3
  6. package/build/agents/harness/index.js +6 -607
  7. package/build/agents/harness/outcome.js +141 -0
  8. package/build/agents/harness/projection.js +310 -0
  9. package/build/agents/harness/router.js +201 -0
  10. package/build/agents/harness/runtime.js +2 -1
  11. package/build/agents/{launch-snapshot_v2.js → launch-snapshot/model.js} +69 -74
  12. package/build/agents/launch-snapshot/resolve.js +72 -0
  13. package/build/agents/opencode-sdk.js +24 -3
  14. package/build/agents/providers/{claude-agent-sdk.js → claude-agent-sdk/adapter.js} +46 -368
  15. package/build/agents/providers/claude-agent-sdk/events.js +218 -0
  16. package/build/agents/providers/claude-agent-sdk/session.js +158 -0
  17. package/build/agents/providers/codex-app-server/adapter.js +347 -0
  18. package/build/agents/providers/codex-app-server/events.js +352 -0
  19. package/build/agents/providers/codex-app-server/session.js +266 -0
  20. package/build/agents/providers/codex-sdk.js +23 -5
  21. package/build/agents/providers/opencode-sdk/adapter.js +344 -0
  22. package/build/agents/providers/opencode-sdk/events.js +354 -0
  23. package/build/agents/providers/opencode-sdk/session.js +180 -0
  24. package/build/agents/providers/pi/adapter.js +269 -0
  25. package/build/agents/providers/pi/checkpoint.js +41 -0
  26. package/build/agents/providers/pi/events.js +282 -0
  27. package/build/agents/{selector_v2.js → selector.js} +8 -6
  28. package/build/cli/commands/akuma/akuma/handler.js +4 -0
  29. package/build/cli/commands/akuma/akuma/meta.js +16 -0
  30. package/build/cli/commands/akuma/catalog.js +8 -0
  31. package/build/cli/commands/akuma/list/handler.js +15 -0
  32. package/build/cli/commands/akuma/list/meta-ls.js +9 -0
  33. package/build/cli/commands/akuma/view/handler.js +34 -0
  34. package/build/cli/commands/akuma/view/meta.js +8 -0
  35. package/build/cli/commands/akuma.js +1 -1
  36. package/build/cli/commands/contract/amend/handler.js +10 -0
  37. package/build/cli/commands/contract/amend/meta.js +12 -0
  38. package/build/cli/commands/contract/arc/handler.js +9 -0
  39. package/build/cli/commands/contract/arc/meta.js +26 -0
  40. package/build/cli/commands/contract/bind/handler.js +23 -0
  41. package/build/cli/commands/contract/bind/meta.js +30 -0
  42. package/build/cli/commands/contract/catalog.js +16 -0
  43. package/build/cli/commands/contract/forfeit/handler.js +13 -0
  44. package/build/cli/commands/contract/forfeit/meta.js +12 -0
  45. package/build/cli/commands/contract/log/handler.js +12 -0
  46. package/build/cli/commands/contract/log/meta.js +12 -0
  47. package/build/cli/commands/contract/petition/handler.js +26 -0
  48. package/build/cli/commands/contract/petition/meta.js +23 -0
  49. package/build/cli/commands/contract/renew/handler.js +10 -0
  50. package/build/cli/commands/contract/renew/meta.js +17 -0
  51. package/build/cli/commands/projection/call/handler.js +39 -0
  52. package/build/cli/commands/projection/call/meta.js +9 -0
  53. package/build/cli/commands/projection/catalog.js +14 -0
  54. package/build/cli/commands/projection/kill/handler.js +35 -0
  55. package/build/cli/commands/projection/kill/meta.js +11 -0
  56. package/build/cli/commands/projection/revive/handler.js +53 -0
  57. package/build/cli/commands/projection/revive/meta.js +9 -0
  58. package/build/cli/commands/projection/status/handler.js +23 -0
  59. package/build/cli/commands/projection/status/meta.js +9 -0
  60. package/build/cli/commands/projection/tell/handler.js +34 -0
  61. package/build/cli/commands/projection/tell/meta.js +9 -0
  62. package/build/cli/commands/projection/wait/handler.js +21 -0
  63. package/build/cli/commands/projection/wait/meta.js +11 -0
  64. package/build/cli/commands/registry.js +100 -0
  65. package/build/cli/commands/shared.js +71 -0
  66. package/build/cli/commands/skills/catalog.js +6 -0
  67. package/build/cli/commands/skills/install/handler.js +10 -0
  68. package/build/cli/commands/skills/install/meta.js +9 -0
  69. package/build/cli/commands/skills/skills/handler.js +4 -0
  70. package/build/cli/commands/skills/skills/meta.js +10 -0
  71. package/build/cli/commands/system/catalog.js +8 -0
  72. package/build/cli/commands/system/completion/handler.js +10 -0
  73. package/build/cli/commands/system/completion/meta.js +9 -0
  74. package/build/cli/commands/system/dump-env/handler.js +3 -0
  75. package/build/cli/commands/system/dump-env/meta.js +10 -0
  76. package/build/cli/commands/system/guide/handler.js +4 -0
  77. package/build/cli/commands/system/guide/meta.js +9 -0
  78. package/build/cli/commands/task/add/handler.js +21 -0
  79. package/build/cli/commands/task/add/meta.js +8 -0
  80. package/build/cli/commands/task/catalog.js +22 -0
  81. package/build/cli/commands/task/doctor/handler.js +4 -0
  82. package/build/cli/commands/task/doctor/meta.js +8 -0
  83. package/build/cli/commands/task/done/handler.js +17 -0
  84. package/build/cli/commands/task/done/meta.js +8 -0
  85. package/build/cli/commands/task/drop/handler.js +6 -0
  86. package/build/cli/commands/task/drop/meta.js +8 -0
  87. package/build/cli/commands/task/ls/handler.js +13 -0
  88. package/build/cli/commands/task/ls/meta.js +8 -0
  89. package/build/cli/commands/task/shared.js +131 -0
  90. package/build/cli/commands/task/start/handler.js +6 -0
  91. package/build/cli/commands/task/start/meta.js +8 -0
  92. package/build/cli/commands/task/stop/handler.js +17 -0
  93. package/build/cli/commands/task/stop/meta.js +8 -0
  94. package/build/cli/commands/task/task/handler.js +5 -0
  95. package/build/cli/commands/task/task/meta.js +11 -0
  96. package/build/cli/commands/task/update/handler.js +18 -0
  97. package/build/cli/commands/task/update/meta.js +8 -0
  98. package/build/cli/commands/task/view/handler.js +14 -0
  99. package/build/cli/commands/task/view/meta.js +8 -0
  100. package/build/cli/completion.js +26 -27
  101. package/build/cli/flags.js +79 -2
  102. package/build/cli/help.js +27 -49
  103. package/build/cli/index.js +121 -374
  104. package/build/cli/output-stream-error-policy.js +17 -0
  105. package/build/cli/parse.js +159 -72
  106. package/build/cli/projection-address.js +5 -0
  107. package/build/cli/render/arc.js +1 -1
  108. package/build/cli/render/errors.js +4 -3
  109. package/build/cli/render/format.js +14 -0
  110. package/build/cli/render/kanshi.js +106 -0
  111. package/build/cli/render/petition.js +24 -1
  112. package/build/cli/render/projection-activity.js +5 -1
  113. package/build/cli/render/shared.js +2 -2
  114. package/build/cli/render/status.js +79 -13
  115. package/build/cli/render/task.js +113 -0
  116. package/build/cli/render/wait.js +23 -3
  117. package/build/cli/types.js +1 -1
  118. package/build/config/{akuma-loader_v2.js → akuma-loader.js} +2 -2
  119. package/build/config/env.js +9 -4
  120. package/build/config/settings/disease.js +26 -0
  121. package/build/config/settings/knobs.js +8 -0
  122. package/build/config/settings/loader.js +244 -0
  123. package/build/config/settings/schema.js +276 -0
  124. package/build/core/addressing.js +1 -1
  125. package/build/core/amend.js +3 -3
  126. package/build/core/arc.js +5 -4
  127. package/build/core/bind-workspace.js +123 -0
  128. package/build/core/bind.js +75 -155
  129. package/build/core/call/call.js +224 -0
  130. package/build/core/call/context.js +238 -0
  131. package/build/core/call/execution.js +217 -0
  132. package/build/core/call/prompt.js +42 -0
  133. package/build/core/call/reference.js +24 -0
  134. package/build/core/call-persist.js +1 -1
  135. package/build/core/claim-delivery.js +247 -0
  136. package/build/core/claim.js +39 -277
  137. package/build/core/context.js +2 -1
  138. package/build/core/{render.js → contract-view.js} +12 -140
  139. package/build/core/draft.js +107 -9
  140. package/build/core/entry.js +9 -1
  141. package/build/core/execution-coordinate.js +4 -20
  142. package/build/core/execution-pact.js +16 -31
  143. package/build/core/forfeit.js +35 -22
  144. package/build/core/hints.js +2 -2
  145. package/build/core/log.js +2 -2
  146. package/build/core/petition-claim-gates.js +8 -6
  147. package/build/core/petition-preview.js +97 -0
  148. package/build/core/petition-run.js +3 -2
  149. package/build/core/petition.js +39 -26
  150. package/build/core/projection/generation/database.js +306 -0
  151. package/build/core/projection/generation/identity.js +84 -0
  152. package/build/core/projection/generation/model.js +201 -0
  153. package/build/core/projection/generation/store.js +73 -0
  154. package/build/core/projection/generation/transitions.js +258 -0
  155. package/build/core/projection/heart.js +0 -307
  156. package/build/core/projection/tell/database.js +109 -0
  157. package/build/core/projection/tell/model.js +97 -0
  158. package/build/core/{projection-tells.js → projection/tell/store.js} +3 -158
  159. package/build/core/projection-activity.js +23 -2
  160. package/build/core/projection-core.js +2 -1
  161. package/build/core/projection-execution-observer.js +259 -0
  162. package/build/core/projection-generation-continuation.js +1 -1
  163. package/build/core/projection-generation-execution.js +90 -20
  164. package/build/core/projection-generation-launcher.js +1 -1
  165. package/build/core/projection-generation-runner.js +198 -4
  166. package/build/core/projection-identity.js +1 -1
  167. package/build/core/projection-kill.js +50 -17
  168. package/build/core/projection-life-observer.js +1 -1
  169. package/build/core/projection-life-protocol.js +10 -0
  170. package/build/core/projection-mint.js +1 -1
  171. package/build/core/projection-status.js +45 -32
  172. package/build/core/projection-wait.js +12 -2
  173. package/build/core/projection-wake.js +5 -2
  174. package/build/core/{queue_v2.js → queue.js} +2 -1
  175. package/build/core/registry.js +1 -1
  176. package/build/core/renew.js +7 -7
  177. package/build/core/response-artifact-catalog-sqlite.js +112 -0
  178. package/build/core/response-artifact-catalog.js +7 -0
  179. package/build/core/seal.js +44 -16
  180. package/build/core/status/board.js +286 -0
  181. package/build/core/status/drift.js +99 -0
  182. package/build/core/status/lifecycle.js +84 -0
  183. package/build/core/status/reconciliation.js +131 -0
  184. package/build/core/stored-agent-event.js +28 -4
  185. package/build/core/target-ref.js +10 -0
  186. package/build/core/task/board.js +175 -0
  187. package/build/core/task/commands.js +211 -0
  188. package/build/core/task/document.js +189 -0
  189. package/build/core/task/model.js +1 -0
  190. package/build/core/task/settlement-git.js +207 -0
  191. package/build/core/task/settlement-policy.js +82 -0
  192. package/build/core/task/source-board.js +84 -0
  193. package/build/core/task/source-model.js +1 -0
  194. package/build/core/task/validation.js +44 -0
  195. package/build/core/task-contract.js +224 -0
  196. package/build/core/task-doctor.js +14 -0
  197. package/build/core/task-git-actor.js +38 -0
  198. package/build/core/task-git-runtime.js +34 -0
  199. package/build/core/task-git-store.js +375 -0
  200. package/build/core/task-repository.js +1 -0
  201. package/build/core/task-store-repository.js +86 -0
  202. package/build/core/task-store.js +1 -0
  203. package/build/core/task-worktree.js +51 -0
  204. package/build/core/task.js +4 -0
  205. package/build/core/transcripts.js +138 -56
  206. package/build/core/validation.js +17 -0
  207. package/build/core/verdict.js +2 -2
  208. package/build/core/worktree-path.js +24 -6
  209. package/build/flow-error.js +3 -2
  210. package/build/generated/version.js +1 -1
  211. package/build/git/commits.js +3 -0
  212. package/build/git/diff/parsers.js +0 -94
  213. package/build/index.js +2 -0
  214. package/build/keiyaku-constants.js +2 -0
  215. package/build/keiyaku.js +4 -3
  216. package/package.json +3 -2
  217. package/skills/keiyaku/SKILL.md +1 -1
  218. package/skills/keiyaku-akuma/SKILL.md +11 -6
  219. package/build/agents/harness/pump.js +0 -158
  220. package/build/agents/providers/codex-app-server.js +0 -864
  221. package/build/agents/providers/opencode-sdk.js +0 -363
  222. package/build/agents/providers/pi.js +0 -557
  223. package/build/config/settings.js +0 -533
  224. package/build/core/call.js +0 -686
  225. package/build/core/projection/generation.js +0 -412
  226. package/build/core/projection/identity.js +0 -81
  227. package/build/core/projection/mint.js +0 -174
  228. package/build/core/projection-generation-store.js +0 -707
  229. package/build/core/status.js +0 -539
@@ -0,0 +1,141 @@
1
+ import { StringTailBuffer } from "../string-tail-buffer.js";
2
+ import { SUBAGENT_SESSION_VERSION, } from "../session.js";
3
+ import { SubagentFailure, } from "../types.js";
4
+ import { renderCapturedText } from "./runtime.js";
5
+ export function createOutcomeState(maxCaptureChars) {
6
+ return {
7
+ outputBuffer: new StringTailBuffer(maxCaptureChars),
8
+ diagnosticsBuffer: new StringTailBuffer(maxCaptureChars),
9
+ warnings: [],
10
+ };
11
+ }
12
+ function mintOutcome(draft) {
13
+ return draft;
14
+ }
15
+ export function restoreOutcome(record) {
16
+ return { ...record };
17
+ }
18
+ export function processEvent(state, event) {
19
+ switch (event.type) {
20
+ case "diagnostic":
21
+ state.diagnosticsBuffer.append(event.text);
22
+ return;
23
+ case "message":
24
+ state.finalMessageCandidate = event.text;
25
+ return;
26
+ case "warning":
27
+ state.warnings.push(event.warning);
28
+ return;
29
+ case "done":
30
+ state.doneEvent = event;
31
+ state.session = event.session;
32
+ if (event.finalMessage !== undefined) {
33
+ state.finalMessageCandidate = event.finalMessage;
34
+ }
35
+ return;
36
+ case "fail":
37
+ state.failEvent = event;
38
+ if (event.diagnostics) {
39
+ state.diagnosticsBuffer.append(event.diagnostics);
40
+ }
41
+ return;
42
+ case "activity":
43
+ case "unknown":
44
+ case "turn":
45
+ case "usage":
46
+ case "thought":
47
+ case "plan":
48
+ case "truncation":
49
+ return;
50
+ }
51
+ }
52
+ export function failFromFailEvent(shared, state, failEvent) {
53
+ const code = failEvent.code === "PROJECTION_STATE_ERROR" || failEvent.code === undefined
54
+ ? "SUBAGENT_EXEC_ERROR"
55
+ : failEvent.code;
56
+ const diagnostics = failEvent.code === "PROJECTION_STATE_ERROR"
57
+ ? [renderCapturedText(state.diagnosticsBuffer), "PROJECTION_STATE_ERROR"].filter(Boolean).join("\n")
58
+ : renderCapturedText(state.diagnosticsBuffer);
59
+ return failWithError(shared, state, {
60
+ code,
61
+ message: failEvent.message,
62
+ timeoutMs: null,
63
+ exitCode: failEvent.exitCode ?? null,
64
+ }, state.finalMessageCandidate, failEvent.diagnostics ?? diagnostics);
65
+ }
66
+ export function classifyFailure(shared, state, error, idleTimedOut) {
67
+ if (shared.dismissed || shared.externallyAborted) {
68
+ return mintOutcome({
69
+ status: "dismissed",
70
+ finalMessage: state.finalMessageCandidate ?? "",
71
+ output: renderCapturedText(state.outputBuffer),
72
+ diagnostics: renderCapturedText(state.diagnosticsBuffer),
73
+ session: state.session ?? fallbackSession(shared),
74
+ warnings: [...state.warnings],
75
+ });
76
+ }
77
+ if (idleTimedOut) {
78
+ return failWithError(shared, state, {
79
+ code: "SUBAGENT_TIMEOUT",
80
+ message: `${shared.terms.provider} exec idle timed out`,
81
+ timeoutMs: shared.terms.idleTimeoutMs,
82
+ exitCode: null,
83
+ }, state.finalMessageCandidate);
84
+ }
85
+ if (error instanceof SubagentFailure) {
86
+ return failWithError(shared, state, {
87
+ code: error.code,
88
+ message: error.message,
89
+ timeoutMs: error.timeoutMs,
90
+ exitCode: error.exitCode,
91
+ }, state.finalMessageCandidate ?? error.message, error.diagnostics || renderCapturedText(state.diagnosticsBuffer), error.output || renderCapturedText(state.outputBuffer));
92
+ }
93
+ const message = error instanceof Error ? error.message : `Unknown ${shared.terms.provider} exec error`;
94
+ appendThrownMessage(state.diagnosticsBuffer, message);
95
+ return failWithError(shared, state, {
96
+ code: "SUBAGENT_EXEC_ERROR",
97
+ message,
98
+ timeoutMs: null,
99
+ exitCode: null,
100
+ }, state.finalMessageCandidate ?? message);
101
+ }
102
+ export function failWithError(shared, state, error, finalMessage, diagnostics = renderCapturedText(state.diagnosticsBuffer), output = renderCapturedText(state.outputBuffer)) {
103
+ return mintOutcome({
104
+ status: "failed",
105
+ error,
106
+ finalMessage: finalMessage ?? error.message,
107
+ output,
108
+ diagnostics,
109
+ session: state.session ?? fallbackSession(shared),
110
+ warnings: [...state.warnings],
111
+ });
112
+ }
113
+ export function completeOutcome(shared, state, finalMessage, session) {
114
+ return mintOutcome({
115
+ status: "completed",
116
+ finalMessage,
117
+ output: renderCapturedText(state.outputBuffer),
118
+ diagnostics: renderCapturedText(state.diagnosticsBuffer),
119
+ session,
120
+ warnings: [...state.warnings],
121
+ });
122
+ }
123
+ export function fallbackSession(shared) {
124
+ return shared.reviveTerms?.session ?? {
125
+ provider: shared.terms.provider,
126
+ version: SUBAGENT_SESSION_VERSION,
127
+ handle: null,
128
+ };
129
+ }
130
+ function appendThrownMessage(buffer, message) {
131
+ if (message.length === 0)
132
+ return;
133
+ const snapshot = buffer.snapshot().text;
134
+ if (snapshot.length > 0 && !snapshot.endsWith("\n")) {
135
+ buffer.append("\n");
136
+ }
137
+ buffer.append(message);
138
+ }
139
+ export function renderOutcomeCapturedText(buffer) {
140
+ return renderCapturedText(buffer);
141
+ }
@@ -0,0 +1,310 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { FlowError } from "../../flow-error.js";
3
+ import { createEventChannel } from "./event-channel.js";
4
+ import { overflowMarkerFromDropped, prepareAgentEventForPersistence, } from "./execution-handle.js";
5
+ import { classifyFailure, completeOutcome, createOutcomeState, failFromFailEvent, failWithError, processEvent, renderOutcomeCapturedText, } from "./outcome.js";
6
+ import { startLiveProjection } from "./router.js";
7
+ import { createAbortError } from "./runtime.js";
8
+ export function call(terms, options) {
9
+ return createProjection(terms, undefined, options);
10
+ }
11
+ export function revive(terms, options) {
12
+ return createProjection(terms, terms, options);
13
+ }
14
+ function createProjection(terms, reviveTerms, options) {
15
+ switch (terms.provider) {
16
+ case "pi":
17
+ case "claude-agent-sdk":
18
+ case "codex-app-server":
19
+ case "opencode-sdk":
20
+ return createSteerableProjection(terms, reviveTerms, options);
21
+ case "codex-sdk":
22
+ return createReplayProjection(terms, reviveTerms, options);
23
+ default:
24
+ return assertNever(terms);
25
+ }
26
+ }
27
+ function createSteerableProjection(terms, reviveTerms, options) {
28
+ const shared = createProjectionState(terms, reviveTerms, options);
29
+ const pendingTells = [];
30
+ let flushActive = false;
31
+ const flushPendingTells = async () => {
32
+ const initialEnqueue = shared.live?.enqueue;
33
+ if (flushActive || shared.terminal || !initialEnqueue)
34
+ return;
35
+ flushActive = true;
36
+ try {
37
+ while (!shared.terminal && pendingTells.length > 0) {
38
+ const enqueue = shared.live?.enqueue;
39
+ if (!enqueue)
40
+ break;
41
+ const nextTell = pendingTells.shift();
42
+ if (!nextTell)
43
+ break;
44
+ await enqueue(nextTell);
45
+ }
46
+ }
47
+ finally {
48
+ flushActive = false;
49
+ if (!shared.terminal && pendingTells.length > 0 && shared.live?.enqueue) {
50
+ void flushPendingTells();
51
+ }
52
+ }
53
+ };
54
+ shared.onLive = (live) => {
55
+ shared.live = live;
56
+ void flushPendingTells();
57
+ };
58
+ const outcome = settleProjection(shared);
59
+ return {
60
+ mode: "steerable",
61
+ get id() {
62
+ return shared.id;
63
+ },
64
+ get events() {
65
+ return shared.publicEvents.iterable;
66
+ },
67
+ get outcome() {
68
+ return outcome;
69
+ },
70
+ tell(tell) {
71
+ if (shared.terminal)
72
+ return;
73
+ pendingTells.push(tell);
74
+ void flushPendingTells();
75
+ },
76
+ recallTells() {
77
+ return pendingTells.splice(0, pendingTells.length);
78
+ },
79
+ abort(mode) {
80
+ return abortProjection(shared, mode);
81
+ },
82
+ dismiss() {
83
+ dismissProjection(shared);
84
+ },
85
+ };
86
+ }
87
+ function createReplayProjection(terms, reviveTerms, options) {
88
+ const shared = createProjectionState(terms, reviveTerms, options);
89
+ shared.onLive = (live) => {
90
+ shared.live = live;
91
+ };
92
+ const outcome = settleProjection(shared);
93
+ return {
94
+ mode: "replay",
95
+ get id() {
96
+ return shared.id;
97
+ },
98
+ get events() {
99
+ return shared.publicEvents.iterable;
100
+ },
101
+ get outcome() {
102
+ return outcome;
103
+ },
104
+ abort(mode) {
105
+ return abortProjection(shared, mode);
106
+ },
107
+ dismiss() {
108
+ dismissProjection(shared);
109
+ },
110
+ };
111
+ }
112
+ function createProjectionState(terms, reviveTerms, options) {
113
+ const shared = {
114
+ id: randomUUID(),
115
+ terms,
116
+ reviveTerms,
117
+ publicEvents: createEventChannel({
118
+ createOverflowMarker: overflowMarkerFromDropped,
119
+ }),
120
+ lifecycleAbort: new AbortController(),
121
+ dismissed: false,
122
+ externallyAborted: false,
123
+ explicitlyAborted: false,
124
+ terminal: false,
125
+ forceWaiters: new Set(),
126
+ onLive() { },
127
+ observer: options?.observer,
128
+ };
129
+ if (terms.signal) {
130
+ const listener = () => {
131
+ shared.externallyAborted = true;
132
+ if (!shared.lifecycleAbort.signal.aborted) {
133
+ shared.lifecycleAbort.abort(terms.signal?.reason);
134
+ }
135
+ };
136
+ terms.signal.addEventListener("abort", listener, { once: true });
137
+ if (terms.signal.aborted) {
138
+ listener();
139
+ }
140
+ }
141
+ return shared;
142
+ }
143
+ function dismissProjection(shared) {
144
+ if (shared.dismissed || shared.terminal)
145
+ return;
146
+ shared.dismissed = true;
147
+ if (!shared.lifecycleAbort.signal.aborted) {
148
+ shared.lifecycleAbort.abort(createAbortError(`${shared.terms.provider} exec dismissed`));
149
+ }
150
+ requestDismissAbort(shared.live);
151
+ }
152
+ async function abortProjection(shared, mode = "graceful") {
153
+ shared.explicitlyAborted = true;
154
+ if (!shared.lifecycleAbort.signal.aborted) {
155
+ shared.lifecycleAbort.abort(createAbortError(`${shared.terms.provider} exec cancelled by client`));
156
+ }
157
+ if (mode !== "force") {
158
+ await shared.live?.abort("graceful");
159
+ return;
160
+ }
161
+ shared.forceAbort ??= (async () => {
162
+ const live = shared.live ?? (shared.terminal ? undefined : await new Promise((resolve) => {
163
+ shared.forceWaiters.add(resolve);
164
+ }));
165
+ await live?.abort("force");
166
+ })();
167
+ await shared.forceAbort;
168
+ }
169
+ function resolveForceWaiters(shared, live) {
170
+ for (const resolve of shared.forceWaiters)
171
+ resolve(live);
172
+ shared.forceWaiters.clear();
173
+ }
174
+ function requestDismissAbort(live) {
175
+ if (!live)
176
+ return;
177
+ void Promise.resolve()
178
+ .then(() => live.abort("graceful"))
179
+ .catch(() => undefined);
180
+ }
181
+ function deliverDriverEvent(shared, state, live, event, refreshIdleTimeout, observerEnabled) {
182
+ const prepared = prepareAgentEventForPersistence(event);
183
+ if (observerEnabled.value && shared.observer) {
184
+ try {
185
+ shared.observer.onEvent(prepared);
186
+ }
187
+ catch (error) {
188
+ observerEnabled.value = false;
189
+ const diagnostic = live.mintEvent({
190
+ type: "diagnostic",
191
+ text: `event persistence degraded: ${String(error)}`,
192
+ });
193
+ if (diagnostic) {
194
+ shared.publicEvents.push(diagnostic);
195
+ processEvent(state, diagnostic);
196
+ }
197
+ }
198
+ }
199
+ shared.publicEvents.push(event);
200
+ refreshIdleTimeout();
201
+ processEvent(state, event);
202
+ }
203
+ async function settleProjection(shared) {
204
+ const state = createOutcomeState(shared.terms.maxCaptureChars);
205
+ let idleTimedOut = false;
206
+ let abortRequested = false;
207
+ const observerEnabled = { value: shared.observer !== undefined };
208
+ let idleTimeout;
209
+ const refreshIdleTimeout = () => {
210
+ if (idleTimeout)
211
+ clearTimeout(idleTimeout);
212
+ idleTimeout = setTimeout(() => {
213
+ idleTimedOut = true;
214
+ shared.lifecycleAbort.abort(createAbortError(`${shared.terms.provider} exec idle timed out`));
215
+ }, shared.terms.idleTimeoutMs);
216
+ idleTimeout.unref?.();
217
+ };
218
+ refreshIdleTimeout();
219
+ const requestLiveAbort = () => {
220
+ if (shared.explicitlyAborted)
221
+ return;
222
+ if (abortRequested)
223
+ return;
224
+ abortRequested = true;
225
+ requestDismissAbort(shared.live);
226
+ };
227
+ shared.lifecycleAbort.signal.addEventListener("abort", requestLiveAbort, { once: true });
228
+ try {
229
+ const live = await startLiveProjection(shared.terms, shared.lifecycleAbort.signal, shared.reviveTerms, refreshIdleTimeout, shared.observer);
230
+ shared.onLive(live);
231
+ resolveForceWaiters(shared, live);
232
+ if (shared.lifecycleAbort.signal.aborted) {
233
+ requestLiveAbort();
234
+ }
235
+ try {
236
+ for await (const event of live.events) {
237
+ deliverDriverEvent(shared, state, live, event, refreshIdleTimeout, observerEnabled);
238
+ }
239
+ }
240
+ catch (error) {
241
+ if (error instanceof Error && error.code === "PROJECTION_STATE_ERROR") {
242
+ const event = live.mintEvent({
243
+ type: "fail",
244
+ code: "PROJECTION_STATE_ERROR",
245
+ message: error.message,
246
+ });
247
+ if (event)
248
+ deliverDriverEvent(shared, state, live, event, refreshIdleTimeout, observerEnabled);
249
+ }
250
+ else {
251
+ const event = live.mintEvent({
252
+ type: "diagnostic",
253
+ text: `pump error: ${String(error)}`,
254
+ });
255
+ if (event)
256
+ deliverDriverEvent(shared, state, live, event, refreshIdleTimeout, observerEnabled);
257
+ }
258
+ }
259
+ const completionResult = await live.completion.then((value) => ({ ok: true, value }), (error) => ({ ok: false, error }));
260
+ const completionOutcome = completionResult.ok ? completionResult.value : undefined;
261
+ if (state.failEvent) {
262
+ return failFromFailEvent(shared, state, state.failEvent);
263
+ }
264
+ if (!completionResult.ok) {
265
+ return classifyFailure(shared, state, completionResult.error, idleTimedOut);
266
+ }
267
+ if (shared.lifecycleAbort.signal.aborted) {
268
+ return classifyFailure(shared, state, shared.lifecycleAbort.signal.reason, idleTimedOut);
269
+ }
270
+ if (!state.doneEvent && !completionOutcome) {
271
+ return failWithError(shared, state, {
272
+ code: "SUBAGENT_EXEC_ERROR",
273
+ message: `${shared.terms.provider} exec ended before completion`,
274
+ timeoutMs: null,
275
+ exitCode: null,
276
+ }, state.finalMessageCandidate);
277
+ }
278
+ const finalMessage = state.doneEvent?.finalMessage ??
279
+ completionOutcome?.finalMessage ??
280
+ state.finalMessageCandidate ??
281
+ renderOutcomeCapturedText(state.outputBuffer).trim();
282
+ const session = state.doneEvent?.session ?? completionOutcome?.session;
283
+ if (!session) {
284
+ return failWithError(shared, state, {
285
+ code: "SUBAGENT_EXEC_ERROR",
286
+ message: `${shared.terms.provider} exec ended without a session handle`,
287
+ timeoutMs: null,
288
+ exitCode: null,
289
+ }, finalMessage);
290
+ }
291
+ return completeOutcome(shared, state, finalMessage, session);
292
+ }
293
+ catch (error) {
294
+ if (error instanceof FlowError) {
295
+ throw error;
296
+ }
297
+ return classifyFailure(shared, state, error, idleTimedOut);
298
+ }
299
+ finally {
300
+ if (idleTimeout)
301
+ clearTimeout(idleTimeout);
302
+ shared.lifecycleAbort.signal.removeEventListener("abort", requestLiveAbort);
303
+ shared.terminal = true;
304
+ resolveForceWaiters(shared, undefined);
305
+ shared.publicEvents.close();
306
+ }
307
+ }
308
+ function assertNever(_value) {
309
+ throw new Error("Unhandled provider");
310
+ }
@@ -0,0 +1,201 @@
1
+ import { FlowError } from "../../flow-error.js";
2
+ import { SUBAGENT_SESSION_VERSION, subagentSessionEnvelopeSchema, } from "../session.js";
3
+ import { startClaudeAgentSdk, claudeSessionSchema, } from "../providers/claude-agent-sdk/adapter.js";
4
+ import { startCodexAppServer, codexAppServerSessionSchema, } from "../providers/codex-app-server/adapter.js";
5
+ import { startCodexSdk, codexThreadSchema, } from "../providers/codex-sdk.js";
6
+ import { startOpencode, opencodeSessionSchema, } from "../providers/opencode-sdk/adapter.js";
7
+ import { startPi, piSessionSchema, } from "../providers/pi/adapter.js";
8
+ function admitResumeShape(provider, schema, session, resumePath) {
9
+ const envelopeResult = subagentSessionEnvelopeSchema.safeParse(session);
10
+ if (!envelopeResult.success) {
11
+ throw new FlowError("INVALID_RESPONSE_PATH", `Resume path file '${resumePath}' includes an invalid session envelope.`);
12
+ }
13
+ if (session.provider !== provider) {
14
+ 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.`);
15
+ }
16
+ if (session.version !== SUBAGENT_SESSION_VERSION) {
17
+ throw new FlowError("INVALID_RESPONSE_PATH", `Resume path file '${resumePath}' uses unsupported session version '${session.version}' for provider '${session.provider}'.`);
18
+ }
19
+ const shapeResult = schema.safeParse(session.handle);
20
+ if (!shapeResult.success) {
21
+ throw new FlowError("INVALID_RESPONSE_PATH", `Resume path file '${resumePath}' includes an invalid session handle for provider '${session.provider}'.`);
22
+ }
23
+ return shapeResult.data;
24
+ }
25
+ function assertNever(_value) {
26
+ throw new Error("Unhandled provider");
27
+ }
28
+ export async function startLiveProjection(terms, signal, reviveTerms, onIngress, observer) {
29
+ const onSyncCheckpoint = observer
30
+ ? (control, checkpoint) => {
31
+ observer.onCheckpoint(control, checkpoint);
32
+ }
33
+ : "onCheckpoint" in terms
34
+ ? terms.onCheckpoint
35
+ : undefined;
36
+ const onDeliveryOpportunity = observer
37
+ ? (control) => {
38
+ observer.onDeliveryOpportunity(control);
39
+ }
40
+ : undefined;
41
+ switch (terms.provider) {
42
+ case "pi": {
43
+ if (reviveTerms) {
44
+ const session = admitResumeShape("pi", piSessionSchema, reviveTerms.session, reviveTerms.resumePath);
45
+ return startPi(terms.prompt, terms.workdir, {
46
+ model: terms.model,
47
+ thinkingLevel: terms.thinkingLevel,
48
+ signal,
49
+ sessionFile: session.sessionFile,
50
+ appendSystemPromptOverride: terms.appendSystemPromptOverride,
51
+ onSyncCheckpoint,
52
+ onEvidence: terms.onEvidence,
53
+ onIngress,
54
+ initialTurn: terms.initialTurn,
55
+ loader: terms.loader,
56
+ });
57
+ }
58
+ return startPi(terms.prompt, terms.workdir, {
59
+ model: terms.model,
60
+ thinkingLevel: terms.thinkingLevel,
61
+ signal,
62
+ appendSystemPromptOverride: terms.appendSystemPromptOverride,
63
+ onSyncCheckpoint,
64
+ onEvidence: terms.onEvidence,
65
+ onIngress,
66
+ initialTurn: terms.initialTurn,
67
+ loader: terms.loader,
68
+ });
69
+ }
70
+ case "claude-agent-sdk": {
71
+ const claudeOptions = {
72
+ model: terms.model,
73
+ executable: terms.executable,
74
+ effort: terms.effort,
75
+ env: terms.env,
76
+ signal,
77
+ permissionMode: terms.permissionMode,
78
+ settingSources: terms.settingSources,
79
+ allowDangerouslySkipPermissions: terms.allowDangerouslySkipPermissions,
80
+ disallowedTools: terms.disallowedTools,
81
+ systemPrompt: terms.systemPrompt,
82
+ onSyncCheckpoint,
83
+ onEvidence: terms.onEvidence,
84
+ onIngress,
85
+ initialTurn: terms.initialTurn,
86
+ loader: terms.loader,
87
+ };
88
+ if (reviveTerms) {
89
+ const session = admitResumeShape("claude-agent-sdk", claudeSessionSchema, reviveTerms.session, reviveTerms.resumePath);
90
+ return startClaudeAgentSdk(terms.prompt, terms.workdir, {
91
+ ...claudeOptions,
92
+ sessionId: session.sessionId,
93
+ });
94
+ }
95
+ return startClaudeAgentSdk(terms.prompt, terms.workdir, claudeOptions);
96
+ }
97
+ case "codex-app-server": {
98
+ if (reviveTerms) {
99
+ const session = admitResumeShape("codex-app-server", codexAppServerSessionSchema, reviveTerms.session, reviveTerms.resumePath);
100
+ return startCodexAppServer(terms.prompt, terms.workdir, {
101
+ model: terms.model,
102
+ effort: terms.effort,
103
+ profile: terms.profile,
104
+ config: terms.config,
105
+ sandboxPolicy: terms.sandboxPolicy,
106
+ approvalPolicy: terms.approvalPolicy,
107
+ executable: terms.executable,
108
+ env: terms.env,
109
+ signal,
110
+ threadId: session.threadId,
111
+ codexHome: session.codexHome,
112
+ developerInstructions: terms.developerInstructions,
113
+ onSyncCheckpoint,
114
+ onDeliveryOpportunity,
115
+ onEvidence: terms.onEvidence,
116
+ onIngress,
117
+ initialTurn: terms.initialTurn,
118
+ });
119
+ }
120
+ return startCodexAppServer(terms.prompt, terms.workdir, {
121
+ model: terms.model,
122
+ effort: terms.effort,
123
+ profile: terms.profile,
124
+ config: terms.config,
125
+ sandboxPolicy: terms.sandboxPolicy,
126
+ approvalPolicy: terms.approvalPolicy,
127
+ executable: terms.executable,
128
+ env: terms.env,
129
+ signal,
130
+ developerInstructions: terms.developerInstructions,
131
+ onSyncCheckpoint,
132
+ onDeliveryOpportunity,
133
+ onEvidence: terms.onEvidence,
134
+ onIngress,
135
+ initialTurn: terms.initialTurn,
136
+ });
137
+ }
138
+ case "codex-sdk": {
139
+ if (reviveTerms) {
140
+ const session = admitResumeShape("codex-sdk", codexThreadSchema, reviveTerms.session, reviveTerms.resumePath);
141
+ return startCodexSdk(terms.prompt, terms.workdir, {
142
+ model: terms.model,
143
+ profile: terms.profile,
144
+ config: terms.config,
145
+ threadOptions: terms.threadOptions,
146
+ executable: terms.executable,
147
+ signal,
148
+ threadId: session.threadId,
149
+ onEvidence: terms.onEvidence,
150
+ onIngress,
151
+ initialTurn: terms.initialTurn,
152
+ codexConstructor: terms.codexConstructor,
153
+ });
154
+ }
155
+ return startCodexSdk(terms.prompt, terms.workdir, {
156
+ model: terms.model,
157
+ profile: terms.profile,
158
+ config: terms.config,
159
+ threadOptions: terms.threadOptions,
160
+ executable: terms.executable,
161
+ signal,
162
+ onEvidence: terms.onEvidence,
163
+ onIngress,
164
+ initialTurn: terms.initialTurn,
165
+ codexConstructor: terms.codexConstructor,
166
+ });
167
+ }
168
+ case "opencode-sdk": {
169
+ if (reviveTerms) {
170
+ const session = admitResumeShape("opencode-sdk", opencodeSessionSchema, reviveTerms.session, reviveTerms.resumePath);
171
+ return startOpencode(terms.prompt, terms.workdir, {
172
+ model: terms.model,
173
+ effort: terms.effort,
174
+ executable: terms.executable,
175
+ env: terms.env,
176
+ signal,
177
+ sessionId: session.sessionId,
178
+ onSyncCheckpoint,
179
+ onDeliveryOpportunity,
180
+ onEvidence: terms.onEvidence,
181
+ onIngress,
182
+ initialTurn: terms.initialTurn,
183
+ });
184
+ }
185
+ return startOpencode(terms.prompt, terms.workdir, {
186
+ model: terms.model,
187
+ effort: terms.effort,
188
+ executable: terms.executable,
189
+ env: terms.env,
190
+ signal,
191
+ onSyncCheckpoint,
192
+ onDeliveryOpportunity,
193
+ onEvidence: terms.onEvidence,
194
+ onIngress,
195
+ initialTurn: terms.initialTurn,
196
+ });
197
+ }
198
+ default:
199
+ return assertNever(terms);
200
+ }
201
+ }
@@ -63,9 +63,10 @@ export function linkAbortSignal(signal, controller, onAbort) {
63
63
  }
64
64
  return () => signal.removeEventListener("abort", handler);
65
65
  }
66
- export function buildSubagentEnv() {
66
+ export function buildSubagentEnv(instanceEnv) {
67
67
  return {
68
68
  ...getConfig().runtimeEnv,
69
+ ...(instanceEnv ?? {}),
69
70
  [DISABLE_SUBAGENT_SPAWN_ENV_KEY]: "1",
70
71
  };
71
72
  }