pi-crew 0.9.15 → 0.9.17

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 (432) hide show
  1. package/CHANGELOG.md +145 -0
  2. package/README.md +19 -0
  3. package/dist/build-meta.json +21790 -0
  4. package/dist/index.mjs +83070 -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/patterns/command-agent-skill.md +1 -1
  14. package/docs/skills/REFERENCE.md +0 -17
  15. package/docs//303/242mmaAAA/303/242 +357 -0
  16. package/index.bundle.ts +25 -0
  17. package/index.ts +95 -4
  18. package/package.json +15 -4
  19. package/skills/iterative-audit/SKILL.md +0 -1
  20. package/skills/widget-rendering/SKILL.md +17 -0
  21. package/src/adapters/claude-adapter.ts +1 -3
  22. package/src/adapters/export-util.ts +16 -16
  23. package/src/adapters/index.ts +5 -5
  24. package/src/agents/agent-config.ts +20 -14
  25. package/src/agents/agent-serializer.ts +1 -1
  26. package/src/agents/discover-agents.ts +83 -39
  27. package/src/benchmark/benchmark-runner.ts +51 -51
  28. package/src/benchmark/feedback-loop.ts +1 -1
  29. package/src/config/config.ts +166 -590
  30. package/src/config/defaults.ts +28 -2
  31. package/src/config/drift-detector.ts +11 -14
  32. package/src/config/markers.ts +201 -203
  33. package/src/config/resilient-parser.ts +14 -6
  34. package/src/config/role-tools.ts +3 -3
  35. package/src/config/suggestions.ts +5 -12
  36. package/src/config/types.ts +9 -25
  37. package/src/errors.ts +151 -157
  38. package/src/extension/action-suggestions.ts +54 -9
  39. package/src/extension/async-notifier.ts +43 -13
  40. package/src/extension/autonomous-policy.ts +77 -37
  41. package/src/extension/command-completions.ts +9 -8
  42. package/src/extension/context-status-injection.ts +14 -12
  43. package/src/extension/crew-autocomplete.ts +8 -16
  44. package/src/extension/crew-cleanup.ts +2 -1
  45. package/src/extension/crew-shortcuts.ts +9 -6
  46. package/src/extension/cross-extension-rpc.ts +136 -42
  47. package/src/extension/help.ts +1 -1
  48. package/src/extension/import-index.ts +10 -5
  49. package/src/extension/knowledge-injection.ts +88 -15
  50. package/src/extension/management.ts +89 -349
  51. package/src/extension/message-renderers.ts +3 -4
  52. package/src/extension/notification-router.ts +22 -5
  53. package/src/extension/notification-sink.ts +6 -3
  54. package/src/extension/pi-api.ts +17 -8
  55. package/src/extension/plan-orchestrate.ts +8 -27
  56. package/src/extension/project-init.ts +21 -6
  57. package/src/extension/register.ts +329 -975
  58. package/src/extension/registration/artifact-cleanup.ts +9 -4
  59. package/src/extension/registration/command-utils.ts +5 -1
  60. package/src/extension/registration/commands.ts +806 -314
  61. package/src/extension/registration/compaction-guard.ts +15 -15
  62. package/src/extension/registration/lifecycle.ts +259 -0
  63. package/src/extension/registration/observability.ts +293 -0
  64. package/src/extension/registration/subagent-helpers.ts +29 -7
  65. package/src/extension/registration/subagent-tools.ts +253 -44
  66. package/src/extension/registration/team-tool.ts +19 -84
  67. package/src/extension/registration/ui.ts +168 -0
  68. package/src/extension/registration/viewers.ts +64 -24
  69. package/src/extension/result-watcher.ts +18 -7
  70. package/src/extension/run-bundle-schema.ts +21 -6
  71. package/src/extension/run-export.ts +15 -6
  72. package/src/extension/run-import.ts +64 -29
  73. package/src/extension/run-index.ts +28 -9
  74. package/src/extension/run-maintenance.ts +32 -12
  75. package/src/extension/session-summary.ts +1 -1
  76. package/src/extension/team-manager-command.ts +64 -7
  77. package/src/extension/team-onboard.ts +151 -150
  78. package/src/extension/team-recommendation.ts +121 -21
  79. package/src/extension/team-tool/anchor.ts +31 -64
  80. package/src/extension/team-tool/api.ts +929 -141
  81. package/src/extension/team-tool/auto-summarize.ts +14 -26
  82. package/src/extension/team-tool/cache-control.ts +1 -5
  83. package/src/extension/team-tool/cancel.ts +138 -38
  84. package/src/extension/team-tool/chain-dispatch.ts +5 -13
  85. package/src/extension/team-tool/chain-executor.ts +29 -51
  86. package/src/extension/team-tool/config-patch.ts +1 -1
  87. package/src/extension/team-tool/context.ts +40 -20
  88. package/src/extension/team-tool/destructive-gate.ts +10 -5
  89. package/src/extension/team-tool/doctor.ts +170 -51
  90. package/src/extension/team-tool/explain.ts +228 -214
  91. package/src/extension/team-tool/failure-patterns.ts +3 -9
  92. package/src/extension/team-tool/goal-wrap.ts +71 -29
  93. package/src/extension/team-tool/goal.ts +185 -35
  94. package/src/extension/team-tool/handle-schedule.ts +34 -15
  95. package/src/extension/team-tool/handle-settings.ts +94 -56
  96. package/src/extension/team-tool/health-monitor.ts +27 -108
  97. package/src/extension/team-tool/inspect.ts +42 -9
  98. package/src/extension/team-tool/intent-policy.ts +4 -1
  99. package/src/extension/team-tool/lifecycle-actions.ts +244 -48
  100. package/src/extension/team-tool/orchestrate.ts +7 -18
  101. package/src/extension/team-tool/parallel-dispatch.ts +51 -29
  102. package/src/extension/team-tool/plan.ts +29 -5
  103. package/src/extension/team-tool/respond.ts +49 -16
  104. package/src/extension/team-tool/run-not-found.ts +3 -8
  105. package/src/extension/team-tool/run.ts +80 -317
  106. package/src/extension/team-tool/status.ts +135 -43
  107. package/src/extension/team-tool/workflow-manage.ts +92 -25
  108. package/src/extension/team-tool-types.ts +8 -1
  109. package/src/extension/team-tool.ts +142 -551
  110. package/src/extension/validate-resources.ts +39 -8
  111. package/src/hooks/registry.ts +66 -17
  112. package/src/hooks/types.ts +1 -1
  113. package/src/i18n.ts +25 -11
  114. package/src/observability/correlation.ts +17 -3
  115. package/src/observability/event-bus.ts +51 -56
  116. package/src/observability/event-to-metric.ts +117 -15
  117. package/src/observability/exporters/otlp-exporter.ts +56 -17
  118. package/src/observability/exporters/prometheus-exporter.ts +1 -1
  119. package/src/observability/metric-registry.ts +16 -4
  120. package/src/observability/metric-retention.ts +8 -2
  121. package/src/observability/metric-sink.ts +11 -3
  122. package/src/observability/metrics-primitives.ts +42 -9
  123. package/src/plugins/plugin-define.ts +2 -2
  124. package/src/plugins/plugin-registry.ts +25 -25
  125. package/src/plugins/plugins/index.ts +1 -1
  126. package/src/plugins/plugins/nextjs.ts +16 -16
  127. package/src/plugins/plugins/vite.ts +7 -11
  128. package/src/plugins/plugins/vitest.ts +6 -11
  129. package/src/runtime/adaptive-plan.ts +225 -40
  130. package/src/runtime/agent-control.ts +58 -15
  131. package/src/runtime/agent-memory.ts +15 -9
  132. package/src/runtime/agent-observability.ts +10 -2
  133. package/src/runtime/anchor-manager.ts +27 -25
  134. package/src/runtime/async-marker.ts +7 -1
  135. package/src/runtime/async-runner.ts +27 -23
  136. package/src/runtime/auto-summarize.ts +7 -13
  137. package/src/runtime/background-runner.ts +189 -251
  138. package/src/runtime/batch-barrier.ts +18 -16
  139. package/src/runtime/cancellation-token.ts +16 -6
  140. package/src/runtime/cancellation.ts +46 -8
  141. package/src/runtime/capability-inventory.ts +6 -4
  142. package/src/runtime/chain-parser.ts +44 -11
  143. package/src/runtime/chain-runner.ts +63 -69
  144. package/src/runtime/checkpoint.ts +12 -56
  145. package/src/runtime/child-pi.ts +343 -78
  146. package/src/runtime/coalesce-tasks.ts +268 -0
  147. package/src/runtime/code-summary.ts +71 -26
  148. package/src/runtime/compact-stages/index.ts +15 -5
  149. package/src/runtime/compact-stages/tail-capture-stage.ts +7 -2
  150. package/src/runtime/compact-stages/truncation-stage.ts +4 -1
  151. package/src/runtime/compaction-summary.ts +17 -10
  152. package/src/runtime/completion-guard.ts +33 -16
  153. package/src/runtime/crash-classification.ts +28 -7
  154. package/src/runtime/crash-recovery.ts +177 -37
  155. package/src/runtime/crew-agent-records.ts +193 -40
  156. package/src/runtime/crew-hooks.ts +9 -24
  157. package/src/runtime/cross-extension-rpc.ts +25 -23
  158. package/src/runtime/custom-tools/irc-tool.ts +43 -15
  159. package/src/runtime/custom-tools/submit-result-tool.ts +16 -5
  160. package/src/runtime/delivery-coordinator.ts +34 -7
  161. package/src/runtime/delta-conflict.ts +9 -21
  162. package/src/runtime/deterministic-ast.ts +1 -1
  163. package/src/runtime/diagnostic-export.ts +53 -20
  164. package/src/runtime/direct-run.ts +12 -2
  165. package/src/runtime/dwf-state-store.ts +1 -1
  166. package/src/runtime/dynamic-workflow-context.ts +186 -58
  167. package/src/runtime/dynamic-workflow-runner.ts +42 -20
  168. package/src/runtime/effectiveness.ts +16 -8
  169. package/src/runtime/errors/crew-errors.ts +7 -11
  170. package/src/runtime/event-stream-bridge.ts +9 -3
  171. package/src/runtime/foreground-control.ts +54 -14
  172. package/src/runtime/foreground-watchdog.ts +9 -6
  173. package/src/runtime/goal-achievement.ts +27 -10
  174. package/src/runtime/goal-evaluator.ts +54 -19
  175. package/src/runtime/goal-loop-runner.ts +280 -99
  176. package/src/runtime/goal-state-store.ts +27 -17
  177. package/src/runtime/green-contract.ts +11 -2
  178. package/src/runtime/group-join.ts +64 -31
  179. package/src/runtime/handoff-manager.ts +37 -42
  180. package/src/runtime/heartbeat-gradient.ts +10 -2
  181. package/src/runtime/heartbeat-watcher.ts +32 -6
  182. package/src/runtime/hidden-handoff.ts +12 -30
  183. package/src/runtime/important-line-classifier.ts +12 -2
  184. package/src/runtime/iteration-hooks.ts +25 -15
  185. package/src/runtime/live-agent-control.ts +55 -7
  186. package/src/runtime/live-agent-manager.ts +130 -27
  187. package/src/runtime/live-control-realtime.ts +23 -3
  188. package/src/runtime/live-irc.ts +4 -1
  189. package/src/runtime/live-session-health.ts +12 -4
  190. package/src/runtime/live-session-runtime.ts +379 -117
  191. package/src/runtime/manifest-cache.ts +28 -12
  192. package/src/runtime/mcp-proxy.ts +8 -16
  193. package/src/runtime/metric-parser.ts +1 -5
  194. package/src/runtime/model-fallback.ts +55 -18
  195. package/src/runtime/model-resolver.ts +2 -6
  196. package/src/runtime/model-scope.ts +19 -3
  197. package/src/runtime/notebook-helpers.ts +60 -62
  198. package/src/runtime/orphan-worker-registry.ts +37 -26
  199. package/src/runtime/output-validator.ts +18 -3
  200. package/src/runtime/overflow-recovery.ts +5 -4
  201. package/src/runtime/parallel-research.ts +29 -5
  202. package/src/runtime/parallel-utils.ts +9 -11
  203. package/src/runtime/path-overlap.ts +150 -0
  204. package/src/runtime/peer-dep.ts +12 -17
  205. package/src/runtime/per-write-validator.ts +1 -3
  206. package/src/runtime/phase-tracker.ts +342 -330
  207. package/src/runtime/pi-args.ts +26 -8
  208. package/src/runtime/pi-json-output.ts +1 -1
  209. package/src/runtime/pi-spawn.ts +30 -19
  210. package/src/runtime/pipeline-runner.ts +56 -55
  211. package/src/runtime/plan-templates.ts +5 -6
  212. package/src/runtime/policy-engine.ts +43 -7
  213. package/src/runtime/post-checks.ts +12 -4
  214. package/src/runtime/post-exit-stdio-guard.ts +2 -2
  215. package/src/runtime/process-lifecycle.ts +20 -10
  216. package/src/runtime/process-status.ts +16 -5
  217. package/src/runtime/progress-event-coalescer.ts +2 -1
  218. package/src/runtime/progress-tracker.ts +103 -103
  219. package/src/runtime/prose-compressor.ts +9 -11
  220. package/src/runtime/recovery-recipes.ts +118 -24
  221. package/src/runtime/replace.ts +25 -10
  222. package/src/runtime/resilient-edit.ts +10 -25
  223. package/src/runtime/result-extractor.ts +1 -2
  224. package/src/runtime/retry-executor.ts +20 -4
  225. package/src/runtime/retry-runner.ts +26 -50
  226. package/src/runtime/role-permission.ts +6 -1
  227. package/src/runtime/run-coalesced-task-group.ts +256 -0
  228. package/src/runtime/run-drift.ts +14 -15
  229. package/src/runtime/run-tracker.ts +6 -28
  230. package/src/runtime/runtime-policy.ts +1 -6
  231. package/src/runtime/runtime-resolver.ts +80 -15
  232. package/src/runtime/scheduler.ts +47 -18
  233. package/src/runtime/semaphore.ts +5 -7
  234. package/src/runtime/sensitive-paths.ts +2 -1
  235. package/src/runtime/session-usage.ts +1 -1
  236. package/src/runtime/settings-store.ts +16 -12
  237. package/src/runtime/sidechain-output.ts +6 -2
  238. package/src/runtime/single-agent-compose.ts +1 -4
  239. package/src/runtime/skill-effectiveness.ts +29 -97
  240. package/src/runtime/skill-instructions.ts +40 -83
  241. package/src/runtime/stale-reconciler.ts +73 -197
  242. package/src/runtime/stream-preview.ts +1 -1
  243. package/src/runtime/streaming-output.ts +1 -1
  244. package/src/runtime/subagent-manager.ts +86 -169
  245. package/src/runtime/subprocess-tool-registry.ts +4 -1
  246. package/src/runtime/supervisor-contact.ts +10 -5
  247. package/src/runtime/task-display.ts +19 -5
  248. package/src/runtime/task-graph-scheduler.ts +95 -21
  249. package/src/runtime/task-graph.ts +5 -11
  250. package/src/runtime/task-health.ts +54 -47
  251. package/src/runtime/task-id.ts +11 -18
  252. package/src/runtime/task-output-context.ts +265 -81
  253. package/src/runtime/task-packet.ts +12 -20
  254. package/src/runtime/task-quality.ts +6 -14
  255. package/src/runtime/task-runner/context-retrieval.ts +4 -13
  256. package/src/runtime/task-runner/live-executor.ts +114 -36
  257. package/src/runtime/task-runner/output-splitter.ts +152 -0
  258. package/src/runtime/task-runner/progress.ts +50 -12
  259. package/src/runtime/task-runner/prompt-builder.ts +31 -7
  260. package/src/runtime/task-runner/prompt-pipeline.ts +31 -7
  261. package/src/runtime/task-runner/result-utils.ts +3 -1
  262. package/src/runtime/task-runner/retrieval-orchestrator.ts +310 -0
  263. package/src/runtime/task-runner/run-projection.ts +27 -8
  264. package/src/runtime/task-runner/state-helpers.ts +29 -8
  265. package/src/runtime/task-runner/tail-read.ts +2 -6
  266. package/src/runtime/task-runner.ts +180 -326
  267. package/src/runtime/team-runner-artifacts.ts +13 -0
  268. package/src/runtime/team-runner.ts +456 -974
  269. package/src/runtime/tool-output-pruner.ts +6 -9
  270. package/src/runtime/tool-progress.ts +11 -21
  271. package/src/runtime/verification-gates.ts +33 -24
  272. package/src/runtime/verification-integrity.ts +1 -4
  273. package/src/runtime/verification-worktree.ts +62 -12
  274. package/src/runtime/worker-heartbeat.ts +5 -1
  275. package/src/runtime/worker-startup.ts +29 -5
  276. package/src/runtime/workflow-state.ts +17 -9
  277. package/src/runtime/workspace-lock.ts +30 -35
  278. package/src/runtime/workspace-tree.ts +20 -32
  279. package/src/runtime/yield-handler.ts +43 -9
  280. package/src/runtime/zombie-scanner.ts +5 -4
  281. package/src/schema/config-schema.ts +266 -172
  282. package/src/schema/team-tool-schema.ts +29 -74
  283. package/src/schema/validation-types.ts +25 -17
  284. package/src/skills/discover-skills.ts +35 -10
  285. package/src/skills/skill-templates.ts +109 -27
  286. package/src/skills/validate.ts +26 -8
  287. package/src/state/active-run-registry.ts +87 -28
  288. package/src/state/artifact-store.ts +9 -5
  289. package/src/state/atomic-write-v2.ts +85 -63
  290. package/src/state/atomic-write.ts +105 -26
  291. package/src/state/blob-store.ts +47 -20
  292. package/src/state/contracts.ts +20 -5
  293. package/src/state/crew-init.ts +5 -22
  294. package/src/state/decision-ledger.ts +19 -73
  295. package/src/state/event-log-rotation.ts +41 -15
  296. package/src/state/event-log.ts +168 -53
  297. package/src/state/event-reconstructor.ts +11 -1
  298. package/src/state/gitignore-manager.ts +2 -8
  299. package/src/state/health-store.ts +57 -57
  300. package/src/state/hook-instinct-bridge.ts +1 -1
  301. package/src/state/hook-integrations.ts +1 -1
  302. package/src/state/instinct-store.ts +17 -5
  303. package/src/state/jsonl-writer.ts +1 -1
  304. package/src/state/locks.ts +23 -9
  305. package/src/state/mailbox.ts +151 -28
  306. package/src/state/observation-store.ts +20 -14
  307. package/src/state/run-cache.ts +142 -135
  308. package/src/state/run-graph.ts +6 -15
  309. package/src/state/run-metrics.ts +5 -18
  310. package/src/state/schedule.ts +15 -9
  311. package/src/state/state-store.ts +129 -45
  312. package/src/state/task-claims.ts +12 -2
  313. package/src/state/tiered-eval.ts +52 -43
  314. package/src/state/types-eval.ts +2 -2
  315. package/src/state/types.ts +24 -20
  316. package/src/state/usage.ts +20 -4
  317. package/src/state/worker-atomic-writer.ts +6 -3
  318. package/src/subagents/index.ts +2 -2
  319. package/src/teams/discover-teams.ts +21 -6
  320. package/src/tools/safe-bash-extension.ts +5 -6
  321. package/src/tools/safe-bash.ts +10 -11
  322. package/src/types/new-api-types.ts +6 -10
  323. package/src/ui/agent-management-overlay.ts +52 -40
  324. package/src/ui/card-colors.ts +13 -4
  325. package/src/ui/crew-footer.ts +8 -7
  326. package/src/ui/crew-select-list.ts +1 -1
  327. package/src/ui/dashboard-panes/agents-pane.ts +41 -25
  328. package/src/ui/dashboard-panes/cancellation-pane.ts +1 -1
  329. package/src/ui/dashboard-panes/capability-pane.ts +32 -15
  330. package/src/ui/dashboard-panes/health-pane.ts +2 -1
  331. package/src/ui/dashboard-panes/metrics-pane.ts +4 -1
  332. package/src/ui/dashboard-panes/progress-pane.ts +12 -9
  333. package/src/ui/heartbeat-aggregator.ts +15 -4
  334. package/src/ui/keybinding-map.ts +40 -7
  335. package/src/ui/live-conversation-overlay.ts +36 -20
  336. package/src/ui/live-duration.ts +1 -4
  337. package/src/ui/live-run-sidebar.ts +88 -25
  338. package/src/ui/loaders.ts +2 -8
  339. package/src/ui/mascot.ts +20 -36
  340. package/src/ui/overlays/agent-picker-overlay.ts +11 -3
  341. package/src/ui/overlays/confirm-overlay.ts +4 -2
  342. package/src/ui/overlays/help-overlay.ts +25 -14
  343. package/src/ui/overlays/mailbox-compose-overlay.ts +48 -11
  344. package/src/ui/overlays/mailbox-compose-preview.ts +20 -5
  345. package/src/ui/overlays/mailbox-detail-overlay.ts +27 -6
  346. package/src/ui/pi-ui-compat.ts +7 -7
  347. package/src/ui/powerbar-publisher.ts +120 -42
  348. package/src/ui/render-diff.ts +10 -3
  349. package/src/ui/render-scheduler.ts +12 -4
  350. package/src/ui/run-action-dispatcher.ts +81 -18
  351. package/src/ui/run-dashboard.ts +172 -76
  352. package/src/ui/run-event-bus.ts +59 -37
  353. package/src/ui/run-snapshot-cache.ts +276 -86
  354. package/src/ui/settings-overlay.ts +361 -74
  355. package/src/ui/status-colors.ts +12 -1
  356. package/src/ui/syntax-highlight.ts +1 -1
  357. package/src/ui/theme-adapter.ts +16 -14
  358. package/src/ui/theme-discovery.ts +13 -2
  359. package/src/ui/tool-progress-formatter.ts +7 -7
  360. package/src/ui/tool-render.ts +128 -56
  361. package/src/ui/tool-renderers/brief-mode.ts +45 -27
  362. package/src/ui/tool-renderers/index.ts +109 -43
  363. package/src/ui/transcript-cache.ts +32 -6
  364. package/src/ui/transcript-entries.ts +25 -23
  365. package/src/ui/transcript-viewer.ts +78 -29
  366. package/src/ui/widget/index.ts +99 -40
  367. package/src/ui/widget/widget-formatters.ts +13 -6
  368. package/src/ui/widget/widget-model.ts +19 -8
  369. package/src/ui/widget/widget-renderer.ts +23 -13
  370. package/src/ui/widget/widget-types.ts +1 -1
  371. package/src/utils/bm25-search.ts +199 -199
  372. package/src/utils/conflict-detect.ts +22 -21
  373. package/src/utils/env-filter.ts +14 -7
  374. package/src/utils/file-coalescer.ts +5 -1
  375. package/src/utils/fingerprint.ts +3 -6
  376. package/src/utils/frontmatter.ts +3 -1
  377. package/src/utils/fs-watch.ts +2 -6
  378. package/src/utils/gh-protocol.ts +119 -44
  379. package/src/utils/git.ts +13 -15
  380. package/src/utils/guards.ts +2 -5
  381. package/src/utils/ids.ts +9 -2
  382. package/src/utils/incremental-reader.ts +14 -3
  383. package/src/utils/internal-error.ts +2 -1
  384. package/src/utils/names.ts +12 -3
  385. package/src/utils/paths.ts +49 -5
  386. package/src/utils/project-detector.ts +2 -2
  387. package/src/utils/redaction.ts +29 -19
  388. package/src/utils/resolve-shell.ts +9 -7
  389. package/src/utils/run-watcher-registry.ts +19 -31
  390. package/src/utils/safe-paths.ts +45 -24
  391. package/src/utils/scan-cache.ts +9 -2
  392. package/src/utils/session-utils.ts +2 -4
  393. package/src/utils/sleep.ts +12 -5
  394. package/src/utils/sse-parser.ts +5 -17
  395. package/src/utils/visual.ts +52 -32
  396. package/src/workflows/discover-workflows.ts +41 -109
  397. package/src/workflows/intermediate-store.ts +5 -21
  398. package/src/workflows/preflight-validator.ts +6 -33
  399. package/src/workflows/topology-analyzer.ts +5 -21
  400. package/src/workflows/workflow-config.ts +7 -6
  401. package/src/worktree/branch-freshness.ts +66 -8
  402. package/src/worktree/cleanup.ts +130 -20
  403. package/src/worktree/worktree-manager.ts +212 -69
  404. package/skills/artifact-analysis-loop/SKILL.md +0 -303
  405. package/skills/detection-pipeline-design/SKILL.md +0 -286
  406. package/skills/hunting-investigation-loop/SKILL.md +0 -402
  407. package/skills/incident-playbook-construction/SKILL.md +0 -384
  408. package/skills/security-review/SKILL.md +0 -561
  409. package/skills/threat-hypothesis-framework/SKILL.md +0 -176
  410. package/skills/ui-render-performance/SKILL.md +0 -58
  411. /package/docs/{followup-review-round3-2026-05-12.md → archive/followup-review-round3-2026-05-12.md} +0 -0
  412. /package/docs/{followup-review-round4-2026-05-13.md → archive/followup-review-round4-2026-05-13.md} +0 -0
  413. /package/docs/{pi-crew-bugs.md → archive/pi-crew-bugs.md} +0 -0
  414. /package/docs/{pi-crew-test-final.md → archive/pi-crew-test-final.md} +0 -0
  415. /package/docs/{pi-crew-test-results.md → archive/pi-crew-test-results.md} +0 -0
  416. /package/docs/{pi-crew-test-round2.md → archive/pi-crew-test-round2.md} +0 -0
  417. /package/docs/{pi-crew-test-round4.md → archive/pi-crew-test-round4.md} +0 -0
  418. /package/docs/{pi-crew-test-round5.md → archive/pi-crew-test-round5.md} +0 -0
  419. /package/docs/{pi-crew-test-round6.md → archive/pi-crew-test-round6.md} +0 -0
  420. /package/docs/{pi-crew-v0.5.10-audit-fix-plan.md → archive/pi-crew-v0.5.10-audit-fix-plan.md} +0 -0
  421. /package/docs/{pi-crew-v0.5.11-audit-fix-plan.md → archive/pi-crew-v0.5.11-audit-fix-plan.md} +0 -0
  422. /package/docs/{pi-crew-v0.5.12-audit-fix-plan.md → archive/pi-crew-v0.5.12-audit-fix-plan.md} +0 -0
  423. /package/docs/{pi-crew-v0.5.13-audit-fix-plan.md → archive/pi-crew-v0.5.13-audit-fix-plan.md} +0 -0
  424. /package/docs/{pi-crew-v0.5.14-audit-fix-plan.md → archive/pi-crew-v0.5.14-audit-fix-plan.md} +0 -0
  425. /package/docs/{pi-crew-v0.5.16-audit-fix-plan.md → archive/pi-crew-v0.5.16-audit-fix-plan.md} +0 -0
  426. /package/docs/{pi-crew-v0.5.17-audit-fix-plan.md → archive/pi-crew-v0.5.17-audit-fix-plan.md} +0 -0
  427. /package/docs/{pi-crew-v0.5.5-audit-fix-plan.md → archive/pi-crew-v0.5.5-audit-fix-plan.md} +0 -0
  428. /package/docs/{pi-crew-v0.5.9-audit-fix-plan.md → archive/pi-crew-v0.5.9-audit-fix-plan.md} +0 -0
  429. /package/docs/{pi-mono-opportunities.md → archive/pi-mono-opportunities.md} +0 -0
  430. /package/docs/{pi-mono-review.md → archive/pi-mono-review.md} +0 -0
  431. /package/docs/{pi-subagent4-comparison.md → archive/pi-subagent4-comparison.md} +0 -0
  432. /package/docs/{pi-subagents3-deep-analysis.md → archive/pi-subagents3-deep-analysis.md} +0 -0
