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
@@ -1,8 +1,7 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
- import type { RunHealth } from "../runtime/task-health.ts";
3
+ import type { ManifestSummary, RunHealth } from "../runtime/task-health.ts";
4
4
  import { computeRunHealth } from "../runtime/task-health.ts";
5
- import type { ManifestSummary } from "../runtime/task-health.ts";
6
5
 
7
6
  // Relative to the crew root (`<cwd>/.crew`). BUG A fix (pts/2 hang
8
7
  // investigation 2026-06-16): this was `.crew/state/health`, which double-joined
@@ -12,65 +11,66 @@ import type { ManifestSummary } from "../runtime/task-health.ts";
12
11
  const HEALTH_DIR = "state/health";
13
12
 
14
13
  export interface HealthSnapshot {
15
- runId: string;
16
- timestamp: number;
17
- gitRef?: string;
18
- score: number;
19
- grade: string;
20
- penalties: { reason: string; deduction: number }[];
14
+ runId: string;
15
+ timestamp: number;
16
+ gitRef?: string;
17
+ score: number;
18
+ grade: string;
19
+ penalties: { reason: string; deduction: number }[];
21
20
  }
22
21
 
23
22
  export class HealthStore {
24
- private readonly crewRoot: string;
25
- constructor(crewRoot: string) {
26
- this.crewRoot = crewRoot;
27
- }
23
+ private readonly crewRoot: string;
24
+ constructor(crewRoot: string) {
25
+ this.crewRoot = crewRoot;
26
+ }
28
27
 
29
- private healthDir(): string {
30
- return path.join(this.crewRoot, HEALTH_DIR);
31
- }
28
+ private healthDir(): string {
29
+ return path.join(this.crewRoot, HEALTH_DIR);
30
+ }
32
31
 
33
- saveSnapshot(manifest: ManifestSummary): HealthSnapshot {
34
- const health = computeRunHealth(manifest);
35
- const snapshot: HealthSnapshot = {
36
- runId: manifest.runId,
37
- timestamp: Date.now(),
38
- score: health.score,
39
- grade: health.grade,
40
- penalties: health.penalties,
41
- };
42
- const dir = this.healthDir();
43
- fs.mkdirSync(dir, { recursive: true });
44
- const file = path.join(dir, `${manifest.runId}.json`);
45
- fs.writeFileSync(file, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
46
- return snapshot;
47
- }
32
+ saveSnapshot(manifest: ManifestSummary): HealthSnapshot {
33
+ const health = computeRunHealth(manifest);
34
+ const snapshot: HealthSnapshot = {
35
+ runId: manifest.runId,
36
+ timestamp: Date.now(),
37
+ score: health.score,
38
+ grade: health.grade,
39
+ penalties: health.penalties,
40
+ };
41
+ const dir = this.healthDir();
42
+ fs.mkdirSync(dir, { recursive: true });
43
+ const file = path.join(dir, `${manifest.runId}.json`);
44
+ fs.writeFileSync(file, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
45
+ return snapshot;
46
+ }
48
47
 
49
- loadLatestSnapshot(): HealthSnapshot | null {
50
- const dir = this.healthDir();
51
- if (!fs.existsSync(dir)) return null;
52
- const snapshots = this.loadAllSnapshots();
53
- if (snapshots.length === 0) return null;
54
- // Sort by timestamp descending (most recent first)
55
- snapshots.sort((a, b) => b.timestamp - a.timestamp);
56
- return snapshots[0];
57
- }
48
+ loadLatestSnapshot(): HealthSnapshot | null {
49
+ const dir = this.healthDir();
50
+ if (!fs.existsSync(dir)) return null;
51
+ const snapshots = this.loadAllSnapshots();
52
+ if (snapshots.length === 0) return null;
53
+ // Sort by timestamp descending (most recent first)
54
+ snapshots.sort((a, b) => b.timestamp - a.timestamp);
55
+ return snapshots[0];
56
+ }
58
57
 
59
- loadAllSnapshots(): HealthSnapshot[] {
60
- const dir = this.healthDir();
61
- if (!fs.existsSync(dir)) return [];
62
- const snapshots = fs.readdirSync(dir)
63
- .filter(f => f.endsWith(".json"))
64
- .map(f => {
65
- try {
66
- return JSON.parse(fs.readFileSync(path.join(dir, f), "utf8"));
67
- } catch {
68
- return null;
69
- }
70
- })
71
- .filter(Boolean) as HealthSnapshot[];
72
- // Sort by timestamp ascending (oldest first) for consistent ordering
73
- snapshots.sort((a, b) => a.timestamp - b.timestamp);
74
- return snapshots;
75
- }
76
- }
58
+ loadAllSnapshots(): HealthSnapshot[] {
59
+ const dir = this.healthDir();
60
+ if (!fs.existsSync(dir)) return [];
61
+ const snapshots = fs
62
+ .readdirSync(dir)
63
+ .filter((f) => f.endsWith(".json"))
64
+ .map((f) => {
65
+ try {
66
+ return JSON.parse(fs.readFileSync(path.join(dir, f), "utf8"));
67
+ } catch {
68
+ return null;
69
+ }
70
+ })
71
+ .filter(Boolean) as HealthSnapshot[];
72
+ // Sort by timestamp ascending (oldest first) for consistent ordering
73
+ snapshots.sort((a, b) => a.timestamp - b.timestamp);
74
+ return snapshots;
75
+ }
76
+ }
@@ -91,4 +91,4 @@ async function getInstinctRecommendations() {
91
91
  } catch {
92
92
  return [];
93
93
  }
94
- }
94
+ }
@@ -48,4 +48,4 @@ export function resetHookStats(): void {
48
48
  tasksFailed = 0;
49
49
  runsCompleted = 0;
50
50
  runsFailed = 0;
51
- }
51
+ }
@@ -1,6 +1,6 @@
1
+ import { randomUUID } from "node:crypto";
1
2
  import * as fs from "node:fs";
