@tea-agent/loop-agent 0.41.1-beta.0 → 0.42.0-next.2

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 (277) hide show
  1. package/CHANGELOG.md +78 -206
  2. package/dist/adapters/context-transfer/optional-pi-handoff.js +31 -0
  3. package/dist/adapters/context-transfer/pi-session.js +61 -0
  4. package/dist/application/dag/generate-task-dag.js +19 -75
  5. package/dist/application/task-lifecycle/advance.js +5 -24
  6. package/dist/application/task-lifecycle/observe.js +17 -171
  7. package/dist/application/task-lifecycle/plan-transitions.js +7 -42
  8. package/dist/application/task-lifecycle/recommendations.js +2 -13
  9. package/dist/build-stamp.json +3 -3
  10. package/dist/cli/command-definitions.js +12 -7
  11. package/dist/cli/program.js +23 -6
  12. package/dist/commands/client-recovery.js +0 -3
  13. package/dist/commands/dag-artifact.js +284 -0
  14. package/dist/commands/dag-context.js +184 -0
  15. package/dist/commands/dag-rerun.js +206 -1
  16. package/dist/commands/init.js +1 -27
  17. package/dist/commands/task-advance.js +0 -19
  18. package/dist/executors/dag-pi-executor.js +266 -3792
  19. package/dist/executors/pi-executor.js +4 -15
  20. package/dist/executors/pi-sdk-executor.js +3 -0
  21. package/dist/executors/shell-executor.js +217 -945
  22. package/dist/executors/shell-write-guard.js +0 -7
  23. package/dist/{worker → infrastructure}/console/app-data.js +4 -0
  24. package/dist/infrastructure/console/artifact-revision-store.js +430 -0
  25. package/dist/infrastructure/console/context-export-store.js +160 -0
  26. package/dist/infrastructure/console/dir-lock.js +132 -0
  27. package/dist/infrastructure/console/operation-store.js +197 -0
  28. package/dist/infrastructure/harness/artifact-store.js +10 -1
  29. package/dist/infrastructure/harness/atomic-write.js +12 -2
  30. package/dist/shared/context-transfer/artifact-revision.js +172 -0
  31. package/dist/shared/context-transfer.js +418 -0
  32. package/dist/shared/dag-failure-category.js +0 -12
  33. package/dist/shared/openspec-spec.js +4 -70
  34. package/dist/shared/operator/capabilities.js +14 -7
  35. package/dist/shared/operator/safe-run-summary.js +1 -0
  36. package/dist/shared/path-safety.js +93 -0
  37. package/dist/shared/preview.js +28 -4
  38. package/dist/task/config-types.js +80 -35
  39. package/dist/task/contract/adopt.js +0 -4
  40. package/dist/task/contract/import-revision.js +0 -4
  41. package/dist/task/contract/project.js +0 -3
  42. package/dist/task/contract/schema.js +1 -2
  43. package/dist/task/frontend-project-capability.js +20 -203
  44. package/dist/task/runtime.js +2 -5
  45. package/dist/task/source-prepare/build-draft.js +3 -3
  46. package/dist/task/source-prepare/fragment-inventory.js +9 -15
  47. package/dist/task/source-prepare/prepare.js +1 -89
  48. package/dist/task/source-prepare/semantic-intake.js +2 -6
  49. package/dist/task/source-references.js +1 -22
  50. package/dist/task/task-demand-routing.js +3 -0
  51. package/dist/worker/console/chat/chat-event-store.js +2 -2
  52. package/dist/worker/console/chat/pi-runtime.js +3 -2
  53. package/dist/worker/console/chat/resource-preferences-store.js +1 -1
  54. package/dist/worker/console/chat/routes.js +13 -4
  55. package/dist/worker/console/chat/semantic-activity.js +12 -11
  56. package/dist/worker/console/chat/session-stats.js +96 -0
  57. package/dist/worker/console/chat/session-store.js +1 -1
  58. package/dist/worker/console/chat/turn-process.js +28 -4
  59. package/dist/worker/console/chat/user-questions.js +1 -1
  60. package/dist/worker/console/console-update-runtime.js +1 -1
  61. package/dist/worker/console/context-transfer-diagnostics.js +198 -0
  62. package/dist/worker/console/dag-confirmation.js +1 -1
  63. package/dist/worker/console/dag-execution-receipt.js +1 -1
  64. package/dist/worker/console/doctor.js +1 -1
  65. package/dist/worker/console/draft-store.js +1 -1
  66. package/dist/worker/console/human-gate-token.js +1 -1
  67. package/dist/worker/console/index.js +3 -6
  68. package/dist/worker/console/interview/assessment.js +1 -1
  69. package/dist/worker/console/interview/session.js +1 -1
  70. package/dist/worker/console/operation-runner.js +45 -4
  71. package/dist/worker/console/operation-sse.js +1 -1
  72. package/dist/worker/console/operation-wait.js +1 -1
  73. package/dist/worker/console/operator-actions.js +107 -168
  74. package/dist/worker/console/operator-surface-health.js +1 -1
  75. package/dist/worker/console/operator-user-error.js +169 -0
  76. package/dist/worker/console/pi-plugins.js +60 -1
  77. package/dist/worker/console/routes.js +637 -8
  78. package/dist/worker/console/security.js +35 -0
  79. package/dist/worker/console/server.js +6 -6
  80. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-Bho4we4c.js → abnfDiagram-N423BO3Z-DZZ8m3PO.js} +1 -1
  81. package/dist/worker/console/static/assets/{arc-TBDkTeK0.js → arc-D6PvaVd-.js} +1 -1
  82. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-BF_fZrn2.js → architectureDiagram-T3A2C74G-B_OTOiI8.js} +1 -1
  83. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-CCnPgUe2.js → blockDiagram-VBNYF7ZC-Bv6rqHBg.js} +1 -1
  84. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BCYZJLAT.js → c4Diagram-5PPSVZJV-B8eHr0oz.js} +1 -1
  85. package/dist/worker/console/static/assets/channel-BU5gOilw.js +1 -0
  86. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-D8K6adhU.js → chunk-2GRJ4B5K-DYwR0im2.js} +1 -1
  87. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DkT1Q78b.js → chunk-2Q5K7J3B-D2WPGqXt.js} +1 -1
  88. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DuhvpIr7.js → chunk-5RXB4S5H-CQISJ_I7.js} +1 -1
  89. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-BnK6dC49.js → chunk-5VM5RSS4-C0o2Du1e.js} +1 -1
  90. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DPz__z7r.js → chunk-6Q2QTUOP-4f8kr-U7.js} +1 -1
  91. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-0kkppM2j.js → chunk-GF5L2VYU-D_OWvXzX.js} +1 -1
  92. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BB41iK5t.js → chunk-JWPE2WC7-CasdPz5X.js} +1 -1
  93. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-CiVrxKHU.js → chunk-KBJHAD2P-Cj8lRrla.js} +1 -1
  94. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-C2h9Xje1.js → chunk-RYQCIY6F-CUvD1FSd.js} +1 -1
  95. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-3iOSHdbM.js → chunk-XXDRQBXY-CqLw_eqB.js} +1 -1
  96. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DIzKJGHr.js +1 -0
  97. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DIzKJGHr.js +1 -0
  98. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BN3A7tkk.js → cose-bilkent-JH36ORCC-ku-WqJPx.js} +1 -1
  99. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-CTuBy0Or.js → cynefin-VYW2F7L2-Bq_PYDhl.js} +1 -1
  100. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-wb6tUlMN.js → cynefinDiagram-MW4NZA55-BiGZV641.js} +1 -1
  101. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-GP1Ivx8B.js → dagre-VZM6K2ZE-C4JRlglF.js} +1 -1
  102. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-ejrcK6L0.js → diagram-7IWD3JNH-B0dNeWYG.js} +1 -1
  103. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-YFkCCvUU.js → diagram-B4RE2ZJO-Cj35YvYM.js} +1 -1
  104. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-B4rrvIaL.js → diagram-LBJQPF4R-uzQoJ2-8.js} +1 -1
  105. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-C-YIZcUf.js → diagram-Q27KOJAE-D1a-Buoz.js} +1 -1
  106. package/dist/worker/console/static/assets/{diagram-UB23O5K3-BPF5wcL1.js → diagram-UB23O5K3-XjRrLRSs.js} +1 -1
  107. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-CU5SzXjO.js → ebnfDiagram-BXEA7PRR-Da_O24cW.js} +1 -1
  108. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-CpL414DE.js → erDiagram-JOGREHBK-BLJ8jrYU.js} +1 -1
  109. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-MrhLzNau.js → flowDiagram-UKHOOZJN-B9GrLjM0.js} +1 -1
  110. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-Bg4qFuUo.js → ganttDiagram-PKOTCBZU-CeJ0TqiK.js} +1 -1
  111. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-ColxSXLR.js → gitGraphDiagram-DS77QQ5N-Bm2eNNFX.js} +1 -1
  112. package/dist/worker/console/static/assets/index-H9rFJiGL.css +1 -0
  113. package/dist/worker/console/static/assets/index-xwu9GxEc.js +451 -0
  114. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-Czvtm6gc.js → infoDiagram-6WML65LV-DB26i3d8.js} +1 -1
  115. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-B7Xp8HyJ.js → ishikawaDiagram-WSZJBQD7-BOGRyeZT.js} +1 -1
  116. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DWYZcvph.js → journeyDiagram-NVQOT4AX-CZRoBO_6.js} +1 -1
  117. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-KTLZRUjx.js → kanban-definition-27J2QSJJ-qlWhJyoB.js} +1 -1
  118. package/dist/worker/console/static/assets/{linear-_Exn7bfl.js → linear-CfUiDDB3.js} +1 -1
  119. package/dist/worker/console/static/assets/{mermaid.core-Cxg8kX8V.js → mermaid.core-BQe6fpqj.js} +5 -5
  120. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-oKrlo2Bt.js → mindmap-definition-FAOFIHXS-zFzWHw64.js} +1 -1
  121. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-XAeteiNd.js → pegDiagram-VL7TDLO6-DFGUqjZO.js} +1 -1
  122. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-BTf1K-lp.js → pieDiagram-7S7Q4E2Y-BB5i0l8Z.js} +1 -1
  123. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-C0IlY0Jf.js → quadrantDiagram-CIZ2JOQS-obbVZ_X5.js} +1 -1
  124. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-BVbKtZhW.js → railroadDiagram-AXF67PYL-BwdaNzc1.js} +1 -1
  125. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-C5e4JFcr.js → requirementDiagram-LRYGKXZP-CkTJaugh.js} +1 -1
  126. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Cz30hc29.js → sankeyDiagram-W5VNT64P-BwJ-hIgq.js} +1 -1
  127. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-DS33n6d0.js → sequenceDiagram-SI44F4Z6-BzSgmm7w.js} +1 -1
  128. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-46w7v-9T.js → sizeCapture-X5ZJPWSS-Bn3oj5Q1.js} +1 -1
  129. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-pbcD5SsZ.js → stateDiagram-OKZ733FA-dxhGtL8K.js} +1 -1
  130. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Cld2qK9v.js +1 -0
  131. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-DuivYBSj.js → swimlanes-SLNWSIFB-BLpEInya.js} +2 -2
  132. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-TIHpiT7w.js +8 -0
  133. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-Cb9VZVIl.js → timeline-definition-Z64GVDOM-ChJGYcXy.js} +1 -1
  134. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-D2-mfOgR.js → vennDiagram-T6HMQDX7-DK-qjRer.js} +1 -1
  135. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-DeS2aC76.js → wardleyDiagram-T6FBY63Y-3qeaWAg-.js} +1 -1
  136. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-WGsrFjxH.js → xychartDiagram-ELKLHX3M-CootlyP9.js} +1 -1
  137. package/dist/worker/console/static/index.html +7 -2
  138. package/dist/worker/console/static-src/app/useOperatorActions.js +3 -2
  139. package/dist/worker/console/static-src/app/useRunProgress.js +9 -2
  140. package/dist/worker/console/static-src/operator-chat/dag-progress-link.js +22 -0
  141. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +2 -0
  142. package/dist/worker/console/static-src/operator-chat/useChatThread.js +6 -0
  143. package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +28 -3
  144. package/dist/worker/console/static-src/pages/tasks/run-panel-progress.js +106 -0
  145. package/dist/worker/console/static-src/shell/console-update-reload.js +25 -0
  146. package/dist/worker/console/workspace-context.js +28 -112
  147. package/dist/worker/console/workspace-registry.js +2 -2
  148. package/dist/worker/continuation/worker-continuation.js +278 -0
  149. package/dist/worker/observability/read-model.js +4 -0
  150. package/dist/worker/observe/health.js +1 -1
  151. package/dist/worker/observe/node-transparency.js +572 -0
  152. package/dist/worker/observe/routes.js +51 -1
  153. package/dist/worker/observe/static/api.js +69 -5
  154. package/dist/worker/observe/static/dag-context-reason-labels.d.ts +9 -0
  155. package/dist/worker/observe/static/dag-context-reason-labels.js +120 -0
  156. package/dist/worker/observe/static/dag-node-purpose.js +0 -5
  157. package/dist/worker/observe/static/state.js +3 -1
  158. package/dist/worker/observe/static/styles.css +1037 -126
  159. package/dist/worker/observe/static/views/dag-inspector.js +1217 -65
  160. package/dist/worker/observe/static/views/session-timeline.js +121 -25
  161. package/dist/worker/outcomes/adapters.js +19 -0
  162. package/dist/worker/outcomes/types.js +1 -0
  163. package/dist/worker/pool/attempt-lease.js +97 -66
  164. package/dist/worker/pool/begin-attempt-with-lease.js +1 -0
  165. package/dist/worker/pool/reconcile.js +46 -1
  166. package/dist/worker/pool/run-store.js +2 -0
  167. package/dist/worker/pool/state-projection.js +2 -0
  168. package/dist/worker/task-spec/workflow-routing.js +8 -3
  169. package/dist/workflows/dag/artifact-bindings.js +149 -0
  170. package/dist/workflows/dag/artifact-revision-schema-registry.js +31 -0
  171. package/dist/workflows/dag/backend-test-case-coverage-analysis.js +99 -4
  172. package/dist/workflows/dag/backend-test-markdown-workflow.js +13 -1
  173. package/dist/workflows/dag/backend-test-result-contract.js +1 -1
  174. package/dist/workflows/dag/backend-test-writer-completeness.js +45 -3
  175. package/dist/workflows/dag/budget-enforcement.js +10 -0
  176. package/dist/workflows/dag/context-receipt.js +305 -0
  177. package/dist/workflows/dag/context-transfer/context-bundle.js +423 -0
  178. package/dist/workflows/dag/context-transfer/operator-actions.js +61 -0
  179. package/dist/workflows/dag/context-transfer/renderers.js +93 -0
  180. package/dist/workflows/dag/contract-validator-registrations.js +2 -1
  181. package/dist/workflows/dag/frontend-implementation-contract.js +162 -932
  182. package/dist/workflows/dag/frontend-plan-render.js +1 -2
  183. package/dist/workflows/dag/frontend-prewrite-gate.js +349 -255
  184. package/dist/workflows/dag/frontend-recovery-plan.js +10 -17
  185. package/dist/workflows/dag/frontend-recovery-run.js +20 -33
  186. package/dist/workflows/dag/frontend-repair.js +432 -1
  187. package/dist/workflows/dag/frontend-review-context.js +15 -261
  188. package/dist/workflows/dag/frontend-verification-trace.js +24 -249
  189. package/dist/workflows/dag/frontend-worktree-diff.js +17 -250
  190. package/dist/workflows/dag/frontend-writer-rollback.js +32 -0
  191. package/dist/workflows/dag/init-hybrid.js +740 -718
  192. package/dist/workflows/dag/interrupt-request.js +0 -7
  193. package/dist/workflows/dag/node-execution.js +136 -759
  194. package/dist/workflows/dag/path-safety.js +1 -0
  195. package/dist/workflows/dag/prompt.js +30 -38
  196. package/dist/workflows/dag/report.js +1 -37
  197. package/dist/workflows/dag/rerun-feedback.js +1 -256
  198. package/dist/workflows/dag/rerun-plan.js +557 -11
  199. package/dist/workflows/dag/rerun-run.js +601 -38
  200. package/dist/workflows/dag/rerun-task.js +0 -29
  201. package/dist/workflows/dag/retry-policy.js +109 -214
  202. package/dist/workflows/dag/runner.js +142 -430
  203. package/dist/workflows/dag/scheduler.js +16 -114
  204. package/dist/workflows/dag/skill-snapshot.js +17 -0
  205. package/dist/workflows/dag/types.js +195 -246
  206. package/dist/workflows/dag/validate.js +12 -28
  207. package/docs/architecture/runtime-boundaries.md +6 -6
  208. package/docs/architecture/worker-and-feature.md +1 -1
  209. package/docs/init-surface.manifest.json +12 -30
  210. package/docs/skills/vetted-skill-registry.md +2 -4
  211. package/docs/templates/README.md +0 -2
  212. package/docs/templates/agent-dag-report.schema.json +2 -8
  213. package/docs/templates/agent-dag.schema.json +33 -1
  214. package/docs/templates/backend-test-dag.json +18 -18
  215. package/docs/templates/frontend-implementation-contract.schema.json +1 -4
  216. package/docs/templates/product-line/task.yaml +1 -1
  217. package/harness.json +3 -3
  218. package/package.json +3 -1
  219. package/skills/frontend-bounded-implement/SKILL.md +14 -15
  220. package/skills/frontend-design-review/SKILL.md +41 -22
  221. package/skills/frontend-implementation/SKILL.md +52 -0
  222. package/skills/frontend-implementation/references/code-standards.md +33 -0
  223. package/skills/frontend-implementation/references/design-spec.md +56 -0
  224. package/skills/frontend-implementation/references/node-contracts.md +31 -0
  225. package/skills/frontend-review/SKILL.md +15 -20
  226. package/skills/frontend-review/references/review-findings.md +7 -6
  227. package/skills/frontend-verification/SKILL.md +1 -1
  228. package/skills/loop-agent/references/command-reference.md +6 -1
  229. package/skills/loop-agent/references/hybrid-dag.md +2 -2
  230. package/dist/commands/dag-follow-up.js +0 -138
  231. package/dist/executors/pi-read-budget-policy.js +0 -239
  232. package/dist/worker/console/frontend-human-decision-adapter.js +0 -19
  233. package/dist/worker/console/frontend-split-operation-adapter.js +0 -20
  234. package/dist/worker/console/operation-store.js +0 -389
  235. package/dist/worker/console/static/assets/channel-bnXW0U3C.js +0 -1
  236. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-rZpq_twR.js +0 -1
  237. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-rZpq_twR.js +0 -1
  238. package/dist/worker/console/static/assets/index-D3CC4eUz.css +0 -1
  239. package/dist/worker/console/static/assets/index-DLt4ZFvD.js +0 -437
  240. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-zBMYiUyi.js +0 -1
  241. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-d_rms-5i.js +0 -8
  242. package/dist/worker/console/static-src/active-run-badge.js +0 -17
  243. package/dist/worker/materialize/frontend-split-task-materializer.js +0 -72
  244. package/dist/workflows/dag/dag-retry-schema.js +0 -138
  245. package/dist/workflows/dag/frontend-closeout.js +0 -221
  246. package/dist/workflows/dag/frontend-design-policy.js +0 -400
  247. package/dist/workflows/dag/frontend-human-decision.js +0 -182
  248. package/dist/workflows/dag/frontend-provider-capability-matrix.js +0 -159
  249. package/dist/workflows/dag/frontend-read-budgets.js +0 -12
  250. package/dist/workflows/dag/frontend-recovery-capsule.js +0 -455
  251. package/dist/workflows/dag/frontend-recovery-controller.js +0 -202
  252. package/dist/workflows/dag/frontend-recovery-lineage.js +0 -178
  253. package/dist/workflows/dag/frontend-review-findings.js +0 -270
  254. package/dist/workflows/dag/frontend-shadow-dual-write.js +0 -914
  255. package/dist/workflows/dag/frontend-shape-capsule-store.js +0 -191
  256. package/dist/workflows/dag/frontend-shape-facts.js +0 -409
  257. package/dist/workflows/dag/frontend-shape.js +0 -427
  258. package/dist/workflows/dag/frontend-source-fidelity-ledger.js +0 -108
  259. package/dist/workflows/dag/frontend-split-application-service.js +0 -203
  260. package/dist/workflows/dag/frontend-split-orchestrator.js +0 -899
  261. package/dist/workflows/dag/frontend-typed-event-store.js +0 -452
  262. package/dist/workflows/dag/frontend-typed-event-transaction.js +0 -180
  263. package/dist/workflows/dag/frontend-writer-admission.js +0 -285
  264. package/dist/workflows/dag/frontend-writer-status.js +0 -256
  265. package/dist/workflows/dag/recovery-lease.js +0 -80
  266. package/docs/templates/frontend-implementation-dag.json +0 -89
  267. package/docs/templates/spec-registry.schema.json +0 -45
  268. package/skills/frontend-bounded-implement/references/code-standards.md +0 -19
  269. package/skills/frontend-contract/SKILL.md +0 -23
  270. package/skills/frontend-contract/references/contract-protocol.md +0 -34
  271. package/skills/frontend-plan/SKILL.md +0 -26
  272. package/skills/frontend-plan/references/decision-contract.md +0 -37
  273. package/skills/frontend-plan/references/design-decisions.md +0 -17
  274. package/skills/frontend-scout/SKILL.md +0 -25
  275. package/skills/frontend-scout/references/design-evidence.md +0 -16
  276. package/skills/frontend-scout/references/scout-evidence.md +0 -23
  277. /package/dist/{worker → infrastructure}/console/repo-fingerprint.js +0 -0