@@ -1,7 +1,12 @@
1
1
  import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { removeGuidance } from "../../config/markers.ts";
4
+ import { appendHookEvent, executeHook } from "../../hooks/registry.ts";
2
5
  import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
3
6
  import { appendEvent } from "../../state/event-log.ts";
4
7
  import { loadRunManifestById } from "../../state/state-store.ts";
8
+ import { projectCrewRoot, userCrewRoot, userPiRoot } from "../../utils/paths.ts";
9
+ import { resolveRealContainedPath } from "../../utils/safe-paths.ts";
5
10
  import { cleanupRunWorktrees } from "../../worktree/cleanup.ts";
6
11
  import { listImportedRuns } from "../import-index.ts";
7
12
  import { exportRunBundle } from "../run-export.ts";
@@ -9,26 +14,42 @@ import { importRunBundle } from "../run-import.ts";
9
14
  import { pruneFinishedRuns } from "../run-maintenance.ts";
10
15
  import type { PiTeamsToolResult } from "../tool-result.ts";
11
16
  import { configRecord, result, type TeamContext } from "./context.ts";
12
- import { RUN_NOT_FOUND_HINT } from "./run-not-found.ts";
13
17
  import { enforceDestructiveIntent, intentFromConfig } from "./intent-policy.ts";
