pi-crew 0.9.53 → 0.9.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (493) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/package.json +6 -3
  3. package/scripts/clean-strip-types.mjs +60 -0
  4. package/src/adapters/claude-adapter.ts +23 -0
  5. package/src/adapters/codex-adapter.ts +21 -0
  6. package/src/adapters/cursor-adapter.ts +17 -0
  7. package/src/adapters/export-util.ts +143 -0
  8. package/src/adapters/index.ts +15 -0
  9. package/src/adapters/registry.ts +18 -0
  10. package/src/adapters/types.ts +23 -0
  11. package/src/agents/agent-config.ts +194 -0
  12. package/src/agents/agent-search.ts +98 -0
  13. package/src/agents/agent-serializer.ts +38 -0
  14. package/src/agents/discover-agents.ts +623 -0
  15. package/src/benchmark/benchmark-runner.ts +313 -0
  16. package/src/benchmark/feedback-loop.ts +73 -0
  17. package/src/config/config.ts +1270 -0
  18. package/src/config/defaults.ts +193 -0
  19. package/src/config/drift-detector.ts +290 -0
  20. package/src/config/markers.ts +330 -0
  21. package/src/config/resilient-parser.ts +117 -0
  22. package/src/config/role-tools.ts +118 -0
  23. package/src/config/suggestions.ts +75 -0
  24. package/src/config/types.ts +280 -0
  25. package/src/errors.ts +194 -0
  26. package/src/extension/action-suggestions.ts +117 -0
  27. package/src/extension/async-notifier.ts +179 -0
  28. package/src/extension/autonomous-policy.ts +209 -0
  29. package/src/extension/command-completions.ts +120 -0
  30. package/src/extension/context-status-injection.ts +185 -0
  31. package/src/extension/crew-autocomplete.ts +131 -0
  32. package/src/extension/crew-cleanup.ts +168 -0
  33. package/src/extension/crew-input-router.ts +93 -0
  34. package/src/extension/crew-shortcuts.ts +87 -0
  35. package/src/extension/crew-vibes/cat-frames.ts +18 -0
  36. package/src/extension/crew-vibes/config.ts +195 -0
  37. package/src/extension/crew-vibes/figures.ts +101 -0
  38. package/src/extension/crew-vibes/font-detect.ts +71 -0
  39. package/src/extension/crew-vibes/footer.ts +292 -0
  40. package/src/extension/crew-vibes/index.ts +432 -0
  41. package/src/extension/crew-vibes/provider-usage.ts +396 -0
  42. package/src/extension/crew-vibes/render.ts +206 -0
  43. package/src/extension/crew-vibes/speed.ts +286 -0
  44. package/src/extension/cross-extension-rpc.ts +350 -0
  45. package/src/extension/help.ts +62 -0
  46. package/src/extension/import-index.ts +74 -0
  47. package/src/extension/knowledge-injection.ts +402 -0
  48. package/src/extension/management.ts +571 -0
  49. package/src/extension/message-renderers.ts +108 -0
  50. package/src/extension/notification-router.ts +152 -0
  51. package/src/extension/notification-sink.ts +54 -0
  52. package/src/extension/pi-api.ts +56 -0
  53. package/src/extension/plan-orchestrate.ts +302 -0
  54. package/src/extension/project-init.ts +170 -0
  55. package/src/extension/register.ts +113 -0
  56. package/src/extension/registration/artifact-cleanup.ts +20 -0
  57. package/src/extension/registration/command-registration.ts +58 -0
  58. package/src/extension/registration/command-utils.ts +58 -0
  59. package/src/extension/registration/commands.ts +1228 -0
  60. package/src/extension/registration/compaction-guard.ts +333 -0
  61. package/src/extension/registration/context-builder.ts +135 -0
  62. package/src/extension/registration/crash-recovery-cache.ts +54 -0
  63. package/src/extension/registration/foreground-run-controller.ts +238 -0
  64. package/src/extension/registration/hook-registration.ts +119 -0
  65. package/src/extension/registration/lazy-configurers.ts +124 -0
  66. package/src/extension/registration/lifecycle-handlers.ts +923 -0
  67. package/src/extension/registration/lifecycle.ts +259 -0
  68. package/src/extension/registration/observability.ts +322 -0
  69. package/src/extension/registration/registration-types.ts +158 -0
  70. package/src/extension/registration/runtime-cleanup.ts +230 -0
  71. package/src/extension/registration/subagent-helpers.ts +125 -0
  72. package/src/extension/registration/subagent-manager-setup.ts +330 -0
  73. package/src/extension/registration/subagent-tools.ts +456 -0
  74. package/src/extension/registration/team-tool.ts +225 -0
  75. package/src/extension/registration/tool-registration.ts +50 -0
  76. package/src/extension/registration/ui.ts +172 -0
  77. package/src/extension/registration/viewers.ts +121 -0
  78. package/src/extension/registration/wire-cross-extension.ts +37 -0
  79. package/src/extension/result-watcher.ts +139 -0
  80. package/src/extension/rpc-hmac.ts +256 -0
  81. package/src/extension/run-bundle-schema.ts +104 -0
  82. package/src/extension/run-export.ts +97 -0
  83. package/src/extension/run-import.ts +168 -0
  84. package/src/extension/run-index.ts +131 -0
  85. package/src/extension/run-maintenance.ts +190 -0
  86. package/src/extension/session-summary.ts +18 -0
  87. package/src/extension/team-manager-command.ts +153 -0
  88. package/src/extension/team-onboard.ts +180 -0
  89. package/src/extension/team-recommendation.ts +288 -0
  90. package/src/extension/team-tool/anchor.ts +172 -0
  91. package/src/extension/team-tool/api.ts +1244 -0
  92. package/src/extension/team-tool/auto-summarize.ts +142 -0
  93. package/src/extension/team-tool/cache-control.ts +19 -0
  94. package/src/extension/team-tool/cancel.ts +337 -0
  95. package/src/extension/team-tool/chain-dispatch.ts +95 -0
  96. package/src/extension/team-tool/chain-executor.ts +379 -0
  97. package/src/extension/team-tool/config-patch.ts +50 -0
  98. package/src/extension/team-tool/context.ts +149 -0
  99. package/src/extension/team-tool/destructive-gate.ts +52 -0
  100. package/src/extension/team-tool/dispatch/automate.ts +80 -0
  101. package/src/extension/team-tool/dispatch/control.ts +42 -0
  102. package/src/extension/team-tool/dispatch/index.ts +95 -0
  103. package/src/extension/team-tool/dispatch/manage.ts +161 -0
  104. package/src/extension/team-tool/dispatch/run.ts +53 -0
  105. package/src/extension/team-tool/dispatch/status.ts +187 -0
  106. package/src/extension/team-tool/doctor.ts +431 -0
  107. package/src/extension/team-tool/explain.ts +282 -0
  108. package/src/extension/team-tool/failure-patterns.ts +118 -0
  109. package/src/extension/team-tool/goal-wrap.ts +330 -0
  110. package/src/extension/team-tool/goal.ts +556 -0
  111. package/src/extension/team-tool/handle-schedule.ts +332 -0
  112. package/src/extension/team-tool/handle-settings.ts +520 -0
  113. package/src/extension/team-tool/health-monitor.ts +481 -0
  114. package/src/extension/team-tool/inspect.ts +88 -0
  115. package/src/extension/team-tool/intent-policy.ts +45 -0
  116. package/src/extension/team-tool/lifecycle-actions.ts +615 -0
  117. package/src/extension/team-tool/orchestrate.ts +98 -0
  118. package/src/extension/team-tool/parallel-dispatch.ts +183 -0
  119. package/src/extension/team-tool/plan.ts +50 -0
  120. package/src/extension/team-tool/respond.ts +150 -0
  121. package/src/extension/team-tool/run-deadline.ts +66 -0
  122. package/src/extension/team-tool/run-not-found.ts +49 -0
  123. package/src/extension/team-tool/run.ts +1051 -0
  124. package/src/extension/team-tool/status.ts +260 -0
  125. package/src/extension/team-tool/workflow-manage.ts +261 -0
  126. package/src/extension/team-tool-types.ts +26 -0
  127. package/src/extension/team-tool.ts +750 -0
  128. package/src/extension/tool-result.ts +16 -0
  129. package/src/extension/validate-resources.ts +108 -0
  130. package/src/hooks/registry.ts +200 -0
  131. package/src/hooks/types.ts +69 -0
  132. package/src/i18n.ts +212 -0
  133. package/src/observability/correlation.ts +50 -0
  134. package/src/observability/event-bus.ts +86 -0
  135. package/src/observability/event-to-metric.ts +170 -0
  136. package/src/observability/exporters/adapter.ts +27 -0
  137. package/src/observability/exporters/otlp-exporter.ts +356 -0
  138. package/src/observability/exporters/prometheus-exporter.ts +54 -0
  139. package/src/observability/metric-registry.ts +100 -0
  140. package/src/observability/metric-retention.ts +64 -0
  141. package/src/observability/metric-sink.ts +99 -0
  142. package/src/observability/metrics-primitives.ts +219 -0
  143. package/src/plugins/plugin-define.ts +6 -0
  144. package/src/plugins/plugin-registry.ts +32 -0
  145. package/src/plugins/plugins/index.ts +3 -0
  146. package/src/plugins/plugins/nextjs.ts +19 -0
  147. package/src/plugins/plugins/vite.ts +10 -0
  148. package/src/plugins/plugins/vitest.ts +9 -0
  149. package/src/prompt/prompt-runtime.ts +380 -0
  150. package/src/runtime/adaptive-plan.ts +563 -0
  151. package/src/runtime/agent-control.ts +215 -0
  152. package/src/runtime/agent-memory.ts +81 -0
  153. package/src/runtime/agent-observability.ts +122 -0
  154. package/src/runtime/anchor-manager.ts +475 -0
  155. package/src/runtime/async-marker.ts +32 -0
  156. package/src/runtime/async-runner.ts +381 -0
  157. package/src/runtime/attention-events.ts +28 -0
  158. package/src/runtime/auto-summarize.ts +344 -0
  159. package/src/runtime/background-runner.ts +840 -0
  160. package/src/runtime/batch-barrier.ts +147 -0
  161. package/src/runtime/broker-issuer.ts +39 -0
  162. package/src/runtime/cancellation-token.ts +99 -0
  163. package/src/runtime/cancellation.ts +99 -0
  164. package/src/runtime/capability-inventory.ts +137 -0
  165. package/src/runtime/chain-parser.ts +237 -0
  166. package/src/runtime/chain-runner.ts +606 -0
  167. package/src/runtime/checkpoint.ts +291 -0
  168. package/src/runtime/child-pi-constants.ts +42 -0
  169. package/src/runtime/child-pi-kill.ts +180 -0
  170. package/src/runtime/child-pi-pool.ts +68 -0
  171. package/src/runtime/child-pi-spawn.ts +287 -0
  172. package/src/runtime/child-pi-steering.ts +128 -0
  173. package/src/runtime/child-pi-streams.ts +296 -0
  174. package/src/runtime/child-pi-transcript.ts +169 -0
  175. package/src/runtime/child-pi.ts +1105 -0
  176. package/src/runtime/coalesce-tasks.ts +268 -0
  177. package/src/runtime/code-summary.ts +292 -0
  178. package/src/runtime/command-trace.ts +105 -0
  179. package/src/runtime/compact-pipeline.ts +56 -0
  180. package/src/runtime/compact-stages/ansi-strip-stage.ts +25 -0
  181. package/src/runtime/compact-stages/blank-collapse-stage.ts +31 -0
  182. package/src/runtime/compact-stages/deduplicate-stage.ts +34 -0
  183. package/src/runtime/compact-stages/head-snap-stage.ts +57 -0
  184. package/src/runtime/compact-stages/index.ts +23 -0
  185. package/src/runtime/compact-stages/tail-capture-stage.ts +77 -0
  186. package/src/runtime/compact-stages/truncation-stage.ts +74 -0
  187. package/src/runtime/compaction-summary.ts +278 -0
  188. package/src/runtime/completion-guard.ts +207 -0
  189. package/src/runtime/concurrency.ts +58 -0
  190. package/src/runtime/crash-classification.ts +229 -0
  191. package/src/runtime/crash-recovery.ts +594 -0
  192. package/src/runtime/crew-agent-records.ts +595 -0
  193. package/src/runtime/crew-agent-runtime.ts +62 -0
  194. package/src/runtime/crew-broker-child.ts +88 -0
  195. package/src/runtime/crew-broker-client.ts +673 -0
  196. package/src/runtime/crew-broker-tokens.ts +159 -0
  197. package/src/runtime/crew-broker.ts +1304 -0
  198. package/src/runtime/crew-hooks.ts +227 -0
  199. package/src/runtime/cross-extension-rpc.ts +143 -0
  200. package/src/runtime/custom-tools/irc-tool.ts +282 -0
  201. package/src/runtime/custom-tools/submit-result-tool.ts +102 -0
  202. package/src/runtime/deadletter.ts +47 -0
  203. package/src/runtime/delivery-coordinator.ts +211 -0
  204. package/src/runtime/delta-conflict.ts +348 -0
  205. package/src/runtime/deterministic-ast.ts +161 -0
  206. package/src/runtime/diagnostic-export.ts +171 -0
  207. package/src/runtime/direct-run.ts +45 -0
  208. package/src/runtime/dwf-state-store.ts +102 -0
  209. package/src/runtime/dynamic-workflow-context.ts +1013 -0
  210. package/src/runtime/dynamic-workflow-runner.ts +325 -0
  211. package/src/runtime/effectiveness.ts +90 -0
  212. package/src/runtime/errors/crew-errors.ts +162 -0
  213. package/src/runtime/event-stream-bridge.ts +98 -0
  214. package/src/runtime/foreground-control.ts +193 -0
  215. package/src/runtime/foreground-watchdog.ts +132 -0
  216. package/src/runtime/global-worker-cap.ts +96 -0
  217. package/src/runtime/goal-achievement.ts +148 -0
  218. package/src/runtime/goal-evaluator.ts +365 -0
  219. package/src/runtime/goal-loop-runner.ts +825 -0
  220. package/src/runtime/goal-state-store.ts +219 -0
  221. package/src/runtime/green-contract.ts +55 -0
  222. package/src/runtime/group-join.ts +267 -0
  223. package/src/runtime/handoff-manager.ts +598 -0
  224. package/src/runtime/heartbeat-gradient.ts +36 -0
  225. package/src/runtime/heartbeat-watcher.ts +239 -0
  226. package/src/runtime/hidden-handoff.ts +407 -0
  227. package/src/runtime/important-line-classifier.ts +140 -0
  228. package/src/runtime/intercom-bridge.ts +187 -0
  229. package/src/runtime/iteration-hooks.ts +305 -0
  230. package/src/runtime/live-agent-control.ts +136 -0
  231. package/src/runtime/live-agent-manager.ts +704 -0
  232. package/src/runtime/live-control-realtime.ts +56 -0
  233. package/src/runtime/live-extension-bridge.ts +148 -0
  234. package/src/runtime/live-irc.ts +97 -0
  235. package/src/runtime/live-session-health.ts +108 -0
  236. package/src/runtime/live-session-runtime.ts +1146 -0
  237. package/src/runtime/loop-gates.ts +128 -0
  238. package/src/runtime/manifest-cache.ts +375 -0
  239. package/src/runtime/mcp-proxy.ts +105 -0
  240. package/src/runtime/metric-parser.ts +36 -0
  241. package/src/runtime/model-fallback.ts +409 -0
  242. package/src/runtime/model-resolver.ts +126 -0
  243. package/src/runtime/model-scope.ts +158 -0
  244. package/src/runtime/orphan-worker-registry.ts +465 -0
  245. package/src/runtime/output-validator.ts +202 -0
  246. package/src/runtime/overflow-recovery.ts +206 -0
  247. package/src/runtime/parallel-research.ts +68 -0
  248. package/src/runtime/parallel-utils.ts +160 -0
  249. package/src/runtime/parent-guard.ts +134 -0
  250. package/src/runtime/path-overlap.ts +150 -0
  251. package/src/runtime/peer-dep.ts +292 -0
  252. package/src/runtime/per-write-validator.ts +181 -0
  253. package/src/runtime/phase-progress.ts +217 -0
  254. package/src/runtime/phase-tracker.ts +385 -0
  255. package/src/runtime/pi-args.ts +655 -0
  256. package/src/runtime/pi-json-output.ts +170 -0
  257. package/src/runtime/pi-spawn.ts +273 -0
  258. package/src/runtime/pipeline-runner.ts +523 -0
  259. package/src/runtime/plan-templates.ts +201 -0
  260. package/src/runtime/policy-engine.ts +115 -0
  261. package/src/runtime/post-checks.ts +142 -0
  262. package/src/runtime/post-exit-stdio-guard.ts +109 -0
  263. package/src/runtime/process-lifecycle.ts +491 -0
  264. package/src/runtime/process-status.ts +154 -0
  265. package/src/runtime/progress-event-coalescer.ts +44 -0
  266. package/src/runtime/progress-tracker.ts +124 -0
  267. package/src/runtime/prose-compressor.ts +162 -0
  268. package/src/runtime/recovery-recipes.ts +203 -0
  269. package/src/runtime/replace.ts +570 -0
  270. package/src/runtime/resilient-edit.ts +153 -0
  271. package/src/runtime/result-extractor.ts +217 -0
  272. package/src/runtime/retry-executor.ts +109 -0
  273. package/src/runtime/retry-runner.ts +336 -0
  274. package/src/runtime/role-permission.ts +59 -0
  275. package/src/runtime/run-coalesced-task-group.ts +308 -0
  276. package/src/runtime/run-drift.ts +219 -0
  277. package/src/runtime/run-tracker.ts +116 -0
  278. package/src/runtime/run-worker.ts +78 -0
  279. package/src/runtime/runtime-policy.ts +29 -0
  280. package/src/runtime/runtime-resolver.ts +172 -0
  281. package/src/runtime/runtime-warmup.ts +160 -0
  282. package/src/runtime/scheduler.ts +353 -0
  283. package/src/runtime/semaphore.ts +141 -0
  284. package/src/runtime/sensitive-paths.ts +93 -0
  285. package/src/runtime/session-resources.ts +25 -0
  286. package/src/runtime/session-snapshot.ts +59 -0
  287. package/src/runtime/session-usage.ts +79 -0
  288. package/src/runtime/settings-store.ts +155 -0
  289. package/src/runtime/sidechain-output.ts +35 -0
  290. package/src/runtime/single-agent-compose.ts +84 -0
  291. package/src/runtime/skill-effectiveness.ts +524 -0
  292. package/src/runtime/skill-instructions.ts +394 -0
  293. package/src/runtime/stale-reconciler.ts +680 -0
  294. package/src/runtime/stream-preview.ts +184 -0
  295. package/src/runtime/streaming-output.ts +50 -0
  296. package/src/runtime/subagent-manager.ts +561 -0
  297. package/src/runtime/subprocess-tool-registry.ts +70 -0
  298. package/src/runtime/supervisor-contact.ts +64 -0
  299. package/src/runtime/task-display.ts +52 -0
  300. package/src/runtime/task-graph-scheduler.ts +227 -0
  301. package/src/runtime/task-graph.ts +290 -0
  302. package/src/runtime/task-health.ts +83 -0
  303. package/src/runtime/task-id.ts +161 -0
  304. package/src/runtime/task-output-context.ts +602 -0
  305. package/src/runtime/task-packet.ts +268 -0
  306. package/src/runtime/task-quality.ts +199 -0
  307. package/src/runtime/task-runner/capabilities.ts +78 -0
  308. package/src/runtime/task-runner/child-executor.ts +790 -0
  309. package/src/runtime/task-runner/context-retrieval.ts +163 -0
  310. package/src/runtime/task-runner/live-executor.ts +227 -0
  311. package/src/runtime/task-runner/output-splitter.ts +152 -0
  312. package/src/runtime/task-runner/post-execution.ts +480 -0
  313. package/src/runtime/task-runner/pre-execution.ts +365 -0
  314. package/src/runtime/task-runner/progress.ts +157 -0
  315. package/src/runtime/task-runner/prompt-builder.ts +278 -0
  316. package/src/runtime/task-runner/prompt-pipeline.ts +88 -0
  317. package/src/runtime/task-runner/result-utils.ts +16 -0
  318. package/src/runtime/task-runner/retrieval-orchestrator.ts +310 -0
  319. package/src/runtime/task-runner/run-projection.ts +125 -0
  320. package/src/runtime/task-runner/scaffold-executor.ts +25 -0
  321. package/src/runtime/task-runner/state-helpers.ts +176 -0
  322. package/src/runtime/task-runner/tail-read.ts +34 -0
  323. package/src/runtime/task-runner.ts +216 -0
  324. package/src/runtime/team-runner-artifacts.ts +13 -0
  325. package/src/runtime/team-runner.ts +2396 -0
  326. package/src/runtime/tool-output-pruner.ts +333 -0
  327. package/src/runtime/tool-progress.ts +278 -0
  328. package/src/runtime/usage-tracker.ts +73 -0
  329. package/src/runtime/verification-gates.ts +579 -0
  330. package/src/runtime/verification-integrity.ts +108 -0
  331. package/src/runtime/verification-worktree.ts +186 -0
  332. package/src/runtime/worker-heartbeat.ts +25 -0
  333. package/src/runtime/worker-startup.ts +83 -0
  334. package/src/runtime/workflow-state.ts +195 -0
  335. package/src/runtime/workspace-lock.ts +443 -0
  336. package/src/runtime/workspace-tree.ts +312 -0
  337. package/src/runtime/yield-handler.ts +224 -0
  338. package/src/runtime/zombie-scanner.ts +298 -0
  339. package/src/schema/config-schema.ts +327 -0
  340. package/src/schema/team-tool-schema.ts +492 -0
  341. package/src/schema/validation-types.ts +159 -0
  342. package/src/skills/discover-skills.ts +203 -0
  343. package/src/skills/skill-templates.ts +456 -0
  344. package/src/skills/validate.ts +285 -0
  345. package/src/state/active-run-registry.ts +439 -0
  346. package/src/state/artifact-store.ts +176 -0
  347. package/src/state/atomic-write.ts +970 -0
  348. package/src/state/blob-store.ts +308 -0
  349. package/src/state/contracts.ts +160 -0
  350. package/src/state/crew-init.ts +269 -0
  351. package/src/state/decision-ledger.ts +372 -0
  352. package/src/state/event-log-rotation.ts +399 -0
  353. package/src/state/event-log.ts +1465 -0
  354. package/src/state/event-reconstructor.ts +229 -0
  355. package/src/state/gitignore-manager.ts +46 -0
  356. package/src/state/health-store.ts +79 -0
  357. package/src/state/hook-instinct-bridge.ts +94 -0
  358. package/src/state/hook-integrations.ts +51 -0
  359. package/src/state/instinct-store.ts +275 -0
  360. package/src/state/jsonl-writer.ts +107 -0
  361. package/src/state/locks.ts +562 -0
  362. package/src/state/mailbox.ts +916 -0
  363. package/src/state/observation-store.ts +176 -0
  364. package/src/state/run-cache.ts +193 -0
  365. package/src/state/run-graph.ts +183 -0
  366. package/src/state/run-metrics.ts +165 -0
  367. package/src/state/schedule.ts +166 -0
  368. package/src/state/session-state-map.ts +51 -0
  369. package/src/state/state-store.ts +973 -0
  370. package/src/state/task-claims.ts +61 -0
  371. package/src/state/tiered-eval.ts +480 -0
  372. package/src/state/types-eval.ts +58 -0
  373. package/src/state/types.ts +447 -0
  374. package/src/state/usage.ts +138 -0
  375. package/src/state/worker-atomic-writer.ts +198 -0
  376. package/src/subagents/async-entry.ts +1 -0
  377. package/src/subagents/index.ts +3 -0
  378. package/src/subagents/live/control.ts +1 -0
  379. package/src/subagents/live/manager.ts +1 -0
  380. package/src/subagents/live/realtime.ts +1 -0
  381. package/src/subagents/live/session-runtime.ts +1 -0
  382. package/src/subagents/manager.ts +1 -0
  383. package/src/subagents/spawn.ts +1 -0
  384. package/src/teams/discover-teams.ts +187 -0
  385. package/src/teams/team-config.ts +27 -0
  386. package/src/teams/team-serializer.ts +38 -0
  387. package/src/tools/safe-bash-extension.ts +54 -0
  388. package/src/tools/safe-bash.ts +505 -0
  389. package/src/types/diff.d.ts +18 -0
  390. package/src/types/new-api-types.ts +35 -0
  391. package/src/ui/agent-management-overlay.ts +160 -0
  392. package/src/ui/card-colors.ts +139 -0
  393. package/src/ui/crew-footer.ts +102 -0
  394. package/src/ui/crew-select-list.ts +112 -0
  395. package/src/ui/dashboard-panes/agents-pane.ts +164 -0
  396. package/src/ui/dashboard-panes/cancellation-pane.ts +66 -0
  397. package/src/ui/dashboard-panes/capability-pane.ts +77 -0
  398. package/src/ui/dashboard-panes/health-pane.ts +31 -0
  399. package/src/ui/dashboard-panes/mailbox-pane.ts +35 -0
  400. package/src/ui/dashboard-panes/metrics-pane.ts +37 -0
  401. package/src/ui/dashboard-panes/progress-pane.ts +38 -0
  402. package/src/ui/dashboard-panes/transcript-pane.ts +10 -0
  403. package/src/ui/deploy-bundled-themes.ts +71 -0
  404. package/src/ui/dwf-phase-display.ts +151 -0
  405. package/src/ui/dynamic-border.ts +35 -0
  406. package/src/ui/format-helpers.ts +31 -0
  407. package/src/ui/heartbeat-aggregator.ts +74 -0
  408. package/src/ui/key-utils.ts +42 -0
  409. package/src/ui/keybinding-map.ts +248 -0
  410. package/src/ui/layout-primitives.ts +106 -0
  411. package/src/ui/live-conversation-overlay.ts +183 -0
  412. package/src/ui/live-duration.ts +55 -0
  413. package/src/ui/live-run-sidebar.ts +293 -0
  414. package/src/ui/loaders.ts +6 -0
  415. package/src/ui/mascot.ts +449 -0
  416. package/src/ui/overlays/agent-picker-overlay.ts +66 -0
  417. package/src/ui/overlays/confirm-overlay.ts +60 -0
  418. package/src/ui/overlays/help-overlay.ts +177 -0
  419. package/src/ui/overlays/mailbox-compose-overlay.ts +181 -0
  420. package/src/ui/overlays/mailbox-compose-preview.ts +78 -0
  421. package/src/ui/overlays/mailbox-detail-overlay.ts +155 -0
  422. package/src/ui/pi-ui-compat.ts +68 -0
  423. package/src/ui/powerbar-publisher.ts +459 -0
  424. package/src/ui/render-coalescer.ts +101 -0
  425. package/src/ui/render-diff.ts +160 -0
  426. package/src/ui/render-scheduler.ts +278 -0
  427. package/src/ui/run-action-dispatcher.ts +182 -0
  428. package/src/ui/run-dashboard.ts +910 -0
  429. package/src/ui/run-event-bus.ts +381 -0
  430. package/src/ui/run-snapshot-cache.ts +1057 -0
  431. package/src/ui/settings-overlay.ts +1067 -0
  432. package/src/ui/shared-overlay-scheduler.ts +96 -0
  433. package/src/ui/snapshot-types.ts +90 -0
  434. package/src/ui/spinner.ts +17 -0
  435. package/src/ui/status-colors.ts +143 -0
  436. package/src/ui/syntax-highlight.ts +136 -0
  437. package/src/ui/terminal-status.ts +269 -0
  438. package/src/ui/theme-adapter.ts +271 -0
  439. package/src/ui/theme-discovery.ts +199 -0
  440. package/src/ui/tool-progress-formatter.ts +93 -0
  441. package/src/ui/tool-renderers/brief-mode.ts +225 -0
  442. package/src/ui/tool-renderers/index.ts +726 -0
  443. package/src/ui/transcript-cache.ts +128 -0
  444. package/src/ui/transcript-entries.ts +256 -0
  445. package/src/ui/transcript-viewer.ts +424 -0
  446. package/src/ui/widget/index.ts +418 -0
  447. package/src/ui/widget/widget-formatters.ts +182 -0
  448. package/src/ui/widget/widget-model.ts +110 -0
  449. package/src/ui/widget/widget-renderer.ts +182 -0
  450. package/src/ui/widget/widget-types.ts +36 -0
  451. package/src/utils/bm25-search.ts +235 -0
  452. package/src/utils/completion-dedupe.ts +63 -0
  453. package/src/utils/conflict-detect.ts +668 -0
  454. package/src/utils/env-allowlist.ts +30 -0
  455. package/src/utils/env-filter.ts +155 -0
  456. package/src/utils/file-coalescer.ts +98 -0
  457. package/src/utils/fingerprint.ts +180 -0
  458. package/src/utils/frontmatter.ts +70 -0
  459. package/src/utils/fs-watch.ts +37 -0
  460. package/src/utils/gh-protocol.ts +556 -0
  461. package/src/utils/git.ts +260 -0
  462. package/src/utils/guards.ts +107 -0
  463. package/src/utils/ids.ts +24 -0
  464. package/src/utils/incremental-reader.ts +220 -0
  465. package/src/utils/internal-error.ts +10 -0
  466. package/src/utils/names.ts +36 -0
  467. package/src/utils/ndjson.ts +115 -0
  468. package/src/utils/paths.ts +227 -0
  469. package/src/utils/project-detector.ts +160 -0
  470. package/src/utils/redaction.ts +370 -0
  471. package/src/utils/resolve-shell.ts +36 -0
  472. package/src/utils/run-watcher-registry.ts +152 -0
  473. package/src/utils/safe-paths.ts +393 -0
  474. package/src/utils/scan-cache.ts +144 -0
  475. package/src/utils/session-utils.ts +110 -0
  476. package/src/utils/sleep.ts +54 -0
  477. package/src/utils/socket-path.ts +164 -0
  478. package/src/utils/sse-parser.ts +131 -0
  479. package/src/utils/task-name-generator.ts +337 -0
  480. package/src/utils/timings.ts +33 -0
  481. package/src/utils/token-counter.ts +200 -0
  482. package/src/utils/visual.ts +207 -0
  483. package/src/workflows/cost-estimator.ts +34 -0
  484. package/src/workflows/discover-workflows.ts +308 -0
  485. package/src/workflows/intermediate-store.ts +166 -0
  486. package/src/workflows/preflight-validator.ts +168 -0
  487. package/src/workflows/topology-analyzer.ts +203 -0
  488. package/src/workflows/validate-workflow.ts +50 -0
  489. package/src/workflows/workflow-config.ts +75 -0
  490. package/src/workflows/workflow-serializer.ts +32 -0
  491. package/src/worktree/branch-freshness.ts +112 -0
  492. package/src/worktree/cleanup.ts +341 -0
  493. package/src/worktree/worktree-manager.ts +1204 -0
