@kontourai/flow-agents 3.11.0 → 3.12.1

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 (254) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/build/src/builder-flow-run-adapter.d.ts +1 -0
  3. package/build/src/builder-flow-run-adapter.js +2 -0
  4. package/build/src/builder-flow-runtime.d.ts +5 -0
  5. package/build/src/builder-flow-runtime.js +90 -68
  6. package/build/src/builder-gate-action-envelope.d.ts +152 -0
  7. package/build/src/builder-gate-action-envelope.js +368 -0
  8. package/build/src/cli/public-contracts.d.ts +139 -0
  9. package/build/src/cli/public-contracts.js +37 -0
  10. package/build/src/cli/workflow-sidecar.js +9 -13
  11. package/build/src/cli/workflow.d.ts +1 -0
  12. package/build/src/cli/workflow.js +49 -12
  13. package/build/src/continuation-driver.d.ts +40 -3
  14. package/build/src/continuation-driver.js +361 -412
  15. package/build/src/continuation-persistence.d.ts +4 -0
  16. package/build/src/continuation-persistence.js +296 -0
  17. package/build/src/continuation-validation.d.ts +9 -0
  18. package/build/src/continuation-validation.js +169 -0
  19. package/build/src/flow-kit/action-metadata.d.ts +28 -0
  20. package/build/src/flow-kit/action-metadata.js +162 -0
  21. package/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  22. package/build/src/flow-kit/action-repository-validation.js +237 -0
  23. package/build/src/flow-kit/validate.d.ts +2 -14
  24. package/build/src/flow-kit/validate.js +18 -345
  25. package/build/src/index.d.ts +4 -2
  26. package/build/src/index.js +2 -1
  27. package/dist/base/build/package.json +1 -1
  28. package/dist/base/build/src/builder-flow-run-adapter.d.ts +1 -0
  29. package/dist/base/build/src/builder-flow-run-adapter.js +2 -0
  30. package/dist/base/build/src/builder-flow-runtime.d.ts +5 -0
  31. package/dist/base/build/src/builder-flow-runtime.js +90 -68
  32. package/dist/base/build/src/builder-gate-action-envelope.d.ts +152 -0
  33. package/dist/base/build/src/builder-gate-action-envelope.js +368 -0
  34. package/dist/base/build/src/cli/public-contracts.d.ts +139 -0
  35. package/dist/base/build/src/cli/public-contracts.js +37 -0
  36. package/dist/base/build/src/cli/workflow-sidecar.js +9 -13
  37. package/dist/base/build/src/cli/workflow.d.ts +1 -0
  38. package/dist/base/build/src/cli/workflow.js +49 -12
  39. package/dist/base/build/src/continuation-driver.d.ts +40 -3
  40. package/dist/base/build/src/continuation-driver.js +361 -412
  41. package/dist/base/build/src/continuation-persistence.d.ts +4 -0
  42. package/dist/base/build/src/continuation-persistence.js +296 -0
  43. package/dist/base/build/src/continuation-validation.d.ts +9 -0
  44. package/dist/base/build/src/continuation-validation.js +169 -0
  45. package/dist/base/build/src/flow-kit/action-metadata.d.ts +28 -0
  46. package/dist/base/build/src/flow-kit/action-metadata.js +162 -0
  47. package/dist/base/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  48. package/dist/base/build/src/flow-kit/action-repository-validation.js +237 -0
  49. package/dist/base/build/src/flow-kit/validate.d.ts +2 -14
  50. package/dist/base/build/src/flow-kit/validate.js +18 -345
  51. package/dist/base/build/src/index.d.ts +4 -2
  52. package/dist/base/build/src/index.js +2 -1
  53. package/dist/base/docs/migrations.md +5 -0
  54. package/dist/base/docs/public-workflow-cli.md +41 -5
  55. package/dist/base/docs/spec/builder-flow-runtime.md +117 -0
  56. package/dist/base/evals/integration/test_builder_step_producers.sh +60 -21
  57. package/dist/base/evals/integration/test_bundle_install.sh +15 -15
  58. package/dist/base/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  59. package/dist/base/install.sh +1 -1
  60. package/dist/base/kits/builder/kit.json +88 -14
  61. package/dist/claude-code/build/package.json +1 -1
  62. package/dist/claude-code/build/src/builder-flow-run-adapter.d.ts +1 -0
  63. package/dist/claude-code/build/src/builder-flow-run-adapter.js +2 -0
  64. package/dist/claude-code/build/src/builder-flow-runtime.d.ts +5 -0
  65. package/dist/claude-code/build/src/builder-flow-runtime.js +90 -68
  66. package/dist/claude-code/build/src/builder-gate-action-envelope.d.ts +152 -0
  67. package/dist/claude-code/build/src/builder-gate-action-envelope.js +368 -0
  68. package/dist/claude-code/build/src/cli/public-contracts.d.ts +139 -0
  69. package/dist/claude-code/build/src/cli/public-contracts.js +37 -0
  70. package/dist/claude-code/build/src/cli/workflow-sidecar.js +9 -13
  71. package/dist/claude-code/build/src/cli/workflow.d.ts +1 -0
  72. package/dist/claude-code/build/src/cli/workflow.js +49 -12
  73. package/dist/claude-code/build/src/continuation-driver.d.ts +40 -3
  74. package/dist/claude-code/build/src/continuation-driver.js +361 -412
  75. package/dist/claude-code/build/src/continuation-persistence.d.ts +4 -0
  76. package/dist/claude-code/build/src/continuation-persistence.js +296 -0
  77. package/dist/claude-code/build/src/continuation-validation.d.ts +9 -0
  78. package/dist/claude-code/build/src/continuation-validation.js +169 -0
  79. package/dist/claude-code/build/src/flow-kit/action-metadata.d.ts +28 -0
  80. package/dist/claude-code/build/src/flow-kit/action-metadata.js +162 -0
  81. package/dist/claude-code/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  82. package/dist/claude-code/build/src/flow-kit/action-repository-validation.js +237 -0
  83. package/dist/claude-code/build/src/flow-kit/validate.d.ts +2 -14
  84. package/dist/claude-code/build/src/flow-kit/validate.js +18 -345
  85. package/dist/claude-code/build/src/index.d.ts +4 -2
  86. package/dist/claude-code/build/src/index.js +2 -1
  87. package/dist/claude-code/docs/migrations.md +5 -0
  88. package/dist/claude-code/docs/public-workflow-cli.md +41 -5
  89. package/dist/claude-code/docs/spec/builder-flow-runtime.md +117 -0
  90. package/dist/claude-code/evals/integration/test_builder_step_producers.sh +60 -21
  91. package/dist/claude-code/evals/integration/test_bundle_install.sh +15 -15
  92. package/dist/claude-code/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  93. package/dist/claude-code/install.sh +1 -1
  94. package/dist/claude-code/kits/builder/kit.json +88 -14
  95. package/dist/codex/build/package.json +1 -1
  96. package/dist/codex/build/src/builder-flow-run-adapter.d.ts +1 -0
  97. package/dist/codex/build/src/builder-flow-run-adapter.js +2 -0
  98. package/dist/codex/build/src/builder-flow-runtime.d.ts +5 -0
  99. package/dist/codex/build/src/builder-flow-runtime.js +90 -68
  100. package/dist/codex/build/src/builder-gate-action-envelope.d.ts +152 -0
  101. package/dist/codex/build/src/builder-gate-action-envelope.js +368 -0
  102. package/dist/codex/build/src/cli/public-contracts.d.ts +139 -0
  103. package/dist/codex/build/src/cli/public-contracts.js +37 -0
  104. package/dist/codex/build/src/cli/workflow-sidecar.js +9 -13
  105. package/dist/codex/build/src/cli/workflow.d.ts +1 -0
  106. package/dist/codex/build/src/cli/workflow.js +49 -12
  107. package/dist/codex/build/src/continuation-driver.d.ts +40 -3
  108. package/dist/codex/build/src/continuation-driver.js +361 -412
  109. package/dist/codex/build/src/continuation-persistence.d.ts +4 -0
  110. package/dist/codex/build/src/continuation-persistence.js +296 -0
  111. package/dist/codex/build/src/continuation-validation.d.ts +9 -0
  112. package/dist/codex/build/src/continuation-validation.js +169 -0
  113. package/dist/codex/build/src/flow-kit/action-metadata.d.ts +28 -0
  114. package/dist/codex/build/src/flow-kit/action-metadata.js +162 -0
  115. package/dist/codex/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  116. package/dist/codex/build/src/flow-kit/action-repository-validation.js +237 -0
  117. package/dist/codex/build/src/flow-kit/validate.d.ts +2 -14
  118. package/dist/codex/build/src/flow-kit/validate.js +18 -345
  119. package/dist/codex/build/src/index.d.ts +4 -2
  120. package/dist/codex/build/src/index.js +2 -1
  121. package/dist/codex/docs/migrations.md +5 -0
  122. package/dist/codex/docs/public-workflow-cli.md +41 -5
  123. package/dist/codex/docs/spec/builder-flow-runtime.md +117 -0
  124. package/dist/codex/evals/integration/test_builder_step_producers.sh +60 -21
  125. package/dist/codex/evals/integration/test_bundle_install.sh +15 -15
  126. package/dist/codex/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  127. package/dist/codex/install.sh +1 -1
  128. package/dist/codex/kits/builder/kit.json +88 -14
  129. package/dist/kiro/build/package.json +1 -1
  130. package/dist/kiro/build/src/builder-flow-run-adapter.d.ts +1 -0
  131. package/dist/kiro/build/src/builder-flow-run-adapter.js +2 -0
  132. package/dist/kiro/build/src/builder-flow-runtime.d.ts +5 -0
  133. package/dist/kiro/build/src/builder-flow-runtime.js +90 -68
  134. package/dist/kiro/build/src/builder-gate-action-envelope.d.ts +152 -0
  135. package/dist/kiro/build/src/builder-gate-action-envelope.js +368 -0
  136. package/dist/kiro/build/src/cli/public-contracts.d.ts +139 -0
  137. package/dist/kiro/build/src/cli/public-contracts.js +37 -0
  138. package/dist/kiro/build/src/cli/workflow-sidecar.js +9 -13
  139. package/dist/kiro/build/src/cli/workflow.d.ts +1 -0
  140. package/dist/kiro/build/src/cli/workflow.js +49 -12
  141. package/dist/kiro/build/src/continuation-driver.d.ts +40 -3
  142. package/dist/kiro/build/src/continuation-driver.js +361 -412
  143. package/dist/kiro/build/src/continuation-persistence.d.ts +4 -0
  144. package/dist/kiro/build/src/continuation-persistence.js +296 -0
  145. package/dist/kiro/build/src/continuation-validation.d.ts +9 -0
  146. package/dist/kiro/build/src/continuation-validation.js +169 -0
  147. package/dist/kiro/build/src/flow-kit/action-metadata.d.ts +28 -0
  148. package/dist/kiro/build/src/flow-kit/action-metadata.js +162 -0
  149. package/dist/kiro/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  150. package/dist/kiro/build/src/flow-kit/action-repository-validation.js +237 -0
  151. package/dist/kiro/build/src/flow-kit/validate.d.ts +2 -14
  152. package/dist/kiro/build/src/flow-kit/validate.js +18 -345
  153. package/dist/kiro/build/src/index.d.ts +4 -2
  154. package/dist/kiro/build/src/index.js +2 -1
  155. package/dist/kiro/docs/migrations.md +5 -0
  156. package/dist/kiro/docs/public-workflow-cli.md +41 -5
  157. package/dist/kiro/docs/spec/builder-flow-runtime.md +117 -0
  158. package/dist/kiro/evals/integration/test_builder_step_producers.sh +60 -21
  159. package/dist/kiro/evals/integration/test_bundle_install.sh +15 -15
  160. package/dist/kiro/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  161. package/dist/kiro/install.sh +1 -1
  162. package/dist/kiro/kits/builder/kit.json +88 -14
  163. package/dist/opencode/build/package.json +1 -1
  164. package/dist/opencode/build/src/builder-flow-run-adapter.d.ts +1 -0
  165. package/dist/opencode/build/src/builder-flow-run-adapter.js +2 -0
  166. package/dist/opencode/build/src/builder-flow-runtime.d.ts +5 -0
  167. package/dist/opencode/build/src/builder-flow-runtime.js +90 -68
  168. package/dist/opencode/build/src/builder-gate-action-envelope.d.ts +152 -0
  169. package/dist/opencode/build/src/builder-gate-action-envelope.js +368 -0
  170. package/dist/opencode/build/src/cli/public-contracts.d.ts +139 -0
  171. package/dist/opencode/build/src/cli/public-contracts.js +37 -0
  172. package/dist/opencode/build/src/cli/workflow-sidecar.js +9 -13
  173. package/dist/opencode/build/src/cli/workflow.d.ts +1 -0
  174. package/dist/opencode/build/src/cli/workflow.js +49 -12
  175. package/dist/opencode/build/src/continuation-driver.d.ts +40 -3
  176. package/dist/opencode/build/src/continuation-driver.js +361 -412
  177. package/dist/opencode/build/src/continuation-persistence.d.ts +4 -0
  178. package/dist/opencode/build/src/continuation-persistence.js +296 -0
  179. package/dist/opencode/build/src/continuation-validation.d.ts +9 -0
  180. package/dist/opencode/build/src/continuation-validation.js +169 -0
  181. package/dist/opencode/build/src/flow-kit/action-metadata.d.ts +28 -0
  182. package/dist/opencode/build/src/flow-kit/action-metadata.js +162 -0
  183. package/dist/opencode/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  184. package/dist/opencode/build/src/flow-kit/action-repository-validation.js +237 -0
  185. package/dist/opencode/build/src/flow-kit/validate.d.ts +2 -14
  186. package/dist/opencode/build/src/flow-kit/validate.js +18 -345
  187. package/dist/opencode/build/src/index.d.ts +4 -2
  188. package/dist/opencode/build/src/index.js +2 -1
  189. package/dist/opencode/docs/migrations.md +5 -0
  190. package/dist/opencode/docs/public-workflow-cli.md +41 -5
  191. package/dist/opencode/docs/spec/builder-flow-runtime.md +117 -0
  192. package/dist/opencode/evals/integration/test_builder_step_producers.sh +60 -21
  193. package/dist/opencode/evals/integration/test_bundle_install.sh +15 -15
  194. package/dist/opencode/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  195. package/dist/opencode/install.sh +1 -1
  196. package/dist/opencode/kits/builder/kit.json +88 -14
  197. package/dist/pi/build/package.json +1 -1
  198. package/dist/pi/build/src/builder-flow-run-adapter.d.ts +1 -0
  199. package/dist/pi/build/src/builder-flow-run-adapter.js +2 -0
  200. package/dist/pi/build/src/builder-flow-runtime.d.ts +5 -0
  201. package/dist/pi/build/src/builder-flow-runtime.js +90 -68
  202. package/dist/pi/build/src/builder-gate-action-envelope.d.ts +152 -0
  203. package/dist/pi/build/src/builder-gate-action-envelope.js +368 -0
  204. package/dist/pi/build/src/cli/public-contracts.d.ts +139 -0
  205. package/dist/pi/build/src/cli/public-contracts.js +37 -0
  206. package/dist/pi/build/src/cli/workflow-sidecar.js +9 -13
  207. package/dist/pi/build/src/cli/workflow.d.ts +1 -0
  208. package/dist/pi/build/src/cli/workflow.js +49 -12
  209. package/dist/pi/build/src/continuation-driver.d.ts +40 -3
  210. package/dist/pi/build/src/continuation-driver.js +361 -412
  211. package/dist/pi/build/src/continuation-persistence.d.ts +4 -0
  212. package/dist/pi/build/src/continuation-persistence.js +296 -0
  213. package/dist/pi/build/src/continuation-validation.d.ts +9 -0
  214. package/dist/pi/build/src/continuation-validation.js +169 -0
  215. package/dist/pi/build/src/flow-kit/action-metadata.d.ts +28 -0
  216. package/dist/pi/build/src/flow-kit/action-metadata.js +162 -0
  217. package/dist/pi/build/src/flow-kit/action-repository-validation.d.ts +16 -0
  218. package/dist/pi/build/src/flow-kit/action-repository-validation.js +237 -0
  219. package/dist/pi/build/src/flow-kit/validate.d.ts +2 -14
  220. package/dist/pi/build/src/flow-kit/validate.js +18 -345
  221. package/dist/pi/build/src/index.d.ts +4 -2
  222. package/dist/pi/build/src/index.js +2 -1
  223. package/dist/pi/docs/migrations.md +5 -0
  224. package/dist/pi/docs/public-workflow-cli.md +41 -5
  225. package/dist/pi/docs/spec/builder-flow-runtime.md +117 -0
  226. package/dist/pi/evals/integration/test_builder_step_producers.sh +60 -21
  227. package/dist/pi/evals/integration/test_bundle_install.sh +15 -15
  228. package/dist/pi/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  229. package/dist/pi/install.sh +1 -1
  230. package/dist/pi/kits/builder/kit.json +88 -14
  231. package/docs/migrations.md +5 -0
  232. package/docs/public-workflow-cli.md +41 -5
  233. package/docs/spec/builder-flow-runtime.md +117 -0
  234. package/evals/integration/test_builder_step_producers.sh +60 -21
  235. package/evals/integration/test_bundle_install.sh +15 -15
  236. package/evals/integration/test_phase_map_and_gate_claim.sh +9 -22
  237. package/kits/builder/kit.json +88 -14
  238. package/package.json +1 -1
  239. package/src/builder-flow-run-adapter.ts +3 -0
  240. package/src/builder-flow-runtime.ts +73 -46
  241. package/src/builder-gate-action-envelope.ts +531 -0
  242. package/src/cli/builder-flow-runtime.test.mjs +289 -58
  243. package/src/cli/continuation-driver.test.mjs +542 -24
  244. package/src/cli/kit-metadata-security.test.mjs +161 -8
  245. package/src/cli/public-contracts.ts +41 -0
  246. package/src/cli/workflow-sidecar.ts +9 -13
  247. package/src/cli/workflow.ts +48 -12
  248. package/src/continuation-driver.ts +466 -378
  249. package/src/continuation-persistence.ts +228 -0
  250. package/src/continuation-validation.ts +137 -0
  251. package/src/flow-kit/action-metadata.ts +155 -0
  252. package/src/flow-kit/action-repository-validation.ts +192 -0
  253. package/src/flow-kit/validate.ts +19 -326
  254. package/src/index.ts +17 -0