14
- import { executeHook, appendHookEvent } from "../../hooks/registry.ts";
15
- import { resolveRealContainedPath } from "../../utils/safe-paths.ts";
16
- import { projectCrewRoot, userCrewRoot, userPiRoot } from "../../utils/paths.ts";
17
- import { removeGuidance } from "../../config/markers.ts";
18
- import * as path from "node:path";
18
+ import { RUN_NOT_FOUND_HINT } from "./run-not-found.ts";
19
19
 
20
20
  export function handleWorktrees(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
21
21
  if (!params.runId) return result("Worktrees requires runId.", { action: "worktrees", status: "error" }, true);
22
22
  const loaded = loadRunManifestById(ctx.cwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
23
23
  if (!loaded) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "worktrees", status: "error" }, true);
24
24
  const withWorktrees = loaded.tasks.filter((task) => task.worktree);
25
- const lines = [`Worktrees for ${loaded.manifest.runId}:`, ...(withWorktrees.length ? withWorktrees.map((task) => `- ${task.id}: ${task.worktree!.path} branch=${task.worktree!.branch} reused=${task.worktree!.reused ? "true" : "false"}`) : ["- (none)"])];
26
- return result(lines.join("\n"), { action: "worktrees", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
25
+ const lines = [
26
+ `Worktrees for ${loaded.manifest.runId}:`,
27
+ ...(withWorktrees.length
28
+ ? withWorktrees.map(
29
+ (task) =>
30
+ `- ${task.id}: ${task.worktree!.path} branch=${task.worktree!.branch} reused=${task.worktree!.reused ? "true" : "false"}`,
31
+ )
32
+ : ["- (none)"]),
33
+ ];
34
+ return result(lines.join("\n"), {
35
+ action: "worktrees",
36
+ status: "ok",
37
+ runId: loaded.manifest.runId,
38
+ artifactsRoot: loaded.manifest.artifactsRoot,
39
+ });
27
40
  }
28
41
 
29
42
  export function handleImports(_params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
30
43
  const imports = listImportedRuns(ctx.cwd);
31
- const lines = ["Imported pi-crew runs:", ...(imports.length ? imports.map((entry) => `- ${entry.runId} (${entry.scope})${entry.status ? ` [${entry.status}]` : ""} ${entry.team ?? "unknown"}/${entry.workflow ?? "none"}: ${entry.goal ?? ""}\n Bundle: ${entry.bundlePath}\n Summary: ${entry.summaryPath}`) : ["- (none)"])];
44
+ const lines = [
45
+ "Imported pi-crew runs:",
46
+ ...(imports.length
47
+ ? imports.map(
48
+ (entry) =>
49
+ `- ${entry.runId} (${entry.scope})${entry.status ? ` [${entry.status}]` : ""} ${entry.team ?? "unknown"}/${entry.workflow ?? "none"}: ${entry.goal ?? ""}\n Bundle: ${entry.bundlePath}\n Summary: ${entry.summaryPath}`,
50
+ )
51
+ : ["- (none)"]),
52
+ ];
32
53
  return result(lines.join("\n"), { action: "imports", status: "ok" });
33
54
  }
34
55
 
@@ -39,7 +60,10 @@ export function handleImport(params: TeamToolParamsValue, ctx: TeamContext): PiT
39
60
  const scope = cfg.scope === "user" ? "user" : "project";
40
61
  try {
41
62
  const imported = importRunBundle(ctx.cwd, bundlePath, scope);
42
- return result([`Imported run bundle ${imported.runId}.`, `Bundle: ${imported.bundlePath}`, `Summary: ${imported.summaryPath}`].join("\n"), { action: "import", status: "ok" });
63
+ return result(
64
+ [`Imported run bundle ${imported.runId}.`, `Bundle: ${imported.bundlePath}`, `Summary: ${imported.summaryPath}`].join("\n"),
65
+ { action: "import", status: "ok" },
66
+ );
43
67
  } catch (error) {
44
68
  const message = error instanceof Error ? error.message : String(error);
45
69
  return result(`Import failed: ${message}`, { action: "import", status: "error" }, true);
@@ -56,18 +80,41 @@ export async function handleExport(params: TeamToolParamsValue, ctx: TeamContext
56
80
  // Risk: exported bundles may contain sensitive data from another session's run.
57
81
  const foreignRun = typeof loaded.manifest.ownerSessionId === "string" && loaded.manifest.ownerSessionId !== ctx.sessionId;
58
82
  if (foreignRun && !params.confirm) {
59
- return result(`Run ${loaded.manifest.runId} belongs to another session. Use confirm: true to export anyway.`, { action: "export", status: "error", runId: loaded.manifest.runId }, true);
83
+ return result(
84
+ `Run ${loaded.manifest.runId} belongs to another session. Use confirm: true to export anyway.`,
85
+ { action: "export", status: "error", runId: loaded.manifest.runId },
86
+ true,
87
+ );
60
88
  }
61
89
 
62
- const hookReport = await executeHook("before_publish", { runId: loaded.manifest.runId, cwd: ctx.cwd });
90
+ const hookReport = await executeHook("before_publish", {
91
+ runId: loaded.manifest.runId,
92
+ cwd: ctx.cwd,
93
+ });
63
94
  appendHookEvent(loaded.manifest, hookReport);
64
95
  if (hookReport.outcome === "block") {
65
- return result(`Export blocked by hook: ${hookReport.reason ?? "before_publish hook blocked the operation."}`, { action: "export", status: "error", runId: loaded.manifest.runId }, true);
96
+ return result(
97
+ `Export blocked by hook: ${hookReport.reason ?? "before_publish hook blocked the operation."}`,
98
+ { action: "export", status: "error", runId: loaded.manifest.runId },
99
+ true,
100
+ );
66
101
  }
67
102
 
68
103
  const exported = exportRunBundle(loaded.manifest, loaded.tasks);
69
- appendEvent(loaded.manifest.eventsPath, { type: "run.exported", runId: loaded.manifest.runId, data: exported });
70
- return result([`Exported run ${loaded.manifest.runId}.`, `JSON: ${exported.jsonPath}`, `Markdown: ${exported.markdownPath}`].join("\n"), { action: "export", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
104
+ appendEvent(loaded.manifest.eventsPath, {
105
+ type: "run.exported",
106
+ runId: loaded.manifest.runId,
107
+ data: exported,
108
+ });
109
+ return result(
110
+ [`Exported run ${loaded.manifest.runId}.`, `JSON: ${exported.jsonPath}`, `Markdown: ${exported.markdownPath}`].join("\n"),
111
+ {
112
+ action: "export",
113
+ status: "ok",
114
+ runId: loaded.manifest.runId,
115
+ artifactsRoot: loaded.manifest.artifactsRoot,
116
+ },
117
+ );
71
118
  }
72
119
 
73
120
  // Note: handlePrune has no ownership check — intentionally cross-session.
@@ -80,16 +127,35 @@ export async function handlePrune(params: TeamToolParamsValue, ctx: TeamContext)
80
127
  const keep = params.keep ?? 20;
81
128
  if (keep < 0 || !Number.isInteger(keep)) return result("keep must be an integer >= 0.", { action: "prune", status: "error" }, true);
82
129
  const intent = intentFromConfig(params.config);
83
- const pruned = pruneFinishedRuns(ctx.cwd, keep, { intent, signal: ctx.signal });
130
+ const pruned = pruneFinishedRuns(ctx.cwd, keep, {
131
+ intent,
132
+ signal: ctx.signal,
133
+ });
84
134
  // Fire hook once with all removed run IDs for batch visibility
85
135
  if (pruned.removed.length > 0) {
86
136
  const sampleManifest = loadRunManifestById(ctx.cwd, pruned.removed[0])?.manifest;
87
137
  if (sampleManifest) {
88
- const hookReport = await executeHook("before_cleanup", { runId: sampleManifest.runId, cwd: ctx.cwd, data: { removedRunIds: pruned.removed, keptCount: pruned.kept.length } });
138
+ const hookReport = await executeHook("before_cleanup", {
139
+ runId: sampleManifest.runId,
140
+ cwd: ctx.cwd,
141
+ data: {
142
+ removedRunIds: pruned.removed,
143
+ keptCount: pruned.kept.length,
144
+ },
145
+ });
89
146
  appendHookEvent(sampleManifest, hookReport);
90
147
  }
91
148
  }
92
- return result([`Pruned finished pi-crew runs.`, `Kept: ${pruned.kept.length}`, `Removed: ${pruned.removed.length}`, ...(pruned.auditPath ? [`Audit: ${pruned.auditPath}`] : []), ...(pruned.removed.length ? ["Removed runs:", ...pruned.removed.map((runId) => `- ${runId}`)] : [])].join("\n"), { action: "prune", status: "ok", intent });
149
+ return result(
150
+ [
151
+ `Pruned finished pi-crew runs.`,
152
+ `Kept: ${pruned.kept.length}`,
153
+ `Removed: ${pruned.removed.length}`,
154
+ ...(pruned.auditPath ? [`Audit: ${pruned.auditPath}`] : []),
155
+ ...(pruned.removed.length ? ["Removed runs:", ...pruned.removed.map((runId) => `- ${runId}`)] : []),
156
+ ].join("\n"),
157
+ { action: "prune", status: "ok", intent },
158
+ );
93
159
  }
94
160
 
95
161
  export async function handleForget(params: TeamToolParamsValue, ctx: TeamContext): Promise<PiTeamsToolResult> {
@@ -102,25 +168,77 @@ export async function handleForget(params: TeamToolParamsValue, ctx: TeamContext
102
168
 
103
169
  // Ownership check — prevent cross-session deletion unless force is set
104
170
  const foreignRun = typeof loaded.manifest.ownerSessionId === "string" && loaded.manifest.ownerSessionId !== ctx.sessionId;
105
- if (foreignRun && !params.force) return result(`Run ${params.runId} belongs to another session. Use force: true to override.`, { action: "forget", status: "error", runId: loaded.manifest.runId }, true);
171
+ if (foreignRun && !params.force)
172
+ return result(
173
+ `Run ${params.runId} belongs to another session. Use force: true to override.`,
174
+ { action: "forget", status: "error", runId: loaded.manifest.runId },
175
+ true,
176
+ );
106
177
 
107
- const hookReport = await executeHook("before_forget", { runId: loaded.manifest.runId, cwd: ctx.cwd });
178
+ const hookReport = await executeHook("before_forget", {
179
+ runId: loaded.manifest.runId,
180
+ cwd: ctx.cwd,
181
+ });
108
182
  appendHookEvent(loaded.manifest, hookReport);
109
183
  if (hookReport.outcome === "block") {
110
- return result(`Forget blocked by hook: ${hookReport.reason ?? "before_forget hook blocked the operation."}`, { action: "forget", status: "error", runId: loaded.manifest.runId }, true);
184
+ return result(
185
+ `Forget blocked by hook: ${hookReport.reason ?? "before_forget hook blocked the operation."}`,
186
+ { action: "forget", status: "error", runId: loaded.manifest.runId },
187
+ true,
188
+ );
111
189
  }
112
190
 
113
- const cleanup = cleanupRunWorktrees(loaded.manifest, { force: params.force });
114
- if (cleanup.preserved.length > 0 && !params.force) return result([`Run '${params.runId}' has preserved worktrees. Use force: true to forget anyway.`, ...cleanup.preserved.map((item) => `- ${item.path}: ${item.reason}`)].join("\n"), { action: "forget", status: "error", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot }, true);
191
+ const cleanup = cleanupRunWorktrees(loaded.manifest, {
192
+ force: params.force,
193
+ });
194
+ if (cleanup.preserved.length > 0 && !params.force)
195
+ return result(
196
+ [
197
+ `Run '${params.runId}' has preserved worktrees. Use force: true to forget anyway.`,
198
+ ...cleanup.preserved.map((item) => `- ${item.path}: ${item.reason}`),
199
+ ].join("\n"),
200
+ {
201
+ action: "forget",
202
+ status: "error",
203
+ runId: loaded.manifest.runId,
204
+ artifactsRoot: loaded.manifest.artifactsRoot,
205
+ },
206
+ true,
207
+ );
115
208
  const intent = intentFromConfig(params.config);
116
- appendEvent(loaded.manifest.eventsPath, { type: "run.forget_requested", runId: loaded.manifest.runId, message: "Run state and artifacts are being forgotten.", data: { force: params.force === true, removedWorktrees: cleanup.removed, preservedWorktrees: cleanup.preserved, intent } });
209
+ appendEvent(loaded.manifest.eventsPath, {
210
+ type: "run.forget_requested",
211
+ runId: loaded.manifest.runId,
212
+ message: "Run state and artifacts are being forgotten.",
213
+ data: {
214
+ force: params.force === true,
215
+ removedWorktrees: cleanup.removed,
216
+ preservedWorktrees: cleanup.preserved,
217
+ intent,
218
+ },
219
+ });
117
220
  // Determine scope from manifest paths (project vs user-level runs)
118
- const crewRoot = loaded.manifest.stateRoot.startsWith(userCrewRoot() + path.sep) ? userCrewRoot() : projectCrewRoot(loaded.manifest.cwd);
221
+ const crewRoot = loaded.manifest.stateRoot.startsWith(userCrewRoot() + path.sep)
222
+ ? userCrewRoot()
223
+ : projectCrewRoot(loaded.manifest.cwd);
119
224
  const resolvedStateRoot = resolveRealContainedPath(crewRoot, loaded.manifest.stateRoot);
120
225
  const resolvedArtifactsRoot = resolveRealContainedPath(crewRoot, loaded.manifest.artifactsRoot);
121
226
  fs.rmSync(resolvedStateRoot, { recursive: true, force: true });
122
227
  fs.rmSync(resolvedArtifactsRoot, { recursive: true, force: true });
123
- return result([`Forgot run ${loaded.manifest.runId}.`, `Removed state: ${loaded.manifest.stateRoot}`, `Removed artifacts: ${loaded.manifest.artifactsRoot}`, ...(cleanup.removed.length ? ["Removed worktrees:", ...cleanup.removed.map((item) => `- ${item}`)] : [])].join("\n"), { action: "forget", status: "ok", runId: loaded.manifest.runId, intent });
228
+ return result(
229
+ [
230
+ `Forgot run ${loaded.manifest.runId}.`,
231
+ `Removed state: ${loaded.manifest.stateRoot}`,
232
+ `Removed artifacts: ${loaded.manifest.artifactsRoot}`,
233
+ ...(cleanup.removed.length ? ["Removed worktrees:", ...cleanup.removed.map((item) => `- ${item}`)] : []),
234
+ ].join("\n"),
235
+ {
236
+ action: "forget",
237
+ status: "ok",
238
+ runId: loaded.manifest.runId,
239
+ intent,
240
+ },
241
+ );
124
242
  }
125
243
 
126
244
  export async function handleCleanup(params: TeamToolParamsValue, ctx: TeamContext): Promise<PiTeamsToolResult> {
@@ -180,11 +298,18 @@ function handleProjectCleanup(params: TeamToolParamsValue, ctx: TeamContext): Pi
180
298
  // 1. Remove the AGENTS.md guidance block (marker-delimited → user content preserved).
181
299
  const guidancePath = path.join(cwd, "AGENTS.md");
182
300
  const guidanceResult = dryRun
183
- ? { path: guidancePath, modified: fs.existsSync(guidancePath), added: [], removed: dryRunRemovedIds(guidancePath) }
301
+ ? {
302
+ path: guidancePath,
303
+ modified: fs.existsSync(guidancePath),
304
+ added: [],
305
+ removed: dryRunRemovedIds(guidancePath),
306
+ }
184
307
  : removeGuidance(guidancePath);
185
308
  lines.push("AGENTS.md guidance block:");
186
309
  if (guidanceResult.modified) {
187
- lines.push(` - ${dryRun ? "would remove" : "removed"}: ${guidanceResult.removed.length ? guidanceResult.removed.join(", ") : "(marker section)"}`);
310
+ lines.push(
311
+ ` - ${dryRun ? "would remove" : "removed"}: ${guidanceResult.removed.length ? guidanceResult.removed.join(", ") : "(marker section)"}`,
312
+ );
188
313
  } else {
189
314
  lines.push(" - (no pi-crew marker section found — nothing to do)");
190
315
  }
@@ -196,7 +321,9 @@ function handleProjectCleanup(params: TeamToolParamsValue, ctx: TeamContext): Pi
196
321
  if (!crewExists) {
197
322
  lines.push(` - (not present at ${crewRoot} — nothing to do)`);
198
323
  } else if (!removeState) {
199
- lines.push(` - present at ${crewRoot} (preserved — use force: true to remove; contains run history/artifacts/worktrees and is irreversible)`);
324
+ lines.push(
325
+ ` - present at ${crewRoot} (preserved — use force: true to remove; contains run history/artifacts/worktrees and is irreversible)`,
326
+ );
200
327
  } else {
201
328
  // SAFETY: realpath + contain-check before rmSync, so a crafted cwd can't
202
329
  // trick us into deleting an arbitrary directory.
@@ -282,10 +409,15 @@ function handleUserCleanup(params: TeamToolParamsValue, ctx: TeamContext): PiTea
282
409
  if (fs.existsSync(crewStateDir)) {
283
410
  try {
284
411
  crewStateBytes = dirSize(crewStateDir);
285
- } catch { /* best-effort size */ }
412
+ } catch {
413
+ /* best-effort size */
414
+ }
286
415
  if (!dryRun) {
287
- try { fs.rmSync(crewStateDir, { recursive: true, force: true }); }
288
- catch (e) { lines.push(` - ERROR removing: ${(e as Error).message}`); }
416
+ try {
417
+ fs.rmSync(crewStateDir, { recursive: true, force: true });
418
+ } catch (e) {
419
+ lines.push(` - ERROR removing: ${(e as Error).message}`);
420
+ }
289
421
  }
290
422
  lines.push(` - ${dryRun ? "would remove" : "removed"}: ${crewStateDir} (${formatBytes(crewStateBytes)})`);
291
423
  } else {
@@ -303,8 +435,11 @@ function handleUserCleanup(params: TeamToolParamsValue, ctx: TeamContext): PiTea
303
435
  lines.push(` - present at ${userConfigPath} (preserved — use force: true to remove; may hold your customized settings)`);
304
436
  } else {
305
437
  if (!dryRun) {
306
- try { fs.rmSync(userConfigPath, { force: true }); }
307
- catch (e) { lines.push(` - ERROR removing: ${(e as Error).message}`); }
438
+ try {
439
+ fs.rmSync(userConfigPath, { force: true });
440
+ } catch (e) {
441
+ lines.push(` - ERROR removing: ${(e as Error).message}`);
442
+ }
308
443
  }
309
444
  lines.push(` - ${dryRun ? "would remove" : "removed"}: ${userConfigPath}`);
310
445
  }
@@ -324,15 +459,20 @@ function handleUserCleanup(params: TeamToolParamsValue, ctx: TeamContext): PiTea
324
459
  bakJunk.push(path.join(agentsDir, entry));
325
460
  }
326
461
  }
327
- } catch { /* best-effort scan */ }
462
+ } catch {
463
+ /* best-effort scan */
464
+ }
328
465
  }