2
3
  import * as path from "node:path";
3
- import { randomUUID } from "node:crypto";
4
4
 
5
5
  /**
6
6
  * Represents a learned instinct that guides agent behavior.
@@ -138,7 +138,10 @@ export class InstinctStore {
138
138
  if (!scope || scope === "project") {
139
139
  const projectsDir = path.join(this.crewRoot, "instincts", "projects");
140
140
  if (fs.existsSync(projectsDir)) {
141
- for (const projectId of fs.readdirSync(projectsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name)) {
141
+ for (const projectId of fs
142
+ .readdirSync(projectsDir, { withFileTypes: true })
143
+ .filter((e) => e.isDirectory())
144
+ .map((e) => e.name)) {
142
145
  const filePath = path.join(projectsDir, projectId, INSTINCT_FILE);
143
146
  results.push(...this.readInstinctsFromFile(filePath));
144
147
  }
@@ -176,7 +179,10 @@ export class InstinctStore {
176
179
  // Search in all project instinct files
177
180
  const projectsDir = path.join(this.crewRoot, "instincts", "projects");
178
181
  if (fs.existsSync(projectsDir)) {
179
- for (const projectId of fs.readdirSync(projectsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name)) {
182
+ for (const projectId of fs
183
+ .readdirSync(projectsDir, { withFileTypes: true })
184
+ .filter((e) => e.isDirectory())
185
+ .map((e) => e.name)) {
180
186
  const filePath = path.join(projectsDir, projectId, INSTINCT_FILE);
181
187
  const instincts = this.readInstinctsFromFile(filePath);
182
188
  const index = instincts.findIndex((i) => i.id === instinctId);
@@ -229,7 +235,10 @@ export class InstinctStore {
229
235
  // Search in project instincts
230
236
  const projectsDir = path.join(this.crewRoot, "instincts", "projects");
231
237
  if (fs.existsSync(projectsDir)) {
232
- for (const projectId of fs.readdirSync(projectsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name)) {
238
+ for (const projectId of fs
239
+ .readdirSync(projectsDir, { withFileTypes: true })
240
+ .filter((e) => e.isDirectory())
241
+ .map((e) => e.name)) {
233
242
  const filePath = path.join(projectsDir, projectId, INSTINCT_FILE);
234
243
  instincts = this.readInstinctsFromFile(filePath);
235
244
  index = instincts.findIndex((i) => i.id === instinctId);
@@ -246,4 +255,7 @@ export class InstinctStore {
246
255
  }
247
256
  }
248
257
 
249
- export { getGlobalStorageDir, getProjectStorageDir } from "../utils/project-detector.ts";
258
+ export {
259
+ getGlobalStorageDir,
260
+ getProjectStorageDir,
261
+ } from "../utils/project-detector.ts";
@@ -1,6 +1,6 @@
1
1
  import * as fs from "node:fs";
2
- import { redactJsonLine } from "../utils/redaction.ts";
3
2
  import { logInternalError } from "../utils/internal-error.ts";
3
+ import { redactJsonLine } from "../utils/redaction.ts";
4
4
 
5
5
  export interface DrainableSource {
6
6
  pause(): void;
@@ -1,10 +1,10 @@
1
+ import { randomUUID, timingSafeEqual } from "node:crypto";
1
2
  import * as fs from "node:fs";
2
3
  import * as path from "node:path";
3
- import { randomUUID, timingSafeEqual } from "node:crypto";
4
- import type { TeamRunManifest } from "./types.ts";
5
4
  import { DEFAULT_LOCKS } from "../config/defaults.ts";
6
5
  import { sleepSync } from "../utils/sleep.ts";
7
6
  import { isSymlinkSafePath } from "./atomic-write.ts";
7
+ import type { TeamRunManifest } from "./types.ts";
8
8
 
9
9
  export interface RunLockOptions {
10
10
  staleMs?: number;
@@ -16,8 +16,6 @@ function lockPath(manifest: TeamRunManifest): string {
16
16
  return path.join(manifest.stateRoot, "run.lock");
17
17
  }
18
18
 
19
-
20
-
21
19
  function parseCreatedAtFromLock(raw: string): number | undefined {
22
20
  try {
23
21
  const payload = JSON.parse(raw) as unknown;
@@ -112,7 +110,9 @@ function readLockSnapshot(filePath: string, staleMs: number): { canSteal: boolea
112
110
  isAlive = false;
113
111
  }
114
112
  }
115
- } catch { /* malformed payload — keep isAlive=true */ }
113
+ } catch {
114
+ /* malformed payload — keep isAlive=true */
115
+ }
116
116
  // Steal if stale OR holder dead — matches the original intent.