@@ -2,11 +2,12 @@ import * as fs from "node:fs";
2
2
  import { execFileSync } from "node:child_process";
3
3
  import { createHash, randomBytes } from "node:crypto";
4
4
  import * as path from "node:path";
5
- import { fileURLToPath } from "node:url";
6
5
  import { isDeepStrictEqual } from "node:util";
7
6
  import { flowAgentsPackageVersion } from "./lib/package-version.js";
8
7
  import { pinnedFlowAgentsCommand } from "./lib/pinned-cli-command.js";
8
+ import { deriveBuilderGateActionEnvelope, deriveBuilderGateActionProgressSnapshot, type GateActionEnvelope, type GateActionProgressSnapshot } from "./builder-gate-action-envelope.js";
9
9
  import {
10
+ evaluateGate,
10
11
  expectationsForGate,
11
12
  lifecycleRequestMatches,
12
13
  openGates,
@@ -50,6 +51,10 @@ export interface BuilderFlowSessionResult {
50
51
  projectRoot: string;
51
52
  run: BuilderFlowRunResult;
52
53
  projection: AnyRecord;
54
+ /** Ephemeral adapter context; deliberately excluded from durable state.json projection. */
55
+ gateActionEnvelope: GateActionEnvelope | null;
56
+ /** Canonical progress observation, retained even when terminal runs emit no action envelope. */
57
+ progressSnapshot: GateActionProgressSnapshot;
53
58
  attached: boolean;
54
59
  }
55
60
 
@@ -137,13 +142,15 @@ export async function recoverBuilderFlowSession(input: BuilderFlowSessionInput):
137
142
  runId: context.slug,
138
143
  });
