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,207 @@
1
+ import * as fs from "node:fs";
2
+ import type { TeamRunManifest, TeamTaskState } from "../state/types.ts";
3
+
4
+ // ============================================================================
5
+ // Phase 1.2: Completion Mutation Guard — detects tasks that claim success but
6
+ // made no observable mutations. Used by task-runner.ts.
7
+ // ============================================================================
8
+
9
+ export interface CompletionMutationGuardInput {
10
+ role: string;
11
+ taskText?: string;
12
+ transcriptPath?: string;
13
+ stdout?: string;
14
+ }
15
+
16
+ export interface CompletionMutationGuardResult {
17
+ expectedMutation: boolean;
18
+ observedMutation: boolean;
19
+ reason?: "no_mutation_observed";
20
+ observedTools: string[];
21
+ }
22
+
23
+ const MUTATING_ROLES = new Set(["executor", "test-engineer"]);
24
+ const MUTATING_TOOLS = new Set([
25
+ "edit",
26
+ "write",
27
+ "multi_edit",
28
+ "apply_patch",
29
+ "replace_in_file",
30
+ "insert",
31
+ "delete_files",
32
+ "create_file",
33
+ "overwrite",
34
+ "patch",
35
+ ]);
36
+ const READ_ONLY_COMMANDS =
37
+ /^(pwd|ls|dir|cat|type|sed|grep|rg|find|git\s+(status|diff|log|show|branch|remote|rev-parse|ls-files)|npm\s+(test|run\s+(typecheck|check|lint|test|ci))|node\s+--test)\b/i;
38
+ const MUTATING_COMMANDS =
39
+ /\b(rm\s+-|del\s+|erase\s+|mv\s+|move\s+|cp\s+|copy\s+|mkdir\b|touch\b|git\s+(add|commit|push|reset|clean|checkout|switch|merge|rebase|stash)|npm\s+(install|i|uninstall|publish|version)|pnpm\s+(add|install|remove)|yarn\s+(add|install|remove)|python\b.*>|node\b.*>|echo\b.*>|Set-Content|Out-File|sed\s+-i|tee\b|dd\b.*of=|wget\b.*-O|curl\b.*-o)\b/i;
40
+ const READ_ONLY_HINTS =
41
+ /\b(read-only|no edits?|do not edit|không sửa|khong sua|chỉ đọc|chi doc|plan only|chỉ lập plan|review only|audit only)\b/i;
42
+
43
+ function asRecord(value: unknown): Record<string, unknown> | undefined {
44
+ return value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;
45
+ }
46
+
47
+ function commandText(value: unknown): string {
48
+ const record = asRecord(value);
49
+ if (!record) return typeof value === "string" ? value : "";
50
+ for (const key of ["command", "cmd", "script", "input"]) {
51
+ const raw = record[key];
52
+ if (typeof raw === "string") return raw;
53
+ }
54
+ return JSON.stringify(record);
55
+ }
56
+
57
+ function isMutatingTool(tool: string, args: unknown): boolean {
58
+ const normalized = tool.toLowerCase();
59
+ if (MUTATING_TOOLS.has(normalized)) return true;
60
+ if (normalized === "bash" || normalized === "shell" || normalized === "powershell") {
61
+ const command = commandText(args).trim();
62
+ if (!command) return false;
63
+ // Check mutating patterns first: sed -i is mutating even though plain sed is read-only.
64
+ if (MUTATING_COMMANDS.test(command)) return true;
65
+ if (READ_ONLY_COMMANDS.test(command)) return false;
66
+ // If the command doesn't match either list, treat unknown bash calls as potentially mutating.
67
+ return true;
68
+ }
69
+ return false;
70
+ }
71
+
72
+ export function collectToolCallsFromEvent(event: unknown): Array<{ tool: string; args?: unknown }> {
73
+ const record = asRecord(event);
74
+ if (!record) return [];
75
+ const calls: Array<{ tool: string; args?: unknown }> = [];
76
+ const directTool = record.toolName ?? record.name ?? record.tool;
77
+ if (
78
+ typeof directTool === "string" &&
79
+ (record.type === "tool_execution_start" || record.type === "toolCall" || record.type === "tool_call")
80
+ ) {
81
+ calls.push({ tool: directTool, args: record.args ?? record.input });
82
+ }
83
+ const content = Array.isArray(record.content) ? record.content : asRecord(record.message)?.content;
84
+ if (Array.isArray(content)) {
85
+ for (const part of content) {
86
+ const item = asRecord(part);
87
+ if (!item) continue;
88
+ const tool = item.name ?? item.toolName ?? item.tool;
89
+ if (typeof tool === "string" && (item.type === "toolCall" || item.type === "tool_call" || item.type === "tool_execution_start"))
90
+ calls.push({ tool, args: item.input ?? item.args });
91
+ }
92
+ }
93
+ return calls;
94
+ }
95
+
96
+ function transcriptText(input: CompletionMutationGuardInput): string {
97
+ if (input.transcriptPath && fs.existsSync(input.transcriptPath)) return fs.readFileSync(input.transcriptPath, "utf-8");
98
+ return input.stdout ?? "";
99
+ }
100
+
101
+ export function expectsImplementationMutation(input: Pick<CompletionMutationGuardInput, "role" | "taskText">): boolean {
102
+ if (!MUTATING_ROLES.has(input.role)) return false;
103
+ return !READ_ONLY_HINTS.test(input.taskText ?? "");
104
+ }
105
+
106
+ export function evaluateCompletionMutationGuard(input: CompletionMutationGuardInput): CompletionMutationGuardResult {
107
+ const expectedMutation = expectsImplementationMutation(input);
108
+ const observedTools: string[] = [];
109
+ let observedMutation = false;
110
+ const text = transcriptText(input);
111
+ for (const line of text.split("\n")) {
112
+ const trimmed = line.trim();
113
+ if (!trimmed) continue;
114
+ let event: unknown;
115
+ try {
116
+ event = JSON.parse(trimmed);
117
+ } catch {
118
+ continue;
119
+ }
120
+ for (const call of collectToolCallsFromEvent(event)) {
121
+ observedTools.push(call.tool);
122
+ if (isMutatingTool(call.tool, call.args)) observedMutation = true;
123
+ }
124
+ }
125
+ return {
126
+ expectedMutation,
127
+ observedMutation,
128
+ observedTools,
129
+ ...(expectedMutation && !observedMutation ? { reason: "no_mutation_observed" as const } : {}),
130
+ };
131
+ }
132
+
133
+ // ============================================================================
134
+ // Phase 11a: Artifact-based Completion Verification — a second layer that
135
+ // checks whether a completed task actually produced meaningful artifacts.
136
+ // ============================================================================
137
+
138
+ /**
139
+ * Guard against false-positive task completions.
140
+ *
141
+ * Checks whether a task that claims success actually produced meaningful output.
142
+ * Returns a verification result with the green level (0-3) and any warnings.
143
+ */
144
+ export interface CompletionVerifyResult {
145
+ /** 0 = no output, 1 = minimal, 2 = moderate, 3 = strong */
146
+ greenLevel: number;
147
+ /** Warnings about potentially incomplete work */
148
+ warnings: string[];
149
+ }
150
+
151
+ const MAX_OUTPUT_PREVIEW = 200;
152
+
153
+ function isTrivialError(error: string | undefined): boolean {
154
+ if (!error) return false;
155
+ return error.trim().length === 0;
156
+ }
157
+
158
+ export function verifyTaskCompletion(task: TeamTaskState, manifest: TeamRunManifest): CompletionVerifyResult {
159
+ const warnings: string[] = [];
160
+ let greenLevel = 0;
161
+
162
+ // Check 1: Has an error?
163
+ if (task.error && !isTrivialError(task.error)) {
164
+ return { greenLevel: 0, warnings: [`Task has error: ${task.error}`] };
165
+ }
166
+
167
+ // Check 2: Has result artifact?
168
+ if (task.resultArtifact) {
169
+ greenLevel += 1;
170
+ }
171
+
172
+ // Check 3: Has transcript?
173
+ if (task.transcriptArtifact) {
174
+ greenLevel += 1;
175
+ }
176
+
177
+ // Check 4: For implementation tasks, verify artifacts were actually produced
178
+ const runArtifacts = manifest.artifacts.filter((a) => a.producer === task.id || a.producer === task.agent);
179
+ if (runArtifacts.length > 0) {
180
+ greenLevel += 1;
181
+ } else if (greenLevel < 3) {
182
+ warnings.push("No run-level artifacts produced by this task");
183
+ }
184
+
185
+ // Check 5: Usage tracking — did the task actually consume tokens?
186
+ if (task.usage) {
187
+ const totalTokens = (task.usage.input ?? 0) + (task.usage.output ?? 0);
188
+ if (totalTokens === 0 && greenLevel < 3) {
189
+ warnings.push("Task reports zero token usage — may not have executed");
190
+ }
191
+ }
192
+
193
+ return {
194
+ greenLevel: Math.min(greenLevel, 3),
195
+ warnings,
196
+ };
197
+ }
198
+
199
+ /**
200
+ * Format a preview of task output for diagnostic display.
201
+ */
202
+ export function formatOutputPreview(output: string | undefined): string {
203
+ if (!output) return "(no output)";
204
+ const trimmed = output.trim();
205
+ if (trimmed.length <= MAX_OUTPUT_PREVIEW) return trimmed;
206
+ return trimmed.slice(0, MAX_OUTPUT_PREVIEW) + "...";
207
+ }
@@ -0,0 +1,58 @@
1
+ import { DEFAULT_CONCURRENCY } from "../config/defaults.ts";
2
+
3
+ export interface ResolveBatchConcurrencyInput {
4
+ workflowName: string;
5
+ workflowMaxConcurrency?: number;
6
+ teamMaxConcurrency?: number;
7
+ limitMaxConcurrentWorkers?: number;
8
+ allowUnboundedConcurrency?: boolean;
9
+ hardCap?: number;
10
+ readyCount: number;
11
+ workspaceMode?: "single" | "worktree";
12
+ readyRoles?: string[];
13
+ }
14
+
15
+ export interface BatchConcurrencyDecision {
16
+ maxConcurrent: number;
17
+ selectedCount: number;
18
+ defaultConcurrency: number;
19
+ reason: string;
20
+ }
21
+
22
+ export function defaultWorkflowConcurrency(workflowName: string, workflowMaxConcurrency?: number): number {
23
+ if (workflowMaxConcurrency !== undefined) return workflowMaxConcurrency;
24
+ if (workflowName === "parallel-research") return DEFAULT_CONCURRENCY.workflow.parallelResearch;
25
+ if (workflowName === "research") return DEFAULT_CONCURRENCY.workflow.research;
26
+ if (workflowName === "implementation") return DEFAULT_CONCURRENCY.workflow.implementation;
27
+ if (workflowName === "review") return DEFAULT_CONCURRENCY.workflow.review;
28
+ if (workflowName === "default") return DEFAULT_CONCURRENCY.workflow.default;
29
+ return DEFAULT_CONCURRENCY.fallback;
30
+ }
31
+
32
+ function positiveInteger(value: number | undefined): number | undefined {
33
+ if (value === undefined || !Number.isFinite(value)) return undefined;
34
+ return Math.max(1, Math.trunc(value));
35
+ }
36
+
37
+ export function resolveBatchConcurrency(input: ResolveBatchConcurrencyInput): BatchConcurrencyDecision {
38
+ const workflowMax = positiveInteger(input.workflowMaxConcurrency);
39
+ const defaultConcurrency = defaultWorkflowConcurrency(input.workflowName, workflowMax);
40
+ const limitMax = positiveInteger(input.limitMaxConcurrentWorkers);
41
+ const teamMax = positiveInteger(input.teamMaxConcurrency);
42
+ const requested = limitMax ?? teamMax ?? workflowMax ?? defaultWorkflowConcurrency(input.workflowName);
43
+ let source: "limit" | "team" | "workflow";
44
+ if (limitMax !== undefined) source = "limit";
45
+ else if (teamMax !== undefined) source = "team";
46
+ else source = "workflow";
47
+ const hardCap = positiveInteger(input.hardCap) ?? DEFAULT_CONCURRENCY.hardCap;
48
+ const maxConcurrent = input.allowUnboundedConcurrency ? requested : Math.min(requested, hardCap);
49
+ const readyCount = Math.max(0, Math.trunc(Number.isFinite(input.readyCount) ? input.readyCount : 0));
50
+ const cappedReason = maxConcurrent < requested ? `;capped:${hardCap}` : "";
51
+ const unboundedReason = input.allowUnboundedConcurrency && requested > hardCap ? `;unbounded:${hardCap}` : "";
52
+ return {
53
+ maxConcurrent,
54
+ selectedCount: readyCount === 0 ? 0 : Math.min(readyCount, maxConcurrent),
55
+ defaultConcurrency,
56
+ reason: `${source}:${requested}${cappedReason}${unboundedReason};ready:${readyCount}`,
57
+ };
58
+ }
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Crash Classification Taxonomy — pure function for categorizing worker exits.
3
+ *
4
+ * Distilled from gajae-code's `debug/crash-diagnostics.ts` (P0 item #1).
5
+ * Unlike the original, this module is pure: it does NOT write crash reports or
6
+ * touch the filesystem. The file-I/O layer is intentionally omitted; callers
7
+ * that want durable crash logs can layer them on top of {@link classifyProcessCrash}.
8
+ *
9
+ * The classification precedence (most-significant first) mirrors the
10
+ * reference implementation:
11
+ *
12
+ * 1. timeout — process was terminated by the response-timeout guard
13
+ * 2. cancelled — cooperative cancellation (AbortSignal) triggered exit
14
+ * 3. spawn_error — child_process emitted an `error` event before `exit`
15
+ * 4. native_panic — stderr indicates a native crash (SIGSEGV / abort / panic)
16
+ * 5. signal_exit — the process was terminated by an OS signal
17
+ * 6. clean_exit — exit code 0
18
+ * 7. non_zero_exit — exit code != 0 (and != null)
19
+ * 8. protocol_exit — exit code is null with no signal (protocol/stream
20
+ * ended before a normal exit was observed)
21
+ * 9. unknown — defensive fallback (should not occur in practice)
22
+ *
23
+ * NOTE on timeout-vs-cancel precedence: when BOTH `timedOut` and `cancelled`
24
+ * are true, `timeout` wins (the timeout terminated the process). This matches
25
+ * gajae-code and the existing child-pi.ts response-timeout guard, which fires
26
+ * the hard kill and is the proximate cause.
27
+ */
28
+
29
+ /**
30
+ * Categorical classification of why a worker process ended.
31
+ *
32
+ * @see classifyProcessCrash
33
+ */
34
+ export type CrashClass =
35
+ | "clean_exit"
36
+ | "non_zero_exit"
37
+ | "signal_exit"
38
+ | "timeout"
39
+ | "cancelled"
40
+ | "spawn_error"
41
+ | "protocol_exit"
42
+ | "native_panic"
43
+ | "unknown";
44
+
45
+ /**
46
+ * Inputs to {@link classifyProcessCrash}. All fields are optional/safe-defaulting
47
+ * so callers can pass a partial view (e.g. just `{ exitCode: 0 }`).
48
+ *
49
+ * Field semantics:
50
+ * - `exitCode` — the OS exit code, or `null` when no code was observed.
51
+ * - `signal` — the terminating signal name (e.g. `"SIGTERM"`) or `null`.
52
+ * - `cancelled` — true when cooperative cancellation (AbortSignal) was requested.
53
+ * - `timedOut` — true when the response-timeout guard fired (and likely killed).
54
+ * - `killed` — true when the parent explicitly killed the child (best-effort).
55
+ * - `spawnError` — truthy when the child emitted a spawn/process `error` event.
56
+ * - `stderrSnippet` — tail of captured stderr, used to detect native panics.
57
+ */
58
+ export interface CrashClassificationInput {
59
+ exitCode?: number | null;
60
+ signal?: string | null;
61
+ cancelled?: boolean;
62
+ timedOut?: boolean;
63
+ killed?: boolean;
64
+ spawnError?: unknown;
65
+ stderrSnippet?: string;
66
+ }
67
+
68
+ /**
69
+ * Result of classifying an exit. `crashClass` is machine-readable;
70
+ * `reason` is a human-friendly one-liner suitable for logs/diagnostics.
71
+ */
72
+ export interface CrashClassification {
73
+ crashClass: CrashClass;
74
+ reason: string;
75
+ }
76
+
77
+ // ── native-panic detection ──────────────────────────────────────────────────
78
+ //
79
+ // We look for a small, well-known set of native-crash signatures in the stderr
80
+ // tail. This is deliberately conservative: false positives would mislabel
81
+ // ordinary non-zero exits as native panics. The patterns are anchored on
82
+ // substrings that do not appear in normal application output.
83
+
84
+ interface NativePanicSignature {
85
+ /** Substring to search for (case-insensitive). */
86
+ pattern: string;
87
+ /** Human-readable class-specific reason suffix. */
88
+ label: string;
89
+ }
90
+
91
+ const NATIVE_PANIC_SIGNATURES: readonly NativePanicSignature[] = [
92
+ { pattern: "sigsegv", label: "segmentation fault" },
93
+ { pattern: "segfault", label: "segmentation fault" },
94
+ { pattern: "segmentation fault", label: "segmentation fault" },
95
+ { pattern: "sigabrt", label: "abort signal" },
96
+ { pattern: "abort(", label: "abort" },
97
+ { pattern: "fatal error", label: "V8/node fatal error" },
98
+ { pattern: "panic:", label: "rust/go panic" },
99
+ { pattern: "thread '", label: "rust panic (thread context)" },
100
+ { pattern: "illegal instruction", label: "illegal instruction" },
101
+ { pattern: "double free", label: "heap corruption (double free)" },
102
+ ];
103
+
104
+ /**
105
+ * If the stderr tail contains a recognizable native-crash signature, return the
106
+ * matching label; otherwise `null`. Case-insensitive.
107
+ */
108
+ function detectNativePanic(stderrSnippet: string | undefined): string | null {
109
+ if (!stderrSnippet) return null;
110
+ const lower = stderrSnippet.toLowerCase();
111
+ for (const sig of NATIVE_PANIC_SIGNATURES) {
112
+ if (lower.includes(sig.pattern)) return sig.label;
113
+ }
114
+ return null;
115
+ }
116
+
117
+ /** Normalize an optional/signal-ish value to `string | null`. */
118
+ function normalizeSignal(signal: string | null | undefined): string | null {
119
+ return signal ?? null;
120
+ }
121
+
122
+ /**
123
+ * Classify a worker exit into a {@link CrashClass}.
124
+ *
125
+ * Pure: no I/O, no globals, no side effects. Deterministic given the same input.
126
+ * Safe to call from any context (including signal handlers).
127
+ *
128
+ * @example
129
+ * classifyProcessCrash({ exitCode: 0 }) // → clean_exit
130
+ * classifyProcessCrash({ exitCode: 1 }) // → non_zero_exit
131
+ * classifyProcessCrash({ signal: "SIGTERM" }) // → signal_exit
132
+ * classifyProcessCrash({ timedOut: true, exitCode: null }) // → timeout
133
+ * classifyProcessCrash({ cancelled: true, exitCode: null }) // → cancelled
134
+ * classifyProcessCrash({ spawnError: new Error("ENOENT") }) // → spawn_error
135
+ * classifyProcessCrash({ exitCode: null }) // → protocol_exit
136
+ * classifyProcessCrash({ exitCode: 139, signal: "SIGSEGV" }) // → signal_exit
137
+ * classifyProcessCrash({ exitCode: 134, stderrSnippet: "abort()" }) // → native_panic
138
+ */
139
+ export function classifyProcessCrash(input: CrashClassificationInput): CrashClassification {
140
+ const exitCode = input.exitCode ?? null;
141
+ const signal = normalizeSignal(input.signal);
142
+
143
+ // 1. Timeout takes precedence: the response-timeout guard is the proximate
144
+ // cause of death even if cancellation was also requested.
145
+ if (input.timedOut) {
146
+ return {
147
+ crashClass: "timeout",
148
+ reason: "process timed out (response timeout guard fired)",
149
+ };
150
+ }
151
+
152
+ // 2. Cooperative cancellation.
153
+ if (input.cancelled) {
154
+ return {
155
+ crashClass: "cancelled",
156
+ reason: "process was cancelled (abort requested)",
157
+ };
158
+ }
159
+
160
+ // 3. Spawn error: the child never started or emitted a process error.
161
+ if (input.spawnError !== undefined && input.spawnError !== null) {
162
+ return {
163
+ crashClass: "spawn_error",
164
+ reason: `spawn error: ${stringifyError(input.spawnError)}`,
165
+ };
166
+ }
167
+
168
+ // 4. Native panic from stderr (only when we have a signal/abnormal exit —
169
+ // never reclassify a clean exit as a panic based on stderr noise).
170
+ const abnormalExit = signal !== null || (exitCode !== null && exitCode !== 0);
171
+ if (abnormalExit) {
172
+ const panic = detectNativePanic(input.stderrSnippet);
173
+ if (panic !== null) {
174
+ return {
175
+ crashClass: "native_panic",
176
+ reason: `native panic detected: ${panic}`,
177
+ };
178
+ }
179
+ }
180
+
181
+ // 5. Signal exit.
182
+ if (signal !== null) {
183
+ return {
184
+ crashClass: "signal_exit",
185
+ reason: `process exited after signal ${signal}`,
186
+ };
187
+ }
188
+
189
+ // 6. Clean exit.
190
+ if (exitCode === 0) {
191
+ return { crashClass: "clean_exit", reason: "process exited cleanly" };
192
+ }
193
+
194
+ // 7. Non-zero exit.
195
+ if (exitCode !== null) {
196
+ return {
197
+ crashClass: "non_zero_exit",
198
+ reason: `process exited with code ${exitCode}`,
199
+ };
200
+ }
201
+
202
+ // 8. Protocol exit: exitCode is null with no signal — the process stream
203
+ // ended before a normal exit was observed (e.g. stdio closed unexpectedly).
204
+ // If `killed` is true but no signal was recorded, treat as protocol_exit
205
+ // (the kill may not have delivered a signal we could capture).
206
+ if (input.killed) {
207
+ return {
208
+ crashClass: "protocol_exit",
209
+ reason: "process was killed but no signal/exit code was captured",
210
+ };
211
+ }
212
+
213
+ // 8b. Truly null exitCode with no other context — protocol/stream ended early.
214
+ return {
215
+ crashClass: "protocol_exit",
216
+ reason: "process exited before protocol completion (exit code unknown)",
217
+ };
218
+ }
219
+
220
+ /** Render an unknown error value to a short message string. */
221
+ function stringifyError(error: unknown): string {
222
+ if (error instanceof Error) return error.message || error.name;
223
+ if (typeof error === "string") return error;
224
+ try {
225
+ return String(error);
226
+ } catch {
227
+ return "(unstringifiable error)";
228
+ }
229
+ }