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,606 @@
1
+ /**
2
+ * ChainRunner - Execute sequential chains with `->` syntax support.
3
+ *
4
+ * Based on pi-boomerang's parseChain pattern:
5
+ * - Parses "teamA -> teamB -> teamC" syntax
6
+ * - Supports per-step overrides for model, skill, thinking
7
+ * - Accumulates handoffs between steps
8
+ * - Executes steps sequentially with context passing
9
+ *
10
+ * @see docs/pi-boomerang-integration-plan.md
11
+ */
12
+
13
+ import { errorMessage } from "../utils/guards.ts";
14
+ import type { ChainStep as DSLChainStep } from "./chain-parser.ts";
15
+ import { parseChainDSL } from "./chain-parser.ts";
16
+ import type { HandoffManager, HandoffSummary, TaskPacket, TaskResult } from "./handoff-manager.ts";
17
+
18
+ /**
19
+ * Single step in a chain.
20
+ */
21
+ export interface ChainStep {
22
+ /** Step name/identifier */
23
+ name: string;
24
+ /** Team to execute (if using team reference) */
25
+ team?: string;
26
+ /** Workflow to execute (if using workflow reference) */
27
+ workflow?: string;
28
+ /** Template to execute (if using template reference) */
29
+ template?: string;
30
+ /** Inline goal text (for literal goals) */
31
+ inlineGoal?: string;
32
+
33
+ /** Per-step model override */
34
+ model?: string;
35
+ /** Per-step skill override */
36
+ skill?: string;
37
+ /** Thinking mode */
38
+ thinking?: "fast" | "standard" | "deep";
39
+
40
+ /** Step-specific context */
41
+ context?: Record<string, unknown>;
42
+ /** Step timeout in milliseconds */
43
+ timeout?: number;
44
+
45
+ /** Whether to continue chain on failure */
46
+ continueOnError?: boolean;
47
+ }
48
+
49
+ /**
50
+ * Parsed chain specification.
51
+ */
52
+ export interface ChainSpec {
53
+ /** Ordered steps in the chain */
54
+ steps: ChainStep[];
55
+ /** Global arguments applied to all steps */
56
+ globalArgs?: Record<string, unknown>;
57
+ /** Global model override */
58
+ globalModel?: string;
59
+ /** Global skill override */
60
+ globalSkill?: string;
61
+ /** Global thinking mode */
62
+ globalThinking?: "fast" | "standard" | "deep";
63
+ /** Continue chain on step failure */
64
+ continueOnError?: boolean;
65
+ }
66
+
67
+ /**
68
+ * Result of a single chain step execution.
69
+ */
70
+ export interface ChainStepResult {
71
+ step: number;
72
+ name: string;
73
+ outcome: "success" | "failure" | "skipped" | "partial";
74
+ result?: TaskResult;
75
+ handoff?: HandoffSummary;
76
+ duration: number;
77
+ error?: string;
78
+ }
79
+
80
+ /**
81
+ * Final chain execution result.
82
+ */
83
+ export interface ChainResult {
84
+ steps: ChainStepResult[];
85
+ totalDuration: number;
86
+ success: boolean;
87
+ /** Total tokens used across all steps */
88
+ totalTokens?: number;
89
+ /** All handoffs generated during chain */
90
+ totalHandoffs: HandoffSummary[];
91
+ }
92
+
93
+ /**
94
+ * Task runner interface for chain execution.
95
+ */
96
+ export interface ChainTaskRunner {
97
+ runTask(packet: TaskPacket): Promise<TaskResult>;
98
+ }
99
+
100
+ /**
101
+ * ChainRunner executes sequential chains with context passing.
102
+ */
103
+ export class ChainRunner {
104
+ /** Maximum number of chain history entries to prevent memory leaks */
105
+ private static readonly MAX_CHAIN_HISTORY_SIZE = 100;
106
+
107
+ /** Maximum size per handoff entry to prevent memory issues from large artifacts */
108
+ private static readonly MAX_HANDOFF_ENTRY_SIZE = 5000; // bytes per entry
109
+
110
+ private taskRunner: ChainTaskRunner;
111
+ private handoffManager: HandoffManager;
112
+
113
+ constructor(taskRunner: ChainTaskRunner, handoffManager: HandoffManager) {
114
+ this.taskRunner = taskRunner;
115
+ this.handoffManager = handoffManager;
116
+ }
117
+
118
+ /**
119
+ * Parse chain syntax: step1 -> step2 -> step3
120
+ *
121
+ * Supports multiple syntaxes:
122
+ * - Team reference: @teamName
123
+ * - Workflow reference: workflow:name
124
+ * - Template reference: template:name
125
+ * - Inline goal: "goal description"
126
+ *
127
+ * @example
128
+ * parseChain("@research -> @implement -> @review")
129
+ * parseChain('"Research AI trends" -> "Analyze findings"')
130
+ * parseChain("@step1 --model claude-opus-3 -> @step2")
131
+ *
132
+ * Also supports DSL syntax from chain-parser for advanced constructs:
133
+ * parseChain("step1 -> parallel(step2, step3) -> step4")
134
+ * parseChain("step1:3 -> step2 --with-context -> step3")
135
+ *
136
+ * @param chainString - The chain string to parse
137
+ * @returns Parsed chain specification
138
+ */
139
+ parseChain(chainString: string): ChainSpec {
140
+ // Try DSL parser first for advanced syntax (parallel groups, loop counts, flags)
141
+ // Falls back to the simple split parser if DSL parsing fails
142
+ if (this.hasDSLConstructs(chainString)) {
143
+ try {
144
+ const dslSteps = parseChainDSL(chainString);
145
+ return this.dslToChainSpec(dslSteps, chainString);
146
+ } catch {
147
+ // DSL parse failed; fall through to simple parser
148
+ }
149
+ }
150
+
151
+ const stepStrings = chainString.split("->").map((s) => s.trim());
152
+
153
+ const steps: ChainStep[] = stepStrings.map((step, index) => {
154
+ return this.parseStep(step, index);
155
+ });
156
+
157
+ // Extract global overrides
158
+ const globalModel = this.extractGlobalFlag(chainString, "global-model");
159
+ const globalSkill = this.extractGlobalFlag(chainString, "global-skill");
160
+ const globalThinking = this.extractGlobalFlag(chainString, "global-thinking") as "fast" | "standard" | "deep" | undefined;
161
+ const continueOnError = this.extractGlobalFlag(chainString, "continue-on-error") === "true";
162
+
163
+ return {
164
+ steps,
165
+ globalModel,
166
+ globalSkill,
167
+ globalThinking,
168
+ continueOnError,
169
+ };
170
+ }
171
+
172
+ /**
173
+ * Execute chain sequentially.
174
+ * Each step receives handoff from previous step.
175
+ *
176
+ * @param spec - Parsed chain specification
177
+ * @param initialContext - Initial context for the chain
178
+ * @param eventsPath - Optional event log path for events
179
+ * @returns Final chain result
180
+ */
181
+ async runChain(spec: ChainSpec, initialContext: Record<string, unknown> = {}, eventsPath?: string): Promise<ChainResult> {
182
+ const stepResults: ChainStepResult[] = [];
183
+ let accumulatedContext = { ...initialContext };
184
+ const startTime = Date.now();
185
+ let totalTokens = 0;
186
+ const allHandoffs: HandoffSummary[] = [];
187
+
188
+ for (let i = 0; i < spec.steps.length; i++) {
189
+ const step = spec.steps[i];
190
+ const stepStart = Date.now();
191
+
192
+ try {
193
+ // Resolve effective config (step overrides global)
194
+ const effectiveConfig = this.getEffectiveConfig(step, spec);
195
+
196
+ // Enrich context with previous handoffs
197
+ const stepContext = this.enrichContextFromHandoffs(accumulatedContext, stepResults);
198
+
199
+ // Execute step
200
+ const result = await this.executeStep(effectiveConfig, stepContext);
201
+
202
+ // Track tokens
203
+ if (result.usage?.totalTokens) {
204
+ totalTokens += result.usage.totalTokens;
205
+ }
206
+
207
+ // Generate handoff for next step
208
+ const handoff = await this.handoffManager.generateSummary(this.createMinimalPacket(step, i), result);
209
+
210
+ stepResults.push({
211
+ step: i + 1,
212
+ name: step.name,
213
+ outcome: result.outcome,
214
+ result,
215
+ handoff,
216
+ duration: Date.now() - stepStart,
217
+ });
218
+
219
+ if (handoff !== null) {
220
+ allHandoffs.push(handoff);
221
+ }
222
+
223
+ // Update accumulated context on success
224
+ if (result.outcome === "success") {
225
+ accumulatedContext = {
226
+ ...accumulatedContext,
227
+ [`step_${i}_result`]: result,
228
+ [`step_${i}_handoff`]: handoff,
229
+ };
230
+ } else {
231
+ // Stop chain on step failure unless configured to continue
232
+ if (!spec.continueOnError && !step.continueOnError) {
233
+ break;
234
+ }
235
+ }
236
+
237
+ // Emit progress event if eventsPath provided
238
+ if (eventsPath) {
239
+ // LAZY: defer dynamic import of ../state/event-log.ts to its call site.
240
+ const { appendEventAsync } = await import("../state/event-log.ts");
241
+ await appendEventAsync(eventsPath, {
242
+ type: "chain.step_completed",
243
+ runId: "chain",
244
+ taskId: `step-${i + 1}`,
245
+ data: {
246
+ step: i + 1,
247
+ name: step.name,
248
+ outcome: result.outcome,
249
+ duration: Date.now() - stepStart,
250
+ },
251
+ });
252
+ }
253
+ } catch (error) {
254
+ const errMsg = errorMessage(error);
255
+
256
+ stepResults.push({
257
+ step: i + 1,
258
+ name: step.name,
259
+ outcome: "failure",
260
+ duration: Date.now() - stepStart,
261
+ error: errMsg,
262
+ });
263
+
264
+ // Stop chain on failure unless configured to continue
265
+ if (!spec.continueOnError && !step.continueOnError) {
266
+ break;
267
+ }
268
+ }
269
+ }
270
+
271
+ return {
272
+ steps: stepResults,
273
+ totalDuration: Date.now() - startTime,
274
+ success: stepResults.every((s) => s.outcome !== "failure"),
275
+ totalTokens: totalTokens > 0 ? totalTokens : undefined,
276
+ totalHandoffs: allHandoffs,
277
+ };
278
+ }
279
+
280
+ /**
281
+ * Parse a single step from the chain string.
282
+ * Includes type safety checks for ChainStep parsing (H3).
283
+ */
284
+ private parseStep(step: string, index: number): ChainStep {
285
+ // Parse team reference: @teamName
286
+ const teamMatch = step.match(/^@([a-zA-Z][a-zA-Z0-9_]*)/);
287
+
288
+ // Parse workflow reference: workflow:name
289
+ const workflowMatch = step.match(/^workflow:([a-zA-Z][a-zA-Z0-9_]*)/);
290
+
291
+ // Parse template reference: template:name
292
+ const templateMatch = step.match(/^template:([a-zA-Z][a-zA-Z0-9_]*)/);
293
+
294
+ // Parse inline goal: "goal description" (can follow other patterns)
295
+ const inlineMatch = step.match(/"([^"]{1,10000})"/);
296
+
297
+ const nameParts = step.split(/\s+/);
298
+ const name = nameParts[0] && nameParts[0].length > 0 && nameParts[0].length <= 100 ? nameParts[0] : `step-${index}`;
299
+
300
+ const parsed: ChainStep = {
301
+ name,
302
+ };
303
+
304
+ // Set step type based on matching pattern with type safety
305
+ if (teamMatch?.[1]) {
306
+ parsed.team = this.sanitizeIdentifier(teamMatch[1]);
307
+ }
308
+ if (workflowMatch?.[1]) {
309
+ parsed.workflow = this.sanitizeIdentifier(workflowMatch[1]);
310
+ }
311
+ if (templateMatch?.[1]) {
312
+ parsed.template = this.sanitizeIdentifier(templateMatch[1]);
313
+ }
314
+ if (inlineMatch?.[1]) {
315
+ parsed.inlineGoal = this.sanitizeInlineGoal(inlineMatch[1]);
316
+ }
317
+
318
+ // Parse per-step overrides with type safety
319
+ const modelVal = this.extractFlag(step, "model");
320
+ if (modelVal && this.isValidModelName(modelVal)) {
321
+ parsed.model = modelVal;
322
+ }
323
+
324
+ const skillVal = this.extractFlag(step, "skill");
325
+ if (skillVal && this.isValidIdentifier(skillVal)) {
326
+ parsed.skill = skillVal;
327
+ }
328
+
329
+ const thinkingVal = this.extractFlag(step, "thinking");
330
+ if (thinkingVal && this.isValidThinkingMode(thinkingVal)) {
331
+ parsed.thinking = thinkingVal;
332
+ }
333
+
334
+ // Parse step timeout
335
+ const timeoutStr = this.extractFlag(step, "timeout");
336
+ if (timeoutStr) {
337
+ const timeoutMs = parseInt(timeoutStr, 10);
338
+ if (!Number.isNaN(timeoutMs) && timeoutMs > 0 && timeoutMs <= 86400000) {
339
+ parsed.timeout = timeoutMs * 1000; // Convert seconds to ms
340
+ }
341
+ }
342
+
343
+ // Parse continueOnError for step
344
+ if (this.extractFlag(step, "continue-on-error") === "true") {
345
+ parsed.continueOnError = true;
346
+ }
347
+
348
+ return parsed;
349
+ }
350
+
351
+ /**
352
+ * Detect if chainString uses DSL constructs that require chain-parser.
353
+ * DSL features: parallel(...), :loopCount, --with-context flag
354
+ */
355
+ private hasDSLConstructs(chainString: string): boolean {
356
+ return /\bparallel\s*\(/.test(chainString) || /\w+:\d+\b/.test(chainString) || /--with-context/.test(chainString);
357
+ }
358
+
359
+ /**
360
+ * Convert DSL AST steps (from chain-parser) to ChainSpec.
361
+ */
362
+ private dslToChainSpec(dslSteps: DSLChainStep[], chainString: string): ChainSpec {
363
+ const steps: ChainStep[] = dslSteps.map((dslStep, index) => {
364
+ // For parallel groups, use a synthetic step name
365
+ if (dslStep.parallel) {
366
+ return {
367
+ name: dslStep.name,
368
+ context: {
369
+ parallel: dslStep.parallel.map((p) => ({
370
+ name: p.name,
371
+ loopCount: p.loopCount,
372
+ withContext: p.withContext,
373
+ args: p.args,
374
+ })),
375
+ },
376
+ loopCount: dslStep.loopCount,
377
+ };
378
+ }
379
+ const step: ChainStep = { name: dslStep.name };
380
+ if (dslStep.loopCount)
381
+ step.context = {
382
+ ...step.context,
383
+ loopCount: dslStep.loopCount,
384
+ };
385
+ if (dslStep.withContext) step.context = { ...step.context, withContext: true };
386
+ if (dslStep.args && dslStep.args.length > 0) step.context = { ...step.context, args: dslStep.args };
387
+ return step;
388
+ });
389
+
390
+ // Extract global overrides using existing logic
391
+ const globalModel = this.extractGlobalFlag(chainString, "global-model");
392
+ const globalSkill = this.extractGlobalFlag(chainString, "global-skill");
393
+ const globalThinking = this.extractGlobalFlag(chainString, "global-thinking") as "fast" | "standard" | "deep" | undefined;
394
+ const continueOnError = this.extractGlobalFlag(chainString, "continue-on-error") === "true";
395
+
396
+ return {
397
+ steps,
398
+ globalModel,
399
+ globalSkill,
400
+ globalThinking,
401
+ continueOnError,
402
+ };
403
+ }
404
+
405
+ /**
406
+ * Sanitize identifier to prevent injection.
407
+ */
408
+ private sanitizeIdentifier(value: string): string {
409
+ return value.replace(/[^a-zA-Z0-9_]/g, "_").substring(0, 100);
410
+ }
411
+
412
+ /**
413
+ * Sanitize inline goal to prevent injection.
414
+ */
415
+ private sanitizeInlineGoal(value: string): string {
416
+ // Remove control characters and limit length
417
+ return value.replace(/[\x00-\x1F\x7F]/g, "").substring(0, 10000);
418
+ }
419
+
420
+ /**
421
+ * Validate model name format.
422
+ */
423
+ private isValidModelName(value: string): boolean {
424
+ return /^[a-zA-Z][a-zA-Z0-9_-]{0,50}$/.test(value);
425
+ }
426
+
427
+ /**
428
+ * Validate identifier format.
429
+ */
430
+ private isValidIdentifier(value: string): boolean {
431
+ return /^[a-zA-Z][a-zA-Z0-9_]{0,50}$/.test(value);
432
+ }
433
+
434
+ /**
435
+ * Validate thinking mode value.
436
+ */
437
+ private isValidThinkingMode(value: string): value is "fast" | "standard" | "deep" {
438
+ return ["fast", "standard", "deep"].includes(value);
439
+ }
440
+
441
+ /**
442
+ * Extract a flag from step string.
443
+ * Uses escaped flag name to prevent regex injection.
444
+ */
445
+ private extractFlag(input: string, flag: string): string | undefined {
446
+ // Escape regex special characters in flag name to prevent injection
447
+ const escapedFlag = flag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
448
+ const match = input.match(new RegExp(`--${escapedFlag}\\s+(\\S+)`));
449
+ return match?.[1];
450
+ }
451
+
452
+ /**
453
+ * Extract a global flag from the chain string.
454
+ * Global flags can appear anywhere in the chain string.
455
+ * Uses escaped flag name to prevent regex injection.
456
+ */
457
+ private extractGlobalFlag(input: string, flag: string): string | undefined {
458
+ // Escape regex special characters in flag name to prevent injection
459
+ const escapedFlag = flag.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
460
+ const patternEq = "--" + escapedFlag + "=\\s*(\\S+)";
461
+ const match = input.match(new RegExp(patternEq, "i"));
462
+ if (match) return match[1];
463
+
464
+ const patternNoEq = "--" + escapedFlag + "\\s+(\\S+)";
465
+ const matchNoEq = input.match(new RegExp(patternNoEq, "i"));
466
+ if (matchNoEq) return matchNoEq[1];
467
+
468
+ return undefined;
469
+ }
470
+
471
+ /**
472
+ * Get effective config with step overrides global.
473
+ */
474
+ private getEffectiveConfig(step: ChainStep, spec: ChainSpec): ChainStep {
475
+ return {
476
+ ...step,
477
+ model: step.model ?? spec.globalModel,
478
+ skill: step.skill ?? spec.globalSkill,
479
+ thinking: step.thinking ?? spec.globalThinking,
480
+ };
481
+ }
482
+
483
+ /**
484
+ * Enrich context with previous handoffs.
485
+ * Limits history size to prevent memory leaks.
486
+ */
487
+ private enrichContextFromHandoffs(context: Record<string, unknown>, previousResults: ChainStepResult[]): Record<string, unknown> {
488
+ const handoffs = previousResults.filter((r) => r.handoff).map((r) => r.handoff!);
489
+
490
+ if (handoffs.length === 0) {
491
+ return context;
492
+ }
493
+
494
+ const notes: string[] = [];
495
+
496
+ // Limit history size to prevent memory leak (H2). Emit a marker so a dropped
497
+ // entry does not vanish silently — this was the only silent-loss path in the
498
+ // output-handling machinery (see research-findings/output-handling-deep-dive.md §F).
499
+ let limitedHandoffs = handoffs;
500
+ if (handoffs.length > ChainRunner.MAX_CHAIN_HISTORY_SIZE) {
501
+ const dropped = handoffs.length - ChainRunner.MAX_CHAIN_HISTORY_SIZE;
502
+ notes.push(
503
+ `[chain history limited to last ${ChainRunner.MAX_CHAIN_HISTORY_SIZE} entries; ${dropped} older entr${dropped === 1 ? "y" : "ies"} omitted]`,
504
+ );
505
+ limitedHandoffs = handoffs.slice(-ChainRunner.MAX_CHAIN_HISTORY_SIZE);
506
+ }
507
+
508
+ // Limit per-entry size to prevent memory issues from large artifacts.
509
+ const filteredHandoffs = limitedHandoffs.filter((h) => {
510
+ const size = JSON.stringify(h).length;
511
+ return size <= ChainRunner.MAX_HANDOFF_ENTRY_SIZE;
512
+ });
513
+ const oversizedDropped = limitedHandoffs.length - filteredHandoffs.length;
514
+ if (oversizedDropped > 0) {
515
+ notes.push(
516
+ `[${oversizedDropped} handoff entr${oversizedDropped === 1 ? "y" : "ies"} omitted (> ${ChainRunner.MAX_HANDOFF_ENTRY_SIZE} bytes each)]`,
517
+ );
518
+ }
519
+
520
+ // Track array-cap drops so capped lists do not vanish silently. Each field
521
+ // over its cap records the full count so a reader knows data was elided.
522
+ const arrayCapNotes: string[] = [];
523
+ const mapped = filteredHandoffs.map((h) => {
524
+ const over: string[] = [];
525
+ if (h.filesCreated && h.filesCreated.length > 50) over.push(`filesCreated=${h.filesCreated.length}`);
526
+ if (h.filesModified && h.filesModified.length > 50) over.push(`filesModified=${h.filesModified.length}`);
527
+ if (h.decisions && h.decisions.length > 20) over.push(`decisions=${h.decisions.length}`);
528
+ if (h.nextSteps && h.nextSteps.length > 20) over.push(`nextSteps=${h.nextSteps.length}`);
529
+ if (over.length > 0) arrayCapNotes.push(`step ${h.taskId}: ${over.join(", ")} (capped)`);
530
+ return {
531
+ step: h.taskId,
532
+ outcome: h.outcome,
533
+ filesCreated: h.filesCreated?.slice(0, 50), // Limit array size
534
+ filesModified: h.filesModified?.slice(0, 50), // Limit array size
535
+ decisions: h.decisions?.slice(0, 20), // Limit array size
536
+ nextSteps: h.nextSteps?.slice(0, 20), // Limit array size
537
+ ...(h.outputText ? { outputText: h.outputText.slice(0, 5000) } : {}), // Size-capped worker output
538
+ };
539
+ });
540
+ if (arrayCapNotes.length > 0) notes.push(`[list caps applied: ${arrayCapNotes.join("; ")}]`);
541
+
542
+ return {
543
+ ...context,
544
+ __chainHistory: mapped,
545
+ ...(notes.length > 0 ? { __chainHistoryNotes: notes } : {}),
546
+ };
547
+ }
548
+
549
+ /**
550
+ * Execute a single step.
551
+ */
552
+ private async executeStep(config: ChainStep, context: Record<string, unknown>): Promise<TaskResult> {
553
+ // Pass step config (team/workflow/model) into the packet context so the
554
+ // concrete ChainTaskRunner can resolve which team/workflow to run. Without
555
+ // this, a step parsed to a @teamName reference would lose its team because
556
+ // the only channel from executeStep to runTask is the TaskPacket. Purely
557
+ // additive — adds sibling keys alongside __chainHistory/Notes.
558
+ const packet: TaskPacket = {
559
+ taskId: `chain-${Date.now()}-${config.name}`,
560
+ runId: "chain",
561
+ goal: config.inlineGoal ?? config.name,
562
+ summarizeThreshold: 3000,
563
+ collapseContext: true,
564
+ context: {
565
+ ...context,
566
+ __chainStepTeam: config.team,
567
+ __chainStepWorkflow: config.workflow,
568
+ __chainStepModel: config.model,
569
+ },
570
+ };
571
+
572
+ return this.taskRunner.runTask(packet);
573
+ }
574
+
575
+ /**
576
+ * Create minimal packet for handoff generation.
577
+ */
578
+ private createMinimalPacket(step: ChainStep, index: number): TaskPacket {
579
+ return {
580
+ taskId: `chain-step-${index}`,
581
+ runId: "chain",
582
+ sessionId: "chain",
583
+ goal: step.inlineGoal ?? step.name,
584
+ };
585
+ }
586
+ }
587
+
588
+ /**
589
+ * Create a ChainRunner with default dependencies.
590
+ */
591
+ export function createChainRunner(taskRunner: ChainTaskRunner, handoffManager: HandoffManager): ChainRunner {
592
+ return new ChainRunner(taskRunner, handoffManager);
593
+ }
594
+
595
+ /**
596
+ * Parse chain from string shorthand.
597
+ */
598
+ export function parseChainString(chainString: string): ChainSpec {
599
+ const runner = new ChainRunner(
600
+ {
601
+ runTask: () => Promise.reject(new Error("Not initialized")),
602
+ } as ChainTaskRunner,
603
+ {} as HandoffManager,
604
+ );
605
+ return runner.parseChain(chainString);
606
+ }