pi-crew 0.9.16 → 0.9.18

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 (435) hide show
  1. package/CHANGELOG.md +130 -0
  2. package/README.md +19 -0
  3. package/dist/build-meta.json +21784 -0
  4. package/dist/index.mjs +83169 -0
  5. package/dist/index.mjs.map +7 -0
  6. package/docs/A +358 -0
  7. package/docs/M-A +357 -0
  8. package/docs/REVIEW-FINDINGS-2026-06 +357 -0
  9. package/docs/Y +357 -0
  10. package/docs/a +357 -0
  11. package/docs/aA +358 -0
  12. package/docs/archive/README.md +91 -0
  13. package/docs/migration/atomic-write-v2-migration.md +297 -0
  14. package/docs/patterns/command-agent-skill.md +1 -1
  15. package/docs/perf/performance-review-2026-07.md +287 -0
  16. package/docs/skills/REFERENCE.md +0 -17
  17. package/docs//303/242mmaAAA/303/242 +357 -0
  18. package/index.bundle.ts +25 -0
  19. package/index.ts +95 -4
  20. package/package.json +15 -4
  21. package/skills/iterative-audit/SKILL.md +0 -1
  22. package/skills/widget-rendering/SKILL.md +17 -0
  23. package/src/adapters/claude-adapter.ts +1 -3
  24. package/src/adapters/export-util.ts +16 -16
  25. package/src/adapters/index.ts +5 -5
  26. package/src/agents/agent-config.ts +20 -14
  27. package/src/agents/agent-serializer.ts +1 -1
  28. package/src/agents/discover-agents.ts +83 -39
  29. package/src/benchmark/benchmark-runner.ts +51 -51
  30. package/src/benchmark/feedback-loop.ts +1 -1
  31. package/src/config/config.ts +303 -591
  32. package/src/config/defaults.ts +28 -2
  33. package/src/config/drift-detector.ts +11 -14
  34. package/src/config/markers.ts +201 -203
  35. package/src/config/resilient-parser.ts +14 -6
  36. package/src/config/role-tools.ts +3 -3
  37. package/src/config/suggestions.ts +5 -12
  38. package/src/config/types.ts +9 -25
  39. package/src/errors.ts +151 -157
  40. package/src/extension/action-suggestions.ts +54 -9
  41. package/src/extension/async-notifier.ts +43 -13
  42. package/src/extension/autonomous-policy.ts +77 -37
  43. package/src/extension/command-completions.ts +9 -8
  44. package/src/extension/context-status-injection.ts +14 -12
  45. package/src/extension/crew-autocomplete.ts +8 -16
  46. package/src/extension/crew-cleanup.ts +2 -1
  47. package/src/extension/crew-shortcuts.ts +9 -6
  48. package/src/extension/cross-extension-rpc.ts +136 -42
  49. package/src/extension/help.ts +1 -1
  50. package/src/extension/import-index.ts +10 -5
  51. package/src/extension/knowledge-injection.ts +88 -15
  52. package/src/extension/management.ts +89 -349
  53. package/src/extension/message-renderers.ts +3 -4
  54. package/src/extension/notification-router.ts +22 -5
  55. package/src/extension/notification-sink.ts +6 -3
  56. package/src/extension/pi-api.ts +17 -8
  57. package/src/extension/plan-orchestrate.ts +8 -27
  58. package/src/extension/project-init.ts +21 -6
  59. package/src/extension/register.ts +329 -975
  60. package/src/extension/registration/artifact-cleanup.ts +9 -4
  61. package/src/extension/registration/command-utils.ts +5 -1
  62. package/src/extension/registration/commands.ts +806 -314
  63. package/src/extension/registration/compaction-guard.ts +15 -15
  64. package/src/extension/registration/lifecycle.ts +259 -0
  65. package/src/extension/registration/observability.ts +293 -0
  66. package/src/extension/registration/subagent-helpers.ts +29 -7
  67. package/src/extension/registration/subagent-tools.ts +253 -44
  68. package/src/extension/registration/team-tool.ts +19 -84
  69. package/src/extension/registration/ui.ts +168 -0
  70. package/src/extension/registration/viewers.ts +64 -24
  71. package/src/extension/result-watcher.ts +18 -7
  72. package/src/extension/run-bundle-schema.ts +21 -6
  73. package/src/extension/run-export.ts +15 -6
  74. package/src/extension/run-import.ts +64 -29
  75. package/src/extension/run-index.ts +28 -9
  76. package/src/extension/run-maintenance.ts +32 -12
  77. package/src/extension/session-summary.ts +1 -1
  78. package/src/extension/team-manager-command.ts +64 -7
  79. package/src/extension/team-onboard.ts +149 -150
  80. package/src/extension/team-recommendation.ts +121 -21
  81. package/src/extension/team-tool/anchor.ts +31 -64
  82. package/src/extension/team-tool/api.ts +929 -141
  83. package/src/extension/team-tool/auto-summarize.ts +14 -26
  84. package/src/extension/team-tool/cache-control.ts +1 -5
  85. package/src/extension/team-tool/cancel.ts +138 -38
  86. package/src/extension/team-tool/chain-dispatch.ts +5 -13
  87. package/src/extension/team-tool/chain-executor.ts +29 -51
  88. package/src/extension/team-tool/config-patch.ts +1 -1
  89. package/src/extension/team-tool/context.ts +40 -20
  90. package/src/extension/team-tool/destructive-gate.ts +10 -5
  91. package/src/extension/team-tool/doctor.ts +170 -51
  92. package/src/extension/team-tool/explain.ts +228 -214
  93. package/src/extension/team-tool/failure-patterns.ts +3 -9
  94. package/src/extension/team-tool/goal-wrap.ts +71 -29
  95. package/src/extension/team-tool/goal.ts +185 -35
  96. package/src/extension/team-tool/handle-schedule.ts +34 -15
  97. package/src/extension/team-tool/handle-settings.ts +94 -56
  98. package/src/extension/team-tool/health-monitor.ts +27 -108
  99. package/src/extension/team-tool/inspect.ts +42 -9
  100. package/src/extension/team-tool/intent-policy.ts +4 -1
  101. package/src/extension/team-tool/lifecycle-actions.ts +244 -48
  102. package/src/extension/team-tool/orchestrate.ts +7 -18
  103. package/src/extension/team-tool/parallel-dispatch.ts +51 -29
  104. package/src/extension/team-tool/plan.ts +29 -5
  105. package/src/extension/team-tool/respond.ts +49 -16
  106. package/src/extension/team-tool/run-not-found.ts +3 -8
  107. package/src/extension/team-tool/run.ts +80 -317
  108. package/src/extension/team-tool/status.ts +135 -43
  109. package/src/extension/team-tool/workflow-manage.ts +92 -25
  110. package/src/extension/team-tool-types.ts +8 -1
  111. package/src/extension/team-tool.ts +142 -551
  112. package/src/extension/validate-resources.ts +39 -8
  113. package/src/hooks/registry.ts +66 -17
  114. package/src/hooks/types.ts +1 -1
  115. package/src/i18n.ts +25 -11
  116. package/src/observability/correlation.ts +17 -3
  117. package/src/observability/event-bus.ts +51 -56
  118. package/src/observability/event-to-metric.ts +117 -15
  119. package/src/observability/exporters/otlp-exporter.ts +56 -17
  120. package/src/observability/exporters/prometheus-exporter.ts +1 -1
  121. package/src/observability/metric-registry.ts +16 -4
  122. package/src/observability/metric-retention.ts +8 -2
  123. package/src/observability/metric-sink.ts +11 -3
  124. package/src/observability/metrics-primitives.ts +42 -9
  125. package/src/plugins/plugin-define.ts +2 -2
  126. package/src/plugins/plugin-registry.ts +25 -25
  127. package/src/plugins/plugins/index.ts +1 -1
  128. package/src/plugins/plugins/nextjs.ts +16 -16
  129. package/src/plugins/plugins/vite.ts +7 -11
  130. package/src/plugins/plugins/vitest.ts +6 -11
  131. package/src/runtime/adaptive-plan.ts +225 -40
  132. package/src/runtime/agent-control.ts +58 -15
  133. package/src/runtime/agent-memory.ts +15 -9
  134. package/src/runtime/agent-observability.ts +10 -2
  135. package/src/runtime/anchor-manager.ts +27 -25
  136. package/src/runtime/async-marker.ts +7 -1
  137. package/src/runtime/async-runner.ts +39 -24
  138. package/src/runtime/auto-summarize.ts +7 -13
  139. package/src/runtime/background-runner.ts +189 -251
  140. package/src/runtime/batch-barrier.ts +18 -16
  141. package/src/runtime/cancellation-token.ts +16 -6
  142. package/src/runtime/cancellation.ts +46 -8
  143. package/src/runtime/capability-inventory.ts +6 -4
  144. package/src/runtime/chain-parser.ts +44 -11
  145. package/src/runtime/chain-runner.ts +63 -69
  146. package/src/runtime/checkpoint.ts +12 -56
  147. package/src/runtime/child-pi.ts +344 -79
  148. package/src/runtime/coalesce-tasks.ts +268 -0
  149. package/src/runtime/code-summary.ts +71 -26
  150. package/src/runtime/compact-stages/index.ts +15 -5
  151. package/src/runtime/compact-stages/tail-capture-stage.ts +7 -2
  152. package/src/runtime/compact-stages/truncation-stage.ts +4 -1
  153. package/src/runtime/compaction-summary.ts +17 -10
  154. package/src/runtime/completion-guard.ts +33 -16
  155. package/src/runtime/crash-classification.ts +28 -7
  156. package/src/runtime/crash-recovery.ts +177 -37
  157. package/src/runtime/crew-agent-records.ts +145 -47
  158. package/src/runtime/crew-hooks.ts +9 -24
  159. package/src/runtime/cross-extension-rpc.ts +25 -23
  160. package/src/runtime/custom-tools/irc-tool.ts +43 -15
  161. package/src/runtime/custom-tools/submit-result-tool.ts +16 -5
  162. package/src/runtime/delivery-coordinator.ts +34 -7
  163. package/src/runtime/delta-conflict.ts +9 -21
  164. package/src/runtime/deterministic-ast.ts +1 -1
  165. package/src/runtime/diagnostic-export.ts +53 -20
  166. package/src/runtime/direct-run.ts +12 -2
  167. package/src/runtime/dwf-state-store.ts +1 -1
  168. package/src/runtime/dynamic-workflow-context.ts +187 -59
  169. package/src/runtime/dynamic-workflow-runner.ts +42 -20
  170. package/src/runtime/effectiveness.ts +16 -8
  171. package/src/runtime/errors/crew-errors.ts +7 -11
  172. package/src/runtime/event-stream-bridge.ts +9 -3
  173. package/src/runtime/foreground-control.ts +54 -14
  174. package/src/runtime/foreground-watchdog.ts +9 -6
  175. package/src/runtime/goal-achievement.ts +27 -10
  176. package/src/runtime/goal-evaluator.ts +54 -19
  177. package/src/runtime/goal-loop-runner.ts +280 -99
  178. package/src/runtime/goal-state-store.ts +27 -17
  179. package/src/runtime/green-contract.ts +11 -2
  180. package/src/runtime/group-join.ts +64 -31
  181. package/src/runtime/handoff-manager.ts +37 -42
  182. package/src/runtime/heartbeat-gradient.ts +10 -2
  183. package/src/runtime/heartbeat-watcher.ts +32 -6
  184. package/src/runtime/hidden-handoff.ts +13 -31
  185. package/src/runtime/important-line-classifier.ts +12 -2
  186. package/src/runtime/iteration-hooks.ts +25 -15
  187. package/src/runtime/live-agent-control.ts +55 -7
  188. package/src/runtime/live-agent-manager.ts +130 -27
  189. package/src/runtime/live-control-realtime.ts +23 -3
  190. package/src/runtime/live-irc.ts +4 -1
  191. package/src/runtime/live-session-health.ts +12 -4
  192. package/src/runtime/live-session-runtime.ts +379 -117
  193. package/src/runtime/manifest-cache.ts +28 -12
  194. package/src/runtime/mcp-proxy.ts +10 -18
  195. package/src/runtime/metric-parser.ts +1 -5
  196. package/src/runtime/model-fallback.ts +55 -18
  197. package/src/runtime/model-resolver.ts +2 -6
  198. package/src/runtime/model-scope.ts +19 -3
  199. package/src/runtime/notebook-helpers.ts +60 -62
  200. package/src/runtime/orphan-worker-registry.ts +37 -26
  201. package/src/runtime/output-validator.ts +18 -3
  202. package/src/runtime/overflow-recovery.ts +5 -4
  203. package/src/runtime/parallel-research.ts +29 -5
  204. package/src/runtime/parallel-utils.ts +9 -11
  205. package/src/runtime/path-overlap.ts +150 -0
  206. package/src/runtime/peer-dep.ts +12 -17
  207. package/src/runtime/per-write-validator.ts +1 -3
  208. package/src/runtime/phase-tracker.ts +342 -330
  209. package/src/runtime/pi-args.ts +26 -8
  210. package/src/runtime/pi-json-output.ts +1 -1
  211. package/src/runtime/pi-spawn.ts +30 -19
  212. package/src/runtime/pipeline-runner.ts +56 -55
  213. package/src/runtime/plan-templates.ts +5 -6
  214. package/src/runtime/policy-engine.ts +43 -7
  215. package/src/runtime/post-checks.ts +12 -4
  216. package/src/runtime/post-exit-stdio-guard.ts +2 -2
  217. package/src/runtime/process-lifecycle.ts +20 -10
  218. package/src/runtime/process-status.ts +16 -5
  219. package/src/runtime/progress-event-coalescer.ts +2 -1
  220. package/src/runtime/progress-tracker.ts +103 -103
  221. package/src/runtime/prose-compressor.ts +9 -11
  222. package/src/runtime/recovery-recipes.ts +118 -24
  223. package/src/runtime/replace.ts +25 -10
  224. package/src/runtime/resilient-edit.ts +10 -25
  225. package/src/runtime/result-extractor.ts +2 -6
  226. package/src/runtime/retry-executor.ts +20 -4
  227. package/src/runtime/retry-runner.ts +27 -51
  228. package/src/runtime/role-permission.ts +6 -1
  229. package/src/runtime/run-coalesced-task-group.ts +256 -0
  230. package/src/runtime/run-drift.ts +14 -15
  231. package/src/runtime/run-tracker.ts +6 -28
  232. package/src/runtime/runtime-policy.ts +1 -6
  233. package/src/runtime/runtime-resolver.ts +80 -15
  234. package/src/runtime/scheduler.ts +47 -18
  235. package/src/runtime/semaphore.ts +5 -7
  236. package/src/runtime/sensitive-paths.ts +2 -1
  237. package/src/runtime/session-usage.ts +1 -1
  238. package/src/runtime/settings-store.ts +16 -12
  239. package/src/runtime/sidechain-output.ts +6 -2
  240. package/src/runtime/single-agent-compose.ts +1 -4
  241. package/src/runtime/skill-effectiveness.ts +29 -97
  242. package/src/runtime/skill-instructions.ts +40 -83
  243. package/src/runtime/stale-reconciler.ts +73 -197
  244. package/src/runtime/stream-preview.ts +1 -1
  245. package/src/runtime/streaming-output.ts +1 -1
  246. package/src/runtime/subagent-manager.ts +44 -169
  247. package/src/runtime/subprocess-tool-registry.ts +4 -1
  248. package/src/runtime/supervisor-contact.ts +10 -5
  249. package/src/runtime/task-display.ts +19 -5
  250. package/src/runtime/task-graph-scheduler.ts +95 -21
  251. package/src/runtime/task-graph.ts +5 -11
  252. package/src/runtime/task-health.ts +54 -47
  253. package/src/runtime/task-id.ts +12 -19
  254. package/src/runtime/task-output-context.ts +265 -81
  255. package/src/runtime/task-packet.ts +12 -20
  256. package/src/runtime/task-quality.ts +6 -14
  257. package/src/runtime/task-runner/context-retrieval.ts +4 -13
  258. package/src/runtime/task-runner/live-executor.ts +114 -36
  259. package/src/runtime/task-runner/output-splitter.ts +152 -0
  260. package/src/runtime/task-runner/progress.ts +50 -12
  261. package/src/runtime/task-runner/prompt-builder.ts +31 -7
  262. package/src/runtime/task-runner/prompt-pipeline.ts +31 -7
  263. package/src/runtime/task-runner/result-utils.ts +3 -1
  264. package/src/runtime/task-runner/retrieval-orchestrator.ts +310 -0
  265. package/src/runtime/task-runner/run-projection.ts +27 -8
  266. package/src/runtime/task-runner/state-helpers.ts +50 -14
  267. package/src/runtime/task-runner/tail-read.ts +2 -6
  268. package/src/runtime/task-runner.ts +180 -326
  269. package/src/runtime/team-runner-artifacts.ts +13 -0
  270. package/src/runtime/team-runner.ts +456 -974
  271. package/src/runtime/tool-output-pruner.ts +6 -9
  272. package/src/runtime/tool-progress.ts +11 -21
  273. package/src/runtime/verification-gates.ts +33 -24
  274. package/src/runtime/verification-integrity.ts +2 -7
  275. package/src/runtime/verification-worktree.ts +62 -12
  276. package/src/runtime/worker-heartbeat.ts +5 -1
  277. package/src/runtime/worker-startup.ts +29 -5
  278. package/src/runtime/workflow-state.ts +17 -9
  279. package/src/runtime/workspace-lock.ts +30 -35
  280. package/src/runtime/workspace-tree.ts +20 -32
  281. package/src/runtime/yield-handler.ts +43 -9
  282. package/src/runtime/zombie-scanner.ts +5 -4
  283. package/src/schema/config-schema.ts +266 -172
  284. package/src/schema/team-tool-schema.ts +29 -74
  285. package/src/schema/validation-types.ts +25 -17
  286. package/src/skills/discover-skills.ts +35 -10
  287. package/src/skills/skill-templates.ts +109 -27
  288. package/src/skills/validate.ts +26 -8
  289. package/src/state/active-run-registry.ts +87 -28
  290. package/src/state/artifact-store.ts +9 -5
  291. package/src/state/atomic-write-v2.ts +85 -63
  292. package/src/state/atomic-write.ts +106 -27
  293. package/src/state/blob-store.ts +47 -20
  294. package/src/state/contracts.ts +20 -5
  295. package/src/state/crew-init.ts +5 -22
  296. package/src/state/decision-ledger.ts +19 -73
  297. package/src/state/event-log-rotation.ts +41 -15
  298. package/src/state/event-log.ts +168 -53
  299. package/src/state/event-reconstructor.ts +11 -1
  300. package/src/state/gitignore-manager.ts +2 -8
  301. package/src/state/health-store.ts +57 -57
  302. package/src/state/hook-instinct-bridge.ts +1 -1
  303. package/src/state/hook-integrations.ts +1 -1
  304. package/src/state/instinct-store.ts +17 -5
  305. package/src/state/jsonl-writer.ts +1 -1
  306. package/src/state/locks.ts +23 -9
  307. package/src/state/mailbox.ts +151 -28
  308. package/src/state/observation-store.ts +20 -14
  309. package/src/state/run-cache.ts +142 -135
  310. package/src/state/run-graph.ts +6 -15
  311. package/src/state/run-metrics.ts +5 -18
  312. package/src/state/schedule.ts +15 -9
  313. package/src/state/state-store.ts +137 -47
  314. package/src/state/task-claims.ts +12 -2
  315. package/src/state/tiered-eval.ts +52 -43
  316. package/src/state/types-eval.ts +2 -2
  317. package/src/state/types.ts +24 -20
  318. package/src/state/usage.ts +20 -4
  319. package/src/state/worker-atomic-writer.ts +6 -3
  320. package/src/subagents/index.ts +2 -2
  321. package/src/teams/discover-teams.ts +21 -6
  322. package/src/tools/safe-bash-extension.ts +5 -6
  323. package/src/tools/safe-bash.ts +10 -11
  324. package/src/types/new-api-types.ts +6 -10
  325. package/src/ui/agent-management-overlay.ts +52 -40
  326. package/src/ui/card-colors.ts +13 -4
  327. package/src/ui/crew-footer.ts +8 -7
  328. package/src/ui/crew-select-list.ts +1 -1
  329. package/src/ui/dashboard-panes/agents-pane.ts +41 -25
  330. package/src/ui/dashboard-panes/cancellation-pane.ts +1 -1
  331. package/src/ui/dashboard-panes/capability-pane.ts +32 -15
  332. package/src/ui/dashboard-panes/health-pane.ts +2 -1
  333. package/src/ui/dashboard-panes/metrics-pane.ts +4 -1
  334. package/src/ui/dashboard-panes/progress-pane.ts +12 -9
  335. package/src/ui/heartbeat-aggregator.ts +15 -4
  336. package/src/ui/keybinding-map.ts +40 -7
  337. package/src/ui/live-conversation-overlay.ts +36 -20
  338. package/src/ui/live-duration.ts +1 -4
  339. package/src/ui/live-run-sidebar.ts +88 -25
  340. package/src/ui/loaders.ts +2 -8
  341. package/src/ui/mascot.ts +20 -36
  342. package/src/ui/overlays/agent-picker-overlay.ts +11 -3
  343. package/src/ui/overlays/confirm-overlay.ts +4 -2
  344. package/src/ui/overlays/help-overlay.ts +25 -14
  345. package/src/ui/overlays/mailbox-compose-overlay.ts +48 -11
  346. package/src/ui/overlays/mailbox-compose-preview.ts +20 -5
  347. package/src/ui/overlays/mailbox-detail-overlay.ts +27 -6
  348. package/src/ui/pi-ui-compat.ts +7 -7
  349. package/src/ui/powerbar-publisher.ts +120 -42
  350. package/src/ui/render-diff.ts +10 -3
  351. package/src/ui/render-scheduler.ts +12 -4
  352. package/src/ui/run-action-dispatcher.ts +81 -18
  353. package/src/ui/run-dashboard.ts +172 -76
  354. package/src/ui/run-event-bus.ts +59 -37
  355. package/src/ui/run-snapshot-cache.ts +276 -86
  356. package/src/ui/settings-overlay.ts +361 -74
  357. package/src/ui/status-colors.ts +12 -1
  358. package/src/ui/syntax-highlight.ts +1 -1
  359. package/src/ui/terminal-status.ts +1 -3
  360. package/src/ui/theme-adapter.ts +16 -14
  361. package/src/ui/theme-discovery.ts +13 -2
  362. package/src/ui/tool-progress-formatter.ts +7 -7
  363. package/src/ui/tool-render.ts +128 -56
  364. package/src/ui/tool-renderers/brief-mode.ts +45 -27
  365. package/src/ui/tool-renderers/index.ts +109 -43
  366. package/src/ui/transcript-cache.ts +32 -6
  367. package/src/ui/transcript-entries.ts +25 -23
  368. package/src/ui/transcript-viewer.ts +78 -29
  369. package/src/ui/widget/index.ts +99 -40
  370. package/src/ui/widget/widget-formatters.ts +13 -6
  371. package/src/ui/widget/widget-model.ts +19 -8
  372. package/src/ui/widget/widget-renderer.ts +23 -13
  373. package/src/ui/widget/widget-types.ts +1 -1
  374. package/src/utils/bm25-search.ts +199 -199
  375. package/src/utils/conflict-detect.ts +22 -21
  376. package/src/utils/env-filter.ts +14 -7
  377. package/src/utils/file-coalescer.ts +5 -1
  378. package/src/utils/fingerprint.ts +3 -6
  379. package/src/utils/frontmatter.ts +3 -1
  380. package/src/utils/fs-watch.ts +2 -6
  381. package/src/utils/gh-protocol.ts +119 -44
  382. package/src/utils/git.ts +13 -15
  383. package/src/utils/guards.ts +2 -5
  384. package/src/utils/ids.ts +9 -2
  385. package/src/utils/incremental-reader.ts +14 -3
  386. package/src/utils/internal-error.ts +2 -1
  387. package/src/utils/names.ts +12 -3
  388. package/src/utils/paths.ts +49 -5
  389. package/src/utils/project-detector.ts +2 -2
  390. package/src/utils/redaction.ts +29 -19
  391. package/src/utils/resolve-shell.ts +9 -7
  392. package/src/utils/run-watcher-registry.ts +19 -31
  393. package/src/utils/safe-paths.ts +46 -29
  394. package/src/utils/scan-cache.ts +9 -2
  395. package/src/utils/session-utils.ts +2 -4
  396. package/src/utils/sleep.ts +12 -5
  397. package/src/utils/sse-parser.ts +5 -17
  398. package/src/utils/visual.ts +52 -32
  399. package/src/workflows/discover-workflows.ts +41 -109
  400. package/src/workflows/intermediate-store.ts +5 -21
  401. package/src/workflows/preflight-validator.ts +6 -33
  402. package/src/workflows/topology-analyzer.ts +5 -21
  403. package/src/workflows/workflow-config.ts +7 -6
  404. package/src/worktree/branch-freshness.ts +66 -8
  405. package/src/worktree/cleanup.ts +130 -20
  406. package/src/worktree/worktree-manager.ts +212 -69
  407. package/skills/artifact-analysis-loop/SKILL.md +0 -303
  408. package/skills/detection-pipeline-design/SKILL.md +0 -286
  409. package/skills/hunting-investigation-loop/SKILL.md +0 -402
  410. package/skills/incident-playbook-construction/SKILL.md +0 -384
  411. package/skills/security-review/SKILL.md +0 -561
  412. package/skills/threat-hypothesis-framework/SKILL.md +0 -176
  413. package/skills/ui-render-performance/SKILL.md +0 -58
  414. /package/docs/{followup-review-round3-2026-05-12.md → archive/followup-review-round3-2026-05-12.md} +0 -0
  415. /package/docs/{followup-review-round4-2026-05-13.md → archive/followup-review-round4-2026-05-13.md} +0 -0
  416. /package/docs/{pi-crew-bugs.md → archive/pi-crew-bugs.md} +0 -0
  417. /package/docs/{pi-crew-test-final.md → archive/pi-crew-test-final.md} +0 -0
  418. /package/docs/{pi-crew-test-results.md → archive/pi-crew-test-results.md} +0 -0
  419. /package/docs/{pi-crew-test-round2.md → archive/pi-crew-test-round2.md} +0 -0
  420. /package/docs/{pi-crew-test-round4.md → archive/pi-crew-test-round4.md} +0 -0
  421. /package/docs/{pi-crew-test-round5.md → archive/pi-crew-test-round5.md} +0 -0
  422. /package/docs/{pi-crew-test-round6.md → archive/pi-crew-test-round6.md} +0 -0
  423. /package/docs/{pi-crew-v0.5.10-audit-fix-plan.md → archive/pi-crew-v0.5.10-audit-fix-plan.md} +0 -0
  424. /package/docs/{pi-crew-v0.5.11-audit-fix-plan.md → archive/pi-crew-v0.5.11-audit-fix-plan.md} +0 -0
  425. /package/docs/{pi-crew-v0.5.12-audit-fix-plan.md → archive/pi-crew-v0.5.12-audit-fix-plan.md} +0 -0
  426. /package/docs/{pi-crew-v0.5.13-audit-fix-plan.md → archive/pi-crew-v0.5.13-audit-fix-plan.md} +0 -0
  427. /package/docs/{pi-crew-v0.5.14-audit-fix-plan.md → archive/pi-crew-v0.5.14-audit-fix-plan.md} +0 -0
  428. /package/docs/{pi-crew-v0.5.16-audit-fix-plan.md → archive/pi-crew-v0.5.16-audit-fix-plan.md} +0 -0
  429. /package/docs/{pi-crew-v0.5.17-audit-fix-plan.md → archive/pi-crew-v0.5.17-audit-fix-plan.md} +0 -0
  430. /package/docs/{pi-crew-v0.5.5-audit-fix-plan.md → archive/pi-crew-v0.5.5-audit-fix-plan.md} +0 -0
  431. /package/docs/{pi-crew-v0.5.9-audit-fix-plan.md → archive/pi-crew-v0.5.9-audit-fix-plan.md} +0 -0
  432. /package/docs/{pi-mono-opportunities.md → archive/pi-mono-opportunities.md} +0 -0
  433. /package/docs/{pi-mono-review.md → archive/pi-mono-review.md} +0 -0
  434. /package/docs/{pi-subagent4-comparison.md → archive/pi-subagent4-comparison.md} +0 -0
  435. /package/docs/{pi-subagents3-deep-analysis.md → archive/pi-subagents3-deep-analysis.md} +0 -0
