stageflow 0.36.0 → 0.40.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 (288) hide show
  1. package/README.md +61 -26
  2. package/dist/agent/claudeAdapter.js +21 -1
  3. package/dist/agent/claudeTools.d.ts +13 -0
  4. package/dist/agent/claudeTools.js +98 -0
  5. package/dist/agent/piAdapter.d.ts +9 -1
  6. package/dist/agent/piAdapter.js +59 -18
  7. package/dist/agent/piIsolatedMcp.js +14 -2
  8. package/dist/agent/piIsolatedMcpProbe.d.ts +5 -1
  9. package/dist/agent/piIsolatedMcpProbe.js +16 -30
  10. package/dist/agent/port.d.ts +5 -0
  11. package/dist/agent/sandboxPiTools.d.ts +99 -0
  12. package/dist/agent/sandboxPiTools.js +109 -0
  13. package/dist/agents/agentId.d.ts +8 -0
  14. package/dist/agents/agentId.js +27 -0
  15. package/dist/agents/approvalBroker.d.ts +16 -0
  16. package/dist/agents/approvalBroker.js +45 -0
  17. package/dist/agents/authorChat.d.ts +19 -0
  18. package/dist/agents/authorChat.js +63 -0
  19. package/dist/agents/chatTurn.d.ts +23 -0
  20. package/dist/agents/chatTurn.js +77 -0
  21. package/dist/agents/communications/agentmail.d.ts +19 -0
  22. package/dist/agents/communications/agentmail.js +46 -0
  23. package/dist/agents/communications/agentmailListener.d.ts +59 -0
  24. package/dist/agents/communications/agentmailListener.js +183 -0
  25. package/dist/agents/communications/allowlist.d.ts +10 -0
  26. package/dist/agents/communications/allowlist.js +36 -0
  27. package/dist/agents/communications/channelConnections.d.ts +3 -0
  28. package/dist/agents/communications/channelConnections.js +51 -0
  29. package/dist/agents/communications/delivery.d.ts +53 -0
  30. package/dist/agents/communications/delivery.js +142 -0
  31. package/dist/agents/communications/email.d.ts +26 -0
  32. package/dist/agents/communications/email.js +20 -0
  33. package/dist/agents/communications/identity.d.ts +13 -0
  34. package/dist/agents/communications/identity.js +18 -0
  35. package/dist/agents/communications/imessageListener.d.ts +41 -0
  36. package/dist/agents/communications/imessageListener.js +92 -0
  37. package/dist/agents/communications/inbound.d.ts +63 -0
  38. package/dist/agents/communications/inbound.js +143 -0
  39. package/dist/agents/communications/listener.d.ts +36 -0
  40. package/dist/agents/communications/listener.js +38 -0
  41. package/dist/agents/communications/photon.d.ts +19 -0
  42. package/dist/agents/communications/photon.js +38 -0
  43. package/dist/agents/communications/port.d.ts +27 -0
  44. package/dist/agents/communications/port.js +6 -0
  45. package/dist/agents/communications/slack.d.ts +28 -0
  46. package/dist/agents/communications/slack.js +65 -0
  47. package/dist/agents/communications/supervisor.d.ts +36 -0
  48. package/dist/agents/communications/supervisor.js +96 -0
  49. package/dist/agents/communications/telegram.d.ts +19 -0
  50. package/dist/agents/communications/telegram.js +52 -0
  51. package/dist/agents/definitionSummary.d.ts +13 -0
  52. package/dist/agents/definitionSummary.js +91 -0
  53. package/dist/agents/delegate.d.ts +3 -0
  54. package/dist/agents/delegate.js +8 -0
  55. package/dist/agents/errors.d.ts +10 -0
  56. package/dist/agents/errors.js +32 -0
  57. package/dist/agents/guardrails.d.ts +24 -0
  58. package/dist/agents/guardrails.js +39 -0
  59. package/dist/agents/historyFit.d.ts +10 -0
  60. package/dist/agents/historyFit.js +26 -0
  61. package/dist/agents/hostContext.d.ts +54 -0
  62. package/dist/agents/hostContext.js +156 -0
  63. package/dist/agents/ledgers.d.ts +29 -0
  64. package/dist/agents/ledgers.js +31 -0
  65. package/dist/agents/lineDiff.d.ts +12 -0
  66. package/dist/agents/lineDiff.js +46 -0
  67. package/dist/agents/ndjson.d.ts +9 -0
  68. package/dist/agents/ndjson.js +47 -0
  69. package/dist/agents/otlpExport.d.ts +9 -0
  70. package/dist/agents/otlpExport.js +58 -0
  71. package/dist/agents/otlpSink.d.ts +7 -0
  72. package/dist/agents/otlpSink.js +23 -0
  73. package/dist/agents/policy.d.ts +31 -0
  74. package/dist/agents/policy.js +84 -0
  75. package/dist/agents/projectRoot.d.ts +5 -0
  76. package/dist/agents/projectRoot.js +15 -0
  77. package/dist/agents/runtime/piRuntime.d.ts +52 -0
  78. package/dist/agents/runtime/piRuntime.js +474 -0
  79. package/dist/agents/runtime/types.d.ts +77 -0
  80. package/dist/agents/runtime/types.js +26 -0
  81. package/dist/agents/sandbox.d.ts +17 -0
  82. package/dist/agents/sandbox.js +10 -0
  83. package/dist/agents/scheduleSource.d.ts +32 -0
  84. package/dist/agents/scheduleSource.js +100 -0
  85. package/dist/agents/service.d.ts +298 -0
  86. package/dist/agents/service.js +1105 -0
  87. package/dist/agents/sessions.d.ts +38 -0
  88. package/dist/agents/sessions.js +321 -0
  89. package/dist/agents/store.d.ts +277 -0
  90. package/dist/agents/store.js +643 -0
  91. package/dist/agents/trace.d.ts +27 -0
  92. package/dist/agents/trace.js +29 -0
  93. package/dist/agents/turnLifecycle.d.ts +72 -0
  94. package/dist/agents/turnLifecycle.js +157 -0
  95. package/dist/agents/webChat/publicChat.d.ts +36 -0
  96. package/dist/agents/webChat/publicChat.js +290 -0
  97. package/dist/agents/webChat/rateLimit.d.ts +15 -0
  98. package/dist/agents/webChat/rateLimit.js +33 -0
  99. package/dist/agents/webChat/slug.d.ts +2 -0
  100. package/dist/agents/webChat/slug.js +9 -0
  101. package/dist/channels/providers/agentmail.js +14 -1
  102. package/dist/channels/providers/photonImessage.js +36 -0
  103. package/dist/channels/providers/slack.js +2 -1
  104. package/dist/channels/providers/telegram.js +2 -1
  105. package/dist/channels/types.d.ts +27 -0
  106. package/dist/cli/agentsCommand.d.ts +14 -0
  107. package/dist/cli/agentsCommand.js +291 -0
  108. package/dist/cli.js +9 -0
  109. package/dist/config/browseCatalog.js +4 -11
  110. package/dist/config/draftPackage.d.ts +1 -0
  111. package/dist/config/draftPackage.js +4 -0
  112. package/dist/config/hostConfig.js +9 -0
  113. package/dist/config/loadAgent.d.ts +266 -0
  114. package/dist/config/loadAgent.js +374 -0
  115. package/dist/config/loadPipeline.js +5 -2
  116. package/dist/config/loadTask.js +34 -1
  117. package/dist/config/mcpHostCatalog.d.ts +50 -0
  118. package/dist/config/mcpHostCatalog.js +405 -0
  119. package/dist/config/mcpOAuth.d.ts +37 -0
  120. package/dist/config/mcpOAuth.js +263 -0
  121. package/dist/config/mcpRedaction.d.ts +42 -0
  122. package/dist/config/mcpRedaction.js +314 -0
  123. package/dist/config/mcpToolCache.d.ts +20 -0
  124. package/dist/config/mcpToolCache.js +43 -0
  125. package/dist/config/mergePipelineIncludes.d.ts +2 -0
  126. package/dist/config/mergePipelineIncludes.js +25 -0
  127. package/dist/config/resolveStageMcpServers.d.ts +35 -3
  128. package/dist/config/resolveStageMcpServers.js +124 -9
  129. package/dist/config/validateCatalog.d.ts +1 -1
  130. package/dist/config/validateCatalog.js +22 -1
  131. package/dist/mcp/agentTools.d.ts +8 -0
  132. package/dist/mcp/agentTools.js +132 -0
  133. package/dist/mcp/catalogTools.js +17 -10
  134. package/dist/mcp/deps.d.ts +6 -0
  135. package/dist/mcp/pipelineAuthorSupport.d.ts +19 -0
  136. package/dist/mcp/pipelineAuthorSupport.js +10 -0
  137. package/dist/mcp/pipelineAuthorTools.d.ts +8 -0
  138. package/dist/mcp/pipelineAuthorTools.js +109 -0
  139. package/dist/mcp/server.js +5 -0
  140. package/dist/mcp/tools.js +4 -0
  141. package/dist/mcp/triggerTools.js +32 -0
  142. package/dist/memory/access.d.ts +36 -0
  143. package/dist/memory/access.js +116 -0
  144. package/dist/memory/agentIssues.d.ts +3 -0
  145. package/dist/memory/agentIssues.js +23 -0
  146. package/dist/memory/bashDeny.d.ts +6 -0
  147. package/dist/memory/bashDeny.js +35 -0
  148. package/dist/memory/host.d.ts +51 -0
  149. package/dist/memory/host.js +394 -0
  150. package/dist/memory/ids.d.ts +15 -0
  151. package/dist/memory/ids.js +31 -0
  152. package/dist/memory/worker.d.ts +1 -0
  153. package/dist/memory/worker.js +84 -0
  154. package/dist/models/catalog.d.ts +113 -0
  155. package/dist/models/catalog.js +238 -0
  156. package/dist/models/response.d.ts +29 -0
  157. package/dist/models/response.js +25 -0
  158. package/dist/operatorAgent/agentAuthorContext.d.ts +17 -0
  159. package/dist/operatorAgent/agentAuthorContext.js +32 -0
  160. package/dist/operatorAgent/fakeHost.js +2 -0
  161. package/dist/operatorAgent/host.js +6 -3
  162. package/dist/operatorAgent/index.d.ts +4 -0
  163. package/dist/operatorAgent/index.js +4 -0
  164. package/dist/operatorAgent/piModel.js +2 -0
  165. package/dist/operatorAgent/profiles/agentAuthor.d.ts +11 -0
  166. package/dist/operatorAgent/profiles/agentAuthor.js +192 -0
  167. package/dist/operatorAgent/profiles/agentAuthorPlaybook.d.ts +1 -0
  168. package/dist/operatorAgent/profiles/agentAuthorPlaybook.js +29 -0
  169. package/dist/operatorAgent/profiles/workshopAuthor.js +2 -2
  170. package/dist/operatorAgent/profiles/workshopAuthorTools.js +3 -3
  171. package/dist/operatorAgent/proposals.d.ts +1 -0
  172. package/dist/operatorAgent/proposals.js +23 -2
  173. package/dist/package-meta.d.ts +1 -1
  174. package/dist/package-meta.js +1 -1
  175. package/dist/preflight/pipelinePreflight.js +1 -0
  176. package/dist/runstore/createStore.d.ts +2 -0
  177. package/dist/runstore/createStore.js +8 -0
  178. package/dist/runstore/overviewSummary.d.ts +56 -0
  179. package/dist/runstore/overviewSummary.js +134 -0
  180. package/dist/runstore/port.d.ts +3 -0
  181. package/dist/runstore/sqlite/SqliteRunStore.d.ts +2 -0
  182. package/dist/runstore/sqlite/SqliteRunStore.js +18 -0
  183. package/dist/runstore/sqlite/migrations/013-agents.d.ts +12 -0
  184. package/dist/runstore/sqlite/migrations/013-agents.js +156 -0
  185. package/dist/runstore/sqlite/migrations/014-agent-deliveries.d.ts +11 -0
  186. package/dist/runstore/sqlite/migrations/014-agent-deliveries.js +32 -0
  187. package/dist/runstore/sqlite/migrations/index.js +4 -0
  188. package/dist/runtime/gitCheckoutCapability.d.ts +1 -0
  189. package/dist/runtime/gitCheckoutCapability.js +1 -1
  190. package/dist/runtime/gitWorktreeCheckout.d.ts +22 -0
  191. package/dist/runtime/gitWorktreeCheckout.js +120 -0
  192. package/dist/runtime/sandboxContainer.d.ts +62 -0
  193. package/dist/runtime/sandboxContainer.js +151 -0
  194. package/dist/runtime/sandboxDesk.d.ts +28 -0
  195. package/dist/runtime/sandboxDesk.js +242 -0
  196. package/dist/runtime/sandboxFiles.d.ts +20 -0
  197. package/dist/runtime/sandboxFiles.js +150 -0
  198. package/dist/runtime/stageAttemptBootstrap.js +15 -1
  199. package/dist/runtime/stageEnvironment.d.ts +2 -0
  200. package/dist/runtime/stageEnvironment.js +8 -1
  201. package/dist/runtime/stageProcessLauncher.js +23 -0
  202. package/dist/runtime/stageRoots.d.ts +9 -0
  203. package/dist/runtime/stageRoots.js +14 -0
  204. package/dist/runtime/stageRunner.d.ts +5 -0
  205. package/dist/runtime/stageRunner.js +38 -4
  206. package/dist/runtime/stageSandbox.d.ts +16 -0
  207. package/dist/runtime/stageSandbox.js +54 -0
  208. package/dist/runtime/stageSecrets.d.ts +6 -1
  209. package/dist/runtime/stageSecrets.js +34 -1
  210. package/dist/runtime/stageWorker.js +138 -105
  211. package/dist/runtime/workspaceBinding.d.ts +2 -1
  212. package/dist/runtime/workspaceBinding.js +20 -4
  213. package/dist/server/agentAuthorRoutes.d.ts +5 -0
  214. package/dist/server/agentAuthorRoutes.js +64 -0
  215. package/dist/server/agentRoutes.d.ts +5 -0
  216. package/dist/server/agentRoutes.js +323 -0
  217. package/dist/server/bootstrap.d.ts +8 -0
  218. package/dist/server/bootstrap.js +36 -10
  219. package/dist/server/controlToken.js +8 -0
  220. package/dist/server/http.d.ts +8 -1
  221. package/dist/server/http.js +172 -20
  222. package/dist/server/mcpHost.js +1 -0
  223. package/dist/server/memoryRoutes.d.ts +5 -0
  224. package/dist/server/memoryRoutes.js +146 -0
  225. package/dist/server/projectMcpRoutes.d.ts +1 -0
  226. package/dist/server/projectMcpRoutes.js +241 -3
  227. package/dist/toolkit/guard.d.ts +27 -0
  228. package/dist/toolkit/guard.js +98 -0
  229. package/dist/toolkit/index.d.ts +48 -0
  230. package/dist/toolkit/index.js +82 -0
  231. package/dist/toolkit/meta.d.ts +36 -0
  232. package/dist/toolkit/meta.js +117 -0
  233. package/dist/toolkit/profiles.d.ts +13 -0
  234. package/dist/toolkit/profiles.js +25 -0
  235. package/dist/toolkit/record.d.ts +15 -0
  236. package/dist/toolkit/record.js +17 -0
  237. package/dist/tools/memoryTools.d.ts +95 -0
  238. package/dist/tools/memoryTools.js +179 -0
  239. package/dist/types/pipeline.d.ts +3 -0
  240. package/dist/types/stage.d.ts +2 -0
  241. package/dist/types/task.d.ts +11 -1
  242. package/dist/ui/assets/AssistantRuntimeProvider-CsiPFhCT.js +9 -0
  243. package/dist/ui/assets/MarkdownText-D7tYaIFO.js +29 -0
  244. package/dist/ui/assets/ReadonlyStore-BfXqHykm.js +6 -0
  245. package/dist/ui/assets/Tooltip-DrpoRRNi.js +1 -0
  246. package/dist/ui/assets/chat-BbLukq9W.js +5 -0
  247. package/dist/ui/assets/chat-zIZU_bP1.css +2 -0
  248. package/dist/ui/assets/jsx-runtime-iVoFAvQ_.js +1 -0
  249. package/dist/ui/assets/{index-Clv4sJpU.css → main-BFo79krC.css} +1 -1
  250. package/dist/ui/assets/main-CijYMeM0.js +259 -0
  251. package/dist/ui/chat.html +25 -0
  252. package/dist/ui/index.html +6 -2
  253. package/dist/workshop/modelSettings.d.ts +2 -2
  254. package/dist/workshop/modelSettings.js +5 -11
  255. package/examples/README.md +1 -0
  256. package/examples/channels-smoke/README.md +12 -1
  257. package/examples/github-release/README.md +1 -1
  258. package/examples/memory/README.md +101 -0
  259. package/examples/memory/desk-outage.task.yaml +15 -0
  260. package/examples/memory/desk-refund.task.yaml +15 -0
  261. package/examples/memory/desk-revisit-outage.task.yaml +11 -0
  262. package/examples/memory/desk-revisit.pipeline.yaml +123 -0
  263. package/examples/memory/desk.pipeline.yaml +192 -0
  264. package/examples/memory/file-card.pipeline.yaml +39 -0
  265. package/examples/memory/file-ledger.task.yaml +22 -0
  266. package/examples/memory/file-release.task.yaml +24 -0
  267. package/examples/memory/file-rich.pipeline.yaml +40 -0
  268. package/examples/memory/file-ticket.task.yaml +7 -0
  269. package/examples/memory/file-timeline.task.yaml +28 -0
  270. package/examples/memory/find-card.pipeline.yaml +46 -0
  271. package/examples/memory/find-ticket.task.yaml +7 -0
  272. package/examples/memory/missing.pipeline.yaml +16 -0
  273. package/examples/memory/probe-bash.task.yaml +3 -0
  274. package/examples/memory/recall.pipeline.yaml +24 -0
  275. package/examples/memory/recall.task.yaml +5 -0
  276. package/examples/memory/remember-ada.task.yaml +6 -0
  277. package/examples/memory/remember-grace.task.yaml +6 -0
  278. package/examples/memory/remember.pipeline.yaml +58 -0
  279. package/examples/memory/sandbox-memory-bash.pipeline.yaml +28 -0
  280. package/examples/memory/stageflow.yaml +12 -0
  281. package/examples/memory/update-card.pipeline.yaml +43 -0
  282. package/examples/memory/update-ledger.task.yaml +23 -0
  283. package/examples/memory/update-rich.pipeline.yaml +44 -0
  284. package/examples/memory/update-ticket.task.yaml +7 -0
  285. package/examples/ship-feature/README.md +15 -0
  286. package/examples/stage-mcp/README.md +1 -1
  287. package/package.json +2 -1
  288. package/dist/ui/assets/index-BOhqnPNg.js +0 -260
