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,163 @@
1
+ /**
2
+ * Iterative retrieval loop — workers progressively discover needed context.
3
+ *
4
+ * Pattern origin: ECC/skills/iterative-retrieval/SKILL.md — 4-phase loop:
5
+ * Dispatch → Evaluate → Refine → Loop. Max 3 cycles. Convergence when
6
+ * ≥3 high-relevance files found AND no critical gaps.
7
+ *
8
+ * This module provides the scoring and convergence logic.
9
+ * The actual file discovery is delegated to the caller (prompt-builder or task-runner).
10
+ */
11
+
12
+ // ── Types ────────────────────────────────────────────────────────────────
13
+
14
+ export interface RetrievalQuery {
15
+ patterns: string[];
16
+ keywords: string[];
17
+ excludes: string[];
18
+ focusAreas?: string[];
19
+ }
20
+
21
+ export interface RelevanceEvaluation {
22
+ path: string;
23
+ relevance: number; // 0.0–1.0
24
+ reason: string;
25
+ missingContext: string[];
26
+ }
27
+
28
+ export interface RetrievalResult {
29
+ query: RetrievalQuery;
30
+ evaluations: RelevanceEvaluation[];
31
+ cycle: number;
32
+ converged: boolean;
33
+ }
34
+
35
+ // ── Scoring ──────────────────────────────────────────────────────────────
36
+
37
+ /**
38
+ * Score relevance of a file to a task description.
39
+ *
40
+ * Uses keyword matching as a heuristic. In production, this would be
41
+ * replaced by embedding-based similarity or BM25 scoring.
42
+ *
43
+ * @param filePath - Path to the file
44
+ * @param fileContent - Content of the file (or excerpt)
45
+ * @param keywords - Task-relevant keywords
46
+ * @returns Relevance score 0.0–1.0
47
+ */
48
+ export function scoreRelevance(filePath: string, fileContent: string, keywords: string[]): number {
49
+ if (keywords.length === 0) return 0;
50
+
51
+ const pathLower = filePath.toLowerCase();
52
+ const contentLower = fileContent.toLowerCase();
53
+ let matchCount = 0;
54
+ let weightedScore = 0;
55
+
56
+ for (const keyword of keywords) {
57
+ const kw = keyword.toLowerCase();
58
+ // Path match is worth more (file naming is intentional)
59
+ if (pathLower.includes(kw)) {
60
+ matchCount++;
61
+ weightedScore += 0.3;
62
+ }
63
+ // Content match
64
+ const contentMatches = contentLower.split(kw).length - 1;
65
+ if (contentMatches > 0) {
66
+ matchCount++;
67
+ // Diminishing returns for repeated matches
68
+ weightedScore += Math.min(0.2, 0.05 * Math.log2(contentMatches + 1));
69
+ }
70
+ }
71
+
72
+ // Normalize: if all keywords matched, score is high
73
+ const keywordCoverage = matchCount / keywords.length;
74
+ const rawScore = keywordCoverage * 0.6 + Math.min(weightedScore, 0.4);
75
+
76
+ return Math.min(1.0, Math.max(0.0, rawScore));
77
+ }
78
+
79
+ // ── Convergence ──────────────────────────────────────────────────────────
80
+
81
+ const CONVERGENCE_MIN_HIGH_RELEVANCE = 3;
82
+ const HIGH_RELEVANCE_THRESHOLD = 0.7;
83
+
84
+ /**
85
+ * Check if retrieval has converged — enough high-relevance files found.
86
+ *
87
+ * @param evaluations - Current relevance evaluations
88
+ * @returns true if converged
89
+ */
90
+ export function hasConverged(evaluations: RelevanceEvaluation[]): boolean {
91
+ const highRelevance = evaluations.filter((e) => e.relevance >= HIGH_RELEVANCE_THRESHOLD);
92
+ if (highRelevance.length < CONVERGENCE_MIN_HIGH_RELEVANCE) return false;
93
+
94
+ // Check for critical gaps — any evaluation with empty missingContext
95
+ const criticalGaps = evaluations.some((e) => e.relevance < 0.3 && e.missingContext.length > 0);
96
+
97
+ return !criticalGaps;
98
+ }
99
+
100
+ // ── Refinement ───────────────────────────────────────────────────────────
101
+
102
+ /**
103
+ * Refine a retrieval query based on evaluation results.
104
+ *
105
+ * Extracts new keywords from high-relevance files, adds discovered
106
+ * terminology, and excludes confirmed-irrelevant paths.
107
+ *
108
+ * @param query - Original query
109
+ * @param evaluations - Results from the current cycle
110
+ * @returns Refined query for the next cycle
111
+ */
112
+ export function refineQuery(query: RetrievalQuery, evaluations: RelevanceEvaluation[]): RetrievalQuery {
113
+ const newKeywords = new Set(query.keywords);
114
+ const newExcludes = new Set(query.excludes);
115
+ const newFocusAreas = new Set(query.focusAreas ?? []);
116
+
117
+ for (const eval_ of evaluations) {
118
+ if (eval_.relevance >= HIGH_RELEVANCE_THRESHOLD) {
119
+ // Extract potential keywords from the file path
120
+ const parts = eval_.path.replace(/[\\/]/g, "/").split("/");
121
+ for (const part of parts) {
122
+ // Skip common non-informative segments
123
+ if (part.length > 2 && !["src", "lib", "test", "dist", "node_modules"].includes(part)) {
124
+ // Use the filename stem as a keyword hint
125
+ const stem = part.replace(/\.[^.]+$/, "").replace(/[.-]/g, " ");
126
+ for (const word of stem.split(/\s+/)) {
127
+ if (word.length > 3) newKeywords.add(word);
128
+ }
129
+ }
130
+ }
131
+ }
132
+
133
+ if (eval_.relevance < 0.2) {
134
+ // Exclude confirmed-irrelevant paths
135
+ newExcludes.add(eval_.path);
136
+ }
137
+
138
+ // Track missing context as focus areas
139
+ for (const gap of eval_.missingContext) {
140
+ newFocusAreas.add(gap);
141
+ }
142
+ }
143
+
144
+ return {
145
+ patterns: query.patterns, // patterns don't change
146
+ keywords: [...newKeywords],
147
+ excludes: [...newExcludes],
148
+ focusAreas: newFocusAreas.size > 0 ? [...newFocusAreas] : undefined,
149
+ };
150
+ }
151
+
152
+ // ── Loop Control ─────────────────────────────────────────────────────────
153
+
154
+ const MAX_CYCLES = 3;
155
+
156
+ /**
157
+ * Determine if another retrieval cycle should run.
158
+ */
159
+ export function shouldContinue(evaluations: RelevanceEvaluation[], cycle: number): boolean {
160
+ if (cycle >= MAX_CYCLES) return false;
161
+ if (hasConverged(evaluations)) return false;
162
+ return true;
163
+ }
@@ -0,0 +1,227 @@
1
+ import * as fs from "node:fs";
2
+ import type { AgentConfig } from "../../agents/agent-config.ts";
3
+ import type { CrewRuntimeConfig } from "../../config/config.ts";
4
+ import { writeArtifact } from "../../state/artifact-store.ts";
5
+ import { appendEventFireAndForget } from "../../state/event-log.ts";
6
+ import { loadRunManifestById } from "../../state/state-store.ts";
7
+ import type { ArtifactDescriptor, TeamRunManifest, TeamTaskState } from "../../state/types.ts";
8
+ import type { WorkflowStep } from "../../workflows/workflow-config.ts";
9
+ import {
10
+ appendCrewAgentEvent,
11
+ appendCrewAgentOutput,
12
+ emptyCrewAgentProgress,
13
+ recordFromTask,
14
+ upsertCrewAgent,
15
+ } from "../crew-agent-records.ts";
16
+ import { runLiveSessionTask } from "../live-session-runtime.ts";
17
+ import type { ParsedPiJsonOutput } from "../pi-json-output.ts";
18
+ import { type ProgressEventSummary, shouldAppendProgressEventUpdate } from "../progress-event-coalescer.ts";
19
+ import { createWorkerHeartbeat, touchWorkerHeartbeat } from "../worker-heartbeat.ts";
20
+ import { createStartupEvidence, type WorkerStartupEvidence } from "../worker-startup.ts";
21
+ import { applyAgentProgressEvent, applyUsageToProgress, progressEventSummary, shouldFlushProgressEvent } from "./progress.ts";
22
+ import { persistSingleTaskUpdate } from "./state-helpers.ts";
23
+
24
+ export interface RunLiveTaskInput {
25
+ manifest: TeamRunManifest;
26
+ tasks: TeamTaskState[];
27
+ task: TeamTaskState;
28
+ step: WorkflowStep;
29
+ agent: AgentConfig;
30
+ prompt: string;
31
+ signal?: AbortSignal;
32
+ runtimeConfig?: CrewRuntimeConfig;
33
+ parentContext?: string;
34
+ parentModel?: unknown;
35
+ modelRegistry?: unknown;
36
+ modelOverride?: string;
37
+ teamRoleModel?: string;
38
+ isCurrent?: () => boolean;
39
+ /** Workspace where this task run was initiated — used for session-scoped live-agent visibility. */
40
+ workspaceId: string;
41
+ /** Phase 2: Output schema for validating yield data. */
42
+ outputSchema?: unknown;
43
+ }
44
+
45
+ export interface RunLiveTaskOutput {
46
+ task: TeamTaskState;
47
+ tasks: TeamTaskState[];
48
+ startupEvidence: WorkerStartupEvidence;
49
+ exitCode: number | null;
50
+ error?: string;
51
+ parsedOutput?: ParsedPiJsonOutput;
52
+ resultArtifact: ArtifactDescriptor;
53
+ logArtifact?: ArtifactDescriptor;
54
+ transcriptArtifact?: ArtifactDescriptor;
55
+ }
56
+
57
+ function updateTask(tasks: TeamTaskState[], updated: TeamTaskState): TeamTaskState[] {
58
+ return tasks.map((task) => (task.id === updated.id ? updated : task));
59
+ }
60
+
61
+ export async function runLiveTask(input: RunLiveTaskInput): Promise<RunLiveTaskOutput> {
62
+ const { manifest, step, agent, prompt } = input;
63
+ let task = input.task;
64
+ let tasks = input.tasks;
65
+ const transcriptPath = `${manifest.artifactsRoot}/transcripts/${task.id}.jsonl`;
66
+ const isCurrent =
67
+ input.isCurrent ??
68
+ (() => {
69
+ if (input.signal?.aborted) return false;
70
+ const loaded = loadRunManifestById(manifest.cwd, manifest.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency;
71
+ const currentTask = loaded?.tasks.find((item) => item.id === task.id);
72
+ if (loaded?.manifest.status && loaded.manifest.status !== "running") return false;
73
+ return currentTask ? currentTask.status === "running" : true;
74
+ });
75
+ let lastAgentRecordPersistedAt = 0;
76
+ let lastRunProgressPersistedAt = 0;
77
+ let lastHeartbeatPersistedAt = 0;
78
+ let lastRunProgressSummary: ProgressEventSummary | undefined;
79
+ const persistLiveProgress = (event: unknown, force = false): void => {
80
+ if (!isCurrent()) return;
81
+ const now = Date.now();
82
+ if (force || shouldFlushProgressEvent(event) || now - lastAgentRecordPersistedAt >= 500) {
83
+ upsertCrewAgent(manifest, recordFromTask(manifest, task, "live-session"));
84
+ lastAgentRecordPersistedAt = now;
85
+ }
86
+ // Bug #5 fix: also persist heartbeat to tasks.json so heartbeat-watcher can detect live-session activity
87
+ if (force || now - lastHeartbeatPersistedAt >= 1000) {
88
+ task = {
89
+ ...task,
90
+ heartbeat: touchWorkerHeartbeat(task.heartbeat ?? createWorkerHeartbeat(task.id)),
91
+ };
92
+ tasks = persistSingleTaskUpdate(manifest, tasks, task);
93
+ lastHeartbeatPersistedAt = now;
94
+ }
95
+ const summary = progressEventSummary(task, event);
96
+ const decision = shouldAppendProgressEventUpdate({
97
+ previous: lastRunProgressSummary,
98
+ next: summary,
99
+ nowMs: now,
100
+ lastAppendMs: lastRunProgressPersistedAt || undefined,
101
+ minIntervalMs: 1000,
102
+ force,
103
+ });
104
+ if (decision.shouldAppend) {
105
+ // 2.2 caller migration: see task-runner.ts.
106
+ appendEventFireAndForget(manifest.eventsPath, {
107
+ type: "task.progress",
108
+ runId: manifest.runId,
109
+ taskId: task.id,
110
+ data: { ...summary, coalesceReason: decision.reason },
111
+ });
112
+ lastRunProgressSummary = summary;
113
+ lastRunProgressPersistedAt = now;
114
+ }
115
+ };
116
+ const attemptStartedAt = new Date();
117
+ // Apply agent-level maxTurns override if specified (only positive integers)
118
+ const agentMax = agent.maxTurns;
119
+ const effectiveRuntimeConfig =
120
+ agentMax != null && agentMax > 0 && (!input.runtimeConfig?.maxTurns || agentMax < input.runtimeConfig.maxTurns)
121
+ ? { ...input.runtimeConfig, maxTurns: agentMax }
122
+ : input.runtimeConfig;
123
+ const liveResult = await runLiveSessionTask({
124
+ manifest,
125
+ task,
126
+ step,
127
+ agent,
128
+ prompt,
129
+ signal: input.signal,
130
+ transcriptPath,
131
+ runtimeConfig: effectiveRuntimeConfig,
132
+ parentContext: input.parentContext,
133
+ parentModel: input.parentModel,
134
+ modelRegistry: input.modelRegistry,
135
+ modelOverride: input.modelOverride,
136
+ teamRoleModel: input.teamRoleModel,
137
+ isCurrent,
138
+ workspaceId: input.workspaceId,
139
+ // Phase 2: Pass output schema for yield validation
140
+ outputSchema: undefined,
141
+ onOutput: (text) => {
142
+ if (!isCurrent()) return;
143
+ appendCrewAgentOutput(manifest, task.id, text);
144
+ },
145
+ onEvent: (event) => {
146
+ if (!isCurrent()) return;
147
+ appendCrewAgentEvent(manifest, task.id, event);
148
+ task = {
149
+ ...task,
150
+ agentProgress: applyAgentProgressEvent(task.agentProgress ?? emptyCrewAgentProgress(), event, task.startedAt),
151
+ };
152
+ tasks = updateTask(tasks, task);
153
+ persistLiveProgress(event);
154
+ },
155
+ });
156
+ const startupEvidence = createStartupEvidence({
157
+ command: "live-session",
158
+ startedAt: attemptStartedAt,
159
+ finishedAt: new Date(),
160
+ promptSentAt: attemptStartedAt,
161
+ promptAccepted: liveResult.exitCode === 0 && !liveResult.error,
162
+ stderr: liveResult.stderr,
163
+ error: liveResult.error,
164
+ exitCode: liveResult.exitCode,
165
+ });
166
+ const exitCode = liveResult.exitCode;
167
+ const error =
168
+ liveResult.error ||
169
+ (liveResult.exitCode && liveResult.exitCode !== 0
170
+ ? liveResult.stderr || `Live session exited with ${liveResult.exitCode}`
171
+ : undefined);
172
+ const parsedOutput = {
173
+ finalText: liveResult.stdout,
174
+ textEvents: liveResult.stdout ? [liveResult.stdout] : [],
175
+ jsonEvents: liveResult.jsonEvents,
176
+ usage: liveResult.usage,
177
+ };
178
+ if (liveResult.usage && isCurrent())
179
+ task = {
180
+ ...task,
181
+ usage: liveResult.usage,
182
+ agentProgress: applyUsageToProgress(task.agentProgress, liveResult.usage),
183
+ };
184
+ persistLiveProgress({ type: "attempt_finished" }, true);
185
+ const resultArtifact = writeArtifact(manifest.artifactsRoot, {
186
+ kind: "result",
187
+ relativePath: `results/${task.id}.txt`,
188
+ content: liveResult.stdout || liveResult.stderr || "(no output)",
189
+ producer: task.id,
190
+ });
191
+ const logArtifact = writeArtifact(manifest.artifactsRoot, {
192
+ kind: "log",
193
+ relativePath: `logs/${task.id}.log`,
194
+ content: [
195
+ `runtime=live-session`,
196
+ `finalExitCode=${exitCode ?? "null"}`,
197
+ `jsonEvents=${liveResult.jsonEvents}`,
198
+ liveResult.usage ? `usage=${JSON.stringify(liveResult.usage)}` : "",
199
+ "",
200
+ "STDOUT:",
201
+ liveResult.stdout,
202
+ "",
203
+ "STDERR:",
204
+ liveResult.stderr,
205
+ ].join("\n"),
206
+ producer: task.id,
207
+ });
208
+ const transcriptArtifact = fs.existsSync(transcriptPath)
209
+ ? writeArtifact(manifest.artifactsRoot, {
210
+ kind: "log",
211
+ relativePath: `transcripts/${task.id}.jsonl`,
212
+ content: fs.readFileSync(transcriptPath, "utf-8"),
213
+ producer: task.id,
214
+ })
215
+ : undefined;
216
+ return {
217
+ task,
218
+ tasks,
219
+ startupEvidence,
220
+ exitCode,
221
+ error: error || undefined,
222
+ parsedOutput,
223
+ resultArtifact,
224
+ logArtifact,
225
+ transcriptArtifact,
226
+ };
227
+ }
@@ -0,0 +1,152 @@
1
+ /**
2
+ * output-splitter.ts — partition one worker's combined output into N
3
+ * per-task results (M6 real-dispatch, MVP).
4
+ *
5
+ * The combined worker is told to wrap each task's result in
6
+ * `<<<TASK_RESULT:{taskId}>>>` ... `<<<END_TASK_RESULT>>>` delimiters.
7
+ * This module parses the raw output and returns a Map<taskId, resultText>.
8
+ *
9
+ * Strategy (in priority order):
10
+ * 1. Delimiter parse — exact match of `<<<TASK_RESULT:id>>>` markers
11
+ * 2. Section heading parse — `### Task N of M` / `## Task N` headers
12
+ * 3. Whole-output broadcast — assign full raw output to ALL taskIds
13
+ * (safe fallback for read-only roles where identical context is OK)
14
+ *
15
+ * Returns an array of { taskId, text } records in input-order. When the
16
+ * delimiter strategy succeeds, each entry contains that task's delimited
17
+ * text. When broadcast fallback is used, all entries contain the full
18
+ * raw output.
19
+ *
20
+ * Note: pure function — no I/O, no LLM calls, deterministic. This is
21
+ * deliberately the simplest possible splitter; we don't try fuzzy
22
+ * matching, NL extraction, or retry-the-LLM. The MVP trusts workers
23
+ * to follow delimiters 99% of the time and broadcasts the rest.
24
+ */
25
+
26
+ export interface SplitResult {
27
+ taskId: string;
28
+ text: string;
29
+ /** Which strategy produced this entry. */
30
+ strategy: "delimiter" | "section" | "broadcast";
31
+ }
32
+
33
+ /**
34
+ * Split a raw worker output into N per-task result texts.
35
+ *
36
+ * @param rawOutput — the worker's combined output text
37
+ * @param taskIds — ordered list of task IDs (matches the dispatch order)
38
+ */
39
+ export function splitCoalescedOutput(rawOutput: string, taskIds: string[]): SplitResult[] {
40
+ if (taskIds.length === 0) return [];
41
+ if (taskIds.length === 1) {
42
+ // Single-task group: return the whole output as the one task's result.
43
+ return [{ taskId: taskIds[0]!, text: rawOutput, strategy: "delimiter" }];
44
+ }
45
+
46
+ const byId = new Map<string, string>();
47
+ const delimiterHits = new Set<string>();
48
+
49
+ // Strategy 1: delimiter parse.
50
+ // Pattern: <<<TASK_RESULT:{id}>>> ... <<<END_TASK_RESULT>>>
51
+ // We match greedily, allowing nested markers between start and end.
52
+ const delimiterRegex = /<<<TASK_RESULT:([^\s>]+)>>>([\s\S]*?)<<<END_TASK_RESULT>>>/g;
53
+ let match: RegExpExecArray | null;
54
+ while ((match = delimiterRegex.exec(rawOutput)) !== null) {
55
+ const id = match[1]!;
56
+ const body = match[2]!.trim();
57
+ if (taskIds.includes(id) && !byId.has(id)) {
58
+ byId.set(id, body);
59
+ delimiterHits.add(id);
60
+ }
61
+ }
62
+
63
+ if (delimiterHits.size === taskIds.length) {
64
+ // All tasks got delimiter hits — return in input order.
65
+ return taskIds.map((id) => ({
66
+ taskId: id,
67
+ text: byId.get(id) ?? "",
68
+ strategy: "delimiter" as const,
69
+ }));
70
+ }
71
+
72
+ // Strategy 2: section heading parse.
73
+ // Look for `### Task N of M` or `## Task {id}` markers. We try both.
74
+ if (delimiterHits.size === 0) {
75
+ const bySection = parseBySectionHeadings(rawOutput, taskIds);
76
+ if (bySection.size === taskIds.length) {
77
+ return taskIds.map((id) => ({
78
+ taskId: id,
79
+ text: bySection.get(id) ?? "",
80
+ strategy: "section" as const,
81
+ }));
82
+ }
83
+ }
84
+
85
+ // Strategy 3: broadcast fallback. All tasks get the full raw output.
86
+ // This is safe for read-only roles (explorers, reviewers) where
87
+ // downstream consumers care about findings, not strict per-task partitioning.
88
+ return taskIds.map((id) => ({
89
+ taskId: id,
90
+ text: rawOutput,
91
+ strategy: "broadcast" as const,
92
+ }));
93
+ }
94
+
95
+ /**
96
+ * Strategy 2 implementation: parse sections by heading patterns.
97
+ *
98
+ * Matches `### Task N of M` (N=1..M) or `### Task N` headers, then
99
+ * captures text up to the next header or end-of-input.
100
+ *
101
+ * Falls back to "first heading wins all text" if no N-of-M numbering is
102
+ * present, which is common in worker output that just labels sections.
103
+ */
104
+ function parseBySectionHeadings(rawOutput: string, taskIds: string[]): Map<string, string> {
105
+ const result = new Map<string, string>();
106
+ // First try numbered: "### Task 1 of N" / "## Task 1" / "### Task 1"
107
+ const numberedRegex = /^(#{2,3})\s+Task\s+(\d+)\s+of\s+\d+.*$/gm;
108
+ const sections: { num: number; start: number }[] = [];
109
+ let m: RegExpExecArray | null;
110
+ while ((m = numberedRegex.exec(rawOutput)) !== null) {
111
+ sections.push({ num: Number(m[2]), start: m.index + m[0].length });
112
+ }
113
+ if (sections.length >= taskIds.length) {
114
+ sections.sort((a, b) => a.start - b.start);
115
+ for (let i = 0; i < sections.length && i < taskIds.length; i += 1) {
116
+ const section = sections[i]!;
117
+ const end = sections[i + 1]?.start ?? rawOutput.length;
118
+ const text = rawOutput.slice(section.start, end).trim();
119
+ const taskId = taskIds[i];
120
+ if (taskId) result.set(taskId, text);
121
+ }
122
+ return result;
123
+ }
124
+ // Try "### Task {taskId}" headers — direct ID matching.
125
+ const idHeaderRegex = /^(#{2,3})\s+Task\s+([^\s].*?)$/gm;
126
+ while ((m = idHeaderRegex.exec(rawOutput)) !== null) {
127
+ const headerText = m[2]!.trim();
128
+ const matchedId = taskIds.find((id) => headerText.includes(id));
129
+ if (matchedId && !result.has(matchedId)) {
130
+ result.set(matchedId, ""); // placeholder; filled below
131
+ }
132
+ }
133
+ if (result.size === taskIds.length) {
134
+ // Re-scan to extract body per matched header
135
+ const headerPositions: { taskId: string; start: number }[] = [];
136
+ const idHeaderRegex2 = /^(#{2,3})\s+Task\s+([^\s].*?)$/gm;
137
+ while ((m = idHeaderRegex2.exec(rawOutput)) !== null) {
138
+ const headerText = m[2]!.trim();
139
+ const matchedId = taskIds.find((id) => headerText.includes(id));
140
+ if (matchedId) headerPositions.push({ taskId: matchedId, start: m.index + m[0].length });
141
+ }
142
+ headerPositions.sort((a, b) => a.start - b.start);
143
+ for (let i = 0; i < headerPositions.length; i += 1) {
144
+ const cur = headerPositions[i]!;
145
+ const next = headerPositions[i + 1];
146
+ const end = next ? rawOutput.lastIndexOf("\n#", next.start) : rawOutput.length;
147
+ const text = rawOutput.slice(cur.start, end > 0 ? end : rawOutput.length).trim();
148
+ result.set(cur.taskId, text);
149
+ }
150
+ }
151
+ return result;
152
+ }