329
466
  if (bakJunk.length === 0) {
330
467
  lines.push(" - (no `*.md.bak-*` test backups found — nothing to do)");
331
468
  } else {
332
469
  for (const junk of bakJunk) {
333
470
  if (!dryRun) {
334
- try { fs.rmSync(junk, { force: true }); }
335
- catch (e) { lines.push(` - ERROR removing ${path.basename(junk)}: ${(e as Error).message}`); }
471
+ try {
472
+ fs.rmSync(junk, { force: true });
473
+ } catch (e) {
474
+ lines.push(` - ERROR removing ${path.basename(junk)}: ${(e as Error).message}`);
475
+ }
336
476
  }
337
477
  }
338
478
  lines.push(` - ${dryRun ? "would remove" : "removed"}: ${bakJunk.length} backup file(s) (pattern *.md.bak-<timestamp>-<hex>)`);
@@ -354,15 +494,20 @@ function dirSize(dir: string): number {
354
494
  while (stack.length > 0) {
355
495
  const cur = stack.pop()!;
356
496
  let entries: string[];
357
- try { entries = fs.readdirSync(cur); }
358
- catch { continue; }
497
+ try {
498
+ entries = fs.readdirSync(cur);
499
+ } catch {
500
+ continue;
501
+ }
359
502
  for (const entry of entries) {
360
503
  const full = path.join(cur, entry);
361
504
  try {
362
505
  const stat = fs.statSync(full);
363
506
  if (stat.isDirectory()) stack.push(full);
364
507
  else total += stat.size;
365
- } catch { /* skip unreadable */ }
508
+ } catch {
509
+ /* skip unreadable */
510
+ }
366
511
  }
367
512
  }
368
513
  return total;
@@ -378,20 +523,71 @@ function formatBytes(n: number): string {
378
523
  /** Per-run worktree cleanup (existing behavior, preserved). */
379
524
  async function handleRunCleanup(params: TeamToolParamsValue, ctx: TeamContext): Promise<PiTeamsToolResult> {
380
525
  const loaded = loadRunManifestById(ctx.cwd, params.runId!); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
381
- if (!loaded) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "cleanup", status: "error", runId: params.runId }, true);
526
+ if (!loaded)
527
+ return result(
528
+ `Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`,
529
+ { action: "cleanup", status: "error", runId: params.runId },
530
+ true,
531
+ );
382
532
  // Ownership check — prevent cross-session worktree cleanup unless force is set
383
533
  const foreignRun = typeof loaded.manifest.ownerSessionId === "string" && loaded.manifest.ownerSessionId !== ctx.sessionId;
384
- if (foreignRun && !params.force) return result(`Run ${params.runId} belongs to another session. Use force: true to override.`, { action: "cleanup", status: "error", runId: loaded.manifest.runId }, true);
534
+ if (foreignRun && !params.force)
535
+ return result(
536
+ `Run ${params.runId} belongs to another session. Use force: true to override.`,
537
+ {
538
+ action: "cleanup",
539
+ status: "error",
540
+ runId: loaded.manifest.runId,
541
+ },
542
+ true,
543
+ );
385
544
 
386
- const hookReport = await executeHook("before_cleanup", { runId: loaded.manifest.runId, cwd: ctx.cwd });
545
+ const hookReport = await executeHook("before_cleanup", {
546
+ runId: loaded.manifest.runId,
547
+ cwd: ctx.cwd,
548
+ });
387
549
  appendHookEvent(loaded.manifest, hookReport);
388
550
  if (hookReport.outcome === "block") {
389
- return result(`Cleanup blocked by hook: ${hookReport.reason ?? "before_cleanup hook blocked the operation."}`, { action: "cleanup", status: "error", runId: loaded.manifest.runId }, true);
551
+ return result(
552
+ `Cleanup blocked by hook: ${hookReport.reason ?? "before_cleanup hook blocked the operation."}`,
553
+ {
554
+ action: "cleanup",
555
+ status: "error",
556
+ runId: loaded.manifest.runId,
557
+ },
558
+ true,
559
+ );
390
560
  }
391
561
 
392
- const cleanup = cleanupRunWorktrees(loaded.manifest, { force: params.force, signal: ctx.signal });
562
+ const cleanup = cleanupRunWorktrees(loaded.manifest, {
563
+ force: params.force,
564
+ signal: ctx.signal,
565
+ });
393
566
  const intent = intentFromConfig(params.config);
394
- appendEvent(loaded.manifest.eventsPath, { type: "worktree.cleanup", runId: loaded.manifest.runId, data: { removed: cleanup.removed, preserved: cleanup.preserved, artifacts: cleanup.artifactPaths, intent } });
395
- const lines = [`Worktree cleanup for ${loaded.manifest.runId}:`, "Removed:", ...(cleanup.removed.length ? cleanup.removed.map((item) => `- ${item}`) : ["- (none)"]), "Preserved:", ...(cleanup.preserved.length ? cleanup.preserved.map((item) => `- ${item.path}: ${item.reason}`) : ["- (none)"]), "Artifacts:", ...(cleanup.artifactPaths.length ? cleanup.artifactPaths.map((item) => `- ${item}`) : ["- (none)"])];
396
- return result(lines.join("\n"), { action: "cleanup", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot, intent });
567
+ appendEvent(loaded.manifest.eventsPath, {
568
+ type: "worktree.cleanup",
569
+ runId: loaded.manifest.runId,
570
+ data: {
571
+ removed: cleanup.removed,
572
+ preserved: cleanup.preserved,
573
+ artifacts: cleanup.artifactPaths,
574
+ intent,
575
+ },
576
+ });
577
+ const lines = [
578
+ `Worktree cleanup for ${loaded.manifest.runId}:`,
579
+ "Removed:",
580
+ ...(cleanup.removed.length ? cleanup.removed.map((item) => `- ${item}`) : ["- (none)"]),
581
+ "Preserved:",
582
+ ...(cleanup.preserved.length ? cleanup.preserved.map((item) => `- ${item.path}: ${item.reason}`) : ["- (none)"]),
583
+ "Artifacts:",
584
+ ...(cleanup.artifactPaths.length ? cleanup.artifactPaths.map((item) => `- ${item}`) : ["- (none)"]),
585
+ ];
586
+ return result(lines.join("\n"), {
587
+ action: "cleanup",
588
+ status: "ok",
589
+ runId: loaded.manifest.runId,
590
+ artifactsRoot: loaded.manifest.artifactsRoot,
591
+ intent,
592
+ });
397
593
  }
