pi-crew 0.9.53 → 0.9.55

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 (493) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/package.json +6 -3
  3. package/scripts/clean-strip-types.mjs +60 -0
  4. package/src/adapters/claude-adapter.ts +23 -0
  5. package/src/adapters/codex-adapter.ts +21 -0
  6. package/src/adapters/cursor-adapter.ts +17 -0
  7. package/src/adapters/export-util.ts +143 -0
  8. package/src/adapters/index.ts +15 -0
  9. package/src/adapters/registry.ts +18 -0
  10. package/src/adapters/types.ts +23 -0
  11. package/src/agents/agent-config.ts +194 -0
  12. package/src/agents/agent-search.ts +98 -0
  13. package/src/agents/agent-serializer.ts +38 -0
  14. package/src/agents/discover-agents.ts +623 -0
  15. package/src/benchmark/benchmark-runner.ts +313 -0
  16. package/src/benchmark/feedback-loop.ts +73 -0
  17. package/src/config/config.ts +1270 -0
  18. package/src/config/defaults.ts +193 -0
  19. package/src/config/drift-detector.ts +290 -0
  20. package/src/config/markers.ts +330 -0
  21. package/src/config/resilient-parser.ts +117 -0
  22. package/src/config/role-tools.ts +118 -0
  23. package/src/config/suggestions.ts +75 -0
  24. package/src/config/types.ts +280 -0
  25. package/src/errors.ts +194 -0
  26. package/src/extension/action-suggestions.ts +117 -0
  27. package/src/extension/async-notifier.ts +179 -0
  28. package/src/extension/autonomous-policy.ts +209 -0
  29. package/src/extension/command-completions.ts +120 -0
  30. package/src/extension/context-status-injection.ts +185 -0
  31. package/src/extension/crew-autocomplete.ts +131 -0
  32. package/src/extension/crew-cleanup.ts +168 -0
  33. package/src/extension/crew-input-router.ts +93 -0
  34. package/src/extension/crew-shortcuts.ts +87 -0
  35. package/src/extension/crew-vibes/cat-frames.ts +18 -0
  36. package/src/extension/crew-vibes/config.ts +195 -0
  37. package/src/extension/crew-vibes/figures.ts +101 -0
  38. package/src/extension/crew-vibes/font-detect.ts +71 -0
  39. package/src/extension/crew-vibes/footer.ts +292 -0
  40. package/src/extension/crew-vibes/index.ts +432 -0
  41. package/src/extension/crew-vibes/provider-usage.ts +396 -0
  42. package/src/extension/crew-vibes/render.ts +206 -0
  43. package/src/extension/crew-vibes/speed.ts +286 -0
  44. package/src/extension/cross-extension-rpc.ts +350 -0
  45. package/src/extension/help.ts +62 -0
  46. package/src/extension/import-index.ts +74 -0
  47. package/src/extension/knowledge-injection.ts +402 -0
  48. package/src/extension/management.ts +571 -0
  49. package/src/extension/message-renderers.ts +108 -0
  50. package/src/extension/notification-router.ts +152 -0
  51. package/src/extension/notification-sink.ts +54 -0
  52. package/src/extension/pi-api.ts +56 -0
  53. package/src/extension/plan-orchestrate.ts +302 -0
  54. package/src/extension/project-init.ts +170 -0
  55. package/src/extension/register.ts +113 -0
  56. package/src/extension/registration/artifact-cleanup.ts +20 -0
  57. package/src/extension/registration/command-registration.ts +58 -0
  58. package/src/extension/registration/command-utils.ts +58 -0
  59. package/src/extension/registration/commands.ts +1228 -0
  60. package/src/extension/registration/compaction-guard.ts +333 -0
  61. package/src/extension/registration/context-builder.ts +135 -0
  62. package/src/extension/registration/crash-recovery-cache.ts +54 -0
  63. package/src/extension/registration/foreground-run-controller.ts +238 -0
  64. package/src/extension/registration/hook-registration.ts +119 -0
  65. package/src/extension/registration/lazy-configurers.ts +124 -0
  66. package/src/extension/registration/lifecycle-handlers.ts +923 -0
  67. package/src/extension/registration/lifecycle.ts +259 -0
  68. package/src/extension/registration/observability.ts +322 -0
  69. package/src/extension/registration/registration-types.ts +158 -0
  70. package/src/extension/registration/runtime-cleanup.ts +230 -0
  71. package/src/extension/registration/subagent-helpers.ts +125 -0
  72. package/src/extension/registration/subagent-manager-setup.ts +330 -0
  73. package/src/extension/registration/subagent-tools.ts +456 -0
  74. package/src/extension/registration/team-tool.ts +225 -0
  75. package/src/extension/registration/tool-registration.ts +50 -0
  76. package/src/extension/registration/ui.ts +172 -0
  77. package/src/extension/registration/viewers.ts +121 -0
  78. package/src/extension/registration/wire-cross-extension.ts +37 -0
  79. package/src/extension/result-watcher.ts +139 -0
  80. package/src/extension/rpc-hmac.ts +256 -0
  81. package/src/extension/run-bundle-schema.ts +104 -0
  82. package/src/extension/run-export.ts +97 -0
  83. package/src/extension/run-import.ts +168 -0
  84. package/src/extension/run-index.ts +131 -0
  85. package/src/extension/run-maintenance.ts +190 -0
  86. package/src/extension/session-summary.ts +18 -0
  87. package/src/extension/team-manager-command.ts +153 -0
  88. package/src/extension/team-onboard.ts +180 -0
  89. package/src/extension/team-recommendation.ts +288 -0
  90. package/src/extension/team-tool/anchor.ts +172 -0
  91. package/src/extension/team-tool/api.ts +1244 -0
  92. package/src/extension/team-tool/auto-summarize.ts +142 -0
  93. package/src/extension/team-tool/cache-control.ts +19 -0
  94. package/src/extension/team-tool/cancel.ts +337 -0
  95. package/src/extension/team-tool/chain-dispatch.ts +95 -0
  96. package/src/extension/team-tool/chain-executor.ts +379 -0
  97. package/src/extension/team-tool/config-patch.ts +50 -0
  98. package/src/extension/team-tool/context.ts +149 -0
  99. package/src/extension/team-tool/destructive-gate.ts +52 -0
  100. package/src/extension/team-tool/dispatch/automate.ts +80 -0
  101. package/src/extension/team-tool/dispatch/control.ts +42 -0
  102. package/src/extension/team-tool/dispatch/index.ts +95 -0
  103. package/src/extension/team-tool/dispatch/manage.ts +161 -0
  104. package/src/extension/team-tool/dispatch/run.ts +53 -0
  105. package/src/extension/team-tool/dispatch/status.ts +187 -0
  106. package/src/extension/team-tool/doctor.ts +431 -0
  107. package/src/extension/team-tool/explain.ts +282 -0
  108. package/src/extension/team-tool/failure-patterns.ts +118 -0
  109. package/src/extension/team-tool/goal-wrap.ts +330 -0
  110. package/src/extension/team-tool/goal.ts +556 -0
  111. package/src/extension/team-tool/handle-schedule.ts +332 -0
  112. package/src/extension/team-tool/handle-settings.ts +520 -0
  113. package/src/extension/team-tool/health-monitor.ts +481 -0
  114. package/src/extension/team-tool/inspect.ts +88 -0
  115. package/src/extension/team-tool/intent-policy.ts +45 -0
  116. package/src/extension/team-tool/lifecycle-actions.ts +615 -0
  117. package/src/extension/team-tool/orchestrate.ts +98 -0
  118. package/src/extension/team-tool/parallel-dispatch.ts +183 -0
  119. package/src/extension/team-tool/plan.ts +50 -0
  120. package/src/extension/team-tool/respond.ts +150 -0
  121. package/src/extension/team-tool/run-deadline.ts +66 -0
  122. package/src/extension/team-tool/run-not-found.ts +49 -0
  123. package/src/extension/team-tool/run.ts +1051 -0
  124. package/src/extension/team-tool/status.ts +260 -0
  125. package/src/extension/team-tool/workflow-manage.ts +261 -0
  126. package/src/extension/team-tool-types.ts +26 -0
  127. package/src/extension/team-tool.ts +750 -0
  128. package/src/extension/tool-result.ts +16 -0
  129. package/src/extension/validate-resources.ts +108 -0
  130. package/src/hooks/registry.ts +200 -0
  131. package/src/hooks/types.ts +69 -0
  132. package/src/i18n.ts +212 -0
  133. package/src/observability/correlation.ts +50 -0
  134. package/src/observability/event-bus.ts +86 -0
  135. package/src/observability/event-to-metric.ts +170 -0
  136. package/src/observability/exporters/adapter.ts +27 -0
  137. package/src/observability/exporters/otlp-exporter.ts +356 -0
  138. package/src/observability/exporters/prometheus-exporter.ts +54 -0
  139. package/src/observability/metric-registry.ts +100 -0
  140. package/src/observability/metric-retention.ts +64 -0
  141. package/src/observability/metric-sink.ts +99 -0
  142. package/src/observability/metrics-primitives.ts +219 -0
  143. package/src/plugins/plugin-define.ts +6 -0
  144. package/src/plugins/plugin-registry.ts +32 -0
  145. package/src/plugins/plugins/index.ts +3 -0
  146. package/src/plugins/plugins/nextjs.ts +19 -0
  147. package/src/plugins/plugins/vite.ts +10 -0
  148. package/src/plugins/plugins/vitest.ts +9 -0
  149. package/src/prompt/prompt-runtime.ts +380 -0
  150. package/src/runtime/adaptive-plan.ts +563 -0
  151. package/src/runtime/agent-control.ts +215 -0
  152. package/src/runtime/agent-memory.ts +81 -0
  153. package/src/runtime/agent-observability.ts +122 -0
  154. package/src/runtime/anchor-manager.ts +475 -0
  155. package/src/runtime/async-marker.ts +32 -0
  156. package/src/runtime/async-runner.ts +381 -0
  157. package/src/runtime/attention-events.ts +28 -0
  158. package/src/runtime/auto-summarize.ts +344 -0
  159. package/src/runtime/background-runner.ts +840 -0
  160. package/src/runtime/batch-barrier.ts +147 -0
  161. package/src/runtime/broker-issuer.ts +39 -0
  162. package/src/runtime/cancellation-token.ts +99 -0
  163. package/src/runtime/cancellation.ts +99 -0
  164. package/src/runtime/capability-inventory.ts +137 -0
  165. package/src/runtime/chain-parser.ts +237 -0
  166. package/src/runtime/chain-runner.ts +606 -0
  167. package/src/runtime/checkpoint.ts +291 -0
  168. package/src/runtime/child-pi-constants.ts +42 -0
  169. package/src/runtime/child-pi-kill.ts +180 -0
  170. package/src/runtime/child-pi-pool.ts +68 -0
  171. package/src/runtime/child-pi-spawn.ts +287 -0
  172. package/src/runtime/child-pi-steering.ts +128 -0
  173. package/src/runtime/child-pi-streams.ts +296 -0
  174. package/src/runtime/child-pi-transcript.ts +169 -0
  175. package/src/runtime/child-pi.ts +1105 -0
  176. package/src/runtime/coalesce-tasks.ts +268 -0
  177. package/src/runtime/code-summary.ts +292 -0
  178. package/src/runtime/command-trace.ts +105 -0
  179. package/src/runtime/compact-pipeline.ts +56 -0
  180. package/src/runtime/compact-stages/ansi-strip-stage.ts +25 -0
  181. package/src/runtime/compact-stages/blank-collapse-stage.ts +31 -0
  182. package/src/runtime/compact-stages/deduplicate-stage.ts +34 -0
  183. package/src/runtime/compact-stages/head-snap-stage.ts +57 -0
  184. package/src/runtime/compact-stages/index.ts +23 -0
  185. package/src/runtime/compact-stages/tail-capture-stage.ts +77 -0
  186. package/src/runtime/compact-stages/truncation-stage.ts +74 -0
  187. package/src/runtime/compaction-summary.ts +278 -0
  188. package/src/runtime/completion-guard.ts +207 -0
  189. package/src/runtime/concurrency.ts +58 -0
  190. package/src/runtime/crash-classification.ts +229 -0
  191. package/src/runtime/crash-recovery.ts +594 -0
  192. package/src/runtime/crew-agent-records.ts +595 -0
  193. package/src/runtime/crew-agent-runtime.ts +62 -0
  194. package/src/runtime/crew-broker-child.ts +88 -0
  195. package/src/runtime/crew-broker-client.ts +673 -0
  196. package/src/runtime/crew-broker-tokens.ts +159 -0
  197. package/src/runtime/crew-broker.ts +1304 -0
  198. package/src/runtime/crew-hooks.ts +227 -0
  199. package/src/runtime/cross-extension-rpc.ts +143 -0
  200. package/src/runtime/custom-tools/irc-tool.ts +282 -0
  201. package/src/runtime/custom-tools/submit-result-tool.ts +102 -0
  202. package/src/runtime/deadletter.ts +47 -0
  203. package/src/runtime/delivery-coordinator.ts +211 -0
  204. package/src/runtime/delta-conflict.ts +348 -0
  205. package/src/runtime/deterministic-ast.ts +161 -0
  206. package/src/runtime/diagnostic-export.ts +171 -0
  207. package/src/runtime/direct-run.ts +45 -0
  208. package/src/runtime/dwf-state-store.ts +102 -0
  209. package/src/runtime/dynamic-workflow-context.ts +1013 -0
  210. package/src/runtime/dynamic-workflow-runner.ts +325 -0
  211. package/src/runtime/effectiveness.ts +90 -0
  212. package/src/runtime/errors/crew-errors.ts +162 -0
  213. package/src/runtime/event-stream-bridge.ts +98 -0
  214. package/src/runtime/foreground-control.ts +193 -0
  215. package/src/runtime/foreground-watchdog.ts +132 -0
  216. package/src/runtime/global-worker-cap.ts +96 -0
  217. package/src/runtime/goal-achievement.ts +148 -0
  218. package/src/runtime/goal-evaluator.ts +365 -0
  219. package/src/runtime/goal-loop-runner.ts +825 -0
  220. package/src/runtime/goal-state-store.ts +219 -0
  221. package/src/runtime/green-contract.ts +55 -0
  222. package/src/runtime/group-join.ts +267 -0
  223. package/src/runtime/handoff-manager.ts +598 -0
  224. package/src/runtime/heartbeat-gradient.ts +36 -0
  225. package/src/runtime/heartbeat-watcher.ts +239 -0
  226. package/src/runtime/hidden-handoff.ts +407 -0
  227. package/src/runtime/important-line-classifier.ts +140 -0
  228. package/src/runtime/intercom-bridge.ts +187 -0
  229. package/src/runtime/iteration-hooks.ts +305 -0
  230. package/src/runtime/live-agent-control.ts +136 -0
  231. package/src/runtime/live-agent-manager.ts +704 -0
  232. package/src/runtime/live-control-realtime.ts +56 -0
  233. package/src/runtime/live-extension-bridge.ts +148 -0
  234. package/src/runtime/live-irc.ts +97 -0
  235. package/src/runtime/live-session-health.ts +108 -0
  236. package/src/runtime/live-session-runtime.ts +1146 -0
  237. package/src/runtime/loop-gates.ts +128 -0
  238. package/src/runtime/manifest-cache.ts +375 -0
  239. package/src/runtime/mcp-proxy.ts +105 -0
  240. package/src/runtime/metric-parser.ts +36 -0
  241. package/src/runtime/model-fallback.ts +409 -0
  242. package/src/runtime/model-resolver.ts +126 -0
  243. package/src/runtime/model-scope.ts +158 -0
  244. package/src/runtime/orphan-worker-registry.ts +465 -0
  245. package/src/runtime/output-validator.ts +202 -0
  246. package/src/runtime/overflow-recovery.ts +206 -0
  247. package/src/runtime/parallel-research.ts +68 -0
  248. package/src/runtime/parallel-utils.ts +160 -0
  249. package/src/runtime/parent-guard.ts +134 -0
  250. package/src/runtime/path-overlap.ts +150 -0
  251. package/src/runtime/peer-dep.ts +292 -0
  252. package/src/runtime/per-write-validator.ts +181 -0
  253. package/src/runtime/phase-progress.ts +217 -0
  254. package/src/runtime/phase-tracker.ts +385 -0
  255. package/src/runtime/pi-args.ts +655 -0
  256. package/src/runtime/pi-json-output.ts +170 -0
  257. package/src/runtime/pi-spawn.ts +273 -0
  258. package/src/runtime/pipeline-runner.ts +523 -0
  259. package/src/runtime/plan-templates.ts +201 -0
  260. package/src/runtime/policy-engine.ts +115 -0
  261. package/src/runtime/post-checks.ts +142 -0
  262. package/src/runtime/post-exit-stdio-guard.ts +109 -0
  263. package/src/runtime/process-lifecycle.ts +491 -0
  264. package/src/runtime/process-status.ts +154 -0
  265. package/src/runtime/progress-event-coalescer.ts +44 -0
  266. package/src/runtime/progress-tracker.ts +124 -0
  267. package/src/runtime/prose-compressor.ts +162 -0
  268. package/src/runtime/recovery-recipes.ts +203 -0
  269. package/src/runtime/replace.ts +570 -0
  270. package/src/runtime/resilient-edit.ts +153 -0
  271. package/src/runtime/result-extractor.ts +217 -0
  272. package/src/runtime/retry-executor.ts +109 -0
  273. package/src/runtime/retry-runner.ts +336 -0
  274. package/src/runtime/role-permission.ts +59 -0
  275. package/src/runtime/run-coalesced-task-group.ts +308 -0
  276. package/src/runtime/run-drift.ts +219 -0
  277. package/src/runtime/run-tracker.ts +116 -0
  278. package/src/runtime/run-worker.ts +78 -0
  279. package/src/runtime/runtime-policy.ts +29 -0
  280. package/src/runtime/runtime-resolver.ts +172 -0
  281. package/src/runtime/runtime-warmup.ts +160 -0
  282. package/src/runtime/scheduler.ts +353 -0
  283. package/src/runtime/semaphore.ts +141 -0
  284. package/src/runtime/sensitive-paths.ts +93 -0
  285. package/src/runtime/session-resources.ts +25 -0
  286. package/src/runtime/session-snapshot.ts +59 -0
  287. package/src/runtime/session-usage.ts +79 -0
  288. package/src/runtime/settings-store.ts +155 -0
  289. package/src/runtime/sidechain-output.ts +35 -0
  290. package/src/runtime/single-agent-compose.ts +84 -0
  291. package/src/runtime/skill-effectiveness.ts +524 -0
  292. package/src/runtime/skill-instructions.ts +394 -0
  293. package/src/runtime/stale-reconciler.ts +680 -0
  294. package/src/runtime/stream-preview.ts +184 -0
  295. package/src/runtime/streaming-output.ts +50 -0
  296. package/src/runtime/subagent-manager.ts +561 -0
  297. package/src/runtime/subprocess-tool-registry.ts +70 -0
  298. package/src/runtime/supervisor-contact.ts +64 -0
  299. package/src/runtime/task-display.ts +52 -0
  300. package/src/runtime/task-graph-scheduler.ts +227 -0
  301. package/src/runtime/task-graph.ts +290 -0
  302. package/src/runtime/task-health.ts +83 -0
  303. package/src/runtime/task-id.ts +161 -0
  304. package/src/runtime/task-output-context.ts +602 -0
  305. package/src/runtime/task-packet.ts +268 -0
  306. package/src/runtime/task-quality.ts +199 -0
  307. package/src/runtime/task-runner/capabilities.ts +78 -0
  308. package/src/runtime/task-runner/child-executor.ts +790 -0
  309. package/src/runtime/task-runner/context-retrieval.ts +163 -0
  310. package/src/runtime/task-runner/live-executor.ts +227 -0
  311. package/src/runtime/task-runner/output-splitter.ts +152 -0
  312. package/src/runtime/task-runner/post-execution.ts +480 -0
  313. package/src/runtime/task-runner/pre-execution.ts +365 -0
  314. package/src/runtime/task-runner/progress.ts +157 -0
  315. package/src/runtime/task-runner/prompt-builder.ts +278 -0
  316. package/src/runtime/task-runner/prompt-pipeline.ts +88 -0
  317. package/src/runtime/task-runner/result-utils.ts +16 -0
  318. package/src/runtime/task-runner/retrieval-orchestrator.ts +310 -0
  319. package/src/runtime/task-runner/run-projection.ts +125 -0
  320. package/src/runtime/task-runner/scaffold-executor.ts +25 -0
  321. package/src/runtime/task-runner/state-helpers.ts +176 -0
  322. package/src/runtime/task-runner/tail-read.ts +34 -0
  323. package/src/runtime/task-runner.ts +216 -0
  324. package/src/runtime/team-runner-artifacts.ts +13 -0
  325. package/src/runtime/team-runner.ts +2396 -0
  326. package/src/runtime/tool-output-pruner.ts +333 -0
  327. package/src/runtime/tool-progress.ts +278 -0
  328. package/src/runtime/usage-tracker.ts +73 -0
  329. package/src/runtime/verification-gates.ts +579 -0
  330. package/src/runtime/verification-integrity.ts +108 -0
  331. package/src/runtime/verification-worktree.ts +186 -0
  332. package/src/runtime/worker-heartbeat.ts +25 -0
  333. package/src/runtime/worker-startup.ts +83 -0
  334. package/src/runtime/workflow-state.ts +195 -0
  335. package/src/runtime/workspace-lock.ts +443 -0
  336. package/src/runtime/workspace-tree.ts +312 -0
  337. package/src/runtime/yield-handler.ts +224 -0
  338. package/src/runtime/zombie-scanner.ts +298 -0
  339. package/src/schema/config-schema.ts +327 -0
  340. package/src/schema/team-tool-schema.ts +492 -0
  341. package/src/schema/validation-types.ts +159 -0
  342. package/src/skills/discover-skills.ts +203 -0
  343. package/src/skills/skill-templates.ts +456 -0
  344. package/src/skills/validate.ts +285 -0
  345. package/src/state/active-run-registry.ts +439 -0
  346. package/src/state/artifact-store.ts +176 -0
  347. package/src/state/atomic-write.ts +970 -0
  348. package/src/state/blob-store.ts +308 -0
  349. package/src/state/contracts.ts +160 -0
  350. package/src/state/crew-init.ts +269 -0
  351. package/src/state/decision-ledger.ts +372 -0
  352. package/src/state/event-log-rotation.ts +399 -0
  353. package/src/state/event-log.ts +1465 -0
  354. package/src/state/event-reconstructor.ts +229 -0
  355. package/src/state/gitignore-manager.ts +46 -0
  356. package/src/state/health-store.ts +79 -0
  357. package/src/state/hook-instinct-bridge.ts +94 -0
  358. package/src/state/hook-integrations.ts +51 -0
  359. package/src/state/instinct-store.ts +275 -0
  360. package/src/state/jsonl-writer.ts +107 -0
  361. package/src/state/locks.ts +562 -0
  362. package/src/state/mailbox.ts +916 -0
  363. package/src/state/observation-store.ts +176 -0
  364. package/src/state/run-cache.ts +193 -0
  365. package/src/state/run-graph.ts +183 -0
  366. package/src/state/run-metrics.ts +165 -0
  367. package/src/state/schedule.ts +166 -0
  368. package/src/state/session-state-map.ts +51 -0
  369. package/src/state/state-store.ts +973 -0
  370. package/src/state/task-claims.ts +61 -0
  371. package/src/state/tiered-eval.ts +480 -0
  372. package/src/state/types-eval.ts +58 -0
  373. package/src/state/types.ts +447 -0
  374. package/src/state/usage.ts +138 -0
  375. package/src/state/worker-atomic-writer.ts +198 -0
  376. package/src/subagents/async-entry.ts +1 -0
  377. package/src/subagents/index.ts +3 -0
  378. package/src/subagents/live/control.ts +1 -0
  379. package/src/subagents/live/manager.ts +1 -0
  380. package/src/subagents/live/realtime.ts +1 -0
  381. package/src/subagents/live/session-runtime.ts +1 -0
  382. package/src/subagents/manager.ts +1 -0
  383. package/src/subagents/spawn.ts +1 -0
  384. package/src/teams/discover-teams.ts +187 -0
  385. package/src/teams/team-config.ts +27 -0
  386. package/src/teams/team-serializer.ts +38 -0
  387. package/src/tools/safe-bash-extension.ts +54 -0
  388. package/src/tools/safe-bash.ts +505 -0
  389. package/src/types/diff.d.ts +18 -0
  390. package/src/types/new-api-types.ts +35 -0
  391. package/src/ui/agent-management-overlay.ts +160 -0
  392. package/src/ui/card-colors.ts +139 -0
  393. package/src/ui/crew-footer.ts +102 -0
  394. package/src/ui/crew-select-list.ts +112 -0
  395. package/src/ui/dashboard-panes/agents-pane.ts +164 -0
  396. package/src/ui/dashboard-panes/cancellation-pane.ts +66 -0
  397. package/src/ui/dashboard-panes/capability-pane.ts +77 -0
  398. package/src/ui/dashboard-panes/health-pane.ts +31 -0
  399. package/src/ui/dashboard-panes/mailbox-pane.ts +35 -0
  400. package/src/ui/dashboard-panes/metrics-pane.ts +37 -0
  401. package/src/ui/dashboard-panes/progress-pane.ts +38 -0
  402. package/src/ui/dashboard-panes/transcript-pane.ts +10 -0
  403. package/src/ui/deploy-bundled-themes.ts +71 -0
  404. package/src/ui/dwf-phase-display.ts +151 -0
  405. package/src/ui/dynamic-border.ts +35 -0
  406. package/src/ui/format-helpers.ts +31 -0
  407. package/src/ui/heartbeat-aggregator.ts +74 -0
  408. package/src/ui/key-utils.ts +42 -0
  409. package/src/ui/keybinding-map.ts +248 -0
  410. package/src/ui/layout-primitives.ts +106 -0
  411. package/src/ui/live-conversation-overlay.ts +183 -0
  412. package/src/ui/live-duration.ts +55 -0
  413. package/src/ui/live-run-sidebar.ts +293 -0
  414. package/src/ui/loaders.ts +6 -0
  415. package/src/ui/mascot.ts +449 -0
  416. package/src/ui/overlays/agent-picker-overlay.ts +66 -0
  417. package/src/ui/overlays/confirm-overlay.ts +60 -0
  418. package/src/ui/overlays/help-overlay.ts +177 -0
  419. package/src/ui/overlays/mailbox-compose-overlay.ts +181 -0
  420. package/src/ui/overlays/mailbox-compose-preview.ts +78 -0
  421. package/src/ui/overlays/mailbox-detail-overlay.ts +155 -0
  422. package/src/ui/pi-ui-compat.ts +68 -0
  423. package/src/ui/powerbar-publisher.ts +459 -0
  424. package/src/ui/render-coalescer.ts +101 -0
  425. package/src/ui/render-diff.ts +160 -0
  426. package/src/ui/render-scheduler.ts +278 -0
  427. package/src/ui/run-action-dispatcher.ts +182 -0
  428. package/src/ui/run-dashboard.ts +910 -0
  429. package/src/ui/run-event-bus.ts +381 -0
  430. package/src/ui/run-snapshot-cache.ts +1057 -0
  431. package/src/ui/settings-overlay.ts +1067 -0
  432. package/src/ui/shared-overlay-scheduler.ts +96 -0
  433. package/src/ui/snapshot-types.ts +90 -0
  434. package/src/ui/spinner.ts +17 -0
  435. package/src/ui/status-colors.ts +143 -0
  436. package/src/ui/syntax-highlight.ts +136 -0
  437. package/src/ui/terminal-status.ts +269 -0
  438. package/src/ui/theme-adapter.ts +271 -0
  439. package/src/ui/theme-discovery.ts +199 -0
  440. package/src/ui/tool-progress-formatter.ts +93 -0
  441. package/src/ui/tool-renderers/brief-mode.ts +225 -0
  442. package/src/ui/tool-renderers/index.ts +726 -0
  443. package/src/ui/transcript-cache.ts +128 -0
  444. package/src/ui/transcript-entries.ts +256 -0
  445. package/src/ui/transcript-viewer.ts +424 -0
  446. package/src/ui/widget/index.ts +418 -0
  447. package/src/ui/widget/widget-formatters.ts +182 -0
  448. package/src/ui/widget/widget-model.ts +110 -0
  449. package/src/ui/widget/widget-renderer.ts +182 -0
  450. package/src/ui/widget/widget-types.ts +36 -0
  451. package/src/utils/bm25-search.ts +235 -0
  452. package/src/utils/completion-dedupe.ts +63 -0
  453. package/src/utils/conflict-detect.ts +668 -0
  454. package/src/utils/env-allowlist.ts +30 -0
  455. package/src/utils/env-filter.ts +155 -0
  456. package/src/utils/file-coalescer.ts +98 -0
  457. package/src/utils/fingerprint.ts +180 -0
  458. package/src/utils/frontmatter.ts +70 -0
  459. package/src/utils/fs-watch.ts +37 -0
  460. package/src/utils/gh-protocol.ts +556 -0
  461. package/src/utils/git.ts +260 -0
  462. package/src/utils/guards.ts +107 -0
  463. package/src/utils/ids.ts +24 -0
  464. package/src/utils/incremental-reader.ts +220 -0
  465. package/src/utils/internal-error.ts +10 -0
  466. package/src/utils/names.ts +36 -0
  467. package/src/utils/ndjson.ts +115 -0
  468. package/src/utils/paths.ts +227 -0
  469. package/src/utils/project-detector.ts +160 -0
  470. package/src/utils/redaction.ts +370 -0
  471. package/src/utils/resolve-shell.ts +36 -0
  472. package/src/utils/run-watcher-registry.ts +152 -0
  473. package/src/utils/safe-paths.ts +393 -0
  474. package/src/utils/scan-cache.ts +144 -0
  475. package/src/utils/session-utils.ts +110 -0
  476. package/src/utils/sleep.ts +54 -0
  477. package/src/utils/socket-path.ts +164 -0
  478. package/src/utils/sse-parser.ts +131 -0
  479. package/src/utils/task-name-generator.ts +337 -0
  480. package/src/utils/timings.ts +33 -0
  481. package/src/utils/token-counter.ts +200 -0
  482. package/src/utils/visual.ts +207 -0
  483. package/src/workflows/cost-estimator.ts +34 -0
  484. package/src/workflows/discover-workflows.ts +308 -0
  485. package/src/workflows/intermediate-store.ts +166 -0
  486. package/src/workflows/preflight-validator.ts +168 -0
  487. package/src/workflows/topology-analyzer.ts +203 -0
  488. package/src/workflows/validate-workflow.ts +50 -0
  489. package/src/workflows/workflow-config.ts +75 -0
  490. package/src/workflows/workflow-serializer.ts +32 -0
  491. package/src/worktree/branch-freshness.ts +112 -0
  492. package/src/worktree/cleanup.ts +341 -0
  493. package/src/worktree/worktree-manager.ts +1204 -0