139
144
  assertRunSubjectBinding(run, subject);
140
- const projection = projectFlowRun(context, run, sidecarSnapshot.state);
145
+ const { projection, gateActionEnvelope, progressSnapshot } = projectFlowRun(context, run, sidecarSnapshot.state);
141
146
  writeProjection(context, projection, sidecarSnapshot.raw, "recovery");
142
147
  return {
143
148
  sessionDir: context.sessionDir,
144
149
  projectRoot: context.projectRoot,
145
150
  run,
146
151
  projection,
152
+ gateActionEnvelope,
153
+ progressSnapshot,
147
154
  attached: false,
148
155
  };
149
156
  }
@@ -154,11 +161,14 @@ export async function inspectBuilderFlowSession(input: BuilderFlowSessionInput):
154
161
  const subject = workflowSubject(sidecarSnapshot.state);
155
162
  const run = await loadBuilderFlowRun({ cwd: context.projectRoot, runId: context.slug });
156
163
  assertRunSubjectBinding(run, subject);
164
+ const { projection, gateActionEnvelope, progressSnapshot } = projectFlowRun(context, run, sidecarSnapshot.state);
157
165
  return {
158
166
  sessionDir: context.sessionDir,
159
167
  projectRoot: context.projectRoot,
160
168
  run,
161
- projection: projectFlowRun(context, run, sidecarSnapshot.state),
169
+ projection,
170
+ gateActionEnvelope,
171
+ progressSnapshot,
162
172
  attached: false,
163
173
  };
