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,598 @@
1
+ // HandoffManager defaults
2
+ const DEFAULT_SUMMARIZE_THRESHOLD = 5000;
3
+ const DEFAULT_HANDOVER_TIMEOUT_MS = 300000; // 5 minutes
4
+ const DEFAULT_CLEANUP_INTERVAL_MS = 60000; // 1 minute
5
+ const MAX_PENDING_HANDOFFS = 1000; // Prevent unbounded growth
6
+
7
+ /**
8
+ * Type guard for HandoffSummary structure validation.
9
+ */
10
+ export function isValidHandoffSummary(value: unknown): value is HandoffSummary {
11
+ if (!value || typeof value !== "object") {
12
+ return false;
13
+ }
14
+ const obj = value as Record<string, unknown>;
15
+
16
+ // Check required fields
17
+ if (typeof obj.taskId !== "string" || !obj.taskId) return false;
18
+ if (typeof obj.runId !== "string" || !obj.runId) return false;
19
+ if (typeof obj.timestamp !== "number") return false;
20
+ if (typeof obj.task !== "string" || !obj.task) return false;
21
+ if (typeof obj.outcome !== "string") return false;
22
+ if (!["success", "failure", "partial"].includes(obj.outcome)) return false;
23
+
24
+ // Check arrays
25
+ if (!Array.isArray(obj.filesCreated)) return false;
26
+ if (!Array.isArray(obj.filesModified)) return false;
27
+ if (!Array.isArray(obj.filesDeleted)) return false;
28
+ if (!Array.isArray(obj.decisions)) return false;
29
+ if (!Array.isArray(obj.blockers)) return false;
30
+ if (!Array.isArray(obj.nextSteps)) return false;
31
+
32
+ // Check metrics object
33
+ if (!obj.metrics || typeof obj.metrics !== "object") return false;
34
+ const metrics = obj.metrics as Record<string, unknown>;
35
+ if (typeof metrics.tokensUsed !== "number") return false;
36
+ if (typeof metrics.duration !== "number") return false;
37
+ if (typeof metrics.iterations !== "number") return false;
38
+ if (!Array.isArray(metrics.toolsUsed)) return false;
39
+
40
+ // Check contextSnapshot
41
+ if (typeof obj.contextSnapshot !== "string") return false;
42
+
43
+ return true;
44
+ }
45
+
46
+ /**
47
+ * HandoffManager - Generates structured summaries for agent handoffs.
48
+ *
49
+ * Based on pi-boomerang's session_before_tree hook pattern:
50
+ * - Detects task completion via agent_end hook
51
+ * - Generates structured summaries with token metrics, artifacts, decisions
52
+ * - Optionally collapses context to reduce token usage
53
+ *
54
+ * @see docs/pi-boomerang-integration-plan.md
55
+ */
56
+
57
+ /**
58
+ * Represents a key decision made during task execution.
59
+ */
60
+ export interface Decision {
61
+ rationale: string;
62
+ outcome: string;
63
+ alternativesConsidered: string[];
64
+ }
65
+
66
+ /**
67
+ * Structured handoff summary for passing context between agents.
68
+ */
69
+ export interface HandoffSummary {
70
+ taskId: string;
71
+ runId: string;
72
+ timestamp: number;
73
+
74
+ // Core summary
75
+ task: string;
76
+ outcome: "success" | "failure" | "partial";
77
+
78
+ // Structured artifacts
79
+ filesCreated: string[];
80
+ filesModified: string[];
81
+ filesDeleted: string[];
82
+
83
+ // Key decisions made
84
+ decisions: Decision[];
85
+
86
+ // Open issues / next steps
87
+ blockers: string[];
88
+ nextSteps: string[];
89
+
90
+ // Metrics
91
+ metrics: {
92
+ tokensUsed: number;
93
+ duration: number;
94
+ iterations: number;
95
+ toolsUsed: string[];
96
+ };
97
+
98
+ // Context snapshot
99
+ contextSnapshot: string;
100
+
101
+ /** Worker output text propagated through the chain (read from resultArtifact). */
102
+ outputText?: string;
103
+ }
104
+
105
+ /**
106
+ * Task result interface (simplified for handoff generation).
107
+ */
108
+ export interface TaskResult {
109
+ outcome: "success" | "failure" | "partial";
110
+ usage?: {
111
+ inputTokens?: number;
112
+ outputTokens?: number;
113
+ totalTokens?: number;
114
+ };
115
+ duration?: number;
116
+ iterations?: number;
117
+ toolsUsed?: string[];
118
+ blockers?: string[];
119
+ nextSteps?: string[];
120
+ filesCreated?: string[];
121
+ filesModified?: string[];
122
+ filesDeleted?: string[];
123
+ decisions?: Decision[];
124
+ error?: string;
125
+
126
+ /** Worker's textual output (read from resultArtifact during chain execution). */
127
+ outputText?: string;
128
+ }
129
+
130
+ /**
131
+ * Task packet interface (minimal for handoff generation).
132
+ */
133
+ export interface TaskPacket {
134
+ taskId: string;
135
+ runId: string;
136
+ goal: string;
137
+ sessionId?: string;
138
+ summarizeThreshold?: number;
139
+ collapseContext?: boolean;
140
+ forceSummarize?: boolean;
141
+ context?: Record<string, unknown>;
142
+ }
143
+
144
+ export interface HandoffManagerOptions {
145
+ /** Default token threshold for triggering summarization */
146
+ defaultSummarizeThreshold?: number;
147
+ /** Enable context collapse after handoff */
148
+ enableContextCollapse?: boolean;
149
+ /** Custom event emitter for handoff events */
150
+ eventEmitter?: HandoffEventEmitter;
151
+ /** Timeout for pending handoffs in ms (default: 300000 = 5 minutes) */
152
+ handoffTimeoutMs?: number;
153
+ /** Interval for cleanup of old pending handoffs in ms (default: 60000 = 1 minute) */
154
+ cleanupIntervalMs?: number;
155
+ }
156
+
157
+ export interface HandoffEventEmitter {
158
+ emit(event: string, data: unknown): void;
159
+ }
160
+
161
+ /**
162
+ * Result of shouldSummarize check.
163
+ */
164
+ export interface SummarizeDecision {
165
+ shouldSummarize: boolean;
166
+ reason: string;
167
+ tokenCount: number;
168
+ }
169
+
170
+ /**
171
+ * HandoffManager generates structured summaries when agents complete tasks,
172
+ * enabling efficient context passing to subsequent agents.
173
+ *
174
+ * H1: Includes memory management to prevent unbounded growth of pendingHandoffs Map.
175
+ */
176
+ export class HandoffManager {
177
+ private pendingHandoffs = new Map<string, HandoffSummary>();
178
+ private options: HandoffManagerOptions;
179
+ private handoffTimestamps = new Map<string, number>(); // Track when handoffs were added
180
+ private cleanupTimer: ReturnType<typeof setInterval> | null = null;
181
+ private disposed = false;
182
+
183
+ constructor(options: HandoffManagerOptions = {}) {
184
+ this.options = {
185
+ defaultSummarizeThreshold: DEFAULT_SUMMARIZE_THRESHOLD,
186
+ handoffTimeoutMs: DEFAULT_HANDOVER_TIMEOUT_MS,
187
+ cleanupIntervalMs: DEFAULT_CLEANUP_INTERVAL_MS,
188
+ ...options,
189
+ };
190
+
191
+ // Start cleanup timer
192
+ this.startCleanupTimer();
193
+ }
194
+
195
+ /**
196
+ * Start the periodic cleanup timer for stale pending handoffs.
197
+ * H1: Prevents memory leak by clearing old entries.
198
+ */
199
+ private startCleanupTimer(): void {
200
+ if (this.disposed) {
201
+ return;
202
+ }
203
+ if (this.cleanupTimer) {
204
+ return;
205
+ }
206
+ this.cleanupTimer = setInterval(() => {
207
+ this.cleanupStaleHandoffs();
208
+ }, this.options.cleanupIntervalMs);
209
+ // FIX (BG2 hang): without .unref(), the cleanup interval keeps the Node
210
+ // event loop alive forever — tests that create HandoffManager without
211
+ // calling dispose() (e.g. chain-runner.test.ts mock helper that does
212
+ // `return new HandoffManager()`) leak an interval per test, and the
213
+ // file-level test never completes because Node waits for all handles
214
+ // to close. .unref() lets the process exit when nothing else is pending
215
+ // — this is the standard Node.js pattern for background timers.
216
+ if (typeof this.cleanupTimer.unref === "function") {
217
+ this.cleanupTimer.unref();
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Clean up stale pending handoffs that have exceeded the timeout.
223
+ * H1: Prevents memory leak by removing old entries.
224
+ * FIX: Iterate over entries() instead of mutating Map during iteration.
225
+ */
226
+ private cleanupStaleHandoffs(): void {
227
+ if (this.disposed) return;
228
+
229
+ const now = Date.now();
230
+ const timeout = this.options.handoffTimeoutMs ?? DEFAULT_HANDOVER_TIMEOUT_MS;
231
+ const cutoff = now - timeout;
232
+
233
+ // Collect keys to delete to avoid mutation during iteration
234
+ const toDelete: string[] = [];
235
+ for (const [sessionId, timestamp] of this.handoffTimestamps.entries()) {
236
+ if (timestamp < cutoff) {
237
+ toDelete.push(sessionId);
238
+ }
239
+ }
240
+ for (const sessionId of toDelete) {
241
+ this.pendingHandoffs.delete(sessionId);
242
+ this.handoffTimestamps.delete(sessionId);
243
+ }
244
+
245
+ // Also enforce max handoffs limit
246
+ if (this.pendingHandoffs.size > MAX_PENDING_HANDOFFS) {
247
+ // Remove oldest entries
248
+ const sortedEntries = [...this.handoffTimestamps.entries()].sort((a, b) => a[1] - b[1]);
249
+ const removeCount = sortedEntries.length - MAX_PENDING_HANDOFFS;
250
+ for (let i = 0; i < removeCount; i++) {
251
+ const sessionId = sortedEntries[i][0];
252
+ this.pendingHandoffs.delete(sessionId);
253
+ this.handoffTimestamps.delete(sessionId);
254
+ }
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Hook: agent_end
260
+ * Called when agent completes a task.
261
+ *
262
+ * @param packet - The task packet
263
+ * @param result - The task result
264
+ */
265
+ async onAgentEnd(packet: TaskPacket, result: TaskResult): Promise<HandoffSummary | null> {
266
+ if (this.disposed) {
267
+ return null;
268
+ }
269
+
270
+ // Check if summarization is needed
271
+ if (!this.shouldSummarize(packet, result).shouldSummarize) {
272
+ return null;
273
+ }
274
+
275
+ // Generate handoff summary
276
+ const summary = await this.generateSummary(packet, result);
277
+
278
+ // H7: Validate generated summary structure
279
+ if (!isValidHandoffSummary(summary)) {
280
+ this.options.eventEmitter?.emit("handoff:validation_failed", {
281
+ packet,
282
+ error: "Generated summary failed structure validation",
283
+ });
284
+ return null;
285
+ }
286
+
287
+ // Store pending handoff for tree navigation
288
+ if (packet.sessionId) {
289
+ this.pendingHandoffs.set(packet.sessionId, summary);
290
+ this.handoffTimestamps.set(packet.sessionId, Date.now());
291
+ }
292
+
293
+ // Emit handoff event
294
+ this.options.eventEmitter?.emit("handoff:generated", {
295
+ packet,
296
+ summary,
297
+ });
298
+
299
+ // Optionally collapse context
300
+ if (packet.collapseContext) {
301
+ await this.collapseContext(packet, summary);
302
+ }
303
+
304
+ return summary;
305
+ }
306
+
307
+ /**
308
+ * Hook: session_before_tree
309
+ * Called before navigating to tree view.
310
+ * Injects pending handoff summaries into the tree.
311
+ *
312
+ * @param sessionId - The session ID
313
+ * @param targetId - The target tree node ID
314
+ */
315
+ async onBeforeTreeNavigation(sessionId: string, targetId: string): Promise<HandoffSummary | null> {
316
+ if (this.disposed) {
317
+ return null;
318
+ }
319
+
320
+ const pendingHandoff = this.pendingHandoffs.get(sessionId);
321
+
322
+ if (pendingHandoff) {
323
+ // Clear the pending handoff after injection
324
+ this.pendingHandoffs.delete(sessionId);
325
+ this.handoffTimestamps.delete(sessionId);
326
+ return pendingHandoff;
327
+ }
328
+
329
+ return null;
330
+ }
331
+
332
+ /**
333
+ * Check if summarization should be performed.
334
+ * H7: Validates input parameters before generating summary.
335
+ */
336
+ shouldSummarize(packet: TaskPacket, result: TaskResult): SummarizeDecision {
337
+ // H7: Validate packet structure
338
+ if (!packet || typeof packet.taskId !== "string" || !packet.taskId) {
339
+ return {
340
+ shouldSummarize: false,
341
+ reason: "Invalid task packet structure",
342
+ tokenCount: 0,
343
+ };
344
+ }
345
+
346
+ // H7: Validate result structure
347
+ if (!result || typeof result.outcome !== "string") {
348
+ return {
349
+ shouldSummarize: false,
350
+ reason: "Invalid task result structure",
351
+ tokenCount: 0,
352
+ };
353
+ }
354
+
355
+ const threshold = packet.summarizeThreshold ?? this.options.defaultSummarizeThreshold ?? DEFAULT_SUMMARIZE_THRESHOLD;
356
+ const tokenCount = result.usage?.totalTokens ?? 0;
357
+
358
+ // Summarize if:
359
+ // 1. Task exceeded threshold tokens
360
+ if (tokenCount > threshold) {
361
+ return {
362
+ shouldSummarize: true,
363
+ reason: `Token count ${tokenCount} exceeds threshold ${threshold}`,
364
+ tokenCount,
365
+ };
366
+ }
367
+
368
+ // 2. Task completed with significant work (3 or more tools used)
369
+ if (result.outcome === "success" && (result.toolsUsed?.length ?? 0) >= 3) {
370
+ return {
371
+ shouldSummarize: true,
372
+ reason: `Task used ${result.toolsUsed?.length ?? 0} tools, exceeding minimum of 3`,
373
+ tokenCount,
374
+ };
375
+ }
376
+
377
+ // 3. Explicitly requested
378
+ if (packet.forceSummarize === true) {
379
+ return {
380
+ shouldSummarize: true,
381
+ reason: "Forced summarization requested",
382
+ tokenCount,
383
+ };
384
+ }
385
+
386
+ // 4. Task has significant artifacts or decisions
387
+ const hasArtifacts = (result.filesCreated?.length ?? 0) > 0 || (result.filesModified?.length ?? 0) > 0;
388
+ const hasDecisions = (result.decisions?.length ?? 0) > 0;
389
+
390
+ if (hasArtifacts || hasDecisions) {
391
+ return {
392
+ shouldSummarize: true,
393
+ reason: "Task produced significant artifacts or decisions",
394
+ tokenCount,
395
+ };
396
+ }
397
+
398
+ // 5. Task outcome is not success (failure or partial)
399
+ if (result.outcome !== "success") {
400
+ return {
401
+ shouldSummarize: true,
402
+ reason: `Task outcome is ${result.outcome}`,
403
+ tokenCount,
404
+ };
405
+ }
406
+
407
+ return {
408
+ shouldSummarize: false,
409
+ reason: "Task below summarization threshold",
410
+ tokenCount,
411
+ };
412
+ }
413
+
414
+ /**
415
+ * Generate a structured handoff summary.
416
+ */
417
+ async generateSummary(packet: TaskPacket, result: TaskResult): Promise<HandoffSummary> {
418
+ const artifacts = this.extractArtifacts(result);
419
+ // Use extractDecisionsFromResult to handle empty array and generate defaults
420
+ const decisions = this.extractDecisionsFromResult(result);
421
+ const contextSnapshot = await this.generateContextSnapshot(packet.runId, packet.taskId, result);
422
+
423
+ return {
424
+ taskId: packet.taskId,
425
+ runId: packet.runId,
426
+ timestamp: Date.now(),
427
+
428
+ task: packet.goal,
429
+ outcome: result.outcome,
430
+
431
+ filesCreated: artifacts.created,
432
+ filesModified: artifacts.modified,
433
+ filesDeleted: artifacts.deleted,
434
+
435
+ decisions,
436
+ blockers: result.blockers ?? [],
437
+ nextSteps: result.nextSteps ?? [],
438
+
439
+ metrics: {
440
+ tokensUsed: result.usage?.totalTokens ?? 0,
441
+ duration: result.duration ?? 0,
442
+ iterations: result.iterations ?? 1,
443
+ toolsUsed: result.toolsUsed ?? [],
444
+ },
445
+
446
+ contextSnapshot,
447
+ ...(result.outputText ? { outputText: result.outputText } : {}),
448
+ };
449
+ }
450
+
451
+ /**
452
+ * Collapse context after handoff.
453
+ * Signals to other extensions not to prompt during collapse.
454
+ */
455
+ async collapseContext(packet: TaskPacket, summary: HandoffSummary): Promise<void> {
456
+ // Set global flag to signal collapse in progress
457
+ (globalThis as Record<string, unknown>).__boomerangCollapseInProgress = true;
458
+
459
+ try {
460
+ // Emit event that context will be collapsed
461
+ this.options.eventEmitter?.emit("handoff:context_collapse", {
462
+ sessionId: packet.sessionId,
463
+ taskId: packet.taskId,
464
+ summary,
465
+ });
466
+ } finally {
467
+ // Clear the flag
468
+ (globalThis as Record<string, unknown>).__boomerangCollapseInProgress = false;
469
+ }
470
+ }
471
+
472
+ /**
473
+ * Get pending handoff for a session.
474
+ */
475
+ getPendingHandoff(sessionId: string): HandoffSummary | undefined {
476
+ return this.pendingHandoffs.get(sessionId);
477
+ }
478
+
479
+ /**
480
+ * Clear pending handoff for a session.
481
+ */
482
+ clearPendingHandoff(sessionId: string): void {
483
+ this.pendingHandoffs.delete(sessionId);
484
+ this.handoffTimestamps.delete(sessionId);
485
+ }
486
+
487
+ /**
488
+ * Clear all pending handoffs.
489
+ * H1: Manual cleanup method for memory management.
490
+ */
491
+ clearAllPendingHandoffs(): void {
492
+ this.pendingHandoffs.clear();
493
+ this.handoffTimestamps.clear();
494
+ }
495
+
496
+ /**
497
+ * Get the count of pending handoffs.
498
+ * Useful for monitoring and debugging.
499
+ */
500
+ getPendingCount(): number {
501
+ return this.pendingHandoffs.size;
502
+ }
503
+
504
+ /**
505
+ * Extract file artifacts from task result.
506
+ */
507
+ private extractArtifacts(result: TaskResult): {
508
+ created: string[];
509
+ modified: string[];
510
+ deleted: string[];
511
+ } {
512
+ return {
513
+ created: result.filesCreated ?? [],
514
+ modified: result.filesModified ?? [],
515
+ deleted: result.filesDeleted ?? [],
516
+ };
517
+ }
518
+
519
+ /**
520
+ * Extract decisions from task result.
521
+ */
522
+ private extractDecisionsFromResult(result: TaskResult): Decision[] {
523
+ if (result.decisions && result.decisions.length > 0) {
524
+ return result.decisions;
525
+ }
526
+
527
+ // Generate a default decision for failure outcomes
528
+ if (result.outcome === "failure") {
529
+ return [
530
+ {
531
+ rationale: "Task failed",
532
+ outcome: result.error ?? "Unknown error",
533
+ alternativesConsidered: [],
534
+ },
535
+ ];
536
+ }
537
+
538
+ return [];
539
+ }
540
+
541
+ /**
542
+ * Generate context snapshot for handoff.
543
+ */
544
+ private async generateContextSnapshot(runId: string, taskId: string, result: TaskResult): Promise<string> {
545
+ const parts: string[] = [];
546
+
547
+ parts.push(`Task: ${taskId}`);
548
+ parts.push(`Outcome: ${result.outcome}`);
549
+
550
+ if (result.usage?.totalTokens) {
551
+ parts.push(`Tokens: ${result.usage.totalTokens}`);
552
+ }
553
+
554
+ if (result.toolsUsed?.length) {
555
+ parts.push(`Tools: ${result.toolsUsed.join(", ")}`);
556
+ }
557
+
558
+ if (result.blockers?.length) {
559
+ parts.push(`Blockers: ${result.blockers.join("; ")}`);
560
+ }
561
+
562
+ if (result.nextSteps?.length) {
563
+ parts.push(`Next Steps: ${result.nextSteps.join("; ")}`);
564
+ }
565
+
566
+ return parts.join("\n");
567
+ }
568
+
569
+ /**
570
+ * H8: Dispose of resources. Call when manager is no longer needed.
571
+ * Clears all pending handoffs and stops cleanup timer.
572
+ */
573
+ dispose(): void {
574
+ this.disposed = true;
575
+
576
+ if (this.cleanupTimer) {
577
+ clearInterval(this.cleanupTimer);
578
+ this.cleanupTimer = null;
579
+ }
580
+
581
+ this.pendingHandoffs.clear();
582
+ this.handoffTimestamps.clear();
583
+ }
584
+
585
+ /**
586
+ * Check if the manager has been disposed.
587
+ */
588
+ isDisposed(): boolean {
589
+ return this.disposed;
590
+ }
591
+ }
592
+
593
+ /**
594
+ * Create a HandoffManager with default options.
595
+ */
596
+ export function createHandoffManager(options?: HandoffManagerOptions): HandoffManager {
597
+ return new HandoffManager(options);
598
+ }
@@ -0,0 +1,36 @@
1
+ import type { WorkerHeartbeatState } from "./worker-heartbeat.ts";
2
+
3
+ export type HeartbeatLevel = "healthy" | "warn" | "stale" | "dead";
4
+
5
+ export interface GradientThresholds {
6
+ warnMs: number;
7
+ staleMs: number;
8
+ deadMs: number;
9
+ }
10
+
11
+ export const DEFAULT_GRADIENT_THRESHOLDS: GradientThresholds = {
12
+ warnMs: 30_000,
13
+ staleMs: 60_000,
14
+ deadMs: 300_000,
15
+ };
16
+
17
+ export function heartbeatAgeMs(heartbeat: WorkerHeartbeatState | undefined, now = Date.now()): number {
18
+ if (!heartbeat) return Number.POSITIVE_INFINITY;
19
+ const lastSeen = Date.parse(heartbeat.lastSeenAt);
20
+ return Number.isFinite(lastSeen) ? Math.max(0, now - lastSeen) : Number.POSITIVE_INFINITY;
21
+ }
22
+
23
+ export function classifyHeartbeat(
24
+ heartbeat: WorkerHeartbeatState | undefined,
25
+ thresholds: GradientThresholds = DEFAULT_GRADIENT_THRESHOLDS,
26
+ now = Date.now(),
27
+ ): HeartbeatLevel {
28
+ if (!heartbeat) return "dead";
29
+ if (heartbeat.alive === false) return "dead";
30
+ const elapsed = heartbeatAgeMs(heartbeat, now);
31
+ if (!Number.isFinite(elapsed)) return "dead";
32
+ if (elapsed > thresholds.deadMs) return "dead";
33
+ if (elapsed > thresholds.staleMs) return "stale";
34
+ if (elapsed > thresholds.warnMs) return "warn";
35
+ return "healthy";
36
+ }