117
117
  return { canSteal: isStale || !isAlive };
118
118
  }
@@ -148,7 +148,15 @@ function writeLockFile(filePath: string, token: string, kind: LockKind = "file")
148
148
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
149
149
  const fd = fs.openSync(filePath, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL, 0o600);
150
150
  try {
151
- fs.writeSync(fd, JSON.stringify({ kind, pid: process.pid, createdAt: new Date().toISOString(), token }));
151
+ fs.writeSync(
152
+ fd,
153
+ JSON.stringify({
154
+ kind,
155
+ pid: process.pid,
156
+ createdAt: new Date().toISOString(),
157
+ token,
158
+ }),
159
+ );
152
160
  } finally {
153
161
  fs.closeSync(fd);
154
162
  }
@@ -198,7 +206,9 @@ function releaseLock(filePath: string, token: string): void {
198
206
  let isSymlink = false;
199
207
  try {
200
208
  isSymlink = fs.lstatSync(filePath).isSymbolicLink();
201
- } catch { /* file doesn't exist — that's fine, we'll handle ENOENT below */ }
209
+ } catch {
210
+ /* file doesn't exist — that's fine, we'll handle ENOENT below */
211
+ }
202
212
  if (isSymlink) return;
203
213
 
204
214
  const stored = readLockToken(filePath);
@@ -240,7 +250,9 @@ function acquireLockWithRetry(filePath: string, staleMs: number, kind: LockKind
240
250
  // Stale or dead holder — forcibly remove the lock.
241
251
  try {
242
252
  fs.rmSync(filePath, { force: true });
243
- } catch { /* race — let loop retry */ }
253
+ } catch {
254
+ /* race — let loop retry */
255
+ }
244
256
  sleepSync(Math.min(250, 25 * 2 ** attempt));
245
257
  attempt++;
246
258
  }
@@ -273,7 +285,9 @@ async function acquireLockWithRetryAsync(filePath: string, staleMs: number, kind
273
285
  // Stale or dead holder — forcibly remove the lock.
274
286
  try {
275
287
  fs.rmSync(filePath, { force: true });
276
- } catch { /* race — let loop retry */ }
288
+ } catch {
289
+ /* race — let loop retry */
290
+ }
277
291
  const delay = Math.min(250, 25 * 2 ** attempt);
278
292
  await sleep(delay);
279
293
  attempt++;
@@ -1,13 +1,13 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
- import type { TeamRunManifest } from "./types.ts";
4
- import { resolveRealContainedPath } from "../utils/safe-paths.ts";
5
- import { redactSecrets } from "../utils/redaction.ts";
3
+ import { DEFAULT_MAILBOX } from "../config/defaults.ts";
6
4
  import { logInternalError } from "../utils/internal-error.ts";
