pi-crew 0.9.16 → 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 +81 -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 +145 -47
  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 +44 -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
@@ -6,39 +6,66 @@ const widthCache = new Map<string, number>();
6
6
  /** Code-point ranges that render as width 2 in most terminals (CJK + emoji). */
7
7
  const WIDE_RANGES: Array<[number, number]> = [
8
8
  // CJK Unified Ideographs
9
- [0x4E00, 0x9FFF],
9
+ [0x4e00, 0x9fff],
10
10
  // CJK Extension A
11
- [0x3400, 0x4DBF],
11
+ [0x3400, 0x4dbf],
12
12
  // CJK Compatibility Ideographs
13
- [0xF900, 0xFAFF],
13
+ [0xf900, 0xfaff],
14
14
  // Hangul Syllables
15
- [0xAC00, 0xD7AF],
15
+ [0xac00, 0xd7af],
16
16
  // CJK Symbols and Punctuation, Hiragana, Katakana
17
- [0x3000, 0x33FF],
17
+ [0x3000, 0x33ff],
18
18
  // Fullwidth forms
19
- [0xFF01, 0xFF60],
19
+ [0xff01, 0xff60],
20
20
  // Emoji blocks
21
21
  // Emoji-presentation codepoints in 0x2600-0x27BF (narrow chars like ✓✗★ excluded)
22
- [0x2615, 0x2615], [0x2648, 0x2653], [0x267F, 0x267F], [0x2693, 0x2693],
23
- [0x26A1, 0x26A1], [0x26AA, 0x26AB], [0x26BD, 0x26BE], [0x26C4, 0x26C5],
24
- [0x26CE, 0x26CE], [0x26D4, 0x26D4], [0x26EA, 0x26EA], [0x26F2, 0x26F3],
25
- [0x26F5, 0x26F5], [0x26FA, 0x26FA], [0x26FD, 0x26FD], [0x2702, 0x2702],
26
- [0x2705, 0x2705], [0x2708, 0x270D], [0x270F, 0x270F], [0x2712, 0x2712],
27
- [0x2714, 0x2714], [0x2716, 0x2716], [0x271D, 0x271D], [0x2721, 0x2721],
28
- [0x2728, 0x2728], [0x2733, 0x2734], [0x2744, 0x2744], [0x2747, 0x2747],
29
- [0x274C, 0x274C], [0x274E, 0x274E], [0x2753, 0x2755], [0x2757, 0x2757],
30
- [0x2763, 0x2764], [0x2795, 0x2797], [0x27A1, 0x27A1], [0x27B0, 0x27B0],
31
- [0x27BF, 0x27BF],
22
+ [0x2615, 0x2615],
23
+ [0x2648, 0x2653],
24
+ [0x267f, 0x267f],
25
+ [0x2693, 0x2693],
26
+ [0x26a1, 0x26a1],
27
+ [0x26aa, 0x26ab],
28
+ [0x26bd, 0x26be],
29
+ [0x26c4, 0x26c5],
30
+ [0x26ce, 0x26ce],
31
+ [0x26d4, 0x26d4],
32
+ [0x26ea, 0x26ea],
33
+ [0x26f2, 0x26f3],
34
+ [0x26f5, 0x26f5],
35
+ [0x26fa, 0x26fa],
36
+ [0x26fd, 0x26fd],
37
+ [0x2702, 0x2702],
38
+ [0x2705, 0x2705],
39
+ [0x2708, 0x270d],
40
+ [0x270f, 0x270f],
41
+ [0x2712, 0x2712],
42
+ [0x2714, 0x2714],
43
+ [0x2716, 0x2716],
44
+ [0x271d, 0x271d],
45
+ [0x2721, 0x2721],
46
+ [0x2728, 0x2728],
47
+ [0x2733, 0x2734],
48
+ [0x2744, 0x2744],
49
+ [0x2747, 0x2747],
50
+ [0x274c, 0x274c],
51
+ [0x274e, 0x274e],
52
+ [0x2753, 0x2755],
53
+ [0x2757, 0x2757],
54
+ [0x2763, 0x2764],
55
+ [0x2795, 0x2797],
56
+ [0x27a1, 0x27a1],
57
+ [0x27b0, 0x27b0],
58
+ [0x27bf, 0x27bf],
32
59
  // Geometric Shapes / Misc Symbols-Arrows emoji that pi-tui upstream counts as
33
60
  // width=2 (RGI emoji). Mismatch here caused the "Rendered line N exceeds
34
61
  // terminal width (160 > 159)" TUI crash: pi-crew truncated to width 159 by
35
62
  // its own (mismatched) measure, then Box padded to 159 chars, but pi-tui
36
63
  // re-measured the padded line at 160 because ⬜ counts as 2 upstream.
37
- [0x2B1B, 0x2B1C], // ⬛ BLACK LARGE SQUARE, ⬜ WHITE LARGE SQUARE
38
- [0x1F300, 0x1F9FF], // Misc Symbols, Emoticons, Transport, Map, Supplement
39
- [0x1FA00, 0x1FAFF], // Symbols Extended-A
40
- [0x1F000, 0x1F02F], // Mahjong, Dominos
41
- [0xFE00, 0xFE0F], // Variation Selectors (emoji presentation)
64
+ [0x2b1b, 0x2b1c], // ⬛ BLACK LARGE SQUARE, ⬜ WHITE LARGE SQUARE
65
+ [0x1f300, 0x1f9ff], // Misc Symbols, Emoticons, Transport, Map, Supplement
66
+ [0x1fa00, 0x1faff], // Symbols Extended-A
67
+ [0x1f000, 0x1f02f], // Mahjong, Dominos
68
+ [0xfe00, 0xfe0f], // Variation Selectors (emoji presentation)
42
69
  ];