@@ -7,15 +7,7 @@ import { logInternalError } from "../utils/internal-error.ts";
7
7
  import { projectCrewRoot } from "../utils/paths.ts";
8
8
  import { redactSecrets } from "../utils/redaction.ts";
9
9
 
10
- export type SubagentStatus =
11
- | "queued"
12
- | "running"
13
- | "completed"
14
- | "failed"
15
- | "cancelled"
16
- | "error"
17
- | "blocked"
18
- | "stopped";
10
+ export type SubagentStatus = "queued" | "running" | "completed" | "failed" | "cancelled" | "error" | "blocked" | "stopped";
19
11
 
20
12
  export interface SubagentSpawnOptions {
21
13
  cwd: string;
@@ -61,10 +53,7 @@ export interface SubagentRecord {
61
53
  lifetimeUsage?: { input: number; output: number; cacheWrite: number };
62
54
  }
63
55
 
64
- type SpawnRunner = (
65
- options: SubagentSpawnOptions,
66
- signal?: AbortSignal,
67
- ) => Promise<PiTeamsToolResult>;
56
+ type SpawnRunner = (options: SubagentSpawnOptions, signal?: AbortSignal) => Promise<PiTeamsToolResult>;
68
57
  type Notify = (record: SubagentRecord) => void;
69
58
  type NotifyEvent = (type: string, data: Record<string, unknown>) => void;
70
59
 
@@ -81,11 +70,7 @@ function isValidSubagentId(id: string): boolean {
81
70
 
82
71
  function persistedSubagentPath(cwd: string, id: string): string {
83
72
  if (!isValidSubagentId(id)) throw new Error(`Invalid subagent id: ${id}`);
84
- return path.join(
85
- projectCrewRoot(cwd),
86
- DEFAULT_PATHS.state.subagentsSubdir,
87
- `${id}.json`,
88
- );
73
+ return path.join(projectCrewRoot(cwd), DEFAULT_PATHS.state.subagentsSubdir, `${id}.json`);
89
74
  }
90
75
 
91
76
  function serializableRecord(record: SubagentRecord): SubagentRecord {
@@ -93,18 +78,11 @@ function serializableRecord(record: SubagentRecord): SubagentRecord {
93
78
  return rest;
94
79
  }
95
80
 
96
- export function savePersistedSubagentRecord(
97
- cwd: string,
98
- record: SubagentRecord,
99
- ): void {
81
+ export function savePersistedSubagentRecord(cwd: string, record: SubagentRecord): void {
100
82
  try {
101
83
  const filePath = persistedSubagentPath(cwd, record.id);
102
84
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
103
- fs.writeFileSync(
104
- filePath,
105
- `${JSON.stringify(redactSecrets(serializableRecord(record)), null, 2)}\n`,
106
- "utf-8",
107
- );
85
+ fs.writeFileSync(filePath, `${JSON.stringify(redactSecrets(serializableRecord(record)), null, 2)}\n`, "utf-8");
108
86
  // SECURITY: Restrict permissions to owner-only (rw-------).
109
87
  // On multi-user systems, other users must not read task prompts,
110
88
  // agent descriptions, and run IDs from subagent record files.
@@ -186,9 +164,7 @@ function sanitizePersistedRecord(raw: unknown): SubagentRecord | undefined {
186
164
  for (const key of Object.keys(obj)) {
187
165
  if (
188
166
  ALLOWED_RECORD_FIELDS.has(key) &&
189
- (typeof obj[key] === "string" ||
190
- typeof obj[key] === "number" ||
191
- typeof obj[key] === "boolean")
167
+ (typeof obj[key] === "string" || typeof obj[key] === "number" || typeof obj[key] === "boolean")
192
168
  ) {
193
169
  clean[key] = obj[key];
194
170
  }
@@ -198,14 +174,9 @@ function sanitizePersistedRecord(raw: unknown): SubagentRecord | undefined {
198
174
  return clean as unknown as SubagentRecord;
199
175
  }
200
176
 
201
- export function readPersistedSubagentRecord(
202
- cwd: string,
203
- id: string,
204
- ): SubagentRecord | undefined {
177
+ export function readPersistedSubagentRecord(cwd: string, id: string): SubagentRecord | undefined {
205
178
  try {
206
- const raw = JSON.parse(
207
- fs.readFileSync(persistedSubagentPath(cwd, id), "utf-8"),
208
- );
179
+ const raw = JSON.parse(fs.readFileSync(persistedSubagentPath(cwd, id), "utf-8"));
209
180
  return sanitizePersistedRecord(raw);
210
181
  } catch {
211
182
  return undefined;
@@ -226,10 +197,7 @@ function detailsRunId(result: PiTeamsToolResult): string | undefined {
226
197
  return typeof details?.runId === "string" ? details.runId : undefined;
227
198
  }
228
199
 
229
- function totalRunTurns(
230
- cwd: string,
231
- runId: string | undefined,
232
- ): number | undefined {
200
+ function totalRunTurns(cwd: string, runId: string | undefined): number | undefined {
233
201
  if (!runId) return undefined;
234
202
  const loaded = loadRunManifestById(cwd, runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
235
203
  if (!loaded) return undefined;
@@ -258,33 +226,20 @@ export class SubagentManager {
258
226
  private readonly onEvent?: NotifyEvent;
259
227
  private readonly pollIntervalMs: number;
260
228
 
261
- constructor(
262
- maxConcurrent = 4,
263
- onComplete?: Notify,
264
- pollIntervalMs = 1000,
265
- onEvent?: NotifyEvent,
266
- ) {
229
+ constructor(maxConcurrent = 4, onComplete?: Notify, pollIntervalMs = 1000, onEvent?: NotifyEvent) {
267
230
  this.maxConcurrent = maxConcurrent;
268
231
  this.onComplete = onComplete;
269
232
  this.onEvent = onEvent;
270
233
  this.pollIntervalMs = pollIntervalMs;
271
234
  }
272
235
 
273
- spawn(
274
- options: SubagentSpawnOptions,
275
- runner: SpawnRunner,
276
- signal?: AbortSignal,
277
- ): SubagentRecord {
236
+ spawn(options: SubagentSpawnOptions, runner: SpawnRunner, signal?: AbortSignal): SubagentRecord {
278
237
  const record: SubagentRecord = {
279
238
  id: `agent_${Date.now().toString(36)}_${(++this.counter).toString(36)}`,
280
239
  type: options.type,
281
240
  description: options.description,
282
241
  prompt: options.prompt,
283
- status:
284
- options.background &&
285
- this.runningBackground >= this.maxConcurrent
286
- ? "queued"
287
- : "running",
242
+ status: options.background && this.runningBackground >= this.maxConcurrent ? "queued" : "running",
288
243
  startedAt: Date.now(),
289
244
  model: options.model,
290
245
  skill: options.skill,
@@ -308,9 +263,7 @@ export class SubagentManager {
308
263
  }
309
264
 
310
265
  listAgents(): SubagentRecord[] {
311
- return [...this.records.values()].sort(
312
- (a, b) => b.startedAt - a.startedAt,
313
- );
266
+ return [...this.records.values()].sort((a, b) => b.startedAt - a.startedAt);
314
267
  }
315
268
 
316
269
  abort(id: string, reason?: string): boolean {
@@ -321,8 +274,7 @@ export class SubagentManager {
321
274
  this.markStopped(record, reason ?? "Aborted by caller.");
322
275
  return true;
323
276
  }
324
- if (record.status !== "running" && record.status !== "blocked")
325
- return false;
277
+ if (record.status !== "running" && record.status !== "blocked") return false;
326
278
  this.controllers.get(id)?.abort();
327
279
  this.markStopped(record, reason ?? "Aborted by caller.");
328
280
  return true;
@@ -350,15 +302,9 @@ export class SubagentManager {
350
302
  while (true) {
351
303
  this.drainQueue();
352
304
  const pending = this.listAgents()
353
- .filter(
354
- (record) =>
355
- record.status === "running" ||
356
- record.status === "queued",
357
- )
305
+ .filter((record) => record.status === "running" || record.status === "queued")
358
306
  .map((record) => record.promise)
359
- .filter((promise): promise is Promise<void> =>
360
- Boolean(promise),
361
- );
307
+ .filter((promise): promise is Promise<void> => Boolean(promise));
362
308
  if (!pending.length) break;
363
309
  await Promise.allSettled(pending);
364
310
  }
@@ -368,15 +314,10 @@ export class SubagentManager {
368
314
  while (true) {
369
315
  const record = this.records.get(id);
370
316
  if (!record) return undefined;
371
- if (record.status !== "running" && record.status !== "queued")
372
- return record;
317
+ if (record.status !== "running" && record.status !== "queued") return record;
373
318
  if (record.promise)
374
319
  await record.promise.catch((error) => {
375
- logInternalError(
376
- "subagent-manager.waitForRecord",
377
- error,
378
- `id=${id}`,
379
- );
320
+ logInternalError("subagent-manager.waitForRecord", error, `id=${id}`);
380
321
  });
381
322
  else await new Promise((resolve) => setTimeout(resolve, 100));
382
323
  }
@@ -387,12 +328,7 @@ export class SubagentManager {
387
328
  this.drainQueue();
388
329
  }
389
330
 
390
- private start(
391
- record: SubagentRecord,
392
- options: SubagentSpawnOptions,
393
- runner: SpawnRunner,
394
- signal?: AbortSignal,
395
- ): void {
331
+ private start(record: SubagentRecord, options: SubagentSpawnOptions, runner: SpawnRunner, signal?: AbortSignal): void {
396
332
  if (options.background) this.runningBackground++;
397
333
  record.status = "running";
398
334
  record.startedAt = Date.now();
@@ -411,8 +347,7 @@ export class SubagentManager {
411
347
  record.error = record.result;
412
348
  throw new Error(record.error);
413
349
  }
414
- if (record.runId)
415
- await this.pollRunToTerminal(options.cwd, record);
350
+ if (record.runId) await this.pollRunToTerminal(options.cwd, record);
416
351
  else record.status = "completed";
417
352
  } catch (error) {
418
353
  if (record.status === "stopped" || runSignal.aborted) {
@@ -420,27 +355,16 @@ export class SubagentManager {
420
355
  ? "Signal aborted — agent cancelled by parent (session switch, user cancel, or tool timeout)."
421
356
  : undefined;
422
357
  record.status = "stopped";
423
- if (!record.error)
424
- record.error =
425
- abortReason ??
426
- (error instanceof Error
427
- ? error.message
428
- : String(error));
358
+ if (!record.error) record.error = abortReason ?? (error instanceof Error ? error.message : String(error));
429
359
  return;
430
360
  }
431
361
  record.status = "error";
432
- record.error =
433
- error instanceof Error ? error.message : String(error);
362
+ record.error = error instanceof Error ? error.message : String(error);
434
363
  throw error; // H4: Propagate rejection so callers awaiting record.promise see the error
435
364
  } finally {
436
365
  this.cleanupRunSignal(record.id);
437
- if (options.background)
438
- this.runningBackground = Math.max(
439
- 0,
440
- this.runningBackground - 1,
441
- );
442
- if (record.status !== "blocked")
443
- record.completedAt = record.completedAt ?? Date.now();
366
+ if (options.background) this.runningBackground = Math.max(0, this.runningBackground - 1);
367
+ if (record.status !== "blocked") record.completedAt = record.completedAt ?? Date.now();
444
368
  savePersistedSubagentRecord(options.cwd, record);
445
369
  if (
446
370
  record.status === "completed" ||
@@ -450,12 +374,8 @@ export class SubagentManager {
450
374
  record.status === "stopped"
451
375
  ) {
452
376
  // Phase 1.6: Populate telemetry fields
453
- record.turnCount =
454
- record.turnCount ??
455
- totalRunTurns(options.cwd, record.runId);
456
- record.durationMs = record.completedAt
457
- ? Math.max(0, record.completedAt - record.startedAt)
458
- : undefined;
377
+ record.turnCount = record.turnCount ?? totalRunTurns(options.cwd, record.runId);
378
+ record.durationMs = record.completedAt ? Math.max(0, record.completedAt - record.startedAt) : undefined;
459
379
  savePersistedSubagentRecord(options.cwd, record);
460
380
  // User policy (v0.9.16): cancelled / stopped subagents leave NO trace.
461
381
  // Successful runs (`completed`) and agent errors (`failed`, `error`)
@@ -477,11 +397,7 @@ export class SubagentManager {
477
397
  // DO await (they still see the rejection) while preventing the
478
398
  // harness-killing failure mode for callers that don't.
479
399
  record.promise.catch((error) => {
480
- logInternalError(
481
- "subagent-manager.start.unhandled",
482
- error,
483
- `id=${record.id}`,
484
- );
400
+ logInternalError("subagent-manager.start.unhandled", error, `id=${record.id}`);
485
401
  });
486
402
  }
487
403
 
@@ -509,9 +425,7 @@ export class SubagentManager {
509
425
  if (signal) {
510
426
  const abort = (): void => controller.abort();
511
427
  signal.addEventListener("abort", abort, { once: true });
512
- this.controllerCleanup.set(id, () =>
513
- signal.removeEventListener("abort", abort),
514
- );
428
+ this.controllerCleanup.set(id, () => signal.removeEventListener("abort", abort));
515
429
  }
516
430
  return controller.signal;
517
431
  }
@@ -523,48 +437,32 @@ export class SubagentManager {
523
437
  }
524
438
 
525
439
  private drainQueue(): void {
526
- while (
527
- this.queue.length > 0 &&
528
- this.runningBackground < this.maxConcurrent
529
- ) {
440
+ while (this.queue.length > 0 && this.runningBackground < this.maxConcurrent) {
530
441
  const next = this.queue.shift();
531
442
  if (!next || next.record.status !== "queued") continue;
532
443
  this.start(next.record, next.options, next.runner, next.signal);
533
444
  }
534
445
  }
535
446
 
536
- private async pollRunToTerminal(
537
- cwd: string,
538
- record: SubagentRecord,
539
- ): Promise<void> {
540
- while (
541
- record.runId &&
542
- (record.status === "running" || record.status === "blocked")
543
- ) {
447
+ private async pollRunToTerminal(cwd: string, record: SubagentRecord): Promise<void> {
448
+ while (record.runId && (record.status === "running" || record.status === "blocked")) {
544
449
  const loaded = loadRunManifestById(cwd, record.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
545
450
  if (!loaded) {
546
- await new Promise((resolve) =>
547
- setTimeout(resolve, this.pollIntervalMs),
548
- );
451
+ await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));
549
452
  continue;
550
453
  }
551
454
  if (loaded.manifest.status === "completed") {
552
455
  record.status = "completed";
553
456
  record.error = undefined;
554
- record.turnCount =
555
- record.turnCount ?? totalRunTurns(cwd, record.runId);
457
+ record.turnCount = record.turnCount ?? totalRunTurns(cwd, record.runId);
556
458
  record.completedAt = Date.now();
557
459
  savePersistedSubagentRecord(cwd, record);
558
460
  return;
559
461
  }
560
- if (
561
- loaded.manifest.status === "failed" ||
562
- loaded.manifest.status === "cancelled"
563
- ) {
462
+ if (loaded.manifest.status === "failed" || loaded.manifest.status === "cancelled") {
564
463
  record.status = loaded.manifest.status;
565
464
  record.error = loaded.manifest.summary;
566
- record.turnCount =
567
- record.turnCount ?? totalRunTurns(cwd, record.runId);
465
+ record.turnCount = record.turnCount ?? totalRunTurns(cwd, record.runId);
568
466
  record.completedAt = Date.now();
569
467
  savePersistedSubagentRecord(cwd, record);
570
468
  return;
@@ -583,20 +481,14 @@ export class SubagentManager {
583
481
  savePersistedSubagentRecord(cwd, record);
584
482
  return;
585
483
  }
586
- await new Promise((resolve) =>
587
- setTimeout(resolve, this.pollIntervalMs),
588
- );
484
+ await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));
589
485
  }
590
486
  }
591
487
 
592
- private scheduleBlockedTerminalPoll(
593
- cwd: string,
594
- record: SubagentRecord,
595
- ): void {
488
+ private scheduleBlockedTerminalPoll(cwd: string, record: SubagentRecord): void {
596
489
  const poll = (): void => {
597
490
  const current = this.records.get(record.id);
598
- if (!current || current.status !== "blocked" || !current.runId)
599
- return;
491
+ if (!current || current.status !== "blocked" || !current.runId) return;
600
492
  const loaded = loadRunManifestById(cwd, current.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
601
493
  if (
602
494
  !loaded ||
@@ -610,25 +502,17 @@ export class SubagentManager {
610
502
  return;
611
503
  }
612
504
  const persisted = readPersistedSubagentRecord(cwd, current.id);
613
- current.resultConsumed =
614
- current.resultConsumed || persisted?.resultConsumed;
505
+ current.resultConsumed = current.resultConsumed || persisted?.resultConsumed;
615
506
  if (loaded.manifest.status === "completed") {
616
507
  current.status = "completed";
617
508
  current.error = undefined;
618
- } else if (
619
- loaded.manifest.status === "failed" ||
620
- loaded.manifest.status === "cancelled"
621
- ) {
509
+ } else if (loaded.manifest.status === "failed" || loaded.manifest.status === "cancelled") {
622
510
  current.status = loaded.manifest.status;
623
511
  current.error = loaded.manifest.summary;
624
512
  } else return;
625
513
  current.completedAt = Date.now();
626
- current.turnCount =
627
- current.turnCount ?? totalRunTurns(cwd, current.runId);
628
- current.durationMs = Math.max(
629
- 0,
630
- current.completedAt - current.startedAt,
631
- );
514
+ current.turnCount = current.turnCount ?? totalRunTurns(cwd, current.runId);
515
+ current.durationMs = Math.max(0, current.completedAt - current.startedAt);
632
516
  savePersistedSubagentRecord(cwd, current);
633
517
  this.onComplete?.(current);
634
518
  };
@@ -636,20 +520,11 @@ export class SubagentManager {
636
520
  timer.unref();
637
521
  }
638
522
 
639
- private scheduleStuckBlockedNotify(
640
- cwd: string,
641
- record: SubagentRecord,
642
- ): void {
523
+ private scheduleStuckBlockedNotify(cwd: string, record: SubagentRecord): void {
643
524
  const threshold = DEFAULT_SUBAGENT.stuckBlockedNotifyMs;
644
525
  const fire = (): void => {
645
526
  const current = this.records.get(record.id);
646
- if (
647
- !current ||
648
- current.status !== "blocked" ||
649
- !current.blockedAt ||
650
- current.stuckNotified
651
- )
652
- return;
527
+ if (!current || current.status !== "blocked" || !current.blockedAt || current.stuckNotified) return;
653
528
  current.stuckNotified = true;
654
529
  this.onEvent?.("subagent.stuck-blocked", {
655
530
  event: "subagent.stuck-blocked",
@@ -2,7 +2,10 @@ export interface SubprocessToolEvent {
2
2
  toolName: string;
3
3
  toolCallId: string;
4
4
  args?: Record<string, unknown>;
5
- result?: { content: Array<{ type: string; text?: string }>; details?: unknown };
5
+ result?: {
6
+ content: Array<{ type: string; text?: string }>;
7
+ details?: unknown;
8
+ };
6
9
  isError?: boolean;
7
10
  }
8
11
 
@@ -1,5 +1,5 @@
1
- import type { TeamRunManifest } from "../state/types.ts";
2
1
  import { appendEvent } from "../state/event-log.ts";
2
+ import type { TeamRunManifest } from "../state/types.ts";
3
3
  import { logInternalError } from "../utils/internal-error.ts";
4
4
 
5
5
  export interface SupervisorContactPayload {
@@ -50,10 +50,15 @@ export function parseSupervisorContactFromLine(line: string): Omit<SupervisorCon
50
50
  if (record.type !== "supervisor_contact" && record.type !== "crew_supervisor_contact") return undefined;
51
51
  return {
52
52
  taskId: typeof record.taskId === "string" ? record.taskId : "",
53
- reason: typeof record.reason === "string" && ["decision_needed", "clarification", "approval", "error_escalation", "custom"].includes(record.reason)
54
- ? record.reason as SupervisorContactPayload["reason"]
55
- : "custom",
53
+ reason:
54
+ typeof record.reason === "string" &&
55
+ ["decision_needed", "clarification", "approval", "error_escalation", "custom"].includes(record.reason)
56
+ ? (record.reason as SupervisorContactPayload["reason"])
57
+ : "custom",
56
58
  message: typeof record.message === "string" ? record.message : String(record.message ?? ""),
57
- data: record.data && typeof record.data === "object" && !Array.isArray(record.data) ? record.data as Record<string, unknown> : undefined,
59
+ data:
60
+ record.data && typeof record.data === "object" && !Array.isArray(record.data)
61
+ ? (record.data as Record<string, unknown>)
62
+ : undefined,
58
63
  };
59
64
  }
@@ -1,13 +1,16 @@
1
- import type { TeamTaskState } from "../state/types.ts";
2
- import type { CrewAgentRecord, CrewRuntimeKind } from "./crew-agent-runtime.ts";
1
+ import type { TeamRunManifest, TeamTaskState } from "../state/types.ts";
3
2
  import { recordFromTask } from "./crew-agent-records.ts";
4
- import type { TeamRunManifest } from "../state/types.ts";
3
+ import type { CrewAgentRecord, CrewRuntimeKind } from "./crew-agent-runtime.ts";
5
4
 
6
5
  export function shouldMaterializeAgent(task: TeamTaskState): boolean {
7
6
  return task.status !== "queued" && task.status !== "skipped";
8
7
  }
9
8
 
10
- export function recordsForMaterializedTasks(manifest: TeamRunManifest, tasks: TeamTaskState[], runtime: CrewRuntimeKind): CrewAgentRecord[] {
9
+ export function recordsForMaterializedTasks(
10
+ manifest: TeamRunManifest,
11
+ tasks: TeamTaskState[],
12
+ runtime: CrewRuntimeKind,
13
+ ): CrewAgentRecord[] {
11
14
  return tasks.filter(shouldMaterializeAgent).map((task) => recordFromTask(manifest, task, runtime));
12
15
  }
13
16
 
@@ -31,7 +34,18 @@ export function waitingReason(task: TeamTaskState, tasks: TeamTaskState[]): stri
31
34
  export function formatTaskGraphLines(tasks: TeamTaskState[]): string[] {
32
35
  if (tasks.length === 0) return ["- (none)"];
33
36
  return tasks.map((task) => {
34
- const icon = task.status === "completed" ? "✓" : task.status === "running" ? "⠋" : task.status === "failed" ? "✗" : task.status === "cancelled" || task.status === "skipped" ? "■" : task.status === "needs_attention" ? "⚠" : "◦";
37
+ const icon =
38
+ task.status === "completed"
39
+ ? "✓"
40
+ : task.status === "running"
41
+ ? "⠋"
42
+ : task.status === "failed"
43
+ ? "✗"
44
+ : task.status === "cancelled" || task.status === "skipped"
45
+ ? "■"
46
+ : task.status === "needs_attention"
47
+ ? "⚠"
48
+ : "◦";
35
49
  const wait = waitingReason(task, tasks);
36
50
  return `- ${icon} ${task.id} [${task.status}] ${task.role}->${task.agent}${wait && wait !== "ready" ? ` (${wait})` : ""}`;
37
51
  });
@@ -17,9 +17,16 @@ export interface TaskGraphIndex {
17
17
 
18
18
  export function buildTaskGraphIndex(tasks: TeamTaskState[]): TaskGraphIndex {
19
19
  return {
20
- doneSteps: new Set(tasks.filter((task) => task.status === "completed").map((task) => task.stepId).filter((id): id is string => id !== undefined)),
20
+ doneSteps: new Set(
21
+ tasks
22
+ .filter((task) => task.status === "completed")
23
+ .map((task) => task.stepId)
24
+ .filter((id): id is string => id !== undefined),
25
+ ),
21
26
  idMap: new Map(tasks.map((task) => [task.id, task])),
22
- stepToTaskId: new Map(tasks.map((task) => [task.stepId, task.id]).filter((entry): entry is [string, string] => entry[0] !== undefined)),
27
+ stepToTaskId: new Map(
28
+ tasks.map((task) => [task.stepId, task.id]).filter((entry): entry is [string, string] => entry[0] !== undefined),
29
+ ),
23
30
  };
24
31
  }
25
32
 
@@ -27,7 +34,12 @@ function taskById(tasks: TeamTaskState[]): Map<string, TeamTaskState> {
27
34
  return new Map(tasks.map((task) => [task.id, task]));
28
35
  }
29
36
 
30
- function dependencySatisfied(task: TeamTaskState, doneStepIds: Set<string>, idMap: Map<string, TeamTaskState>, stepMap: Map<string, string>): boolean {
37
+ function dependencySatisfied(
38
+ task: TeamTaskState,
39
+ doneStepIds: Set<string>,
40
+ idMap: Map<string, TeamTaskState>,
41
+ stepMap: Map<string, string>,
42
+ ): boolean {
31
43
  return task.dependsOn.every((dependency) => {
32
44
  if (doneStepIds.has(dependency)) return true;
33
45
  const taskId = stepMap.get(dependency) ?? dependency;
@@ -38,15 +50,27 @@ function dependencySatisfied(task: TeamTaskState, doneStepIds: Set<string>, idMa
38
50
  function withQueue(task: TeamTaskState, index: TaskGraphIndex): TeamTaskState {
39
51
  if (task.status === "queued") {
40
52
  const isReady = dependencySatisfied(task, index.doneSteps, index.idMap, index.stepToTaskId);
41
- return { ...task, graph: task.graph ? { ...task.graph, queue: isReady ? "ready" : "blocked" } : task.graph };
53
+ return {
54
+ ...task,
55
+ graph: task.graph ? { ...task.graph, queue: isReady ? "ready" : "blocked" } : task.graph,
56
+ };
42
57
  }
43
58
  if (task.status === "running") {
44
- return { ...task, graph: task.graph ? { ...task.graph, queue: "running" } : task.graph };
59
+ return {
60
+ ...task,
61
+ graph: task.graph ? { ...task.graph, queue: "running" } : task.graph,
62
+ };
45
63
  }
46
64
  if (task.status === "completed" || task.status === "skipped" || task.status === "needs_attention") {
47
- return { ...task, graph: task.graph ? { ...task.graph, queue: "done" } : task.graph };
65
+ return {
66
+ ...task,
67
+ graph: task.graph ? { ...task.graph, queue: "done" } : task.graph,
68
+ };
48
69
  }
49
- return { ...task, graph: task.graph ? { ...task.graph, queue: "blocked" } : task.graph };
70
+ return {
71
+ ...task,
72
+ graph: task.graph ? { ...task.graph, queue: "blocked" } : task.graph,
73
+ };
50
74
  }
51
75
 
52
76
  function ensureIndex(tasks: TeamTaskState[], index?: TaskGraphIndex): TaskGraphIndex {
@@ -59,20 +83,49 @@ export function refreshTaskGraphQueues(tasks: TeamTaskState[], index?: TaskGraph
59
83
  }
60
84
 
61
85
  export function getReadyTasks(tasks: TeamTaskState[], maxCount = 1, index?: TaskGraphIndex): TeamTaskState[] {
62
- return refreshTaskGraphQueues(tasks, index).filter((task) => task.status === "queued" && task.graph?.queue === "ready").slice(0, Math.max(0, maxCount));
86
+ return refreshTaskGraphQueues(tasks, index)
87
+ .filter((task) => task.status === "queued" && task.graph?.queue === "ready")
88
+ .slice(0, Math.max(0, maxCount));
63
89
  }
64
90
 
65
91
  export function markTaskRunning(tasks: TeamTaskState[], taskId: string, now = new Date(), index?: TaskGraphIndex): TeamTaskState[] {
66
92
  const resolved = ensureIndex(tasks, index);
67
- return refreshTaskGraphQueues(tasks, resolved).map((task) => task.id === taskId ? withQueue({ ...task, status: "running", startedAt: task.startedAt ?? now.toISOString() }, resolved) : task);
93
+ return refreshTaskGraphQueues(tasks, resolved).map((task) =>
94
+ task.id === taskId
95
+ ? withQueue(
96
+ {
97
+ ...task,
98
+ status: "running",
99
+ startedAt: task.startedAt ?? now.toISOString(),
100
+ },
101
+ resolved,
102
+ )
103
+ : task,
104
+ );
68
105
  }
69
106
 
70
107
  export function markTaskDone(tasks: TeamTaskState[], taskId: string, now = new Date(), index?: TaskGraphIndex): TeamTaskState[] {
71
108
  const resolved = ensureIndex(tasks, index);
72
- return refreshTaskGraphQueues(tasks.map((task) => task.id === taskId ? { ...task, status: "completed", finishedAt: task.finishedAt ?? now.toISOString() } : task), resolved);
109
+ return refreshTaskGraphQueues(
110
+ tasks.map((task) =>
111
+ task.id === taskId
112
+ ? {
113
+ ...task,
114
+ status: "completed",
115
+ finishedAt: task.finishedAt ?? now.toISOString(),
116
+ }
117
+ : task,
118
+ ),
119
+ resolved,
120
+ );
73
121
  }
74
122
 
75
- export function cancelTaskSubtree(tasks: TeamTaskState[], rootTaskId: string, reason = "Cancelled by task graph scheduler.", now = new Date()): TeamTaskState[] {
123
+ export function cancelTaskSubtree(
124
+ tasks: TeamTaskState[],
125
+ rootTaskId: string,
126
+ reason = "Cancelled by task graph scheduler.",
127
+ now = new Date(),
128
+ ): TeamTaskState[] {
76
129
  const ids = taskById(tasks);
77
130
  const toCancel = new Set<string>();
78
131
  const stack = [rootTaskId];
@@ -83,11 +136,18 @@ export function cancelTaskSubtree(tasks: TeamTaskState[], rootTaskId: string, re
83
136
  const task = ids.get(current);
84
137
  for (const child of task?.graph?.children ?? []) stack.push(child);
85
138
  }
86
- return refreshTaskGraphQueues(tasks.map((task) => {
87
- if (!toCancel.has(task.id)) return task;
88
- if (task.status === "completed") return task;
89
- return { ...task, status: "cancelled", error: reason, finishedAt: task.finishedAt ?? now.toISOString() };
90
- }));
139
+ return refreshTaskGraphQueues(
140
+ tasks.map((task) => {
141
+ if (!toCancel.has(task.id)) return task;
142
+ if (task.status === "completed") return task;
143
+ return {
144
+ ...task,
145
+ status: "cancelled",
146
+ error: reason,
147
+ finishedAt: task.finishedAt ?? now.toISOString(),
148
+ };
149
+ }),
150
+ );
91
151
  }
92
152
 
93
153
  export function failTaskAndBlockChildren(tasks: TeamTaskState[], rootTaskId: string, reason: string, now = new Date()): TeamTaskState[] {
@@ -102,11 +162,25 @@ export function failTaskAndBlockChildren(tasks: TeamTaskState[], rootTaskId: str
102
162
  const task = ids.get(current);
103
163
  for (const child of task?.graph?.children ?? []) stack.push(child);
104
164
  }
105
- return refreshTaskGraphQueues(tasks.map((task) => {
106
- if (task.id === rootTaskId) return { ...task, status: "failed", error: reason, finishedAt: task.finishedAt ?? now.toISOString() };
107
- if (blocked.has(task.id) && task.status === "queued") return { ...task, status: "skipped", error: `Blocked by failed task '${rootTaskId}'.`, finishedAt: task.finishedAt ?? now.toISOString() };
108
- return task;
109
- }));
165
+ return refreshTaskGraphQueues(
166
+ tasks.map((task) => {
167
+ if (task.id === rootTaskId)
168
+ return {
169
+ ...task,
170
+ status: "failed",
171
+ error: reason,
172
+ finishedAt: task.finishedAt ?? now.toISOString(),
173
+ };
174
+ if (blocked.has(task.id) && task.status === "queued")
175
+ return {
176
+ ...task,
177
+ status: "skipped",
178
+ error: `Blocked by failed task '${rootTaskId}'.`,
179
+ finishedAt: task.finishedAt ?? now.toISOString(),
180
+ };
181
+ return task;
182
+ }),
183
+ );
110
184
  }
111
185
 
112
186
  export function taskGraphSnapshot(tasks: TeamTaskState[], index?: TaskGraphIndex): TaskGraphSchedulerSnapshot {