@@ -0,0 +1,161 @@
1
+ /**
2
+ * deterministic-ast.ts — AST-based determinism enforcement for dynamic-workflow scripts (round-13 P0-2).
3
+ *
4
+ * Rejects `Date.now()`, `Math.random()`, and `new Date()` at workflow-load time
5
+ * using a true AST walk (not regex) so that:
6
+ * - Prompts mentioning "Date.now()" as string literals are accepted.
7
+ * - Comments containing "Date.now()" are accepted.
8
+ * - `Date.parse()`, `Date.UTC()`, `Math.floor()`, etc. are accepted (only `now` and `random` are blocked).
9
+ *
10
+ * Adapted from pi-dynamic-workflows/src/workflow.ts (MIT) — see NOTICE.md.
11
+ *
12
+ * The walker uses acorn's parse() with permissive flags (allowAwaitOutsideFunction,
13
+ * allowReturnOutsideFunction) so we don't reject perfectly valid workflow scripts
14
+ * that contain top-level `await` or `return`.
15
+ *
16
+ * On parse error, this function returns silently: jiti will surface a clearer
17
+ * parse error downstream. We don't double-report parse errors.
18
+ */
19
+
20
+ import { parse } from "acorn";
21
+
22
+ const NONDETERMINISM_ERROR =
23
+ "Workflow scripts must be deterministic: Date.now()/Math.random()/new Date() are unavailable. These introduce non-reproducible behavior across runs. Use ctx.vars for cached state, or pass a fixed seed via ctx.setArgs(). To bypass this check (escape hatch), set PI_CREW_DWF_SKIP_DETERMINISM_CHECK=1.";
24
+
25
+ export class DeterminismError extends Error {
26
+ constructor() {
27
+ super(NONDETERMINISM_ERROR);
28
+ this.name = "DeterminismError";
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Parse `script` and walk the AST looking for non-deterministic calls.
34
+ * Throws DeterminismError on the first hit. Silently returns on parse error
35
+ * (jiti will produce a clearer message downstream).
36
+ */
37
+ export function assertDeterministicScript(script: string): void {
38
+ let ast: AstNode;
39
+ try {
40
+ ast = parse(script, {
41
+ ecmaVersion: "latest",
42
+ sourceType: "module",
43
+ allowAwaitOutsideFunction: true,
44
+ allowReturnOutsideFunction: true,
45
+ ranges: false,
46
+ }) as unknown as AstNode;
47
+ } catch {
48
+ // Parse errors are handled by jiti downstream — don't double-report.
49
+ return;
50
+ }
51
+ assertDeterministicAst(ast);
52
+ }
53
+
54
+ /**
55
+ * Escape hatch: when PI_CREW_DWF_SKIP_DETERMINISM_CHECK=1 the check is bypassed.
56
+ * Power users may need this when a workflow legitimately depends on time/random
57
+ * (e.g. randomized benchmark scripts).
58
+ */
59
+ export function isDeterminismCheckEnabled(): boolean {
60
+ return process.env.PI_CREW_DWF_SKIP_DETERMINISM_CHECK !== "1";
61
+ }
62
+
63
+ // ---------------------------------------------------------------------------
64
+ // AST walker
65
+ // ---------------------------------------------------------------------------
66
+
67
+ interface AstNode {
68
+ type: string;
69
+ [key: string]: unknown;
70
+ }
71
+
72
+ function asAstNode(value: unknown): AstNode | undefined {
73
+ if (!value || typeof value !== "object") return undefined;
74
+ const obj = value as Record<string, unknown>;
75
+ if (typeof obj.type !== "string") return undefined;
76
+ return obj as AstNode;
77
+ }
78
+
79
+ function astChildren(node: AstNode): AstNode[] {
80
+ const out: AstNode[] = [];
81
+ for (const value of Object.values(node)) {
82
+ if (Array.isArray(value)) {
83
+ for (const item of value) {
84
+ const child = asAstNode(item);
85
+ if (child) out.push(child);
86
+ }
87
+ } else {
88
+ const child = asAstNode(value);
89
+ if (child) out.push(child);
90
+ }
91
+ }
92
+ return out;
93
+ }
94
+
95
+ function assertDeterministicAst(node: AstNode): void {
96
+ if (isDateNowCall(node) || isMathRandomCall(node) || isNewDateExpression(node)) {
97
+ throw new DeterminismError();
98
+ }
99
+ for (const child of astChildren(node)) assertDeterministicAst(child);
100
+ }
101
+
102
+ function isDateNowCall(node: AstNode): boolean {
103
+ return node.type === "CallExpression" && isMemberExpression(node, "callee", "Date", "now");
104
+ }
105
+
106
+ function isMathRandomCall(node: AstNode): boolean {
107
+ return node.type === "CallExpression" && isMemberExpression(node, "callee", "Math", "random");
108
+ }
109
+
110
+ function isNewDateExpression(node: AstNode): boolean {
111
+ if (node.type !== "NewExpression") return false;
112
+ const callee = asAstNode(node.callee);
113
+ return callee?.type === "Identifier" && callee.name === "Date";
114
+ }
115
+
116
+ /**
117
+ * Test whether `node[childKey]` is a MemberExpression of shape `objectName.propertyName`,
118
+ * where the property is either a static Identifier or a resolvable static string.
119
+ * `childKey` is the property name on `node` (usually "callee" for CallExpression).
120
+ */
121
+ function isMemberExpression(node: AstNode, childKey: string, objectName: string, propertyName: string): boolean {
122
+ const child = asAstNode(node[childKey]);
123
+ if (child?.type !== "MemberExpression") return false;
124
+ const object = asAstNode(child.object);
125
+ if (object?.type !== "Identifier" || object.name !== objectName) return false;
126
+ return propertyNameOf(child) === propertyName;
127
+ }
128
+
129
+ function propertyNameOf(node: AstNode): string | undefined {
130
+ const computed = node.computed === true;
131
+ const property = asAstNode(node.property);
132
+ if (!property) return undefined;
133
+ if (!computed && property.type === "Identifier") {
134
+ return property.name as string | undefined;
135
+ }
136
+ return staticStringOf(property);
137
+ }
138
+
139
+ function staticStringOf(node: AstNode | undefined): string | undefined {
140
+ if (!node) return undefined;
141
+ if (node.type === "Literal" && typeof node.value === "string") return node.value;
142
+ if (node.type === "TemplateLiteral") {
143
+ const expressions = node.expressions;
144
+ if (Array.isArray(expressions) && expressions.length > 0) return undefined;
145
+ const quasis = node.quasis;
146
+ if (!Array.isArray(quasis)) return undefined;
147
+ return quasis
148
+ .map((q) => {
149
+ const quasi = asAstNode(q);
150
+ const value = quasi?.value as { cooked?: string; raw?: string } | undefined;
151
+ return value?.cooked ?? value?.raw ?? "";
152
+ })
153
+ .join("");
154
+ }
155
+ if (node.type === "BinaryExpression" && node.operator === "+") {
156
+ const left = staticStringOf(asAstNode(node.left));
157
+ const right = staticStringOf(asAstNode(node.right));
158
+ if (left !== undefined && right !== undefined) return left + right;
159
+ }
160
+ return undefined;
161
+ }
@@ -0,0 +1,171 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
4
+ import type { MetricRegistry } from "../observability/metric-registry.ts";
5
+ import type { MetricSnapshot } from "../observability/metrics-primitives.ts";
6
+ import { atomicWriteFile } from "../state/atomic-write.ts";
7
+ import { readEvents, type TeamEvent } from "../state/event-log.ts";
8
+ import { loadRunManifestById } from "../state/state-store.ts";
9
+ import type { TeamRunManifest, TeamTaskState } from "../state/types.ts";
10
+ import { type HeartbeatSummary, summarizeHeartbeats } from "../ui/heartbeat-aggregator.ts";
11
+ import type { RunUiSnapshot } from "../ui/snapshot-types.ts";
12
+ import { isSecretKey, redactSecrets } from "../utils/redaction.ts";
13
+ import { readCrewAgents } from "./crew-agent-records.ts";
14
+ import { buildRecoveryLedger, type RecoveryLedgerEntry } from "./recovery-recipes.ts";
15
+
16
+ export { isSecretKey, redactSecrets } from "../utils/redaction.ts";
17
+
18
+ export interface DiagnosticReport {
19
+ schemaVersion?: number;
20
+ runId: string;
21
+ exportedAt: string;
22
+ manifest: TeamRunManifest;
23
+ tasks: TeamTaskState[];
24
+ recentEvents: TeamEvent[];
25
+ heartbeat: HeartbeatSummary;
26
+ agents: unknown[];
27
+ envRedacted: Record<string, string>;
28
+ metricsSnapshot?: MetricSnapshot[];
29
+ // Layer 8: task diagnostics
30
+ taskDiagnostics: Record<string, Record<string, unknown>>;
31
+ // Layer 9: terminal evidence
32
+ terminalEvidence: Record<string, TeamTaskState["terminalEvidence"]>;
33
+ // Layer 10: model attempts and routing
34
+ modelAttempts: {
35
+ taskId: string;
36
+ attempts: TeamTaskState["modelAttempts"];
37
+ routing: TeamTaskState["modelRouting"];
38
+ }[];
39
+ // Layer 11: pending mailbox
40
+ pendingMailbox: {
41
+ taskId: string;
42
+ pendingSteers: TeamTaskState["pendingSteers"];
43
+ }[];
44
+ runMailboxUnread: RunUiSnapshot["mailbox"];
45
+ // Layer 12: recovery ledger
46
+ recoveryLedger: RecoveryLedgerEntry[];
47
+ }
48
+
49
+ const ENV_DEBUG_ALLOWLIST =
50
+ /^(PI_CREW_|PI_TEAMS_|PI_.*HOME|NODE_ENV|NODE_VERSION|OS|PROCESSOR|TERM|LANG|HOME|USERPROFILE|APPDATA|PLATFORM|ARCH|WIN32|DOCKER|CI|VERBOSE|DEBUG|NO_COLOR|FORCE_COLOR|NPM_CONFIG|npm_)/i;
51
+
52
+ function envRedacted(): Record<string, string> {
53
+ const output: Record<string, string> = {};
54
+ for (const [key, value] of Object.entries(process.env)) {
55
+ if (isSecretKey(key)) output[key] = "***";
56
+ else if (typeof value === "string" && ENV_DEBUG_ALLOWLIST.test(key)) output[key] = value;
57
+ // All other env vars are omitted to prevent leaking sensitive paths or system topology.
58
+ }
59
+ return output;
60
+ }
61
+
62
+ function buildSnapshot(manifest: TeamRunManifest, tasks: TeamTaskState[]): RunUiSnapshot {
63
+ const agents = readCrewAgents(manifest);
64
+ return {
65
+ runId: manifest.runId,
66
+ cwd: manifest.cwd,
67
+ fetchedAt: Date.now(),
68
+ signature: `${manifest.runId}:${manifest.updatedAt}`,
69
+ manifest,
70
+ tasks,
71
+ agents,
72
+ progress: {
73
+ total: tasks.length,
74
+ completed: tasks.filter((task) => task.status === "completed").length,
75
+ running: tasks.filter((task) => task.status === "running").length,
76
+ failed: tasks.filter((task) => task.status === "failed").length,
77
+ queued: tasks.filter((task) => task.status === "queued").length,
78
+ },
79
+ usage: { tokensIn: 0, tokensOut: 0, toolUses: 0 },
80
+ mailbox: { inboxUnread: 0, outboxPending: 0, needsAttention: 0 },
81
+ recentEvents: [],
82
+ recentOutputLines: [],
83
+ };
84
+ }
85
+
86
+ export async function exportDiagnostic(
87
+ ctx: Pick<ExtensionContext, "cwd">,
88
+ runId: string,
89
+ options: { registry?: MetricRegistry } = {},
90
+ ): Promise<{ path: string; report: DiagnosticReport }> {
91
+ const loaded = loadRunManifestById(ctx.cwd, runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency;
92
+ if (!loaded) throw new Error(`Run '${runId}' not found.`);
93
+ const exportedAt = new Date().toISOString();
94
+ const safeTimestamp = exportedAt.replace(/[:.]/g, "-");
95
+ const recentEvents = readEvents(loaded.manifest.eventsPath).slice(-200);
96
+ const metricsSnapshot = options.registry?.snapshot();
97
+ const taskDiagnostics: Record<string, Record<string, unknown>> = {};
98
+ const terminalEvidence: Record<string, TeamTaskState["terminalEvidence"]> = {};
99
+ const modelAttempts: {
100
+ taskId: string;
101
+ attempts: TeamTaskState["modelAttempts"];
102
+ routing: TeamTaskState["modelRouting"];
103
+ }[] = [];
104
+ const pendingMailbox: {
105
+ taskId: string;
106
+ pendingSteers: TeamTaskState["pendingSteers"];
107
+ }[] = [];
108
+ for (const task of loaded.tasks) {
109
+ if (task.diagnostics) taskDiagnostics[task.id] = task.diagnostics;
110
+ if (task.terminalEvidence) terminalEvidence[task.id] = task.terminalEvidence;
111
+ if (task.modelAttempts || task.modelRouting) {
112
+ modelAttempts.push({
113
+ taskId: task.id,
114
+ attempts: task.modelAttempts,
115
+ routing: task.modelRouting,
116
+ });
117
+ }
118
+ if (task.pendingSteers) {
119
+ pendingMailbox.push({
120
+ taskId: task.id,
121
+ pendingSteers: task.pendingSteers,
122
+ });
123
+ }
124
+ }
125
+ const recoveryLedger = loaded.manifest.policyDecisions ? buildRecoveryLedger(loaded.manifest.policyDecisions).entries : [];
126
+ const snapshot = buildSnapshot(loaded.manifest, loaded.tasks);
127
+ const report: DiagnosticReport = {
128
+ ...(metricsSnapshot ? { schemaVersion: 2 } : {}),
129
+ runId,
130
+ exportedAt,
131
+ manifest: redactSecrets(loaded.manifest) as TeamRunManifest,
132
+ tasks: redactSecrets(loaded.tasks) as TeamTaskState[],
133
+ recentEvents: redactSecrets(recentEvents) as TeamEvent[],
134
+ heartbeat: summarizeHeartbeats(snapshot),
135
+ agents: redactSecrets(readCrewAgents(loaded.manifest)) as unknown[],
136
+ envRedacted: envRedacted(),
137
+ ...(metricsSnapshot
138
+ ? {
139
+ metricsSnapshot: redactSecrets(metricsSnapshot) as MetricSnapshot[],
140
+ }
141
+ : {}),
142
+ taskDiagnostics,
143
+ terminalEvidence,
144
+ modelAttempts,
145
+ pendingMailbox,
146
+ runMailboxUnread: snapshot.mailbox,
147
+ recoveryLedger,
148
+ };
149
+ const dir = path.join(loaded.manifest.artifactsRoot, "diagnostic");
150
+ fs.mkdirSync(dir, { recursive: true });
151
+ const filePath = path.join(dir, `diagnostic-${safeTimestamp}.json`);
152
+ atomicWriteFile(filePath, `${JSON.stringify(report, null, 2)}\n`);
153
+ return { path: filePath, report };
154
+ }
155
+
156
+ export function listRecentDiagnostic(dir: string, windowMs: number, now = Date.now()): string | undefined {
157
+ try {
158
+ if (!fs.existsSync(dir)) return undefined;
159
+ return fs
160
+ .readdirSync(dir)
161
+ .filter((file) => file.startsWith("diagnostic-") && file.endsWith(".json"))
162
+ .map((file) => ({
163
+ file,
164
+ mtimeMs: fs.statSync(path.join(dir, file)).mtimeMs,
165
+ }))
166
+ .filter((entry) => now - entry.mtimeMs < windowMs)
167
+ .sort((a, b) => b.mtimeMs - a.mtimeMs)[0]?.file;
168
+ } catch {
169
+ return undefined;
170
+ }
171
+ }
@@ -0,0 +1,45 @@
1
+ import type { AgentConfig } from "../agents/agent-config.ts";
2
+ import type { TeamRunManifest, TeamTaskState } from "../state/types.ts";
3
+ import type { TeamConfig } from "../teams/team-config.ts";
4
+ import type { WorkflowConfig } from "../workflows/workflow-config.ts";
5
+
6
+ export function isDirectRun(manifest: Pick<TeamRunManifest, "team" | "workflow">): boolean {
7
+ return manifest.workflow === "direct-agent";
8
+ }
9
+
10
+ export function directTeamAndWorkflowFromRun(
11
+ manifest: TeamRunManifest,
12
+ tasks: TeamTaskState[],
13
+ agents: AgentConfig[],
14
+ ): { team: TeamConfig; workflow: WorkflowConfig } | undefined {
15
+ if (!isDirectRun(manifest)) return undefined;
16
+ const firstTask = tasks[0];
17
+ const agentName = firstTask?.agent ?? (manifest.team.replace(/^direct-/, "") || "executor");
18
+ const agent = agents.find((candidate) => candidate.name === agentName);
19
+ const role = firstTask?.role ?? "agent";
20
+ const stepId = firstTask?.stepId ?? "01_agent";
21
+ return {
22
+ team: {
23
+ name: manifest.team,
24
+ description: `Direct subagent run for ${agentName}`,
25
+ source: "builtin",
26
+ filePath: "<generated>",
27
+ roles: [
28
+ {
29
+ name: role,
30
+ agent: agentName,
31
+ description: agent?.description,
32
+ },
33
+ ],
34
+ defaultWorkflow: "direct-agent",
35
+ workspaceMode: manifest.workspaceMode,
36
+ },
37
+ workflow: {
38
+ name: manifest.workflow ?? "direct-agent",
39
+ description: `Direct task for ${agentName}`,
40
+ source: "builtin",
41
+ filePath: "<generated>",
42
+ steps: [{ id: stepId, role, task: "{goal}", model: firstTask?.model }],
43
+ },
44
+ };
45
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * dwf-state-store.ts — Persistent checkpoint state for dynamic-workflow runs (P2-3, round-18).
3
+ *
4
+ * Modeled on GoalStore (goal-state-store.ts) and FileCheckpointStore (checkpoint.ts),
5
+ * but scoped to a single run's stateRoot (which is already <crewRoot>/state/runs/<runId>).
6
+ *
7
+ * Stores DwfCheckpointState as atomic JSON at <stateRoot>/dwf-checkpoint.json.
8
+ * atomicWriteJson (temp + rename + fsync) guarantees either the old or the new file,
9
+ * never a partial write — safe across crashes.
10
+ *
11
+ * Resume semantics (round-18): the runner loads a checkpoint on run start and hydrates
12
+ * ctx.vars/phases/logs from it; on clean completion the runner deletes it. A missing or
13
+ * corrupt checkpoint is treated as a fresh run (load() returns undefined). If a crash
14
+ * happens mid-agent, that agent simply re-runs from scratch on resume — agent results
15
+ * are expected to be idempotent-ish.
16
+ */
17
+
18
+ import { existsSync, mkdirSync, readFileSync, unlinkSync } from "node:fs";
19
+ import { dirname } from "node:path";
20
+ import { atomicWriteJson } from "../state/atomic-write.ts";
21
+ import { logInternalError } from "../utils/internal-error.ts";
22
+
23
+ export interface DwfCheckpointState {
24
+ runId: string;
25
+ vars: Record<string, unknown>;
26
+ phases: string[];
27
+ currentPhase: string | undefined;
28
+ logs: string[]; // capped copy (≤1000); the events log (dwf.log) is the durable source of truth
29
+ spent: number; // budget accumulator (round-14 P1-2)
30
+ agentCount: number;
31
+ /** PERS-1: per-agent-call idempotency cache. Maps a deterministic call ID to the
32
+ * cached result so a DWF resume skips already-completed agent calls (avoids
33
+ * duplicating artifacts/mailbox/tokens). Uses Record (not Map) for JSON
34
+ * serialization safety. */
35
+ completedAgentCalls?: Record<string, { text: string; usage?: { input: number; output: number } }>;
36
+ updatedAt: string;
37
+ }
38
+
39
+ /**
40
+ * DwfStore — atomic CRUD for a single run's DWF checkpoint.
41
+ *
42
+ * Concurrency: writes are atomic (atomicWriteJson). The DWF runner is the sole
43
+ * writer during a run; `team resume` loads the checkpoint read-only before the
44
+ * script re-executes. No file-lock is needed here because only one runner owns a
45
+ * run's stateRoot at a time (run locks protect manifest transitions elsewhere).
46
+ *
47
+ * Note: the constructor takes the run's stateRoot directly (NOT cwd + runId) to
48
+ * avoid a double-nesting bug — stateRoot is already <crewRoot>/state/runs/<runId>,
49
+ * so the checkpoint lands at <crewRoot>/state/runs/<runId>/dwf-checkpoint.json.
50
+ * This mirrors FileCheckpointStore (checkpoint.ts: constructor(stateRoot)).
51
+ */
52
+ export class DwfStore {
53
+ private readonly stateRoot: string;
54
+
55
+ constructor(stateRoot: string) {
56
+ this.stateRoot = stateRoot;
57
+ }
58
+
59
+ private get path(): string {
60
+ return `${this.stateRoot}/dwf-checkpoint.json`;
61
+ }
62
+
63
+ /** Load the checkpoint for this run's stateRoot. Returns undefined if missing or corrupt (fresh run). */
64
+ load(): DwfCheckpointState | undefined {
65
+ const path = this.path;
66
+ try {
67
+ if (!existsSync(path)) return undefined;
68
+ const raw = readFileSync(path, "utf-8");
69
+ const parsed = JSON.parse(raw);
70
+ // Corrupt-guard: a valid checkpoint must be an object with a string runId
71
+ // (mirrors GoalStore.load's typeof parsed.goalId !== "string" check).
72
+ if (!parsed || typeof parsed !== "object" || typeof parsed.runId !== "string") return undefined;
73
+ return parsed as DwfCheckpointState;
74
+ } catch {
75
+ return undefined;
76
+ }
77
+ }
78
+
79
+ /** Atomically persist a checkpoint state. Stamps `updatedAt` (callers need not set it). */
80
+ save(state: DwfCheckpointState): void {
81
+ const path = this.path;
82
+ const next = { ...state, updatedAt: new Date().toISOString() };
83
+ try {
84
+ mkdirSync(dirname(path), { recursive: true });
85
+ atomicWriteJson(path, next);
86
+ } catch (error) {
87
+ logInternalError("dwf-state-store.save", error, `runId=${state.runId}`);
88
+ throw error;
89
+ }
90
+ }
91
+
92
+ /** Remove the checkpoint file (after a clean completion). Best-effort; never throws. */
93
+ delete(): void {
94
+ const path = this.path;
95
+ try {
96
+ if (!existsSync(path)) return;
97
+ unlinkSync(path);
98
+ } catch (error) {
99
+ logInternalError("dwf-state-store.delete", error);
100
+ }
101
+ }
102
+ }