164
174
  }
@@ -182,10 +192,10 @@ export async function cancelBuilderFlowSession(input: BuilderFlowAuthorizedLifec
182
192
  reason: `canonical Flow run canceled by ${prepared.authorization.request.authority.request_ref}`,
183
193
  tolerateNoActiveClaim: true,
184
194
  });
185
- const projection = projectFlowRun(prepared.context, changed, prepared.sidecarSnapshot.state);
195
+ const { projection, gateActionEnvelope, progressSnapshot } = projectFlowRun(prepared.context, changed, prepared.sidecarSnapshot.state);
186
196
  writeProjection(prepared.context, projection, prepared.sidecarSnapshot.raw, "cancellation projection");
187
197
  recordAuthorizationConsumed(prepared.context.artifactRoot, prepared.authorization);
188
- return { sessionDir: prepared.context.sessionDir, projectRoot: prepared.context.projectRoot, run: changed, projection, attached: false, assignmentReleased: released !== null, idempotent: changed.idempotent };
198
+ return { sessionDir: prepared.context.sessionDir, projectRoot: prepared.context.projectRoot, run: changed, projection, gateActionEnvelope, progressSnapshot, attached: false, assignmentReleased: released !== null, idempotent: changed.idempotent };
189
199
  });
190
200
  }