@@ -7,13 +7,14 @@ import { runCoverageAudit } from "../commands/coverage-audit.js";
7
7
  import { runCoverageReport } from "../commands/coverage-report.js";
8
8
  import { parseCursorPromptArgs, printCursorPromptUsage, runCursorPrompt, } from "../commands/cursor-prompt.js";
9
9
  import { runDagApprove } from "../commands/dag-approve.js";
10
+ import { runDagArtifact } from "../commands/dag-artifact.js";
10
11
  import { runDagFinalVerification } from "../commands/dag-final-verification.js";
12
+ import { runDagContext } from "../commands/dag-context.js";
11
13
  import { runDagInitHybrid } from "../commands/dag-init-hybrid.js";
12
14
  import { runDagReconcileTasks } from "../commands/dag-reconcile-tasks.js";
13
15
  import { runDagReconcileRun } from "../commands/dag-reconcile-run.js";
14
16
  import { runDagRequestInterrupt } from "../commands/dag-request-interrupt.js";
15
17
  import { runDagRerunTask } from "../commands/dag-rerun-task.js";
16
- import { runDagFollowUp } from "../commands/dag-follow-up.js";
17
18
  import { runDagRerun } from "../commands/dag-rerun.js";
18
19
  import { runDagReject } from "../commands/dag-reject.js";