5
+ import { redactSecrets } from "../utils/redaction.ts";
6
+ import { resolveRealContainedPath } from "../utils/safe-paths.ts";
7
7
  import { atomicWriteFile } from "./atomic-write.ts";
8
8
  import { withEventLogLockSync } from "./event-log.ts";
9
9
  import { withFileLockSync } from "./locks.ts";
10
- import { DEFAULT_MAILBOX } from "../config/defaults.ts";
10
+ import type { TeamRunManifest } from "./types.ts";
11
11
 
12
12
  export type MailboxDirection = "inbox" | "outbox";
13
13
  export type MailboxMessageStatus = "queued" | "delivered" | "acknowledged";
@@ -81,7 +81,9 @@ function safeMailboxDir(manifest: TeamRunManifest, create = false): string {
81
81
  const realDir = fs.realpathSync(path.dirname(dir));
82
82
  const correctedDir = path.join(realDir, path.basename(dir));
83
83
  fs.mkdirSync(correctedDir, { recursive: true });
84
- } catch { throw error; }
84
+ } catch {
85
+ throw error;
86
+ }
85
87
  } else {
86
88
  throw error;
87
89
  }
@@ -104,7 +106,8 @@ function safeMailboxDir(manifest: TeamRunManifest, create = false): string {
104
106
  }
105
107
 
106
108
  function safeTaskId(taskId: string): string {
107
- if (!/^[\w.-]+$/.test(taskId) || taskId.includes("..") || path.isAbsolute(taskId)) throw new Error(`Invalid mailbox task id: ${taskId}`);
109
+ if (!/^[\w.-]+$/.test(taskId) || taskId.includes("..") || path.isAbsolute(taskId))
110
+ throw new Error(`Invalid mailbox task id: ${taskId}`);
108
111
  return taskId;
109
112
  }
110
113
 
@@ -130,7 +133,9 @@ function taskMailboxDir(manifest: TeamRunManifest, taskId: string, create = fals
130
133
  }
131
134
 
132
135
  function mailboxPath(manifest: TeamRunManifest, direction: MailboxDirection, taskId?: string, create = false): string {
133
- return taskId ? path.join(taskMailboxDir(manifest, taskId, create), `${direction}.jsonl`) : path.join(safeMailboxDir(manifest, create), `${direction}.jsonl`);
136
+ return taskId
137
+ ? path.join(taskMailboxDir(manifest, taskId, create), `${direction}.jsonl`)
138
+ : path.join(safeMailboxDir(manifest, create), `${direction}.jsonl`);
134
139
  }
135
140
 