191
201
 
@@ -195,7 +205,8 @@ export async function releaseBuilderFlowAssignment(input: BuilderFlowAgentLifecy
195
205
  const prepared = prepareAgentLifecycleChange(input, context);
196
206
  const run = await loadBuilderFlowRun({ cwd: context.projectRoot, runId: context.slug });
197
207
  const released = performLocalReleaseUnderLock(context.artifactRoot, context.slug, prepared.actor, { actorKey: prepared.actorKey, reason: input.reason });
198
- return { sessionDir: context.sessionDir, projectRoot: context.projectRoot, run, projection: prepared.sidecarSnapshot.state, attached: false, assignmentReleased: released !== null };
208
+ const { progressSnapshot } = projectFlowRun(context, run, prepared.sidecarSnapshot.state);
209
+ return { sessionDir: context.sessionDir, projectRoot: context.projectRoot, run, projection: prepared.sidecarSnapshot.state, gateActionEnvelope: null, progressSnapshot, attached: false, assignmentReleased: released !== null };
199
210
  });
200
211
  }
201
212
 
@@ -231,12 +242,15 @@ export async function archiveBuilderFlowSession(input: BuilderFlowAuthorizedLife
231
242
  clearCurrentPointers(prepared.context.artifactRoot, prepared.context.slug);
232
243
  recordAuthorizationConsumed(prepared.context.artifactRoot, prepared.authorization);
233
244
  }