19
20
  import { runDagCloseoutDraft, runDagReport } from "../commands/dag-report.js";
@@ -358,15 +359,18 @@ async function runDagAction(repoRoot, subcommand, rest) {
358
359
  case "rerun-task":
359
360
  await runDagRerunTask(repoRoot, args);
360
361
  return;
361
- case "follow-up":
362
- await runDagFollowUp(repoRoot, args);
363
- return;
364
362
  case "reconcile-tasks":
365
363
  await runDagReconcileTasks(repoRoot, args);
366
364
  return;
367
365
  case "final-verification":
368
366
  await runDagFinalVerification(repoRoot, args);
369
367
  return;
368
+ case "context":
369
+ await runDagContext(repoRoot, args);
370
+ return;
371
+ case "artifact":
372
+ await runDagArtifact(repoRoot, args);
373
+ return;
370
374
  case "decision": {
371
375
  const [decisionSubcommand, ...decisionArgs] = args;
372
376
  if (decisionSubcommand === "inspect") {
@@ -380,7 +384,7 @@ async function runDagAction(repoRoot, subcommand, rest) {
380
384
  throw new Error("usage: dag decision <inspect|validate> --run-id <id> [--node-id <node-id>]");
381
385
  }
382
386
  default:
383
- throw new Error("usage: dag <init-hybrid|execute|validate|workflow-plan|workflow-validate|workflow-compile|approve|reject|resume|status|doctor|report|closeout-draft|reconcile-run|request-interrupt|rerun|rerun-task|reconcile-tasks|final-verification|decision> ...");
387
+ throw new Error("usage: dag <init-hybrid|execute|validate|workflow-plan|workflow-validate|workflow-compile|approve|reject|resume|status|doctor|report|closeout-draft|reconcile-run|request-interrupt|rerun|rerun-task|reconcile-tasks|final-verification|context|artifact|decision> ...");
384
388
  }
385
389
  }
386
390
  function compactArgs(args) {
@@ -549,10 +553,23 @@ function addDagCommand(program, defaultRepoRoot) {
549
553
  "request-interrupt",
550
554
  "rerun",
551
555
  "rerun-task",
552
- "follow-up",
553
556
  "reconcile-tasks",
554
557
  "final-verification",
558
+ "context",
559
+ "artifact",
555
560
  ], defaultRepoRoot);
561
+ const context = dag.commands.find((command) => command.name() === "context");
562
+ if (!context)
563
+ throw new Error("dag context command registration failed");
564
+ context
565
+ .description("Inspect or export a captured effective node context")
566
+ .addHelpText("after", "\nActions:\n show --run-id <id> --node-id <id> --attempt <n> [--json]\n export --run-id <id> --node-id <id> --attempt <n> --output <zip> [--target <generic|pi-session|pi-handoff|readable>] [--redaction <redacted|raw>] [--acknowledge-sensitive-data] [--json]");
567
+ const artifact = dag.commands.find((command) => command.name() === "artifact");
568
+ if (!artifact)
569
+ throw new Error("dag artifact command registration failed");
570
+ artifact
571
+ .description("Inspect artifact consumers or manage staged artifact revisions")
572
+ .addHelpText("after", "\nActions:\n consumers --run-id <id> --node-id <producer> --artifact <path> [--json]\n revision stage --run-id <id> --node-id <producer> --artifact <path> --file <replacement> --request-id <id> [--json]\n revision discard --revision-id <id> --request-id <id> [--json]");
556
573
  const validate = createRawArgsCommand("validate", "Validate an Agent DAG spec", defaultRepoRoot);
557
574
  configureDagValidate(validate);
558
575
  replaceActionWithOptionAwareDispatch(validate, defaultRepoRoot);
@@ -1328,15 +1328,12 @@ export async function runClientRecovery(input) {
1328
1328
  }
1329
1329
  const plugin = await installProjectOpenCodePlugin({
1330
1330
  repoRoot: input.repoRoot,
1331
- onlyIfMissing: true,
1332
1331
  });
1333
1332
  const overflowPlugin = await installProjectOpenCodeOverflowCompactPlugin({
1334
1333
  repoRoot: input.repoRoot,
1335
- onlyIfMissing: true,
1336
1334
  });
1337
1335
  const piExtension = await installProjectPiContextOverflowExtension({
1338
1336
  repoRoot: input.repoRoot,
1339
- onlyIfMissing: true,
1340
1337
  });
1341
1338
  const pi = await applyProjectPiSettingsMerge({ repoRoot: input.repoRoot });
1342
1339
  if (mode !== "user") {
@@ -0,0 +1,284 @@
1
+ import { createHash } from "node:crypto";
2
+ import { lstat, readFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { readRevisionParentArtifact } from "../workflows/dag/context-transfer/operator-actions.js";
5
+ import { readFileBoundarySafe } from "../shared/path-safety.js";
6
+ import { openConsoleAppData } from "../infrastructure/console/app-data.js";
7
+ import { artifactRevisionUploadPath, createArtifactRevision, discardArtifactRevision, acquireArtifactRevisionLease, releaseArtifactRevisionLease, } from "../infrastructure/console/artifact-revision-store.js";
8
+ import { OperationStore } from "../infrastructure/console/operation-store.js";
9
+ import { buildArtifactBindingGraph } from "../workflows/dag/artifact-bindings.js";
10
+ import { resolveArtifactRevisionSchema } from "../workflows/dag/artifact-revision-schema-registry.js";
11
+ import { locateDagRun, readDagRunSpec } from "../workflows/dag/lifecycle.js";
12
+ function parseArtifactArgs(args) {
13
+ const [first, second] = args;
14
+ const action = first === "consumers"
15
+ ? "consumers"
16
+ : first === "revision" && second === "stage"
17
+ ? "stage"
18
+ : first === "revision" && second === "discard"
19
+ ? "discard"
20
+ : undefined;
21
+ if (!action) {
22
+ throw new Error("usage: dag artifact consumers --run-id <run> --node-id <producer> --artifact <path> [--json] | dag artifact revision <stage|discard> ...");
23
+ }
24
+ let runId;
25
+ let nodeId;
26
+ let artifactPath;
27
+ let artifactId;
28
+ let file;
29
+ let candidateUpload;
30
+ let revisionId;
31
+ let requestId;
32
+ let json = false;
33
+ for (let index = action === "consumers" ? 1 : 2; index < args.length; index += 1) {
34
+ const arg = args[index];
35
+ const next = () => args[++index];
36
+ if (arg === "--run-id")
37
+ runId = next();
38
+ else if (arg.startsWith("--run-id="))
39
+ runId = arg.slice(9);
40
+ else if (arg === "--node-id")
41
+ nodeId = next();
42
+ else if (arg.startsWith("--node-id="))
43
+ nodeId = arg.slice(10);
44
+ else if (arg === "--artifact")
45
+ artifactPath = next();
46
+ else if (arg.startsWith("--artifact="))
47
+ artifactPath = arg.slice(11);
48
+ else if (arg === "--artifact-id")
49
+ artifactId = next();
50
+ else if (arg.startsWith("--artifact-id="))
51
+ artifactId = arg.slice(14);
52
+ else if (arg === "--file")
53
+ file = next();
54
+ else if (arg.startsWith("--file="))
55
+ file = arg.slice(7);
56
+ else if (arg === "--candidate-upload")
57
+ candidateUpload = next();
58
+ else if (arg.startsWith("--candidate-upload="))
59
+ candidateUpload = arg.slice(19);
60
+ else if (arg === "--revision-id")
61
+ revisionId = next();
62
+ else if (arg.startsWith("--revision-id="))
63
+ revisionId = arg.slice(14);
64
+ else if (arg === "--request-id")
65
+ requestId = next();
66
+ else if (arg.startsWith("--request-id="))
67
+ requestId = arg.slice(13);
68
+ else if (arg === "--json")
69
+ json = true;
70
+ else
71
+ throw new Error(`unknown dag artifact flag: ${arg}`);
72
+ }
73
+ return { action, runId, nodeId, artifactPath, artifactId, file, candidateUpload, revisionId, requestId, json };
74
+ }
75
+ function sha256(bytes) {
76
+ return createHash("sha256").update(bytes).digest("hex");
77
+ }
78
+ function print(value, json, fallback) {
79
+ process.stdout.write(json ? `${JSON.stringify(value, null, 2)}\n` : `${fallback}\n`);
80
+ }
81
+ export async function runDagArtifactCore(repoRoot, args, cliOptions) {
82
+ const input = parseArtifactArgs(args);
83
+ if (input.action === "discard") {
84
+ if (!input.revisionId || !input.requestId) {
85
+ throw new Error("dag artifact revision discard requires --revision-id and --request-id");
86
+ }
87
+ const appData = openConsoleAppData({ repoRoot, ...(cliOptions?.appDataRoot ? { appDataRoot: cliOptions.appDataRoot } : {}) });
88
+ const operations = new OperationStore(appData);
89
+ const created = await operations.create({
90
+ clientRequestId: input.requestId,
91
+ action: "cliArtifactRevisionDiscard",
92
+ actionParams: { revisionId: input.revisionId },
93
+ });
94
+ if (created.kind === "conflict")
95
+ throw new Error(created.code);
96
+ if (created.kind === "idempotent" && created.operation.state === "succeeded") {
97
+ return asRecord(created.operation.result);
98
+ }
99
+ const leaseHolder = `cli-discard:${input.requestId}`;
100
+ const revision = await acquireArtifactRevisionLease({
101
+ appData,
102
+ revisionId: input.revisionId,
103
+ holder: leaseHolder,
104
+ })
105
+ .then(() => discardArtifactRevision({
106
+ appData,
107
+ revisionId: input.revisionId,
108
+ holder: leaseHolder,
109
+ }))
110
+ .finally(() => releaseArtifactRevisionLease({
111
+ appData,
112
+ revisionId: input.revisionId,
113
+ holder: leaseHolder,
114
+ }).catch(() => { }));
115
+ const result = { ok: true, revisionId: revision.revisionId, state: revision.state };
116
+ await operations.update(created.operation.operationId, {
117
+ state: "succeeded",
118
+ startedAt: created.operation.createdAt,
119
+ finishedAt: new Date().toISOString(),
120
+ result,
121
+ });
122
+ return result;
123
+ }
124
+ if (!input.runId || !input.nodeId || (!input.artifactPath && !input.artifactId)) {
125
+ throw new Error("dag artifact requires --run-id, --node-id, and --artifact <relative-path> or --artifact-id <id>");
126
+ }
127
+ const located = await locateDagRun(repoRoot, input.runId);
128
+ if (!located)
129
+ throw new Error(`dag run not found: ${input.runId}`);
130
+ const graph = buildArtifactBindingGraph(await readDagRunSpec(located.runDir));
131
+ const declaration = graph.artifacts.find((item) => item.producerNodeId === input.nodeId &&
132
+ (input.artifactId
133
+ ? item.artifactId === input.artifactId
134
+ : item.path === input.artifactPath));
135
+ if (!declaration)
136
+ throw new Error("ARTIFACT_BINDING_UNAVAILABLE");
137
+ if (input.action === "consumers") {
138
+ return {
139
+ schemaVersion: 1,
140
+ runId: input.runId,
141
+ nodeId: input.nodeId,
142
+ artifactId: declaration.artifactId,
143
+ artifactPath: declaration.path,
144
+ directConsumerNodeIds: declaration.directConsumerNodeIds,
145
+ graphSha256: graph.artifactGraphSha256,
146
+ };
147
+ }
148
+ if (!input.requestId || (!input.file && !input.candidateUpload)) {
149
+ throw new Error("dag artifact revision stage requires --file or --candidate-upload, and --request-id");
150
+ }
151
+ const appData = openConsoleAppData({
152
+ repoRoot,
153
+ ...(cliOptions?.appDataRoot ? { appDataRoot: cliOptions.appDataRoot } : {}),
154
+ });
155
+ // The candidate upload lives in app-data and is cross-process mutable;
156
+ // resolve + read it TOCTOU-safe (O_NOFOLLOW fd read) instead of
157
+ // lstat-then-readFile, so a swapped symlink can never feed an unintended
158
+ // file into the stage. Both the path resolution (assertSafeAppDataPath
159
+ // rejects symlinks/hardlinks) and the fd read map to the stable
160
+ // ARTIFACT_REVISION_PATH_INVALID code.
161
+ let candidateBytes;
162
+ if (input.candidateUpload) {
163
+ try {
164
+ if (!/^[a-f0-9]{64}$/.test(input.candidateUpload)) {
165
+ throw new Error("invalid --candidate-upload hash");
166
+ }
167
+ const candidatePath = artifactRevisionUploadPath(appData, input.candidateUpload);
168
+ candidateBytes = await readFileBoundarySafe({
169
+ boundaryRoot: path.dirname(candidatePath),
170
+ targetPath: candidatePath,
171
+ label: "candidate upload",
172
+ });
173
+ }
174
+ catch (error) {
175
+ const message = error instanceof Error ? error.message : String(error);
176
+ if (/symlink|hardlink|single-link|regular|boundary|escap|app-data/i.test(message)) {
177
+ throw new Error("ARTIFACT_REVISION_PATH_INVALID");
178
+ }
179
+ throw error;
180
+ }
181
+ }
182
+ else {
183
+ const candidatePath = path.resolve(repoRoot, input.file);
184
+ const stat = await lstat(candidatePath);
185
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.nlink !== 1) {
186
+ throw new Error("candidate must be an owned regular file");
187
+ }
188
+ candidateBytes = await readFile(candidatePath);
189
+ }
190
+ if (candidateBytes.byteLength > 10 * 1024 * 1024)
191
+ throw new Error("candidate exceeds 10 MiB");
192
+ const operations = new OperationStore(appData);
193
+ const actionParams = {
194
+ runId: input.runId,
195
+ nodeId: input.nodeId,
196
+ artifactPath: declaration.path,
197
+ candidateSha256: sha256(candidateBytes),
198
+ candidateBytes: candidateBytes.byteLength,
199
+ };
200
+ const created = await operations.create({
201
+ clientRequestId: input.requestId,
202
+ action: "cliArtifactRevisionStage",
203
+ actionParams,
204
+ });
205
+ if (created.kind === "conflict")
206
+ throw new Error(created.code);
207
+ if (created.kind === "idempotent" && created.operation.state === "succeeded") {
208
+ return asRecord(created.operation.result);
209
+ }
210
+ const parent = await readRevisionParentArtifact({
211
+ cwd: repoRoot,
212
+ runId: input.runId,
213
+ producerNodeId: input.nodeId,
214
+ artifactId: declaration.artifactId,
215
+ });
216
+ const revision = await createArtifactRevision({
217
+ appData,
218
+ parentRunId: input.runId,
219
+ producerNodeId: input.nodeId,
220
+ declaration: parent.declaration,
221
+ parentSha256: parent.parentSha256,
222
+ parentBytes: parent.parentBytes,
223
+ candidateBytes,
224
+ mediaType: declaration.mediaType,
225
+ artifactSchemaResolver: resolveArtifactRevisionSchema,
226
+ });
227
+ const projected = {
228
+ revisionId: revision.revisionId,
229
+ state: revision.state,
230
+ parent: revision.parent,
231
+ candidate: {
232
+ sha256: revision.candidate.sha256,
233
+ bytes: revision.candidate.bytes,
234
+ mediaType: revision.candidate.mediaType,
235
+ uploadedAt: revision.candidate.uploadedAt,
236
+ },
237
+ validation: revision.validation,
238
+ diff: {
239
+ kind: revision.diff.kind,
240
+ summary: revision.diff.summary,
241
+ truncated: revision.diff.truncated,
242
+ },
243
+ expiresAt: revision.expiresAt,
244
+ };
245
+ const result = { ok: true, revision: projected };
246
+ await operations.update(created.operation.operationId, {
247
+ state: "succeeded",
248
+ startedAt: created.operation.createdAt,
249
+ finishedAt: new Date().toISOString(),
250
+ result,
251
+ });
252
+ return result;
253
+ }
254
+ function asRecord(value) {
255
+ return value && typeof value === "object" ? value : { ok: true };
256
+ }
257
+ export async function runDagArtifact(repoRoot, args) {
258
+ const input = parseArtifactArgs(args);
259
+ try {
260
+ const result = await runDagArtifactCore(repoRoot, args);
261
+ if (input.action === "discard") {
262
+ print(result, input.json, `Discarded ${String(result.revisionId ?? "")}`);
263
+ }
264
+ else if (input.action === "consumers") {
265
+ const consumers = result;
266
+ print(result, input.json, `${consumers.artifactPath}: ${(consumers.directConsumerNodeIds ?? []).join(", ") || "no consumers"}`);
267
+ }
268
+ else {
269
+ print(result, input.json, `Staged revision ${String(result.revisionId ?? "")}`);
270
+ }
271
+ }
272
+ catch (error) {
273
+ if (!input.json)
274
+ throw error;
275
+ const message = error instanceof Error ? error.message : String(error);
276
+ const candidateCode = message.split(":", 1)[0]?.trim() ?? "";
277
+ const code = /^[A-Z][A-Z0-9_]+$/.test(candidateCode)
278
+ ? candidateCode
279
+ : "INTERNAL_ERROR";
280
+ process.stdout.write(`${JSON.stringify({ schemaVersion: 1, ok: false, error: { code, message } }, null, 2)}\n`);
281
+ process.stderr.write(`${message}\n`);
282
+ process.exitCode = 1;
283
+ }
284
+ }
@@ -0,0 +1,184 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { link, lstat, readFile, rm, writeFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { buildContextBundle } from "../workflows/dag/context-transfer/context-bundle.js";
5
+ import { effectiveNodeContextV1Schema } from "../shared/context-transfer.js";
6
+ import { locateDagRun } from "../workflows/dag/lifecycle.js";
7
+ function parseContextArgs(args) {
8
+ const action = args[0];
9
+ if (action !== "show" && action !== "export") {
10
+ throw new Error("usage: dag context <show|export> --run-id <id> --node-id <id> --attempt <n> [--json]");
11
+ }
12
+ let runId = "";
13
+ let nodeId = "";
14
+ let attempt = 0;
15
+ let json = false;
16
+ let target = "generic";
17
+ let profile = "redacted";
18
+ let output;
19
+ let acknowledgeSensitiveData = false;
20
+ for (let index = 1; index < args.length; index += 1) {
21
+ const arg = args[index];
22
+ if (arg === "--run-id")
23
+ runId = args[++index] ?? "";
24
+ else if (arg.startsWith("--run-id="))
25
+ runId = arg.slice(9);
26
+ else if (arg === "--node-id")
27
+ nodeId = args[++index] ?? "";
28
+ else if (arg.startsWith("--node-id="))
29
+ nodeId = arg.slice(10);
30
+ else if (arg === "--attempt")
31
+ attempt = Number(args[++index]);
32
+ else if (arg.startsWith("--attempt="))
33
+ attempt = Number(arg.slice(10));
34
+ else if (arg === "--target")
35
+ target = (args[++index] ?? "");
36
+ else if (arg.startsWith("--target="))
37
+ target = arg.slice(9);
38
+ else if (arg === "--redaction")
39
+ profile = (args[++index] ?? "");
40
+ else if (arg.startsWith("--redaction="))
41
+ profile = arg.slice(12);
42
+ else if (arg === "--output")
43
+ output = args[++index];
44
+ else if (arg.startsWith("--output="))
45
+ output = arg.slice(9);
46
+ else if (arg === "--acknowledge-sensitive-data")
47
+ acknowledgeSensitiveData = true;
48
+ else if (arg === "--json")
49
+ json = true;
50
+ else
51
+ throw new Error(`unknown dag context flag: ${arg}`);
52
+ }
53
+ if (!runId || !nodeId || !Number.isSafeInteger(attempt) || attempt < 1) {
54
+ throw new Error("dag context requires --run-id, --node-id, and positive --attempt");
55
+ }
56
+ if (!["generic", "pi-session", "pi-handoff", "readable"].includes(target)) {
57
+ throw new Error(`unsupported context target: ${target}`);
58
+ }
59
+ if (profile !== "redacted" && profile !== "raw") {
60
+ throw new Error(`unsupported redaction profile: ${profile}`);
61
+ }
62
+ if (action === "export" && !output) {
63
+ throw new Error("dag context export requires --output <path>");
64
+ }
65
+ if (action === "export" && profile === "raw" && !acknowledgeSensitiveData) {
66
+ throw new Error("raw context export requires --acknowledge-sensitive-data");
67
+ }
68
+ return {
69
+ action,
70
+ runId,
71
+ nodeId,
72
+ attempt,
73
+ json,
74
+ target,
75
+ profile,
76
+ ...(output ? { output } : {}),
77
+ acknowledgeSensitiveData,
78
+ };
79
+ }
80
+ function receiptPath(runDir, nodeId, attempt) {
81
+ return path.join(runDir, nodeId, "context-receipts", `attempt-${attempt}.json`);
82
+ }
83
+ function outputLabel(repoRoot, outputPath) {
84
+ const relative = path
85
+ .relative(repoRoot, outputPath)
86
+ .split(path.sep)
87
+ .join("/");
88
+ return relative && !relative.startsWith("../") && relative !== ".."
89
+ ? relative
90
+ : path.basename(outputPath);
91
+ }
92
+ export async function runDagContextCore(repoRoot, args) {
93
+ const input = parseContextArgs(args);
94
+ const located = await locateDagRun(repoRoot, input.runId);
95
+ if (!located)
96
+ throw new Error(`dag run not found: ${input.runId}`);
97
+ if (input.action === "show") {
98
+ let receipt;
99
+ try {
100
+ receipt = effectiveNodeContextV1Schema.parse(JSON.parse(await readFile(receiptPath(located.runDir, input.nodeId, input.attempt), "utf8")));
101
+ }
102
+ catch {
103
+ throw new Error("CONTEXT_RECEIPT_MISSING");
104
+ }
105
+ return {
106
+ schemaVersion: 1,
107
+ runId: input.runId,
108
+ nodeId: input.nodeId,
109
+ attempt: input.attempt,
110
+ capturedAt: receipt.identity.capturedAt,
111
+ contextDigest: receipt.contextDigest,
112
+ componentCount: receipt.orderedComponents.length,
113
+ truncationCount: receipt.promptAssembly.truncations.length,
114
+ runtime: {
115
+ executor: receipt.runtime.executor,
116
+ model: receipt.runtime.resolvedModel ?? receipt.runtime.modelHint ?? null,
117
+ skills: receipt.runtime.skills,
118
+ extensions: receipt.runtime.extensions,
119
+ tools: receipt.runtime.activeTools,
120
+ },
121
+ };
122
+ }
123
+ const outputPath = path.resolve(repoRoot, input.output);
124
+ const parent = path.dirname(outputPath);
125
+ const parentStat = await lstat(parent).catch(() => undefined);
126
+ if (parentStat?.isSymbolicLink())
127
+ throw new Error("unsafe output parent symlink");
128
+ const existing = await lstat(outputPath).catch(() => undefined);
129
+ if (existing)
130
+ throw new Error("context export output already exists");
131
+ const bundle = await buildContextBundle({
132
+ runDir: located.runDir,
133
+ runId: input.runId,
134
+ nodeId: input.nodeId,
135
+ attempt: input.attempt,
136
+ profile: input.profile,
137
+ target: input.target,
138
+ ...(input.profile === "raw" && input.acknowledgeSensitiveData
139
+ ? {
140
+ rawAcknowledgement: {
141
+ requestId: `cli-${bundleRequestIdentity(input)}`,
142
+ acknowledgedAt: new Date().toISOString(),
143
+ },
144
+ }
145
+ : {}),
146
+ });
147
+ const temporaryPath = `${outputPath}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
148
+ try {
149
+ await writeFile(temporaryPath, bundle.zipBytes, { flag: "wx", mode: 0o600 });
150
+ await link(temporaryPath, outputPath);
151
+ await rm(temporaryPath, { force: true });
152
+ }
153
+ catch (error) {
154
+ await rm(temporaryPath, { force: true }).catch(() => undefined);
155
+ throw error;
156
+ }
157
+ return {
158
+ schemaVersion: 1,
159
+ bundleId: bundle.manifest.bundleId,
160
+ bundleSha256: bundle.manifest.bundleSha256,
161
+ profile: bundle.manifest.profile,
162
+ target: bundle.manifest.target,
163
+ bytes: bundle.zipBytes.byteLength,
164
+ output: outputLabel(repoRoot, outputPath),
165
+ };
166
+ }
167
+ export async function runDagContext(repoRoot, args) {
168
+ const input = parseContextArgs(args);
169
+ const result = await runDagContextCore(repoRoot, args);
170
+ if (input.action === "show") {
171
+ const summary = result;
172
+ process.stdout.write(input.json
173
+ ? `${JSON.stringify(result, null, 2)}\n`
174
+ : `Context ${summary.runId}/${summary.nodeId} attempt ${summary.attempt}\nDigest: ${summary.contextDigest}\nComponents: ${summary.componentCount}\n`);
175
+ return;
176
+ }
177
+ const exported = result;
178
+ process.stdout.write(input.json
179
+ ? `${JSON.stringify(result, null, 2)}\n`
180
+ : `Exported ${exported.bundleId} to ${exported.output} (${exported.bytes} bytes)\n`);
181
+ }
182
+ function bundleRequestIdentity(input) {
183
+ return `${input.runId}-${input.nodeId}-${input.attempt}`.replace(/[^a-zA-Z0-9._-]/g, "-");
184
+ }