@@ -6,16 +6,16 @@
6
6
  import * as fs from "node:fs";
7
7
  import * as path from "node:path";
8
8
  import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
9
- import type { PiTeamsToolResult } from "../tool-result.ts";
10
- import { result, type TeamContext } from "./context.ts";
9
+ import { resolveContainedPath } from "../../utils/safe-paths.ts";
11
10
  import {
12
11
  buildAgentChain,
13
12
  formatPlanOverview,
13
+ type OrchestratedStep,
14
14
  parsePlanDocument,
15
15
  parsePlanDocumentSimple,
16
- type OrchestratedStep,
17
16
  } from "../plan-orchestrate.ts";
18
- import { resolveContainedPath } from "../../utils/safe-paths.ts";
17
+ import type { PiTeamsToolResult } from "../tool-result.ts";
18
+ import { result, type TeamContext } from "./context.ts";
19
19
 
20
20
  /**
21
21
  * Handle the orchestrate action.
@@ -25,10 +25,7 @@ import { resolveContainedPath } from "../../utils/safe-paths.ts";
25
25
  *
26
26
  * Usage: `team action='orchestrate' planPath='/path/to/plan.md'`
27
27
  */
28
- export function handleOrchestrate(
29
- params: TeamToolParamsValue,
30
- ctx: TeamContext,
31
- ): PiTeamsToolResult {
28
+ export function handleOrchestrate(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
32
29
  const planPath = params.planPath as string | undefined;
33
30
 
34
31
  if (!planPath) {
@@ -44,19 +41,11 @@ export function handleOrchestrate(
44
41
  try {
45
42
  resolvedPath = resolveContainedPath(ctx.cwd, planPath);
46
43
  } catch {
47
- return result(
48
- `planPath must be within project directory: ${planPath}`,
49
- { action: "orchestrate", status: "error" },
50
- true,
51
- );
44
+ return result(`planPath must be within project directory: ${planPath}`, { action: "orchestrate", status: "error" }, true);
52
45
  }
53
46
 
54
47
  if (!fs.existsSync(resolvedPath)) {
55
- return result(
56
- `Plan document not found: ${resolvedPath}`,
57
- { action: "orchestrate", status: "error" },
58
- true,
59
- );
48
+ return result(`Plan document not found: ${resolvedPath}`, { action: "orchestrate", status: "error" }, true);
60
49
  }
61
50
 
62
51
  // Try primary parser
@@ -8,18 +8,18 @@
8
8
  */
9
9
  import { discoverAgents } from "../../agents/discover-agents.ts";
10
10
  import { loadConfig } from "../../config/config.ts";
11
+ import { resolveCrewRuntime } from "../../runtime/runtime-resolver.ts";
11
12
  import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
12
- import { createRunManifest } from "../../state/state-store.ts";
13
13
  import { appendEvent } from "../../state/event-log.ts";
14
+ import { createRunManifest } from "../../state/state-store.ts";
14
15
  import { spawnBackgroundTeamRun } from "../../subagents/async-entry.ts";
15
- import { resolveCrewRuntime } from "../../runtime/runtime-resolver.ts";
16
- import { resolveCwdOverride } from "../registration/team-tool.ts";
17
- import { result, type TeamContext } from "./context.ts";
18
- import type { PiTeamsToolResult } from "../tool-result.ts";
19
16
  import { discoverTeams } from "../../teams/discover-teams.ts";
20
- import { discoverWorkflows } from "../../workflows/discover-workflows.ts";
21
17
  import type { TeamConfig } from "../../teams/team-config.ts";
18
+ import { discoverWorkflows } from "../../workflows/discover-workflows.ts";
22
19
  import type { WorkflowConfig } from "../../workflows/workflow-config.ts";
20
+ import { resolveCwdOverride } from "../registration/team-tool.ts";
21
+ import type { PiTeamsToolResult } from "../tool-result.ts";
22
+ import { result, type TeamContext } from "./context.ts";
23
23
 
24
24
  const MAX_CONCURRENCY = 8;
25
25
  const DEFAULT_CONCURRENCY = 4;
@@ -32,10 +32,7 @@ export async function handleParallel(params: TeamToolParamsValue, ctx: TeamConte
32
32
  return result("parallel action requires config.tasks: [{goal, agent?}]", { action: "parallel", status: "error" }, true);
33
33
  }
34
34
 
35
- const concurrency = Math.min(
36
- Math.max(1, Math.floor((params.config?.concurrency as number) ?? DEFAULT_CONCURRENCY)),
37
- MAX_CONCURRENCY,
38
- );
35
+ const concurrency = Math.min(Math.max(1, Math.floor((params.config?.concurrency as number) ?? DEFAULT_CONCURRENCY)), MAX_CONCURRENCY);
39
36
 
40
37
  const config = loadConfig(ctx.cwd);
41
38
  const agentsResult = discoverAgents(ctx.cwd);
@@ -44,16 +41,16 @@ export async function handleParallel(params: TeamToolParamsValue, ctx: TeamConte
44
41
  const workflows = discoverWorkflows(ctx.cwd);
45
42
 
46
43
  const teamName = (params.config?.team as string) ?? DEFAULT_TEAM;
47
- const team = teams.builtin.find((t) => t.name === teamName)
48
- ?? teams.user.find((t) => t.name === teamName)
49
- ?? teams.project.find((t) => t.name === teamName);
44
+ const team =
45
+ teams.builtin.find((t) => t.name === teamName) ??
46
+ teams.user.find((t) => t.name === teamName) ??
47
+ teams.project.find((t) => t.name === teamName);
50
48
  if (!team) {
51
49
  return result(`Team '${teamName}' not found`, { action: "parallel", status: "error" }, true);
52
50
  }
53
51
 
54
52
  // H2: Use team's defaultWorkflow, fall back to "fast-fix"
55
- const workflow = workflows.builtin.find((w) => w.name === team.defaultWorkflow)
56
- ?? workflows.builtin.find((w) => w.name === "fast-fix");
53
+ const workflow = workflows.builtin.find((w) => w.name === team.defaultWorkflow) ?? workflows.builtin.find((w) => w.name === "fast-fix");
57
54
  if (!workflow) {
58
55
  return result("No suitable workflow found for parallel dispatch", { action: "parallel", status: "error" }, true);
59
56
  }
@@ -75,15 +72,15 @@ export async function handleParallel(params: TeamToolParamsValue, ctx: TeamConte
75
72
  errors.push(res.value.error);
76
73
  } else {
77
74
  const reason = (res as PromiseRejectedResult).reason;
78
- errors.push({ goal: "(unknown)", error: reason instanceof Error ? reason.message : String(reason) });
75
+ errors.push({
76
+ goal: "(unknown)",
77
+ error: reason instanceof Error ? reason.message : String(reason),
78
+ });
79
79
  }
80
80
  }
81
81
  }
82
82
 
83
- const lines: string[] = [
84
- `Parallel dispatch: ${launched.length}/${tasksParam.length} tasks launched (concurrency: ${concurrency})`,
85
- "",
86
- ];
83
+ const lines: string[] = [`Parallel dispatch: ${launched.length}/${tasksParam.length} tasks launched (concurrency: ${concurrency})`, ""];
87
84
  for (const l of launched) {
88
85
  lines.push(` ✅ ${l.runId} — ${l.agent}: ${l.goal.slice(0, 80)}`);
89
86
  }
@@ -91,13 +88,20 @@ export async function handleParallel(params: TeamToolParamsValue, ctx: TeamConte
91
88
  lines.push(` ❌ ${e.goal.slice(0, 80)}: ${e.error}`);
92
89
  }
93
90
 
94
- return result(lines.join("\n"), {
95
- action: "parallel",
96
- status: errors.length === tasksParam.length ? "error" : "ok",
97
- }, errors.length === tasksParam.length);
91
+ return result(
92
+ lines.join("\n"),
93
+ {
94
+ action: "parallel",
95
+ status: errors.length === tasksParam.length ? "error" : "ok",
96
+ },
97
+ errors.length === tasksParam.length,
98
+ );
98
99
  }
99
100
 
100
- type SpawnOk = { ok: true; value: { runId: string; goal: string; agent: string } };
101
+ type SpawnOk = {
102
+ ok: true;
103
+ value: { runId: string; goal: string; agent: string };
104
+ };
101
105
  type SpawnErr = { ok: false; error: { goal: string; error: string } };
102
106
  type SpawnResult = SpawnOk | SpawnErr;
103
107
 
@@ -116,12 +120,21 @@ async function spawnSingleTask(
116
120
  const rawCwd = (taskRec.cwd as string) ?? undefined;
117
121
 
118
122
  if (!goal) {
119
- return { ok: false, error: { goal: "(missing)", error: "Each task must have a 'goal' field" } };
123
+ return {
124
+ ok: false,
125
+ error: {
126
+ goal: "(missing)",
127
+ error: "Each task must have a 'goal' field",
128
+ },
129
+ };
120
130
  }
121
131
 
122
132
  const agent = allAgentsList.find((a) => a.name === agentName);
123
133
  if (!agent) {
124
- return { ok: false, error: { goal, error: `Agent '${agentName}' not found` } };
134
+ return {
135
+ ok: false,
136
+ error: { goal, error: `Agent '${agentName}' not found` },
137
+ };
125
138
  }
126
139
 
127
140
  // H1: Validate taskCwd containment against project root
@@ -148,9 +161,18 @@ async function spawnSingleTask(
148
161
  await spawnBackgroundTeamRun(created.manifest);
149
162
  }
150
163
 
151
- return { ok: true, value: { runId: created.manifest.runId, goal, agent: agentName } };
164
+ return {
165
+ ok: true,
166
+ value: { runId: created.manifest.runId, goal, agent: agentName },
167
+ };
152
168
  } catch (error) {
153
169
  const goal = ((task as Record<string, unknown>).goal as string) ?? "(unknown)";
154
- return { ok: false, error: { goal, error: error instanceof Error ? error.message : String(error) } };
170
+ return {
171
+ ok: false,
172
+ error: {
173
+ goal,
174
+ error: error instanceof Error ? error.message : String(error),
175
+ },
176
+ };
155
177
  }
156
178
  }