245
+ const { progressSnapshot } = projectFlowRun(prepared.context, run, prepared.sidecarSnapshot.state);
234
246
  fs.renameSync(prepared.context.sessionDir, archiveDir);
235
247
  return {
236
248
  sessionDir: archiveDir,
237
249
  projectRoot: prepared.context.projectRoot,
238
250
  run,
239
251
  projection: archivedState,
252
+ gateActionEnvelope: null,
253
+ progressSnapshot,
240
254
  attached: false,
241
255
  archiveDir,
242
256
  };
@@ -257,13 +271,15 @@ async function changeBuilderFlowSessionLifecycle(
257
271
  runId: context.slug,
258
272
  request: { reason: input.reason, authority: { kind: "operator_request", actor: prepared.actorKey, request_ref: `flow-agents://assignment/${context.slug}/${operation}/${at}`, requested_at: at } },
259
273
  });
260
- const projection = projectFlowRun(context, run, prepared.sidecarSnapshot.state);
274
+ const { projection, gateActionEnvelope, progressSnapshot } = projectFlowRun(context, run, prepared.sidecarSnapshot.state);
261
275
  writeProjection(context, projection, prepared.sidecarSnapshot.raw, `${operation} projection`);
262
276
  return {
263
277
  sessionDir: context.sessionDir,
264
278
  projectRoot: context.projectRoot,
265
279
  run,
266
280
  projection,
281
+ gateActionEnvelope,
282
+ progressSnapshot,
267
283
  attached: false,
268
284
  };
269
285
  });
@@ -374,6 +390,7 @@ async function syncAndProject(
374
390
  run.state.subject,
375
391
  context.projectRoot,
376
392
  manifestEvidence(run.manifest),
393
+ run.config,
377
394
  );
378
395
  if (gateEvidence) {
379
396
  const alreadyAttached = manifestEvidence(run.manifest).some((entry) =>
@@ -407,17 +424,30 @@ async function syncAndProject(
407
424
  removeTrustBundleSnapshot(snapshot);
408
425
  }
409
426
  }
410
- const projection = projectFlowRun(context, run, sidecarSnapshot.state);
427
+ if (!attached && gates.length === 1 && gateCanPassWithoutNewEvidence(run, gates[0]!)) {
428
+ run = await evaluateBuilderFlowRun({ cwd: context.projectRoot, runId: context.slug });
429
+ }
430
+ const { projection, gateActionEnvelope, progressSnapshot } = projectFlowRun(context, run, sidecarSnapshot.state);
411
431
  writeProjection(context, projection, sidecarSnapshot.raw, "projection");
412
432
  return {
413
433
  sessionDir: context.sessionDir,
414
434
  projectRoot: context.projectRoot,
415
435
  run,
416
436
  projection,
437
+ gateActionEnvelope,
438
+ progressSnapshot,
417
439
  attached,
418
440
  };
419
441
  }
420
442
 