136
141
  function deliveryPath(manifest: TeamRunManifest, create = false): string {
@@ -221,11 +226,41 @@ function isDeliveryMode(value: unknown): value is MailboxDeliveryMode {
221
226
  function parseMailboxMessage(raw: unknown, expectedDirection: MailboxDirection): MailboxMessage | undefined {
222
227
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) return undefined;
223
228
  const obj = raw as Record<string, unknown>;
224
- if (typeof obj.id !== "string" || typeof obj.runId !== "string" || !isDirection(obj.direction) || typeof obj.from !== "string" || typeof obj.to !== "string" || typeof obj.body !== "string" || typeof obj.createdAt !== "string" || !isStatus(obj.status)) return undefined;
229
+ if (
230
+ typeof obj.id !== "string" ||
231
+ typeof obj.runId !== "string" ||
232
+ !isDirection(obj.direction) ||
233
+ typeof obj.from !== "string" ||
234
+ typeof obj.to !== "string" ||
235
+ typeof obj.body !== "string" ||
236
+ typeof obj.createdAt !== "string" ||
237
+ !isStatus(obj.status)
238
+ )
239
+ return undefined;
225
240
  if (obj.direction !== expectedDirection) return undefined;
226
- const data = obj.data && typeof obj.data === "object" && !Array.isArray(obj.data) ? obj.data as Record<string, unknown> : undefined;
241
+ const data = obj.data && typeof obj.data === "object" && !Array.isArray(obj.data) ? (obj.data as Record<string, unknown>) : undefined;
227
242
  const dataKind = data?.kind;
228
- return { id: obj.id, runId: obj.runId, direction: obj.direction, from: obj.from, to: obj.to, body: obj.body, createdAt: obj.createdAt, status: obj.status, kind: isKind(obj.kind) ? obj.kind : isKind(dataKind) ? dataKind : undefined, priority: isPriority(obj.priority) ? obj.priority : undefined, deliveryMode: isDeliveryMode(obj.deliveryMode) ? obj.deliveryMode : undefined, taskId: typeof obj.taskId === "string" ? obj.taskId : undefined, acknowledgedAt: typeof obj.acknowledgedAt === "string" ? obj.acknowledgedAt : undefined, data, replyTo: typeof obj.replyTo === "string" ? obj.replyTo : undefined, replyFrom: typeof obj.replyFrom === "string" ? obj.replyFrom : undefined, replyDeadline: typeof obj.replyDeadline === "number" ? obj.replyDeadline : undefined, repliedAt: typeof obj.repliedAt === "string" ? obj.repliedAt : undefined, replyContent: typeof obj.replyContent === "string" ? obj.replyContent : undefined };
243
+ return {
244
+ id: obj.id,
245
+ runId: obj.runId,
246
+ direction: obj.direction,
247
+ from: obj.from,
248
+ to: obj.to,
249
+ body: obj.body,
250
+ createdAt: obj.createdAt,
251
+ status: obj.status,
252
+ kind: isKind(obj.kind) ? obj.kind : isKind(dataKind) ? dataKind : undefined,
253
+ priority: isPriority(obj.priority) ? obj.priority : undefined,
254
+ deliveryMode: isDeliveryMode(obj.deliveryMode) ? obj.deliveryMode : undefined,
255
+ taskId: typeof obj.taskId === "string" ? obj.taskId : undefined,
256
+ acknowledgedAt: typeof obj.acknowledgedAt === "string" ? obj.acknowledgedAt : undefined,
257
+ data,
258
+ replyTo: typeof obj.replyTo === "string" ? obj.replyTo : undefined,
259
+ replyFrom: typeof obj.replyFrom === "string" ? obj.replyFrom : undefined,
260
+ replyDeadline: typeof obj.replyDeadline === "number" ? obj.replyDeadline : undefined,
261
+ repliedAt: typeof obj.repliedAt === "string" ? obj.repliedAt : undefined,
262
+ replyContent: typeof obj.replyContent === "string" ? obj.replyContent : undefined,
263
+ };
229
264
  }
230
265
 
231
266
  function readMailboxFile(filePath: string, direction: MailboxDirection): MailboxMessage[] {
@@ -308,13 +343,21 @@ function pruneOldMailboxArchives(mailboxFilePath: string): void {
308
343
  }
309
344
  }
310
345
 
311
- export function readMailbox(manifest: TeamRunManifest, direction?: MailboxDirection, taskId?: string, kind?: MailboxMessageKind): MailboxMessage[] {
312
- const directions = direction ? [direction] : ["inbox", "outbox"] as const;
313
- return directions.flatMap((item) => safeReadMailboxFile(mailboxFile(manifest, item, taskId), item)).filter((msg) => !kind || msg.kind === kind).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
346
+ export function readMailbox(
347
+ manifest: TeamRunManifest,
348
+ direction?: MailboxDirection,
349
+ taskId?: string,
350
+ kind?: MailboxMessageKind,
351
+ ): MailboxMessage[] {
352
+ const directions = direction ? [direction] : (["inbox", "outbox"] as const);
353
+ return directions
354
+ .flatMap((item) => safeReadMailboxFile(mailboxFile(manifest, item, taskId), item))
355
+ .filter((msg) => !kind || msg.kind === kind)
356
+ .sort((a, b) => a.createdAt.localeCompare(b.createdAt));
314
357
  }
315
358
 
316
359
  export function readAllMailboxMessages(manifest: TeamRunManifest, direction?: MailboxDirection, signal?: AbortSignal): MailboxMessage[] {
317
- const directions = direction ? [direction] : ["inbox", "outbox"] as const;
360
+ const directions = direction ? [direction] : (["inbox", "outbox"] as const);
318
361
  return directions.flatMap((item) => readAllMessages(manifest, item, signal)).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
319
362
  }
320
363
 
@@ -344,7 +387,10 @@ export function readDeliveryState(manifest: TeamRunManifest): MailboxDeliverySta
344
387
  if (obj.messages && typeof obj.messages === "object" && !Array.isArray(obj.messages)) {
345
388
  for (const [id, status] of Object.entries(obj.messages)) if (isStatus(status)) messages[id] = status;
346
389
  }
347
- return { messages, updatedAt: typeof obj.updatedAt === "string" ? obj.updatedAt : new Date().toISOString() };
390
+ return {
391
+ messages,
392
+ updatedAt: typeof obj.updatedAt === "string" ? obj.updatedAt : new Date().toISOString(),
393
+ };
348
394
  } catch {
349
395
  return { messages: {}, updatedAt: new Date().toISOString() };
350
396
  }
@@ -377,7 +423,13 @@ function writeDeliveryState(manifest: TeamRunManifest, state: MailboxDeliverySta
377
423
  * If pi-crew ever exposes mailbox writes to external/untrusted input, sender
378
424
  * authentication (HMAC or session key) must be added.
379
425
  */
380
- export function appendMailboxMessage(manifest: TeamRunManifest, message: Omit<MailboxMessage, "id" | "runId" | "createdAt" | "status"> & { id?: string; status?: MailboxMessageStatus }): MailboxMessage {
426
+ export function appendMailboxMessage(
427
+ manifest: TeamRunManifest,
428
+ message: Omit<MailboxMessage, "id" | "runId" | "createdAt" | "status"> & {
429
+ id?: string;
430
+ status?: MailboxMessageStatus;
431
+ },
432
+ ): MailboxMessage {
381
433
  if (message.taskId) ensureTaskMailbox(manifest, message.taskId);
382
434
  else ensureRunMailbox(manifest);
383
435
  const createdAt = new Date().toISOString();
@@ -403,7 +455,11 @@ export function appendMailboxMessage(manifest: TeamRunManifest, message: Omit<Ma
403
455
  };
404
456
  // H2 fix: wrap append in cross-process lock to prevent interleaving on Windows.
405
457
  withEventLogLockSync(mailboxFile(manifest, complete.direction, complete.taskId), () => {
406
- fs.appendFileSync(mailboxFile(manifest, complete.direction, complete.taskId), `${JSON.stringify(redactSecrets(complete))}\n`, "utf-8");
458
+ fs.appendFileSync(
459
+ mailboxFile(manifest, complete.direction, complete.taskId),
460
+ `${JSON.stringify(redactSecrets(complete))}\n`,
461
+ "utf-8",
462
+ );
407
463
  });
408
464
  // 3.3 — rotate mailbox file if it has grown past 10 MB. Cheap stat
409
465
  // check; rotates at most once per append.
@@ -421,16 +477,64 @@ export function appendMailboxMessage(manifest: TeamRunManifest, message: Omit<Ma
421
477
  return complete;
422
478
  }
423
479
 
424
- export function appendSteeringMessage(manifest: TeamRunManifest, input: { taskId: string; body: string; from?: string; to?: string; priority?: MailboxMessagePriority; status?: MailboxMessageStatus; data?: Record<string, unknown> }): MailboxMessage {
425
- return appendMailboxMessage(manifest, { direction: "inbox", from: input.from ?? "leader", to: input.to ?? input.taskId, taskId: input.taskId, body: input.body, kind: "steer", priority: input.priority ?? "urgent", deliveryMode: "interrupt", status: input.status, data: { ...(input.data ?? {}), kind: "steer" } });
480
+ export function appendSteeringMessage(
481
+ manifest: TeamRunManifest,
482
+ input: {
483
+ taskId: string;
484
+ body: string;
485
+ from?: string;
486
+ to?: string;
487
+ priority?: MailboxMessagePriority;
488
+ status?: MailboxMessageStatus;
489
+ data?: Record<string, unknown>;
490
+ },
491
+ ): MailboxMessage {
492
+ return appendMailboxMessage(manifest, {
493
+ direction: "inbox",
494
+ from: input.from ?? "leader",
495
+ to: input.to ?? input.taskId,
496
+ taskId: input.taskId,
497
+ body: input.body,
498
+ kind: "steer",
499
+ priority: input.priority ?? "urgent",
500
+ deliveryMode: "interrupt",
501
+ status: input.status,
502
+ data: { ...(input.data ?? {}), kind: "steer" },
503
+ });
426
504
  }
427
505
 
428
- export function appendFollowUpMessage(manifest: TeamRunManifest, input: { taskId: string; body: string; from?: string; to?: string; priority?: MailboxMessagePriority; status?: MailboxMessageStatus; data?: Record<string, unknown> }): MailboxMessage {
429
- return appendMailboxMessage(manifest, { direction: "inbox", from: input.from ?? "leader", to: input.to ?? input.taskId, taskId: input.taskId, body: input.body, kind: "follow-up", priority: input.priority ?? "normal", deliveryMode: "next_turn", status: input.status, data: { ...(input.data ?? {}), kind: "follow-up" } });
506
+ export function appendFollowUpMessage(
507
+ manifest: TeamRunManifest,
508
+ input: {
509
+ taskId: string;
510
+ body: string;
511
+ from?: string;
512
+ to?: string;
513
+ priority?: MailboxMessagePriority;
514
+ status?: MailboxMessageStatus;
515
+ data?: Record<string, unknown>;
516
+ },
517
+ ): MailboxMessage {
518
+ return appendMailboxMessage(manifest, {
519
+ direction: "inbox",
520
+ from: input.from ?? "leader",
521
+ to: input.to ?? input.taskId,
522
+ taskId: input.taskId,
523
+ body: input.body,
524
+ kind: "follow-up",
525
+ priority: input.priority ?? "normal",
526
+ deliveryMode: "next_turn",
527
+ status: input.status,
528
+ data: { ...(input.data ?? {}), kind: "follow-up" },
529
+ });
430
530
  }
431
531
 
432
532
  export function listMailboxByKind(manifest: TeamRunManifest, kind: MailboxMessageKind, direction?: MailboxDirection): MailboxMessage[] {
433
- const messages = direction ? readAllMessages(manifest, direction) : [...readAllMessages(manifest, "inbox"), ...readAllMessages(manifest, "outbox")].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
533
+ const messages = direction
534
+ ? readAllMessages(manifest, direction)
535
+ : [...readAllMessages(manifest, "inbox"), ...readAllMessages(manifest, "outbox")].sort((a, b) =>
536
+ a.createdAt.localeCompare(b.createdAt),
537
+ );
434
538
  return messages.filter((message) => message.kind === kind || message.data?.kind === kind);
435
539
  }
436
540
 
@@ -464,16 +568,25 @@ export function updateMailboxMessageReply(manifest: TeamRunManifest, originalMes
464
568
  const directions: MailboxDirection[] = ["inbox", "outbox"];
465
569
 
466
570
  // Collect all mailbox file paths (global + task-specific)
467
- const filesToSearch: Array<{ filePath: string; direction: MailboxDirection }> = [];
571
+ const filesToSearch: Array<{
572
+ filePath: string;
573
+ direction: MailboxDirection;
574
+ }> = [];
468
575
  for (const direction of directions) {
469
- filesToSearch.push({ filePath: mailboxFile(manifest, direction), direction });
576
+ filesToSearch.push({
577
+ filePath: mailboxFile(manifest, direction),
578
+ direction,
579
+ });
470
580
  }
471
581
  const tasksDir = safeMailboxTasksRoot(manifest);
472
582
  if (fs.existsSync(tasksDir)) {
473
583
  for (const entry of fs.readdirSync(tasksDir, { withFileTypes: true })) {
474
584
  if (!entry.isDirectory()) continue;
475
585
  for (const direction of directions) {
476
- filesToSearch.push({ filePath: mailboxFile(manifest, direction, entry.name), direction });
586
+ filesToSearch.push({
587
+ filePath: mailboxFile(manifest, direction, entry.name),
588
+ direction,
589
+ });
477
590
  }
478
591
  }
479
592
  }
@@ -517,7 +630,9 @@ export function replayPendingMailboxMessages(manifest: TeamRunManifest): Mailbox
517
630
  // clobber concurrent appends/acknowledgments. FIX: wrap in a file lock.
518
631
  return withFileLockSync(deliveryFile(manifest, true), () => {
519
632
  const delivery = readDeliveryState(manifest);
520
- const pending = readAllInboxMessages(manifest).filter((message) => message.status !== "acknowledged" && delivery.messages[message.id] !== "acknowledged");
633
+ const pending = readAllInboxMessages(manifest).filter(
634
+ (message) => message.status !== "acknowledged" && delivery.messages[message.id] !== "acknowledged",
635
+ );
521
636
  if (!pending.length) return { messages: [], updatedAt: delivery.updatedAt };
522
637
  const updatedAt = new Date().toISOString();
523
638
  for (const message of pending) delivery.messages[message.id] = "delivered";
@@ -527,7 +642,10 @@ export function replayPendingMailboxMessages(manifest: TeamRunManifest): Mailbox
527
642
  });
528
643
  }
529
644
 
530
- export function validateMailbox(manifest: TeamRunManifest, options: { repair?: boolean; signal?: AbortSignal } = {}): MailboxValidationReport {
645
+ export function validateMailbox(
646
+ manifest: TeamRunManifest,
647
+ options: { repair?: boolean; signal?: AbortSignal } = {},
648
+ ): MailboxValidationReport {
531
649
  ensureRunMailbox(manifest);
532
650
  const issues: MailboxValidationIssue[] = [];
533
651
  const repaired: string[] = [];
@@ -564,7 +682,12 @@ export function validateMailbox(manifest: TeamRunManifest, options: { repair?: b
564
682
  const allMessages = readMailbox(manifest);
565
683
  for (const message of allMessages) {
566
684
  if (options.signal?.aborted) break;
567
- if (!delivery.messages[message.id]) issues.push({ level: "warning", path: deliveryFile(manifest), message: `Missing delivery entry for ${message.id}.` });
685
+ if (!delivery.messages[message.id])
686
+ issues.push({
687
+ level: "warning",
688
+ path: deliveryFile(manifest),
689
+ message: `Missing delivery entry for ${message.id}.`,
690
+ });
568
691
  }
569
692
  if (options.repair) {
570
693
  for (const message of allMessages) delivery.messages[message.id] ??= message.status;
@@ -8,8 +8,8 @@
8
8
  * Actual capture hooks into the lifecycle events (Pattern 12).
9
9
  */
10
10
 
11
- import { readFileSync, existsSync, appendFileSync } from "node:fs";
12
11
  import * as fs from "node:fs";
12
+ import { appendFileSync, existsSync, readFileSync } from "node:fs";
13
13
  import * as path from "node:path";
14
14
  import { logInternalError } from "../utils/internal-error.ts";
15
15
  import { atomicWriteJson } from "./atomic-write.ts";
@@ -40,7 +40,7 @@ export interface CompressedObservation {
40
40
  export interface ObservationStoreConfig {
41
41
  maxObservations: number;
42
42
  maxCompressed: number;
43
- privacyTags: string[]; // tags to strip before storage
43
+ privacyTags: string[]; // tags to strip before storage
44
44
  }
45
45
 
46
46
  const DEFAULT_CONFIG: ObservationStoreConfig = {
@@ -127,9 +127,7 @@ export class ObservationStore {
127
127
  * Get compressed observations for injection.
128
128
  */
129
129
  getCompressed(limit = 5): CompressedObservation[] {
130
- return this.compressed
131
- .sort((a, b) => b.relevanceScore - a.relevanceScore)
132
- .slice(0, limit);
130
+ return this.compressed.sort((a, b) => b.relevanceScore - a.relevanceScore).slice(0, limit);
133
131
  }
134
132
 
135
133
  /**
@@ -139,14 +137,19 @@ export class ObservationStore {
139
137
  const items = this.getCompressed(limit);
140
138
  if (items.length === 0) return "";
141
139
 
142
- return "## Observations from Previous Sessions\n\n" +
143
- items.map((o) =>
144
- `### ${o.summary}\n` +
145
- `Patterns: ${o.patterns.join(", ")}\n` +
146
- `Decisions: ${o.decisions.join(", ")}\n` +
147
- `Files: ${o.filesAffected.join(", ")}`,
148
- ).join("\n\n") +
149
- "\n";
140
+ return (
141
+ "## Observations from Previous Sessions\n\n" +
142
+ items
143
+ .map(
144
+ (o) =>
145
+ `### ${o.summary}\n` +
146
+ `Patterns: ${o.patterns.join(", ")}\n` +
147
+ `Decisions: ${o.decisions.join(", ")}\n` +
148
+ `Files: ${o.filesAffected.join(", ")}`,
149
+ )
150
+ .join("\n\n") +
151
+ "\n"
152
+ );
150
153
  }
151
154
 
152
155
  /**
@@ -167,7 +170,10 @@ export class ObservationStore {
167
170
  }
168
171
 
169
172
  get stats(): { observations: number; compressed: number } {
170
- return { observations: this.observations.length, compressed: this.compressed.length };
173
+ return {
174
+ observations: this.observations.length,
175
+ compressed: this.compressed.length,
176
+ };
171
177
  }
172
178
 
173
179
  private load(): void {