43
70
  // NOTE: U+200D (Zero Width Joiner, ZWJ) is intentionally NOT listed as wide.
44
71
  // ZWJ has zero advance width by Unicode definition; miscounting it as 2 caused
@@ -113,7 +140,7 @@ export function truncateToWidth(value: string, width: number, ellipsis = "…"):
113
140
  continue;
114
141
  }
115
142
  const char = value[i] as string;
116
- const nextIndex = ((char.codePointAt(0) ?? 0) > 0xFFFF) ? i + 2 : i + 1;
143
+ const nextIndex = (char.codePointAt(0) ?? 0) > 0xffff ? i + 2 : i + 1;
117
144
  const segment = value.slice(i, nextIndex);
118
145
  const charWidth = visibleWidth(segment);
119
146
  if (renderedWidth + charWidth > width - ellipsis.length) {
@@ -183,7 +210,7 @@ function readAnsiCode(input: string, index: number): string | undefined {
183
210
  function takeCodePoint(input: string, index: number): { chunk: string; nextIndex: number } {
184
211
  const code = input.codePointAt(index);
185
212
  if (code === undefined) return { chunk: "", nextIndex: index + 1 };
186
- if (code >= 0xD800 && code <= 0xDBFF && index + 1 < input.length) {
213
+ if (code >= 0xd800 && code <= 0xdbff && index + 1 < input.length) {
187
214
  return { chunk: input.slice(index, index + 2), nextIndex: index + 2 };
188
215
  }
189
216
  return { chunk: input[index] ?? "", nextIndex: index + 1 };
@@ -231,20 +258,13 @@ export interface VisualTruncateResult {
231
258
  skippedCount: number;
232
259
  }
233
260
 
234
- export function truncateToVisualLines(
235
- text: string,
236
- maxVisualLines: number,
237
- width: number,
238
- paddingX = 0,
239
- ): VisualTruncateResult {
261
+ export function truncateToVisualLines(text: string, maxVisualLines: number, width: number, paddingX = 0): VisualTruncateResult {
240
262
  if (!text) {
241
263
  return { visualLines: [], skippedCount: 0 };
242
264
  }
243
265
  const effectiveWidth = Math.max(1, width - paddingX * 2);
244
266
  const limit = Math.max(1, maxVisualLines);
245
- const visualLines = text
246
- .split("\n")
247
- .flatMap((line) => wrapHard(pad(line, Math.max(0, effectiveWidth)).trimEnd(), effectiveWidth));
267
+ const visualLines = text.split("\n").flatMap((line) => wrapHard(pad(line, Math.max(0, effectiveWidth)).trimEnd(), effectiveWidth));
248
268
  if (visualLines.length <= limit) return { visualLines, skippedCount: 0 };
249
269
  const truncated = visualLines.slice(-limit);
250
270
  return { visualLines: truncated, skippedCount: visualLines.length - limit };
@@ -64,57 +64,38 @@ function parseStepSection(id: string, body: string): WorkflowStep | undefined {
64
64
  reads: config.reads === "false" ? false : parseCsv(config.reads),
65
65
  model: config.model || undefined,
66
66
  skills: config.skills === "false" ? false : parseCsv(config.skills),
67
- progress:
68
- config.progress === "true"
69
- ? true
70
- : config.progress === "false"
71
- ? false
72
- : undefined,
73
- worktree:
74
- config.worktree === "true"
75
- ? true
76
- : config.worktree === "false"
77
- ? false
78
- : undefined,
79
- verify:
80
- config.verify === "true"
81
- ? true
82
- : config.verify === "false"
83
- ? false
84
- : undefined,
67
+ progress: config.progress === "true" ? true : config.progress === "false" ? false : undefined,
68
+ worktree: config.worktree === "true" ? true : config.worktree === "false" ? false : undefined,
69
+ verify: config.verify === "true" ? true : config.verify === "false" ? false : undefined,
85
70
  seedPaths: parseCsv(config.seedPaths) || undefined,
86
71
  preStepScript: config.preStepScript || undefined,
87
72
  preStepArgs: parseCsv(config.preStepArgs) || undefined,
88
- preStepTimeout:
89
- parseOptionalInteger(config.preStepTimeout) ?? undefined,
90
- preStepOptional:
91
- config.preStepOptional === "true" || config.preStepOptional === "1",
73
+ preStepTimeout: parseOptionalInteger(config.preStepTimeout) ?? undefined,
74
+ preStepOptional: config.preStepOptional === "true" || config.preStepOptional === "1",
92
75
  };
93
76
  }
94
77
 
95
- const parseOptionalInteger = (
96
- value: string | undefined,
97
- ): number | undefined => {
98
- if (!value) return undefined;
99
- const parsed = Number.parseInt(value, 10);
100
- if (!Number.isFinite(parsed) || parsed < 1) return undefined;
101
- return Math.trunc(parsed);
78
+ const parseOptionalInteger = (value: string | undefined): number | undefined => {
79
+ const trimmed = value?.trim();
80
+ if (!trimmed) return undefined;
81
+ const n = Number.parseInt(trimmed, 10);
82
+ return Number.isNaN(n) ? undefined : n;
83
+ };
84
+
85
+ const parseOptionalBoolean = (value: string | undefined): boolean | undefined => {
86
+ const trimmed = value?.trim().toLowerCase();
87
+ if (!trimmed) return undefined;
88
+ if (trimmed === "true" || trimmed === "yes" || trimmed === "1") return true;
89
+ if (trimmed === "false" || trimmed === "no" || trimmed === "0") return false;
90
+ return undefined;
102
91
  };
103
92
 
104
93
  /** Parse frontmatter `topology:` field. Validates against allowed enum; bad values are silently
105
94
  * dropped (fall through to auto-classification in topology-analyzer). */
106
- const parseTopology = (
107
- value: string | undefined,
108
- ): WorkflowConfig["topology"] => {
95
+ const parseTopology = (value: string | undefined): WorkflowConfig["topology"] => {
109
96
  if (!value) return undefined;
110
97
  const v = value.trim().toLowerCase();
111
- if (
112
- v === "single" ||
113
- v === "sequential" ||
114
- v === "concurrent" ||
115
- v === "complex-dag" ||
116
- v === "dynamic"
117
- ) {
98
+ if (v === "single" || v === "sequential" || v === "concurrent" || v === "complex-dag" || v === "dynamic") {
118
99
  return v;
119
100
  }
120
101
  return undefined;
@@ -129,15 +110,9 @@ function hasSectionBoundary(body: string, match: RegExpMatchArray): boolean {
129
110
  }
130
111
 
131
112
  function isStepHeading(body: string, match: RegExpMatchArray): boolean {
132
- const sectionStart =
133
- match.index! +
134
- match[0].length +
135
- (body[match.index! + match[0].length] === "\n" ? 1 : 0);
113
+ const sectionStart = match.index! + match[0].length + (body[match.index! + match[0].length] === "\n" ? 1 : 0);
136
114
  const nextHeading = body.slice(sectionStart).search(/^##\s+.+[^\S\n]*$/m);
137
- const section = body.slice(
138
- sectionStart,
139
- nextHeading >= 0 ? sectionStart + nextHeading : body.length,
140
- );
115
+ const section = body.slice(sectionStart, nextHeading >= 0 ? sectionStart + nextHeading : body.length);
141
116
  for (const line of section.split("\n")) {
142
117
  const trimmed = line.trim();
143
118
  if (!trimmed) continue;
@@ -148,58 +123,39 @@ function isStepHeading(body: string, match: RegExpMatchArray): boolean {
148
123
  return false;
149
124
  }
150
125
 
151
- function parseWorkflowFile(
152
- filePath: string,
153
- source: ResourceSource,
154
- ): WorkflowConfig | undefined {
126
+ function parseWorkflowFile(filePath: string, source: ResourceSource): WorkflowConfig | undefined {
155
127
  try {
156
128
  const content = fs.readFileSync(filePath, "utf-8");
157
129
  const { frontmatter, body } = parseFrontmatter(content);
158
- const name =
159
- frontmatter.name?.trim() || path.basename(filePath, ".workflow.md");
130
+ const name = frontmatter.name?.trim() || path.basename(filePath, ".workflow.md");
160
131
  const matches = [...body.matchAll(/^##\s+(.+)[^\S\n]*$/gm)];
161
132
  const explicitStepIndexes = new Set(
162
133
  matches
163
- .map((match, index) =>
164
- isStepHeading(body, match) ? index : undefined,
165
- )
134
+ .map((match, index) => (isStepHeading(body, match) ? index : undefined))
166
135
  .filter((index): index is number => index !== undefined),
167
136
  );
168
137
  const effectiveMatches = matches.filter(
169
138
  (match, index) =>
170
- explicitStepIndexes.has(index) ||
171
- (hasSectionBoundary(body, match) &&
172
- /^[a-z][a-z0-9-]*$/.test(match[1]?.trim() ?? "")),
139
+ explicitStepIndexes.has(index) || (hasSectionBoundary(body, match) && /^[a-z][a-z0-9-]*$/.test(match[1]?.trim() ?? "")),
173
140
  );
174
- const parseMatches = explicitStepIndexes.size
175
- ? effectiveMatches
176
- : matches;
141
+ const parseMatches = explicitStepIndexes.size ? effectiveMatches : matches;
177
142
  const steps: WorkflowStep[] = [];
178
143
  for (let i = 0; i < parseMatches.length; i++) {
179
144
  const match = parseMatches[i]!;
180
145
  const id = match[1]!.trim();
181
- const sectionStart =
182
- match.index! +
183
- match[0].length +
184
- (body[match.index! + match[0].length] === "\n" ? 1 : 0);
185
- const sectionEnd =
186
- i + 1 < parseMatches.length
187
- ? parseMatches[i + 1]!.index!
188
- : body.length;
189
- const step = parseStepSection(
190
- id,
191
- body.slice(sectionStart, sectionEnd),
192
- );
146
+ const sectionStart = match.index! + match[0].length + (body[match.index! + match[0].length] === "\n" ? 1 : 0);
147
+ const sectionEnd = i + 1 < parseMatches.length ? parseMatches[i + 1]!.index! : body.length;
148
+ const step = parseStepSection(id, body.slice(sectionStart, sectionEnd));
193
149
  if (step) steps.push(step);
194
150
  }
195
151
  return {
196
152
  name,
197
- description:
198
- frontmatter.description?.trim() || "No description provided.",
153
+ description: frontmatter.description?.trim() || "No description provided.",
199
154
  source,
200
155
  filePath,
201
156
  maxConcurrency: parseOptionalInteger(frontmatter.maxConcurrency),
202
157
  topology: parseTopology(frontmatter.topology),
158
+ coalesceMicroTasks: parseOptionalBoolean(frontmatter.coalesceMicroTasks),
203
159
  steps,
204
160
  };
205
161
  } catch {
@@ -207,37 +163,25 @@ function parseWorkflowFile(
207
163
  }
208
164
  }
209
165
 
210
- function readWorkflowDir(
211
- dir: string,
212
- source: ResourceSource,
213
- ): WorkflowConfig[] {
166
+ function readWorkflowDir(dir: string, source: ResourceSource): WorkflowConfig[] {
214
167
  if (!fs.existsSync(dir)) return [];
215
168
  const staticWorkflows = fs
216
169
  .readdirSync(dir)
217
170
  .filter((entry) => entry.endsWith(".workflow.md"))
218
171
  .map((entry) => parseWorkflowFile(path.join(dir, entry), source))
219
- .filter(
220
- (workflow): workflow is WorkflowConfig => workflow !== undefined,
221
- )
172
+ .filter((workflow): workflow is WorkflowConfig => workflow !== undefined)
222
173
  .sort((a, b) => a.name.localeCompare(b.name));
223
174
  // P2: also discover dynamic workflows (*.dwf.ts). A .dwf.ts's default export is a JS orchestrator.
224
175
  const dynamicWorkflows = fs
225
176
  .readdirSync(dir)
226
177
  .filter((entry) => entry.endsWith(".dwf.ts"))
227
178
  .map((entry) => parseDynamicWorkflowFile(path.join(dir, entry), source))
228
- .filter(
229
- (workflow): workflow is WorkflowConfig => workflow !== undefined,
230
- );
231
- return [...staticWorkflows, ...dynamicWorkflows].sort((a, b) =>
232
- a.name.localeCompare(b.name),
233
- );
179
+ .filter((workflow): workflow is WorkflowConfig => workflow !== undefined);
180
+ return [...staticWorkflows, ...dynamicWorkflows].sort((a, b) => a.name.localeCompare(b.name));
234
181
  }
235
182
 
236
183
  /** P2: a .dwf.ts is a dynamic workflow. Name = filename stem; script = the file itself. */
237
- function parseDynamicWorkflowFile(
238
- filePath: string,
239
- source: ResourceSource,
240
- ): WorkflowConfig | undefined {
184
+ function parseDynamicWorkflowFile(filePath: string, source: ResourceSource): WorkflowConfig | undefined {
241
185
  try {
242
186
  const basename = path.basename(filePath, ".dwf.ts");
243
187
  return {
@@ -259,28 +203,16 @@ export function discoverWorkflows(cwd: string): WorkflowDiscoveryResult {
259
203
  return { builtin: [], user: [], project: [] };
260
204
  }
261
205
  return {
262
- builtin: readWorkflowDir(
263
- path.join(packageRoot(), "workflows"),
264
- "builtin",
265
- ),
206
+ builtin: readWorkflowDir(path.join(packageRoot(), "workflows"), "builtin"),
266
207
  user: readWorkflowDir(path.join(userPiRoot(), "workflows"), "user"),
267
- project: readWorkflowDir(
268
- path.join(projectCrewRoot(cwd), "workflows"),
269
- "project",
270
- ),
208
+ project: readWorkflowDir(path.join(projectCrewRoot(cwd), "workflows"), "project"),
271
209
  };
272
210
  }
273
211
 
274
- export function allWorkflows(
275
- discovery: WorkflowDiscoveryResult | undefined,
276
- ): WorkflowConfig[] {
212
+ export function allWorkflows(discovery: WorkflowDiscoveryResult | undefined): WorkflowConfig[] {
277
213
  if (!discovery) return [];
278
214
  const byName = new Map<string, WorkflowConfig>();
279
- for (const workflow of [
280
- ...discovery.project,
281
- ...discovery.builtin,
282
- ...discovery.user,
283
- ]) {
215
+ for (const workflow of [...discovery.project, ...discovery.builtin, ...discovery.user]) {
284
216
  byName.set(workflow.name, workflow);
285
217
  }
286
218
  return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
@@ -9,7 +9,7 @@
9
9
  * - Debugging (inspect intermediate outputs)
10
10
  */
11
11
 
12
- import { mkdirSync, readFileSync, writeFileSync, existsSync, readdirSync, unlinkSync } from "node:fs";
12
+ import { existsSync, mkdirSync, readdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
13
13
  import path from "node:path";
14
14
  import { logInternalError } from "../utils/internal-error.ts";
15
15
  import { isSafePathId } from "../utils/safe-paths.ts";
@@ -55,12 +55,7 @@ export function ensureIntermediateDir(config: Partial<IntermediateStoreConfig> =
55
55
  * @param data - Phase output data
56
56
  * @returns Path to the written file
57
57
  */
58
- export function writeIntermediate(
59
- config: Partial<IntermediateStoreConfig>,
60
- phase: string,
61
- stepId: string,
62
- data: unknown,
63
- ): string {
58
+ export function writeIntermediate(config: Partial<IntermediateStoreConfig>, phase: string, stepId: string, data: unknown): string {
64
59
  const dir = ensureIntermediateDir(config);
65
60
  const filename = `${phase}-${stepId}.json`;
66
61
  const filePath = path.join(dir, filename);
@@ -84,11 +79,7 @@ export function writeIntermediate(
84
79
  * @param stepId - Step ID
85
80
  * @returns Parsed intermediate output, or undefined if not found
86
81
  */
87
- export function readIntermediate(
88
- config: Partial<IntermediateStoreConfig>,
89
- phase: string,
90
- stepId: string,
91
- ): IntermediateOutput | undefined {
82
+ export function readIntermediate(config: Partial<IntermediateStoreConfig>, phase: string, stepId: string): IntermediateOutput | undefined {
92
83
  // M-2 fix (code-review 2026-06-23): validate phase/stepId before building the
93
84
  // filename to prevent path traversal via a poisoned stepId.
94
85
  if (!isSafePathId(phase) || !isSafePathId(stepId)) return undefined;
@@ -113,10 +104,7 @@ export function readIntermediate(
113
104
  * Useful when you don't know the exact stepId but want the latest
114
105
  * output from a phase (e.g., for incremental re-runs).
115
106
  */
116
- export function readLatestIntermediate(
117
- config: Partial<IntermediateStoreConfig>,
118
- phase: string,
119
- ): IntermediateOutput | undefined {
107
+ export function readLatestIntermediate(config: Partial<IntermediateStoreConfig>, phase: string): IntermediateOutput | undefined {
120
108
  const dir = config.intermediateDir ?? DEFAULT_CONFIG.intermediateDir;
121
109
  if (!existsSync(dir)) return undefined;
122
110
 
@@ -168,10 +156,6 @@ export function cleanupIntermediates(config: Partial<IntermediateStoreConfig> =
168
156
  /**
169
157
  * Check if a phase has completed (intermediate exists).
170
158
  */
171
- export function hasPhaseCompleted(
172
- config: Partial<IntermediateStoreConfig>,
173
- phase: string,
174
- stepId: string,
175
- ): boolean {
159
+ export function hasPhaseCompleted(config: Partial<IntermediateStoreConfig>, phase: string, stepId: string): boolean {
176
160
  return readIntermediate(config, phase, stepId) !== undefined;
177
161
  }
@@ -11,10 +11,7 @@
11
11
  // result they receive. This keeps the validator side-effect free and
12
12
  // trivially testable.
13
13
 
14
- import {
15
- analyzeWorkflowTopology,
16
- type WorkflowTopology,
17
- } from "./topology-analyzer.ts";
14
+ import { analyzeWorkflowTopology, type WorkflowTopology } from "./topology-analyzer.ts";
18
15
  import type { WorkflowConfig } from "./workflow-config.ts";
19
16
 
20
17
  export interface PreflightOptions {
@@ -43,12 +40,7 @@ export interface PreflightResult {
43
40
  recommendation: string;
44
41
  }
45
42
 
46
- function info(
47
- topology: WorkflowTopology,
48
- stepCount: number,
49
- recommendation: string,
50
- message: string,
51
- ): PreflightResult {
43
+ function info(topology: WorkflowTopology, stepCount: number, recommendation: string, message: string): PreflightResult {
52
44
  return {
53
45
  level: "info",
54
46
  message,
@@ -59,12 +51,7 @@ function info(
59
51
  };
60
52
  }
61
53
 
62
- function note(
63
- topology: WorkflowTopology,
64
- stepCount: number,
65
- recommendation: string,
66
- message: string,
67
- ): PreflightResult {
54
+ function note(topology: WorkflowTopology, stepCount: number, recommendation: string, message: string): PreflightResult {
68
55
  return {
69
56
  level: "note",
70
57
  message,
@@ -75,13 +62,7 @@ function note(
75
62
  };
76
63
  }
77
64
 
78
- function warn(
79
- topology: WorkflowTopology,
80
- stepCount: number,
81
- recommendation: string,
82
- message: string,
83
- suggestion: string,
84
- ): PreflightResult {
65
+ function warn(topology: WorkflowTopology, stepCount: number, recommendation: string, message: string, suggestion: string): PreflightResult {
85
66
  return {
86
67
  level: "warn",
87
68
  message,
@@ -108,21 +89,13 @@ function warn(
108
89
  * No `block` level exists — there is no scenario where pi-crew hard-rejects a call.
109
90
  * The agent always gets to decide.
110
91
  */
111
- export function validateWorkflowUsage(
112
- workflow: WorkflowConfig,
113
- options: PreflightOptions = {},
114
- ): PreflightResult {
92
+ export function validateWorkflowUsage(workflow: WorkflowConfig, options: PreflightOptions = {}): PreflightResult {
115
93
  const analysis = analyzeWorkflowTopology(workflow);
116
94
  const { topology, stepCount, recommendation } = analysis;
117
95
 
118
96
  // Rule 0: dynamic workflows are runtime-decided.
119
97
  if (topology === "dynamic") {
120
- return info(
121
- topology,
122
- stepCount,
123
- recommendation,
124
- "Dynamic workflow — runtime decides topology.",
125
- );
98
+ return info(topology, stepCount, recommendation, "Dynamic workflow — runtime decides topology.");
126
99
  }
127
100
 
128
101
  // Rule 0b: explicit force-bypass acknowledged (still log it).
@@ -20,19 +20,9 @@
20
20
 
21
21
  import type { WorkflowConfig, WorkflowStep } from "./workflow-config.ts";
22
22
 
23
- export type WorkflowTopology =
24
- | "single"
25
- | "sequential"
26
- | "concurrent"
27
- | "complex-dag"
28
- | "dynamic";
23
+ export type WorkflowTopology = "single" | "sequential" | "concurrent" | "complex-dag" | "dynamic";
29
24
 
30
- export type TopologyRecommendation =
31
- | "raw_agent"
32
- | "fast_fix"
33
- | "parallel_research"
34
- | "implementation_adaptive"
35
- | "any";
25
+ export type TopologyRecommendation = "raw_agent" | "fast_fix" | "parallel_research" | "implementation_adaptive" | "any";
36
26
 
37
27
  export interface TopologyAnalysis {
38
28
  topology: WorkflowTopology;
@@ -58,10 +48,7 @@ export function fanOutDegreeFromSteps(steps: WorkflowStep[]): number {
58
48
  const counts = new Map<string, number>();
59
49
  for (const step of steps) {
60
50
  if (step.parallelGroup === undefined) continue;
61
- counts.set(
62
- step.parallelGroup,
63
- (counts.get(step.parallelGroup) ?? 0) + 1,
64
- );
51
+ counts.set(step.parallelGroup, (counts.get(step.parallelGroup) ?? 0) + 1);
65
52
  }
66
53
  let max = 0;
67
54
  for (const count of counts.values()) if (count > max) max = count;
@@ -129,9 +116,7 @@ function hasMultiDeps(steps: WorkflowStep[]): boolean {
129
116
  * Classify a workflow's topology. See file header for the rule order.
130
117
  * Pure function — no I/O, no side effects, no exceptions.
131
118
  */
132
- export function analyzeWorkflowTopology(
133
- workflow: WorkflowConfig,
134
- ): TopologyAnalysis {
119
+ export function analyzeWorkflowTopology(workflow: WorkflowConfig): TopologyAnalysis {
135
120
  // Chain/dynamic workflows: runtime decides the topology at execution time.
136
121
  // Don't try to classify the empty `steps: []` (DynamicWorkflowConfig forces
137
122
  // it to be empty).
@@ -186,8 +171,7 @@ export function analyzeWorkflowTopology(
186
171
  if (stepCount === 1) {
187
172
  topology = "single";
188
173
  recommendation = "raw_agent";
189
- reason =
190
- "Single-task workflow: no concurrency or DAG structure to justify pi-crew overhead.";
174
+ reason = "Single-task workflow: no concurrency or DAG structure to justify pi-crew overhead.";
191
175
  } else if (parallelGroupCount >= 1 && fanOutDegree >= 3) {
192
176
  topology = "concurrent";
193
177
  recommendation = "parallel_research";
@@ -53,12 +53,13 @@ export interface WorkflowConfig {
53
53
  * Used by preflight-validator to enforce "don't use pi-crew for sequential chains".
54
54
  * Valid values: 'single' | 'sequential' | 'concurrent' | 'complex-dag' | 'dynamic'.
55
55
  * Absent = auto-classify from step structure (default). */
56
- topology?:
57
- | "single"
58
- | "sequential"
59
- | "concurrent"
60
- | "complex-dag"
61
- | "dynamic";
56
+ topology?: "single" | "sequential" | "concurrent" | "complex-dag" | "dynamic";
57
+ /** Round 25 (M6): coalesce micro-tasks. Default false (off). When true,
58
+ * multiple ready tasks sharing role + cwd are grouped into a single
59
+ * multi-task worker prompt to reduce per-task cold-start cost. Disabled
60
+ * in v0.9.17 unless the workflow author opts in. See
61
+ * src/runtime/coalesce-tasks.ts. */
62
+ coalesceMicroTasks?: boolean;
62
63
  }
63
64
 
64
65
  /** A dynamic workflow (runtime === "dynamic"). steps is empty — the script is the source of truth. */