443
+ function gateCanPassWithoutNewEvidence(run: BuilderFlowRunResult, gate: FlowGate & { id: string }): boolean {
444
+ const definition = JSON.parse(fs.readFileSync(path.join(run.dir, "definition.json"), "utf8"));
445
+ const expectations = expectationsForGate(gate, run.config) as FlowExpectation[];
446
+ const outcome = evaluateGate(definition, run.state, run.manifest, gate.id, run.config);
447
+ return outcome.status === "pass"
448
+ && (typeof outcome.accepted_exception_id === "string" || expectations.every((expectation) => !expectation.required));
449
+ }
450
+
421
451
  function assertRunSubjectBinding(run: BuilderFlowRunResult, subject: string): void {
422
452
  if (run.state.subject !== subject) {
423
453
  throw new BuilderBuildRunInputError("flow_run.state.subject", "must match the selected Work Item");
@@ -497,9 +527,10 @@ async function bundleGateEvidence(
497
527
  subject: string,
498
528
  projectRoot: string,
499
529
  manifest: AnyRecord[],
530
+ config: JsonObject,
500
531
  ): Promise<{ failed: boolean; routeReason: string | null; expectationIds: string[]; visitEnteredAt: number } | null> {
501
532
  if (!isRecord(bundle) || !Array.isArray(bundle.claims)) return null;
502
- const expectations = expectationsForGate(gate) as FlowExpectation[];
533
+ const expectations = expectationsForGate(gate, config) as FlowExpectation[];
503
534
  const visit = currentGateVisit(state, String((gate as AnyRecord).step));
504
535
  const enteredAt = visit.enteredAt;
505
536
  const synchronizedAt = Date.now();
@@ -855,7 +886,7 @@ function manifestEvidence(manifest: JsonObject): AnyRecord[] {
855
886
  return Array.isArray(manifest.evidence) ? manifest.evidence.filter(isRecord) : [];
856
887
  }
857
888
 
858
- function projectFlowRun(context: SessionContext, run: BuilderFlowRunResult, sidecar: AnyRecord): AnyRecord {
889
+ function projectFlowRun(context: SessionContext, run: BuilderFlowRunResult, sidecar: AnyRecord): { projection: AnyRecord; gateActionEnvelope: GateActionEnvelope | null; progressSnapshot: GateActionProgressSnapshot } {
859
890
  const definition = JSON.parse(fs.readFileSync(path.join(run.dir, "definition.json"), "utf8"));
860
891
  const gates = openGates(definition, run.state) as Array<FlowGate & { id: string }>;
861
892
  const complete = run.state.status === "completed";
@@ -863,17 +894,32 @@ function projectFlowRun(context: SessionContext, run: BuilderFlowRunResult, side
863
894
  const canceled = run.state.status === "canceled";
864
895
  const needsDecision = run.state.status === "needs_decision";
865
896
  const failed = run.state.status === "failed";
866
- const action = complete || paused || canceled || needsDecision || failed ? { skills: [], operations: [] } : stepAction(run.definitionId, run.state.current_step);
867
- if (!action) {
868
- throw new BuilderBuildRunInputError("kit.flow_step_actions", `does not declare Builder step ${run.state.current_step}`);
869
- }
870
- const required = gates.flatMap((gate) => (expectationsForGate(gate) as FlowExpectation[])
897
+ const progressSnapshot = deriveBuilderGateActionProgressSnapshot({
898
+ sessionDir: context.sessionDir,
899
+ projectRoot: context.projectRoot,
900
+ run,
901
+ definition: definition as AnyRecord,
902
+ });
903
+ const envelope = complete || paused || canceled || needsDecision || failed
904
+ ? null
905
+ : deriveBuilderGateActionEnvelope({
906
+ sessionDir: context.sessionDir,
907
+ projectRoot: context.projectRoot,
908
+ run,
909
+ definition: definition as AnyRecord,
910
+ });
911
+ const action = envelope ? {
912
+ skills: envelope.action.skills.map((skill) => skill.id),
913
+ operations: envelope.action.operations,
914
+ } : { skills: [], operations: [] };
915
+ const required = gates.flatMap((gate) => (expectationsForGate(gate, run.config) as FlowExpectation[])
871
916
  .filter((expectation: FlowExpectation) => expectation.required)
872
917
  .map((expectation: FlowExpectation) => `${expectation.id} (${expectation.bundle_claim.claimType}/${expectation.bundle_claim.subjectType ?? "any"})`));
873
- const skills = action?.skills ?? [];
874
- const operations = action?.operations ?? [];
918
+ const skills = action.skills;
919
+ const operations = action.operations;
875
920
  const syncCommand = pinnedFlowAgentsCommand(flowAgentsPackageVersion(), ["workflow", "status", "--session-dir", `.kontourai/flow-agents/${context.slug}`, "--json"]);
876
921
  const routeBack = latestRouteBack(run.state);
922
+ const externalCapability = envelope?.stop_condition.external_capability;
877
923
  const skillText = skills.length ? `Activate ${skills.map((skill) => `\`${skill}\``).join(" then ")}.` : "No Builder skill is required.";
878
924
  const operationText = operations.length ? ` Perform ${operations.map((operation) => `\`${operation}\``).join(" then ")}.` : "";
879
925
  const gateText = gates.length
@@ -892,6 +938,14 @@ function projectFlowRun(context: SessionContext, run: BuilderFlowRunResult, side
892
938
  ? { status: "blocked", summary: "Canonical Flow requires an external decision before continuation." }
893
939
  : failed
894
940
  ? { status: "failed", summary: "Canonical Flow run failed; no continuation turn is allowed." }
941
+ : externalCapability
942
+ ? {
943
+ status: "blocked",
944
+ summary: `Flow step \`${run.state.current_step}\` is waiting for external capability \`${externalCapability.capability}\`. Flow Agents has no authenticated executor and cannot record provider completion.`,
945
+ skills,
946
+ operations,
947
+ external_capability: externalCapability,
948
+ }
895
949
  : {
896
950
  status: "continue",
897
951
  summary: `Flow step \`${run.state.current_step}\`: ${skillText}${operationText} ${gateText}${routeText} Then synchronize the recorded evidence.`,
@@ -900,7 +954,7 @@ function projectFlowRun(context: SessionContext, run: BuilderFlowRunResult, side
900
954
  command: syncCommand,
901
955
  };
902
956
  const phase = phaseForStep(definition.phase_map, run.state.current_step) ?? sidecar.phase;
903
- return {
957
+ return { gateActionEnvelope: envelope, progressSnapshot, projection: {
904
958
  ...sidecar,
905
959
  status: complete ? "delivered" : canceled ? "canceled" : failed ? "failed" : (paused || needsDecision) ? "blocked" : (run.state.transitions.length > 0 ? "in_progress" : sidecar.status),
906
960
  phase: complete || canceled || failed ? "done" : phase,
@@ -917,7 +971,7 @@ function projectFlowRun(context: SessionContext, run: BuilderFlowRunResult, side
917
971
  ...(typeof routeBack?.max_attempts === "number" ? { route_back_max_attempts: routeBack.max_attempts } : {}),
918
972
  },
919
973
  next_action: nextAction,
920
- };
974
+ } };
921
975
  }
922
976
 
923
977
  function writeProjection(context: SessionContext, projection: AnyRecord, expectedStateRaw: string, operation: string): void {
@@ -1081,23 +1135,6 @@ function writeExistingFileNoFollow(file: string, content: string): void {
1081
1135
  }
1082
1136
  }
1083
1137
 
1084
- function stepAction(flowId: BuilderFlowId, stepId: string): { skills: string[]; operations: string[] } | null {
1085
- const manifest = JSON.parse(fs.readFileSync(path.join(packageRoot(), "kits", "builder", "kit.json"), "utf8"));
1086
- const actions = Array.isArray(manifest.flow_step_actions) ? manifest.flow_step_actions : [];
1087
- const action = actions.find((candidate: unknown) =>
1088
- isRecord(candidate)
1089
- && candidate.flow_id === flowId
1090
- && candidate.step_id === stepId
1091
- );
1092
- if (!isRecord(action) || !Array.isArray(action.skills) || !action.skills.every((skill: unknown) => typeof skill === "string")) {
1093
- return null;
1094
- }
1095
- const operations = Array.isArray(action.operations) && action.operations.every((operation: unknown) => typeof operation === "string")
1096
- ? action.operations
1097
- : [];
1098
- return { skills: action.skills, operations };
1099
- }
1100
-
1101
1138
  function phaseForStep(phaseMap: unknown, stepId: string): string | null {
1102
1139
  if (!isRecord(phaseMap)) return stepId === "design-probe" ? "pickup" : null;
1103
1140
  return Object.entries(phaseMap).find(([, step]) => step === stepId)?.[0] ?? (stepId === "design-probe" ? "pickup" : null);
@@ -1108,16 +1145,6 @@ function latestRouteBack(state: FlowRunState): AnyRecord | null {
1108
1145
  return [...outcomes].reverse().find((outcome) => isRecord(outcome) && outcome.status === "route-back") ?? null;
1109
1146
  }
1110
1147
 
1111
- function packageRoot(): string {
1112
- let directory = path.dirname(fileURLToPath(import.meta.url));
1113
- while (!fs.existsSync(path.join(directory, "package.json"))) {
1114
- const parent = path.dirname(directory);
1115
- if (parent === directory) throw new Error("unable to locate Flow Agents package root");
1116
- directory = parent;
1117
- }
1118
- return directory;
1119
- }
1120
-
1121
1148
  function isRunNotFound(error: unknown): boolean {
1122
1149
  return isRecord(error) && (
1123
1150
  error.code === "flow.run_location.not_found"