@@ -0,0 +1,152 @@
1
+ import { logInternalError } from "../utils/internal-error.ts";
2
+
3
+ export type Severity = "info" | "warning" | "error" | "critical";
4
+
5
+ export interface NotificationDescriptor {
6
+ id?: string;
7
+ severity: Severity;
8
+ source: string;
9
+ runId?: string;
10
+ title: string;
11
+ body?: string;
12
+ timestamp?: number;
13
+ }
14
+
15
+ export interface NotificationRouterOptions {
16
+ dedupWindowMs?: number;
17
+ batchWindowMs?: number;
18
+ quietHours?: string;
19
+ severityFilter?: Severity[];
20
+ sink?: (notification: NotificationDescriptor) => void;
21
+ now?: () => number;
22
+ }
23
+
24
+ const DEFAULT_SEVERITY_FILTER: Severity[] = ["warning", "error", "critical"];
25
+ const SEVERITY_RANK: Record<Severity, number> = {
26
+ info: 0,
27
+ warning: 1,
28
+ error: 2,
29
+ critical: 3,
30
+ };
31
+
32
+ export function parseHHMMRange(range: string): {
33
+ startMin: number;
34
+ endMin: number;
35
+ } {
36
+ const match = /^(\d{2}):(\d{2})-(\d{2}):(\d{2})$/.exec(range);
37
+ if (!match) throw new Error(`Invalid quiet-hours range '${range}'. Expected HH:MM-HH:MM.`);
38
+ const [, sh, sm, eh, em] = match;
39
+ const startHour = Number(sh);
40
+ const startMinute = Number(sm);
41
+ const endHour = Number(eh);
42
+ const endMinute = Number(em);
43
+ if (startHour > 23 || endHour > 23 || startMinute > 59 || endMinute > 59) throw new Error(`Invalid quiet-hours range '${range}'.`);
44
+ return {
45
+ startMin: startHour * 60 + startMinute,
46
+ endMin: endHour * 60 + endMinute,
47
+ };
48
+ }
49
+
50
+ export function isInQuietHours(range: string, now = new Date()): boolean {
51
+ const { startMin, endMin } = parseHHMMRange(range);
52
+ const current = now.getHours() * 60 + now.getMinutes();
53
+ if (startMin === endMin) return false;
54
+ return startMin <= endMin ? current >= startMin && current < endMin : current >= startMin || current < endMin;
55
+ }
56
+
57
+ function notificationKey(notification: NotificationDescriptor): string {
58
+ return notification.id ?? `${notification.source}:${notification.runId ?? "global"}:${notification.title}`;
59
+ }
60
+
61
+ function batchSeverity(items: NotificationDescriptor[]): Severity {
62
+ return items.reduce(
63
+ (highest, item) => (SEVERITY_RANK[item.severity] > SEVERITY_RANK[highest] ? item.severity : highest),
64
+ "info" as Severity,
65
+ );
66
+ }
67
+
68
+ export class NotificationRouter {
69
+ private readonly opts: NotificationRouterOptions;
70
+ private readonly deliver: (notification: NotificationDescriptor) => void;
71
+ private readonly seen = new Map<string, number>();
72
+ private batch: NotificationDescriptor[] = [];
73
+ private timer: ReturnType<typeof setTimeout> | undefined;
74
+ private static readonly SEEN_MAP_MAX_SIZE = 10000;
75
+
76
+ constructor(opts: NotificationRouterOptions = {}, deliver: (notification: NotificationDescriptor) => void) {
77
+ this.opts = opts;
78
+ this.deliver = deliver;
79
+ }
80
+
81
+ /**
82
+ * Evict oldest entries from seen Map if it exceeds MAX_SIZE.
83
+ * This prevents unbounded memory growth from notifications without TTL.
84
+ */
85
+ private evictSeenIfNeeded(): void {
86
+ if (this.seen.size > NotificationRouter.SEEN_MAP_MAX_SIZE) {
87
+ // Sort by timestamp (oldest first) and keep only half
88
+ const entries = [...this.seen.entries()].sort((a, b) => a[1] - b[1]);
89
+ const keepCount = Math.floor(NotificationRouter.SEEN_MAP_MAX_SIZE / 2);
90
+ for (const [key] of entries.slice(0, entries.length - keepCount)) {
91
+ this.seen.delete(key);
92
+ }
93
+ }
94
+ }
95
+
96
+ enqueue(notification: NotificationDescriptor): boolean {
97
+ const now = this.opts.now?.() ?? Date.now();
98
+ const withTime = {
99
+ ...notification,
100
+ timestamp: notification.timestamp ?? now,
101
+ };
102
+ try {
103
+ this.opts.sink?.(withTime);
104
+ } catch (sinkError) {
105
+ logInternalError("notification-sink", sinkError);
106
+ }
107
+ const filter = this.opts.severityFilter ?? DEFAULT_SEVERITY_FILTER;
108
+ if (!filter.includes(withTime.severity)) return false;
109
+ if (this.opts.quietHours && isInQuietHours(this.opts.quietHours, new Date(now))) return false;
110
+ const key = notificationKey(withTime);
111
+ const dedupWindow = this.opts.dedupWindowMs ?? 30_000;
112
+ const previous = this.seen.get(key);
113
+ if (previous !== undefined && now - previous < dedupWindow) return false;
114
+ this.seen.set(key, now);
115
+ this.evictSeenIfNeeded();
116
+ const batchWindow = this.opts.batchWindowMs ?? 0;
117
+ if (batchWindow <= 0) {
118
+ this.deliver(withTime);
119
+ return true;
120
+ }
121
+ this.batch.push(withTime);
122
+ if (!this.timer) this.timer = setTimeout(() => this.flush(), batchWindow);
123
+ return true;
124
+ }
125
+
126
+ flush(): void {
127
+ if (this.timer) clearTimeout(this.timer);
128
+ this.timer = undefined;
129
+ if (this.batch.length === 0) return;
130
+ const items = this.batch;
131
+ this.batch = [];
132
+ if (items.length === 1) {
133
+ this.deliver(items[0]!);
134
+ return;
135
+ }
136
+ this.deliver({
137
+ id: `batch:${items.map((item) => notificationKey(item)).join(",")}`,
138
+ severity: batchSeverity(items),
139
+ source: "batch",
140
+ title: `${items.length} pi-crew notifications`,
141
+ body: items.map((item) => `• ${item.title}`).join("\n"),
142
+ timestamp: this.opts.now?.() ?? Date.now(),
143
+ });
144
+ }
145
+
146
+ dispose(): void {
147
+ if (this.timer) clearTimeout(this.timer);
148
+ this.timer = undefined;
149
+ this.batch = [];
150
+ this.seen.clear();
151
+ }
152
+ }
@@ -0,0 +1,54 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { logInternalError } from "../utils/internal-error.ts";
4
+ import { redactSecrets } from "../utils/redaction.ts";
5
+ import type { NotificationDescriptor } from "./notification-router.ts";
6
+
7
+ export interface NotificationSink {
8
+ write(notification: NotificationDescriptor): void;
9
+ dispose(): void;
10
+ }
11
+
12
+ function rotateOldFiles(dir: string, retentionDays: number, now = Date.now()): void {
13
+ if (!fs.existsSync(dir)) return;
14
+ const cutoff = now - retentionDays * 24 * 60 * 60 * 1000;
15
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
16
+ if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
17
+ const filePath = path.join(dir, entry.name);
18
+ try {
19
+ if (fs.statSync(filePath).mtimeMs < cutoff) fs.unlinkSync(filePath);
20
+ } catch (error) {
21
+ logInternalError("notification-sink.rotate", error, filePath);
22
+ }
23
+ }
24
+ }
25
+
26
+ export function createJsonlSink(crewRoot: string, retentionDays = 7): NotificationSink {
27
+ const dir = path.join(crewRoot, "state", "notifications");
28
+ let lastRotateDate = "";
29
+ return {
30
+ write(notification: NotificationDescriptor): void {
31
+ try {
32
+ const timestamp = notification.timestamp ?? Date.now();
33
+ const date = new Date(timestamp).toISOString().slice(0, 10);
34
+ if (date !== lastRotateDate) {
35
+ rotateOldFiles(dir, retentionDays, timestamp);
36
+ lastRotateDate = date;
37
+ }
38
+ fs.mkdirSync(dir, { recursive: true });
39
+ const payload = redactSecrets({
40
+ ...notification,
41
+ timestamp,
42
+ }) as NotificationDescriptor;
43
+ fs.appendFileSync(path.join(dir, `${date}.jsonl`), `${JSON.stringify(payload)}\n`, "utf-8");
44
+ } catch (error) {
45
+ logInternalError("notification-sink.write", error);
46
+ }
47
+ },
48
+ dispose(): void {
49
+ // Synchronous append-only sink has no resources to close.
50
+ },
51
+ };
52
+ }
53
+
54
+ export const __test__ = { rotateOldFiles };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * pi-api.ts — pi-crew's stable seam against the Pi extension API.
3
+ *
4
+ * PURPOSE (roadmap Phase 0 / Pillar 4 "Pi-Native, Protocol-Aware"):
5
+ * Centralize every symbol pi-crew imports from
6
+ * `@earendil-works/pi-coding-agent` so that:
7
+ * 1. The coupling surface is auditable in ONE file (8 symbols today).
8
+ * 2. A Pi API rename/restructure requires updating only this seam.
9
+ * 3. New code imports from here ("./pi-api") rather than the raw package,
10
+ * establishing the indirection that hedges Pi-coupling risk.
11
+ *
12
+ * COUpling SURFACE (kept intentionally small — public extension API only):
13
+ * - ExtensionAPI the registration entry point (pi)
14
+ * - ExtensionContext per-event/session context (ctx)
15
+ * - ExtensionCommandContext slash-command context
16
+ * - ToolDefinition tool schema type
17
+ * - defineTool tool factory
18
+ * - createBashTool built-in bash tool (for custom tooling)
19
+ * - AgentSessionEvent session event type
20
+ * - BeforeAgentStartEvent pre-turn system-prompt hook event
21
+ *
22
+ * NEW code should `import { ExtensionAPI, ExtensionContext } from "./pi-api"`.
23
+ * Existing files may keep their direct imports; migrate opportunistically
24
+ * (no big-bang refactor — see roadmap Phase 0 T0.3/T0.4 notes).
25
+ *
26
+ * Note: these are TYPE-level re-exports (erased at runtime). Runtime coupling
27
+ * to Pi is via the `pi` and `ctx` objects passed by Pi's loader — that is
28
+ * unavoidable and correct (pi-crew IS a Pi extension). This seam documents
29
+ * and centralizes the type-level surface.
30
+ */
31
+ export type {
32
+ AgentSessionEvent,
33
+ BeforeAgentStartEvent,
34
+ ExtensionAPI,
35
+ ExtensionCommandContext,
36
+ ExtensionContext,
37
+ ToolDefinition,
38
+ } from "@earendil-works/pi-coding-agent";
39
+
40
+ export { createBashTool, defineTool } from "@earendil-works/pi-coding-agent";
41
+
42
+ /**
43
+ * @deprecated Drift detector removed in Phase 5 follow-up to H1.
44
+ *
45
+ * History: this constant was meant to surface version-drift between
46
+ * dev-time type-check and runtime peer-dep version. pi-crew declares
47
+ * peer deps as `*` so the runtime version is set by whatever host pi
48
+ * install the user has — pinning this constant to a specific devDep
49
+ * range was a false invariant that did not reflect how extensions
50
+ * actually consume peer packages.
51
+ *
52
+ * Kept exported (now `"0.0.0-unset"`) only for any downstream consumers
53
+ * that may import it via re-exports. No diagnostic uses it anymore.
54
+ * Will be removed in a future major version.
55
+ */
56
+ export const BUILT_AGAINST_PI_VERSION = "0.0.0-unset";
@@ -0,0 +1,302 @@
1
+ /**
2
+ * Plan Orchestrate — Decompose plan documents into agent chain commands.
3
+ *
4
+ * Parses tagged sections from markdown plan documents and builds commands
5
+ * for sequential agent chain execution based on ECC recommendations.
6
+ */
7
+
8
+ import * as fs from "node:fs";
9
+
10
+ /**
11
+ * Tag → Agent chain mapping from ECC recommendations.
12
+ */
13
+ export const TAG_TO_CHAIN: Record<string, string[]> = {
14
+ design: ["planner", "architect"],
15
+ impl: ["tdd-guide", "lang-reviewer"],
16
+ security: ["security-reviewer", "lang-reviewer"],
17
+ build: ["build-error-resolver"],
18
+ test: ["test-engineer", "verifier"],
19
+ review: ["reviewer"],
20
+ } as const;
21
+
22
+ /**
23
+ * Options for plan orchestration.
24
+ */
25
+ export interface OrchestrateOptions {
26
+ /** Path to the plan markdown document. */
27
+ planPath: string;
28
+ }
29
+
30
+ /**
31
+ * A single orchestrated step parsed from a plan section.
32
+ */
33
+ export interface OrchestratedStep {
34
+ /** Unique step identifier. */
35
+ stepId: string;
36
+ /** Tag from the parsed section. */
37
+ tag: string;
38
+ /** Agent chain for this step. */
39
+ chain: string[];
40
+ /** Prompt/goal text extracted from the section. */
41
+ prompt: string;
42
+ /** Raw heading text if present. */
43
+ heading?: string;
44
+ }
45
+
46
+ /**
47
+ * Parse tagged sections from a plan markdown document.
48
+ *
49
+ * Expected format:
50
+ * ```markdown
51
+ * # Design Phase
52
+ * <!-- tag: design -->
53
+ * Design the authentication system...
54
+ *
55
+ * # Implementation
56
+ * <!-- tag: impl -->
57
+ * Implement the JWT auth...
58
+ * ```
59
+ *
60
+ * @param planPath - Path to the plan markdown document.
61
+ * @returns Array of OrchestratedStep parsed from the document.
62
+ */
63
+ export function parsePlanDocument(planPath: string): OrchestratedStep[] {
64
+ if (!fs.existsSync(planPath)) {
65
+ throw new Error(`Plan document not found: ${planPath}`);
66
+ }
67
+
68
+ const content = fs.readFileSync(planPath, "utf-8");
69
+ return parsePlanDocumentContent(content);
70
+ }
71
+
72
+ /**
73
+ * Parse tagged sections from plan content string.
74
+ * This is the core parsing logic used by both parsePlanDocument and parsePlanDocumentSimple.
75
+ */
76
+ function parsePlanDocumentContent(content: string): OrchestratedStep[] {
77
+ const steps: OrchestratedStep[] = [];
78
+
79
+ // Find all tag matches with their positions
80
+ const tagRegex = /<!--\s*tag:\s*(\w+)\s*-->/g;
81
+ const tagMatches: Array<{ tag: string; start: number; end: number }> = [];
82
+
83
+ let match: RegExpExecArray | null;
84
+ while ((match = tagRegex.exec(content)) !== null) {
85
+ tagMatches.push({
86
+ tag: match[1],
87
+ start: match.index,
88
+ end: match.index + match[0].length,
89
+ });
90
+ }
91
+
92
+ if (tagMatches.length === 0) {
93
+ return [];
94
+ }
95
+
96
+ // For each tag, extract the content before it (to get heading)
97
+ // and the content after it until either another tag or section
98
+ for (let i = 0; i < tagMatches.length; i++) {
99
+ const current = tagMatches[i];
100
+ const nextTagStart = i < tagMatches.length - 1 ? tagMatches[i + 1].start : content.length;
101
+
102
+ // Find the heading by looking back from the tag position.
103
+ // Use global regex to find ALL headings in the window, then take the LAST
104
+ // (nearest to the tag) — simple `.match()` only finds the FIRST heading.
105
+ const textBeforeTag = content.slice(Math.max(0, current.start - 500), current.start);
106
+ const headingRegex = /(^|\n)(#{1,6})\s+(.+?)(\n|$)/g;
107
+ let lastHeadingMatch: RegExpExecArray | null = null;
108
+ let hm: RegExpExecArray | null;
109
+ while ((hm = headingRegex.exec(textBeforeTag)) !== null) {
110
+ lastHeadingMatch = hm;
111
+ }
112
+ const heading = lastHeadingMatch ? lastHeadingMatch[3].trim() : undefined;
113
+
114
+ // Get content after the tag until next tag or heading
115
+ // Start from end of tag comment, skip any whitespace/newline
116
+ const afterTagContent = content.slice(current.end);
117
+
118
+ // Find the section content: capture until next heading (##) or next tag
119
+ const sectionEndMatch = afterTagContent.search(/(^|\n)(#{1,6}\s|\n<!--\s*tag:)/m);
120
+ const sectionContent = sectionEndMatch >= 0 ? afterTagContent.slice(0, sectionEndMatch) : afterTagContent;
121
+
122
+ // Extract prompt text - remove the tag comment lines and empty lines
123
+ const promptLines: string[] = [];
124
+ const lines = sectionContent.split("\n");
125
+ for (const line of lines) {
126
+ const trimmed = line.trim();
127
+ if (!trimmed || trimmed.startsWith("<!--")) continue;
128
+ promptLines.push(trimmed);
129
+ }
130
+
131
+ const prompt = promptLines.join("\n").trim();
132
+ if (!prompt) continue;
133
+
134
+ const chain = TAG_TO_CHAIN[current.tag] ?? [];
135
+
136
+ steps.push({
137
+ stepId: `step-${(i + 1).toString().padStart(2, "0")}-${current.tag}`,
138
+ tag: current.tag,
139
+ chain,
140
+ prompt,
141
+ heading,
142
+ });
143
+ }
144
+
145
+ return steps;
146
+ }
147
+
148
+ /**
149
+ * Alternative simpler parser for plans that use explicit tag blocks.
150
+ * Actually uses the same core logic as parsePlanDocument.
151
+ *
152
+ * @param planPath - Path to the plan markdown document.
153
+ * @returns Array of OrchestratedStep parsed from the document.
154
+ */
155
+ export function parsePlanDocumentSimple(planPath: string): OrchestratedStep[] {
156
+ if (!fs.existsSync(planPath)) {
157
+ throw new Error(`Plan document not found: ${planPath}`);
158
+ }
159
+
160
+ const content = fs.readFileSync(planPath, "utf-8");
161
+ const steps = parsePlanDocumentContent(content);
162
+
163
+ if (steps.length === 0) {
164
+ // Try implicit detection
165
+ const tag = detectImplicitTag(content);
166
+ if (tag) {
167
+ return [
168
+ {
169
+ stepId: "step-01-unknown",
170
+ tag,
171
+ chain: TAG_TO_CHAIN[tag] ?? [],
172
+ prompt: content.trim(),
173
+ },
174
+ ];
175
+ }
176
+ }
177
+
178
+ return steps;
179
+ }
180
+
181
+ /**
182
+ * Detect implicit tag from content keywords when no explicit tag is present.
183
+ */
184
+ function detectImplicitTag(content: string): string | undefined {
185
+ const lowerContent = content.toLowerCase();
186
+ // Use word-boundary regex to avoid substring false matches.
187
+ // E.g., "implementation" must NOT trigger "impl" — only the word "implement" should.
188
+ const hasWord = (word: string): boolean => new RegExp(`\\b${word}\\b`).test(lowerContent);
189
+
190
+ if (hasWord("design") || hasWord("architecture")) return "design";
191
+ if (hasWord("implement") || hasWord("coding")) return "impl";
192
+ if (hasWord("security") || hasWord("audit")) return "security";
193
+ if (hasWord("build") || hasWord("compile")) return "build";
194
+ if (hasWord("test") || hasWord("verify")) return "test";
195
+ if (hasWord("review") || hasWord("feedback")) return "review";
196
+ return undefined;
197
+ }
198
+
199
+ /**
200
+ * Build agent chain command strings from orchestrated steps.
201
+ *
202
+ * @param steps - Array of OrchestratedStep to convert to commands.
203
+ * @returns Array of command strings for execution.
204
+ */
205
+ export function buildAgentChain(steps: OrchestratedStep[]): string[] {
206
+ return steps.map((step) => {
207
+ const agentList = step.chain.join(",");
208
+ // Escape single quotes in the goal for shell safety
209
+ const escapedGoal = step.prompt.replace(/'/g, "'\\''");
210
+ return `team action='run' agent='${agentList}' goal='${escapedGoal}'`;
211
+ });
212
+ }
213
+
214
+ /**
215
+ * Build structured chain data (useful for programmatic use).
216
+ *
217
+ * @param steps - Array of OrchestratedStep to convert.
218
+ * @returns Array of chain objects with step data and commands.
219
+ */
220
+ export function buildChainData(steps: OrchestratedStep[]): Array<{
221
+ step: OrchestratedStep;
222
+ commands: string[];
223
+ }> {
224
+ return steps.map((step) => ({
225
+ step,
226
+ commands: buildAgentChain([step]),
227
+ }));
228
+ }
229
+
230
+ /**
231
+ * Parse and return a formatted overview of the plan.
232
+ *
233
+ * @param planPath - Path to the plan markdown document.
234
+ * @returns Summary string with step count and breakdown by tag.
235
+ */
236
+ export function formatPlanOverview(planPath: string): string {
237
+ const steps = parsePlanDocument(planPath);
238
+
239
+ if (steps.length === 0) {
240
+ // Try simple parser
241
+ const simpleSteps = parsePlanDocumentSimple(planPath);
242
+ if (simpleSteps.length === 0) {
243
+ return "No tagged sections found in plan document.";
244
+ }
245
+ return formatStepsOverview(simpleSteps);
246
+ }
247
+
248
+ return formatStepsOverview(steps);
249
+ }
250
+
251
+ function formatStepsOverview(steps: OrchestratedStep[]): string {
252
+ const lines: string[] = [`Plan Orchestration: ${steps.length} step(s)`, ""];
253
+
254
+ const tagCounts: Record<string, number> = {};
255
+ for (const step of steps) {
256
+ tagCounts[step.tag] = (tagCounts[step.tag] ?? 0) + 1;
257
+ }
258
+
259
+ lines.push("Summary by tag:");
260
+ for (const [tag, count] of Object.entries(tagCounts)) {
261
+ const chain = TAG_TO_CHAIN[tag]?.join(", ") ?? "(unknown)";
262
+ lines.push(` - ${tag}: ${count} step(s) → agents: ${chain}`);
263
+ }
264
+
265
+ lines.push("", "Steps:");
266
+ for (const step of steps) {
267
+ const preview = step.prompt.length > 60 ? step.prompt.slice(0, 60) + "..." : step.prompt;
268
+ // Include heading if available (e.g., "Security Review" from the plan's heading)
269
+ const headingPrefix = step.heading ? `${step.heading}: ` : "";
270
+ lines.push(` ${step.stepId} [${step.tag}] ${step.chain.join(",")}: ${headingPrefix}${preview}`);
271
+ }
272
+
273
+ return lines.join("\n");
274
+ }
275
+
276
+ /**
277
+ * Main orchestration function that parses a plan and returns pre-formatted output.
278
+ */
279
+ export async function orchestratePlan(options: OrchestrateOptions): Promise<{
280
+ steps: OrchestratedStep[];
281
+ chain: string[];
282
+ overview: string;
283
+ }> {
284
+ const { planPath } = options;
285
+
286
+ // Try primary parser first
287
+ let steps = parsePlanDocument(planPath);
288
+
289
+ // Fall back to simple parser if no results
290
+ if (steps.length === 0) {
291
+ steps = parsePlanDocumentSimple(planPath);
292
+ }
293
+
294
+ if (steps.length === 0) {
295
+ throw new Error(`No tagged sections found in plan document: ${planPath}`);
296
+ }
297
+
298
+ const chain = buildAgentChain(steps);
299
+ const overview = formatPlanOverview(planPath);
300
+
301
+ return { steps, chain, overview };
302
+ }