@@ -11,6 +11,7 @@ import { bindPiAgentDirEnv, overlayStageBindingEnv, rootsForStageWorker, stageBi
11
11
  import { buildStageEnvironment } from "./stageEnvironment.js";
12
12
  import { ensureStageCacheDirs } from "./stageCacheEnv.js";
13
13
  import { PACKAGE_VERSION } from "../package-meta.js";
14
+ import { openStageSandbox } from "./stageSandbox.js";
14
15
  import { runStage, isRunStageWaiting, } from "./stageRunner.js";
15
16
  import { openStageAttempt } from "./stageAttemptBootstrap.js";
16
17
  import { attemptContext } from "./stageAttemptContext.js";
@@ -60,97 +61,137 @@ export async function runStageWorker(input) {
60
61
  .filter((e) => e[1] !== undefined));
61
62
  const mode = input.mode ?? "run";
62
63
  const attempt = input.attempt ?? 1;
63
- loadNamedSecretsFromAttemptDir(attemptWorkspaceDir(workspaceDir, input.stageId, attempt));
64
+ const attemptDir = attemptWorkspaceDir(workspaceDir, input.stageId, attempt);
65
+ loadNamedSecretsFromAttemptDir(attemptDir);
64
66
  const attemptCtx = input.attempt !== undefined ? attemptContext(input.attempt) : undefined;
65
67
  const eventOptions = { attempt };
66
- const roots = withResolvedAuthPath(rootsForStageWorker(workspaceDir, input.stageId, stage.model, checkoutRoot, attemptCtx), input.rootDir);
68
+ let roots = withResolvedAuthPath(rootsForStageWorker(workspaceDir, input.stageId, stage.model, checkoutRoot, attemptCtx), input.rootDir);
67
69
  const unbindAgentDir = bindPiAgentDirEnv(roots.agentDir);
70
+ const sandbox = await openStageSandbox({
71
+ env: process.env,
72
+ roots,
73
+ runId: input.runId,
74
+ stageId: input.stageId,
75
+ attempt,
76
+ attemptDir,
77
+ ...(checkoutRoot !== undefined ? { checkoutRoot } : {}),
78
+ });
79
+ roots = sandbox.roots;
80
+ const beforeVerify = sandbox.beforeVerify;
81
+ let outcome;
82
+ let thrown;
68
83
  try {
69
- if (mode === "resume") {
70
- const opened = await openStageAttempt({
71
- agent,
72
- store,
73
- runId: input.runId,
74
- stage,
75
- stageId: input.stageId,
76
- task,
77
- dag,
78
- checkoutRoot,
79
- workspaceDir,
80
- factoryCwd: input.rootDir,
81
- attemptCtx,
82
- operatorCatalog: input.operatorCatalog,
83
- roots,
84
- resumeToken: input.sessionFilePath,
85
- sessionMode: "waiting_resume",
86
- stageEnv,
87
- onActivity: (event) => {
88
- void store.appendStageEvent(input.runId, input.stageId, event, eventOptions);
89
- },
90
- });
91
- if (!opened.ok) {
92
- return { ok: false, reason: opened.reason };
84
+ outcome = await (async () => {
85
+ if (sandbox.failure !== undefined) {
86
+ return { ok: false, reason: sandbox.failure };
93
87
  }
94
- opened.handle.deliverAnswer(input.resumeAnswer);
95
- const outcome = await runStage({
96
- agent,
97
- store,
98
- runId: input.runId,
99
- stage,
100
- stageId: input.stageId,
101
- task,
102
- dag,
103
- checkoutRoot,
104
- workspaceDir,
105
- skipStarted: true,
106
- existingHandle: opened.handle,
107
- workerMode: true,
108
- roots,
109
- attemptCtx,
110
- factoryCwd: input.rootDir,
111
- operatorCatalog: input.operatorCatalog,
112
- skipGates: input.skipGates,
113
- stageEnv,
114
- });
115
- return outcome;
116
- }
117
- if (mode === "feedback_resume" || mode === "new_session") {
118
- const feedbackLoopContext = await loadActiveFeedbackLoopContext(store, input.runId, input.stageId);
119
- if (mode === "feedback_resume" && feedbackLoopContext === undefined) {
120
- return {
121
- ok: false,
122
- reason: "feedback_resume requires an active feedback-loop context",
123
- };
88
+ if (mode === "resume") {
89
+ const opened = await openStageAttempt({
90
+ agent,
91
+ store,
92
+ runId: input.runId,
93
+ stage,
94
+ stageId: input.stageId,
95
+ task,
96
+ dag,
97
+ checkoutRoot,
98
+ workspaceDir,
99
+ factoryCwd: input.rootDir,
100
+ attemptCtx,
101
+ operatorCatalog: input.operatorCatalog,
102
+ roots,
103
+ resumeToken: input.sessionFilePath,
104
+ sessionMode: "waiting_resume",
105
+ stageEnv,
106
+ onActivity: (event) => {
107
+ void store.appendStageEvent(input.runId, input.stageId, event, eventOptions);
108
+ },
109
+ });
110
+ if (!opened.ok) {
111
+ return { ok: false, reason: opened.reason };
112
+ }
113
+ opened.handle.deliverAnswer(input.resumeAnswer);
114
+ const outcome = await runStage({
115
+ agent,
116
+ store,
117
+ runId: input.runId,
118
+ stage,
119
+ stageId: input.stageId,
120
+ task,
121
+ dag,
122
+ checkoutRoot,
123
+ workspaceDir,
124
+ skipStarted: true,
125
+ existingHandle: opened.handle,
126
+ workerMode: true,
127
+ roots,
128
+ attemptCtx,
129
+ factoryCwd: input.rootDir,
130
+ operatorCatalog: input.operatorCatalog,
131
+ skipGates: input.skipGates,
132
+ stageEnv,
133
+ beforeVerify,
134
+ });
135
+ return outcome;
124
136
  }
125
- const priorAttempt = feedbackLoopContext?.prior_stage_attempt;
126
- const resumeToken = input.sessionFilePath ??
127
- (mode === "feedback_resume" && priorAttempt !== undefined
128
- ? attemptContext(priorAttempt).sessionPath(workspaceDir, input.stageId)
129
- : undefined);
130
- const opened = await openStageAttempt({
131
- agent,
132
- store,
133
- runId: input.runId,
134
- stage,
135
- stageId: input.stageId,
136
- task,
137
- dag,
138
- checkoutRoot,
139
- workspaceDir,
140
- factoryCwd: input.rootDir,
141
- attemptCtx,
142
- operatorCatalog: input.operatorCatalog,
143
- roots,
144
- ...(resumeToken !== undefined ? { resumeToken } : {}),
145
- sessionMode: mode,
146
- ...(feedbackLoopContext !== undefined ? { feedbackLoopContext } : {}),
147
- stageEnv,
148
- onActivity: (event) => {
149
- void store.appendStageEvent(input.runId, input.stageId, event, eventOptions);
150
- },
151
- });
152
- if (!opened.ok) {
153
- return { ok: false, reason: opened.reason };
137
+ if (mode === "feedback_resume" || mode === "new_session") {
138
+ const feedbackLoopContext = await loadActiveFeedbackLoopContext(store, input.runId, input.stageId);
139
+ if (mode === "feedback_resume" && feedbackLoopContext === undefined) {
140
+ return {
141
+ ok: false,
142
+ reason: "feedback_resume requires an active feedback-loop context",
143
+ };
144
+ }
145
+ const priorAttempt = feedbackLoopContext?.prior_stage_attempt;
146
+ const resumeToken = input.sessionFilePath ??
147
+ (mode === "feedback_resume" && priorAttempt !== undefined
148
+ ? attemptContext(priorAttempt).sessionPath(workspaceDir, input.stageId)
149
+ : undefined);
150
+ const opened = await openStageAttempt({
151
+ agent,
152
+ store,
153
+ runId: input.runId,
154
+ stage,
155
+ stageId: input.stageId,
156
+ task,
157
+ dag,
158
+ checkoutRoot,
159
+ workspaceDir,
160
+ factoryCwd: input.rootDir,
161
+ attemptCtx,
162
+ operatorCatalog: input.operatorCatalog,
163
+ roots,
164
+ ...(resumeToken !== undefined ? { resumeToken } : {}),
165
+ sessionMode: mode,
166
+ ...(feedbackLoopContext !== undefined ? { feedbackLoopContext } : {}),
167
+ stageEnv,
168
+ onActivity: (event) => {
169
+ void store.appendStageEvent(input.runId, input.stageId, event, eventOptions);
170
+ },
171
+ });
172
+ if (!opened.ok) {
173
+ return { ok: false, reason: opened.reason };
174
+ }
175
+ return runStage({
176
+ agent,
177
+ store,
178
+ runId: input.runId,
179
+ stage,
180
+ stageId: input.stageId,
181
+ task,
182
+ dag,
183
+ checkoutRoot,
184
+ workspaceDir,
185
+ existingHandle: opened.handle,
186
+ workerMode: true,
187
+ roots,
188
+ attemptCtx,
189
+ factoryCwd: input.rootDir,
190
+ operatorCatalog: input.operatorCatalog,
191
+ skipGates: input.skipGates,
192
+ stageEnv,
193
+ beforeVerify,
194
+ });
154
195
  }
155
196
  return runStage({
156
197
  agent,
@@ -162,7 +203,6 @@ export async function runStageWorker(input) {
162
203
  dag,
163
204
  checkoutRoot,
164
205
  workspaceDir,
165
- existingHandle: opened.handle,
166
206
  workerMode: true,
167
207
  roots,
168
208
  attemptCtx,
@@ -170,30 +210,23 @@ export async function runStageWorker(input) {
170
210
  operatorCatalog: input.operatorCatalog,
171
211
  skipGates: input.skipGates,
172
212
  stageEnv,
213
+ beforeVerify,
173
214
  });
174
- }
175
- return runStage({
176
- agent,
177
- store,
178
- runId: input.runId,
179
- stage,
180
- stageId: input.stageId,
181
- task,
182
- dag,
183
- checkoutRoot,
184
- workspaceDir,
185
- workerMode: true,
186
- roots,
187
- attemptCtx,
188
- factoryCwd: input.rootDir,
189
- operatorCatalog: input.operatorCatalog,
190
- skipGates: input.skipGates,
191
- stageEnv,
192
- });
215
+ })();
216
+ }
217
+ catch (err) {
218
+ thrown = err;
193
219
  }
194
220
  finally {
195
221
  unbindAgentDir();
222
+ await sandbox.close();
223
+ }
224
+ if (thrown !== undefined)
225
+ throw thrown;
226
+ if (outcome === undefined) {
227
+ throw new Error("stage worker finished without an outcome");
196
228
  }
229
+ return outcome;
197
230
  }
198
231
  export function sendWorkerResult(result) {
199
232
  if (typeof process.send !== "function") {
@@ -1,4 +1,5 @@
1
1
  import { type LoadOutcome } from "../config/loadOutcome.js";
2
+ import type { CheckoutDescriptor } from "../types/task.js";
2
3
  export type WorkspaceBinding = {
3
4
  kind: "repository";
4
5
  repository: string;
@@ -12,7 +13,7 @@ export type WorkspaceBinding = {
12
13
  export type WorkspaceBindingInput = {
13
14
  repository?: string;
14
15
  ref?: string;
15
- checkout?: string;
16
+ checkout?: CheckoutDescriptor;
16
17
  };
17
18
  export type ResolveWorkspaceBindingOptions = {
18
19
  checkoutOverride?: string;
@@ -9,12 +9,25 @@ function nonEmptyTrimmed(value) {
9
9
  function isGithubOwnerRepo(repository) {
10
10
  return OWNER_REPO_RE.test(repository);
11
11
  }
12
+ function resolveCheckoutBinding(checkout, checkoutOverride) {
13
+ const override = nonEmptyTrimmed(checkoutOverride);
14
+ if (override !== undefined)
15
+ return override;
16
+ if (checkout === undefined)
17
+ return undefined;
18
+ if (typeof checkout === "string")
19
+ return nonEmptyTrimmed(checkout);
20
+ if (typeof checkout === "object" && checkout !== null && !Array.isArray(checkout)) {
21
+ return checkout;
22
+ }
23
+ return undefined;
24
+ }
12
25
  export function resolveWorkspaceBinding(task, options) {
13
26
  const repository = nonEmptyTrimmed(task.repository);
14
27
  const ref = nonEmptyTrimmed(task.ref);
15
- const checkoutPath = nonEmptyTrimmed(options?.checkoutOverride ?? task.checkout);
28
+ const checkoutBinding = resolveCheckoutBinding(task.checkout, options?.checkoutOverride);
16
29
  const hasRepositoryField = repository !== undefined;
17
- if (hasRepositoryField && checkoutPath !== undefined) {
30
+ if (hasRepositoryField && checkoutBinding !== undefined) {
18
31
  return loadFailure([
19
32
  {
20
33
  code: "task.binding_conflict",
@@ -53,8 +66,11 @@ export function resolveWorkspaceBinding(task, options) {
53
66
  }
54
67
  return loadSuccess({ kind: "repository", repository, ref });
55
68
  }
56
- if (checkoutPath !== undefined) {
57
- return loadSuccess({ kind: "checkout", path: checkoutPath });
69
+ if (typeof checkoutBinding === "string") {
70
+ return loadSuccess({ kind: "checkout", path: checkoutBinding });
71
+ }
72
+ if (typeof checkoutBinding === "object") {
73
+ return loadSuccess({ kind: "checkout", path: "" });
58
74
  }
59
75
  return loadSuccess({ kind: "unbound" });
60
76
  }
@@ -0,0 +1,5 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { OperatorAgentHost } from "../operatorAgent/index.js";
3
+ type Json = (res: ServerResponse, status: number, body: unknown) => void;
4
+ export declare function handleAgentAuthorRoutes(req: IncomingMessage, method: string, pathname: string, projectRoot: string, host: OperatorAgentHost, res: ServerResponse, json: Json): Promise<boolean>;
5
+ export {};
@@ -0,0 +1,64 @@
1
+ import { parseAgentAuthorDraft, runAgentAuthorTurn, undoAgentAuthorTurn } from "../agents/authorChat.js";
2
+ async function readBody(req) {
3
+ const chunks = [];
4
+ let size = 0;
5
+ for await (const chunk of req) {
6
+ const buffer = typeof chunk === "string" ? Buffer.from(chunk) : chunk;
7
+ size += buffer.length;
8
+ if (size > 65536)
9
+ return { __tooLarge: true };
10
+ chunks.push(buffer);
11
+ }
12
+ if (chunks.length === 0)
13
+ return {};
14
+ try {
15
+ const parsed = JSON.parse(Buffer.concat(chunks).toString("utf8"));
16
+ return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
17
+ ? parsed
18
+ : { __invalid: true };
19
+ }
20
+ catch {
21
+ return { __invalid: true };
22
+ }
23
+ }
24
+ export async function handleAgentAuthorRoutes(req, method, pathname, projectRoot, host, res, json) {
25
+ const chat = pathname === "/api/agent-author/chat";
26
+ const undo = pathname === "/api/agent-author/undo";
27
+ if (!chat && !undo)
28
+ return false;
29
+ if (method !== "POST") {
30
+ json(res, 405, { code: "agent.invalid" });
31
+ return true;
32
+ }
33
+ const body = await readBody(req);
34
+ if (body.__tooLarge || body.__invalid) {
35
+ json(res, 400, { code: "agent.invalid" });
36
+ return true;
37
+ }
38
+ try {
39
+ if (undo) {
40
+ const sessionId = typeof body.sessionId === "string" ? body.sessionId.trim() : "";
41
+ if (!sessionId) {
42
+ json(res, 400, { code: "agent.invalid" });
43
+ return true;
44
+ }
45
+ json(res, 200, { draft: undoAgentAuthorTurn(sessionId) });
46
+ return true;
47
+ }
48
+ const message = typeof body.message === "string" ? body.message : "";
49
+ const result = await runAgentAuthorTurn({
50
+ host,
51
+ projectRoot,
52
+ message,
53
+ ...(typeof body.sessionId === "string" ? { sessionId: body.sessionId } : {}),
54
+ draft: parseAgentAuthorDraft(body.draft),
55
+ });
56
+ json(res, 200, result);
57
+ }
58
+ catch (err) {
59
+ const code = err instanceof Error ? err.message : "agent.internal";
60
+ const status = code === "agent.session_not_found" ? 404 : code === "agent.conflict" ? 409 : 400;
61
+ json(res, status, { code: code.startsWith("agent.") ? code : "agent.internal" });
62
+ }
63
+ return true;
64
+ }
@@ -0,0 +1,5 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { AgentHostContext } from "../agents/hostContext.js";
3
+ type Json = (res: ServerResponse, status: number, body: unknown) => void;
4
+ export declare function handleAgentRoutes(req: IncomingMessage, method: string, pathname: string, host: AgentHostContext, projectRoot: string, res: ServerResponse, json: Json): Promise<boolean>;
5
+ export {};