pi-crew 0.9.56 → 0.9.57

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 (307) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +29 -0
  3. package/README.md +53 -5
  4. package/dist/index.mjs +5350 -4350
  5. package/docs/README.md +54 -0
  6. package/package.json +12 -12
  7. package/skills/real-test-pi-crew/SKILL.md +93 -3
  8. package/src/agents/discover-agents.ts +68 -10
  9. package/src/benchmark/feedback-loop.ts +1 -1
  10. package/src/config/config.ts +2 -1
  11. package/src/config/types.ts +12 -0
  12. package/src/extension/action-suggestions.ts +16 -63
  13. package/src/extension/async-notifier.ts +3 -3
  14. package/src/extension/command-completions.ts +2 -2
  15. package/src/extension/crew-cleanup.ts +3 -3
  16. package/src/extension/crew-vibes/footer.ts +4 -2
  17. package/src/extension/cross-extension-rpc.ts +10 -5
  18. package/src/extension/knowledge-injection.ts +57 -10
  19. package/src/extension/register.ts +2 -2
  20. package/src/extension/registration/artifact-cleanup.ts +41 -3
  21. package/src/extension/registration/commands.ts +4 -4
  22. package/src/extension/registration/context-builder.ts +10 -10
  23. package/src/extension/registration/crash-recovery-cache.ts +3 -3
  24. package/src/extension/registration/foreground-run-controller.ts +1 -1
  25. package/src/extension/registration/lazy-configurers.ts +2 -2
  26. package/src/extension/registration/lifecycle-handlers.ts +12 -12
  27. package/src/extension/registration/lifecycle.ts +2 -2
  28. package/src/extension/registration/observability.ts +2 -2
  29. package/src/extension/registration/registration-types.ts +3 -3
  30. package/src/extension/registration/runtime-cleanup.ts +1 -1
  31. package/src/extension/registration/subagent-helpers.ts +2 -2
  32. package/src/extension/registration/subagent-manager-setup.ts +2 -2
  33. package/src/extension/registration/subagent-tools.ts +21 -16
  34. package/src/extension/registration/team-tool.ts +108 -17
  35. package/src/extension/registration/viewers.ts +3 -4
  36. package/src/extension/registration/wire-cross-extension.ts +7 -7
  37. package/src/extension/rpc-hmac.ts +3 -2
  38. package/src/extension/run-bundle-schema.ts +13 -4
  39. package/src/extension/run-export.ts +2 -2
  40. package/src/extension/run-index.ts +2 -3
  41. package/src/extension/run-maintenance.ts +57 -1
  42. package/src/extension/team-manager-command.ts +3 -1
  43. package/src/extension/team-tool/anchor.ts +8 -2
  44. package/src/extension/team-tool/api.ts +117 -39
  45. package/src/extension/team-tool/cancel.ts +23 -8
  46. package/src/extension/team-tool/chain-executor.ts +1 -1
  47. package/src/extension/team-tool/dispatch/automate.ts +17 -2
  48. package/src/extension/team-tool/dispatch/control.ts +17 -2
  49. package/src/extension/team-tool/dispatch/manage.ts +34 -2
  50. package/src/extension/team-tool/dispatch/run.ts +17 -2
  51. package/src/extension/team-tool/dispatch/status.ts +37 -5
  52. package/src/extension/team-tool/doctor.ts +2 -2
  53. package/src/extension/team-tool/explain.ts +1 -1
  54. package/src/extension/team-tool/goal-wrap.ts +5 -5
  55. package/src/extension/team-tool/goal.ts +30 -9
  56. package/src/extension/team-tool/handle-schedule.ts +37 -19
  57. package/src/extension/team-tool/inspect.ts +21 -5
  58. package/src/extension/team-tool/lifecycle-actions.ts +53 -10
  59. package/src/extension/team-tool/parallel-dispatch.ts +14 -5
  60. package/src/extension/team-tool/param-error.ts +24 -0
  61. package/src/extension/team-tool/respond.ts +20 -6
  62. package/src/extension/team-tool/run.ts +27 -17
  63. package/src/extension/team-tool/status.ts +11 -5
  64. package/src/extension/team-tool.ts +26 -19
  65. package/src/hooks/registry.ts +1 -1
  66. package/src/i18n.ts +22 -0
  67. package/src/observability/event-bus.ts +1 -1
  68. package/src/prompt/prompt-runtime.ts +2 -2
  69. package/src/runtime/README.md +35 -0
  70. package/src/runtime/agent-control.ts +1 -1
  71. package/src/runtime/anchor-manager.ts +0 -2
  72. package/src/runtime/async-runner.ts +1 -1
  73. package/src/runtime/attention-events.ts +1 -1
  74. package/src/runtime/auto-summarize.ts +0 -2
  75. package/src/runtime/background-runner.ts +103 -30
  76. package/src/runtime/{crew-broker-child.ts → broker/crew-broker-child.ts} +2 -2
  77. package/src/runtime/{crew-broker-client.ts → broker/crew-broker-client.ts} +4 -7
  78. package/src/runtime/{crew-broker.ts → broker/crew-broker.ts} +13 -21
  79. package/src/runtime/chain-runner.ts +50 -5
  80. package/src/runtime/{child-pi-constants.ts → child-pi/child-pi-constants.ts} +1 -1
  81. package/src/runtime/{child-pi-kill.ts → child-pi/child-pi-kill.ts} +3 -3
  82. package/src/runtime/{child-pi-spawn.ts → child-pi/child-pi-spawn.ts} +28 -12
  83. package/src/runtime/{child-pi-steering.ts → child-pi/child-pi-steering.ts} +1 -1
  84. package/src/runtime/{child-pi-streams.ts → child-pi/child-pi-streams.ts} +11 -4
  85. package/src/runtime/{child-pi-transcript.ts → child-pi/child-pi-transcript.ts} +6 -6
  86. package/src/runtime/{child-pi.ts → child-pi/child-pi.ts} +28 -72
  87. package/src/runtime/{compact-stages → compaction/compact-stages}/bounded-tail.ts +1 -1
  88. package/src/runtime/{compact-stages → compaction/compact-stages}/index.ts +2 -2
  89. package/src/runtime/{compaction-summary.ts → compaction/compaction-summary.ts} +3 -3
  90. package/src/runtime/{tool-output-pruner.ts → compaction/tool-output-pruner.ts} +1 -1
  91. package/src/runtime/custom-tools/irc-tool.ts +2 -2
  92. package/src/runtime/delivery-coordinator.ts +0 -3
  93. package/src/runtime/diagnostic-export.ts +3 -3
  94. package/src/runtime/foreground-control.ts +1 -1
  95. package/src/runtime/foreground-watchdog.ts +1 -1
  96. package/src/runtime/{adaptive-plan.ts → goal-workflow/adaptive-plan.ts} +8 -8
  97. package/src/runtime/{dynamic-workflow-context.ts → goal-workflow/dynamic-workflow-context.ts} +16 -16
  98. package/src/runtime/{dynamic-workflow-runner.ts → goal-workflow/dynamic-workflow-runner.ts} +10 -10
  99. package/src/runtime/{goal-achievement.ts → goal-workflow/goal-achievement.ts} +3 -3
  100. package/src/runtime/{goal-evaluator.ts → goal-workflow/goal-evaluator.ts} +8 -8
  101. package/src/runtime/{goal-loop-runner.ts → goal-workflow/goal-loop-runner.ts} +27 -25
  102. package/src/runtime/{goal-state-store.ts → goal-workflow/goal-state-store.ts} +8 -8
  103. package/src/runtime/{plan-templates.ts → goal-workflow/plan-templates.ts} +1 -1
  104. package/src/runtime/group-join.ts +3 -3
  105. package/src/runtime/handoff-manager.ts +0 -2
  106. package/src/runtime/{heartbeat-watcher.ts → heartbeat/heartbeat-watcher.ts} +7 -7
  107. package/src/runtime/iteration-hooks.ts +1 -1
  108. package/src/runtime/{live-agent-control.ts → live-session/live-agent-control.ts} +2 -2
  109. package/src/runtime/{live-agent-manager.ts → live-session/live-agent-manager.ts} +4 -4
  110. package/src/runtime/{live-session-runtime.ts → live-session/live-session-runtime.ts} +39 -41
  111. package/src/runtime/manifest-cache.ts +1 -1
  112. package/src/runtime/{model-fallback.ts → model/model-fallback.ts} +1 -1
  113. package/src/runtime/{pi-args.ts → model/pi-args.ts} +20 -5
  114. package/src/runtime/model/provider-extensions.ts +116 -0
  115. package/src/runtime/{runtime-policy.ts → model/runtime-policy.ts} +2 -2
  116. package/src/runtime/{runtime-resolver.ts → model/runtime-resolver.ts} +3 -3
  117. package/src/runtime/{runtime-warmup.ts → model/runtime-warmup.ts} +8 -8
  118. package/src/runtime/orphan-worker-registry.ts +1 -1
  119. package/src/runtime/{progress-tracker.ts → output/progress-tracker.ts} +1 -1
  120. package/src/runtime/{result-extractor.ts → output/result-extractor.ts} +4 -4
  121. package/src/runtime/{sidechain-output.ts → output/sidechain-output.ts} +2 -2
  122. package/src/runtime/{stream-preview.ts → output/stream-preview.ts} +1 -1
  123. package/src/runtime/{streaming-output.ts → output/streaming-output.ts} +2 -2
  124. package/src/runtime/{tool-progress.ts → output/tool-progress.ts} +1 -1
  125. package/src/runtime/parent-guard.ts +30 -10
  126. package/src/runtime/pipeline-runner.ts +2 -2
  127. package/src/runtime/policy-engine.ts +2 -2
  128. package/src/runtime/{cancellation.ts → process/cancellation.ts} +1 -1
  129. package/src/runtime/{post-exit-stdio-guard.ts → process/post-exit-stdio-guard.ts} +1 -1
  130. package/src/runtime/{process-lifecycle.ts → process/process-lifecycle.ts} +3 -3
  131. package/src/runtime/{checkpoint.ts → recovery/checkpoint.ts} +4 -4
  132. package/src/runtime/{crash-recovery.ts → recovery/crash-recovery.ts} +93 -21
  133. package/src/runtime/{overflow-recovery.ts → recovery/overflow-recovery.ts} +1 -1
  134. package/src/runtime/{recovery-recipes.ts → recovery/recovery-recipes.ts} +1 -1
  135. package/src/runtime/{retry-executor.ts → recovery/retry-executor.ts} +2 -2
  136. package/src/runtime/{retry-runner.ts → recovery/retry-runner.ts} +2 -8
  137. package/src/runtime/run-tracker.ts +1 -1
  138. package/src/runtime/run-worker.ts +3 -3
  139. package/src/runtime/{coalesce-tasks.ts → scheduling/coalesce-tasks.ts} +3 -3
  140. package/src/runtime/{concurrency.ts → scheduling/concurrency.ts} +1 -1
  141. package/src/runtime/{parallel-research.ts → scheduling/parallel-research.ts} +4 -2
  142. package/src/runtime/{run-coalesced-task-group.ts → scheduling/run-coalesced-task-group.ts} +95 -36
  143. package/src/runtime/{task-graph-scheduler.ts → scheduling/task-graph-scheduler.ts} +1 -1
  144. package/src/runtime/session-resources.ts +1 -1
  145. package/src/runtime/settings-store.ts +1 -1
  146. package/src/runtime/single-agent-compose.ts +1 -0
  147. package/src/runtime/stale-reconciler.ts +1 -1
  148. package/src/runtime/subagent-manager.ts +1 -1
  149. package/src/runtime/supervisor-contact.ts +1 -1
  150. package/src/runtime/task-output-context.ts +7 -5
  151. package/src/runtime/task-runner/child-executor.ts +62 -22
  152. package/src/runtime/task-runner/live-executor.ts +8 -8
  153. package/src/runtime/task-runner/post-execution.ts +12 -12
  154. package/src/runtime/task-runner/pre-execution.ts +6 -6
  155. package/src/runtime/task-runner/progress.ts +1 -1
  156. package/src/runtime/task-runner/run-projection.ts +1 -1
  157. package/src/runtime/task-runner/scaffold-executor.ts +1 -1
  158. package/src/runtime/task-runner/state-helpers.ts +2 -2
  159. package/src/runtime/task-runner.ts +4 -4
  160. package/src/runtime/team-runner.ts +380 -139
  161. package/src/runtime/{completion-guard.ts → verification/completion-guard.ts} +1 -1
  162. package/src/runtime/{green-contract.ts → verification/green-contract.ts} +1 -1
  163. package/src/runtime/{post-checks.ts → verification/post-checks.ts} +4 -4
  164. package/src/runtime/{verification-gates.ts → verification/verification-gates.ts} +5 -5
  165. package/src/runtime/{verification-integrity.ts → verification/verification-integrity.ts} +1 -1
  166. package/src/schema/config-schema.ts +1 -0
  167. package/src/schema/team-tool-schema.ts +133 -177
  168. package/src/state/README.md +44 -0
  169. package/src/state/atomic-write.ts +24 -3
  170. package/src/state/{locks.ts → coordination/locks.ts} +118 -38
  171. package/src/state/{mailbox.ts → coordination/mailbox.ts} +14 -8
  172. package/src/state/{schedule.ts → coordination/schedule.ts} +3 -3
  173. package/src/state/{task-claims.ts → coordination/task-claims.ts} +1 -1
  174. package/src/state/decision-ledger.ts +1 -1
  175. package/src/state/{event-log-rotation.ts → event-log/event-log-rotation.ts} +161 -31
  176. package/src/state/{event-log.ts → event-log/event-log.ts} +38 -26
  177. package/src/state/{jsonl-writer.ts → event-log/jsonl-writer.ts} +14 -6
  178. package/src/state/hook-instinct-bridge.ts +2 -2
  179. package/src/state/{active-run-registry.ts → stores/active-run-registry.ts} +7 -7
  180. package/src/state/{artifact-store.ts → stores/artifact-store.ts} +62 -4
  181. package/src/state/{blob-store.ts → stores/blob-store.ts} +3 -3
  182. package/src/state/{health-store.ts → stores/health-store.ts} +3 -3
  183. package/src/state/{instinct-store.ts → stores/instinct-store.ts} +3 -3
  184. package/src/state/{observation-store.ts → stores/observation-store.ts} +2 -2
  185. package/src/state/{run-cache.ts → stores/run-cache.ts} +4 -4
  186. package/src/state/{run-graph.ts → stores/run-graph.ts} +4 -4
  187. package/src/state/{run-metrics.ts → stores/run-metrics.ts} +3 -3
  188. package/src/state/{state-store.ts → stores/state-store.ts} +236 -17
  189. package/src/state/types.ts +27 -3
  190. package/src/ui/component.ts +55 -0
  191. package/src/ui/crew-select-list.ts +3 -1
  192. package/src/ui/dashboard-panes/agents-pane.ts +1 -1
  193. package/src/ui/dwf-phase-display.ts +1 -1
  194. package/src/ui/heartbeat-aggregator.ts +1 -1
  195. package/src/ui/keybinding-map.ts +179 -6
  196. package/src/ui/layout-primitives.ts +9 -5
  197. package/src/ui/live-conversation-overlay.ts +1 -1
  198. package/src/ui/live-run-sidebar.ts +1 -1
  199. package/src/ui/overlay-stack.ts +148 -0
  200. package/src/ui/overlays/agent-picker-overlay.ts +1 -1
  201. package/src/ui/overlays/mailbox-compose-overlay.ts +1 -1
  202. package/src/ui/overlays/mailbox-detail-overlay.ts +2 -2
  203. package/src/ui/powerbar-publisher.ts +1 -1
  204. package/src/ui/render-scheduler.ts +1 -1
  205. package/src/ui/run-action-dispatcher.ts +3 -3
  206. package/src/ui/run-dashboard.ts +5 -33
  207. package/src/ui/run-event-bus.ts +3 -3
  208. package/src/ui/run-snapshot-cache.ts +37 -18
  209. package/src/ui/settings-overlay.ts +13 -21
  210. package/src/ui/snapshot-types.ts +1 -1
  211. package/src/ui/status-colors.ts +0 -2
  212. package/src/ui/terminal-status.ts +1 -1
  213. package/src/ui/theme-adapter.ts +33 -13
  214. package/src/ui/tool-renderers/index.ts +8 -0
  215. package/src/ui/transcript-viewer.ts +37 -13
  216. package/src/ui/widget/index.ts +32 -9
  217. package/src/ui/widget/widget-formatters.ts +62 -4
  218. package/src/ui/widget/widget-model.ts +2 -2
  219. package/src/ui/widget/widget-renderer.ts +1 -1
  220. package/src/utils/conflict-detect.ts +58 -5
  221. package/src/utils/ndjson.ts +2 -2
  222. package/src/utils/socket-path.ts +1 -1
  223. package/src/workflows/workflow-config.ts +1 -1
  224. package/src/worktree/cleanup.ts +1 -1
  225. package/src/worktree/worktree-manager.ts +88 -39
  226. package/workflows/chain.workflow.md +2 -2
  227. package/index.bundle.ts +0 -25
  228. package/scripts/bench-check.mjs +0 -96
  229. package/scripts/bench-cold-start.mjs +0 -216
  230. package/scripts/build-bundle.mjs +0 -92
  231. package/scripts/check-all-skills.ts +0 -294
  232. package/scripts/check-bundle-size.mjs +0 -38
  233. package/scripts/check-bundle-staleness.mjs +0 -97
  234. package/scripts/check-conflict-markers.mjs +0 -91
  235. package/scripts/check-lazy-imports.mjs +0 -28
  236. package/scripts/dev-runner.mjs +0 -106
  237. package/scripts/profile-startup.mjs +0 -125
  238. package/scripts/release-smoke.mjs +0 -74
  239. package/scripts/run-bench.mjs +0 -47
  240. package/scripts/run-real-chain.ts +0 -41
  241. package/scripts/smoke-team-perf.ts +0 -43
  242. package/scripts/test-issue-29-crash.ts +0 -111
  243. package/scripts/test-issue-29-e2e.ts +0 -183
  244. package/scripts/test-issue-29-real-runtime.ts +0 -330
  245. package/scripts/test-issue-29-real-tasks.ts +0 -387
  246. package/scripts/test-issue-29-team-tool.ts +0 -105
  247. package/scripts/test-runner.mjs +0 -84
  248. package/scripts/verify-flicker-fix.ts +0 -109
  249. package/scripts/verify-skill.ts +0 -550
  250. package/scripts/watch-bundle.mjs +0 -259
  251. package/scripts/watchdog-harness.ts +0 -119
  252. package/src/adapters/claude-adapter.ts +0 -23
  253. package/src/adapters/codex-adapter.ts +0 -21
  254. package/src/adapters/cursor-adapter.ts +0 -17
  255. package/src/adapters/export-util.ts +0 -143
  256. package/src/adapters/index.ts +0 -15
  257. package/src/adapters/registry.ts +0 -18
  258. package/src/adapters/types.ts +0 -23
  259. package/src/runtime/code-summary.ts +0 -292
  260. package/src/runtime/cross-extension-rpc.ts +0 -143
  261. package/src/runtime/hidden-handoff.ts +0 -407
  262. package/src/runtime/prose-compressor.ts +0 -162
  263. package/src/subagents/async-entry.ts +0 -1
  264. package/src/subagents/index.ts +0 -3
  265. package/src/subagents/live/control.ts +0 -1
  266. package/src/subagents/live/manager.ts +0 -1
  267. package/src/subagents/live/realtime.ts +0 -1
  268. package/src/subagents/live/session-runtime.ts +0 -1
  269. package/src/subagents/manager.ts +0 -1
  270. package/src/subagents/spawn.ts +0 -1
  271. package/test-integration-check.ts +0 -118
  272. /package/src/runtime/{broker-issuer.ts → broker/broker-issuer.ts} +0 -0
  273. /package/src/runtime/{crew-broker-tokens.ts → broker/crew-broker-tokens.ts} +0 -0
  274. /package/src/runtime/{child-pi-pool.ts → child-pi/child-pi-pool.ts} +0 -0
  275. /package/src/runtime/{compact-pipeline.ts → compaction/compact-pipeline.ts} +0 -0
  276. /package/src/runtime/{compact-stages → compaction/compact-stages}/ansi-strip-stage.ts +0 -0
  277. /package/src/runtime/{compact-stages → compaction/compact-stages}/blank-collapse-stage.ts +0 -0
  278. /package/src/runtime/{compact-stages → compaction/compact-stages}/deduplicate-stage.ts +0 -0
  279. /package/src/runtime/{compact-stages → compaction/compact-stages}/head-snap-stage.ts +0 -0
  280. /package/src/runtime/{compact-stages → compaction/compact-stages}/tail-capture-stage.ts +0 -0
  281. /package/src/runtime/{compact-stages → compaction/compact-stages}/truncation-stage.ts +0 -0
  282. /package/src/runtime/{important-line-classifier.ts → compaction/important-line-classifier.ts} +0 -0
  283. /package/src/runtime/{heartbeat-gradient.ts → heartbeat/heartbeat-gradient.ts} +0 -0
  284. /package/src/runtime/{worker-heartbeat.ts → heartbeat/worker-heartbeat.ts} +0 -0
  285. /package/src/runtime/{worker-startup.ts → heartbeat/worker-startup.ts} +0 -0
  286. /package/src/runtime/{intercom-bridge.ts → live-session/intercom-bridge.ts} +0 -0
  287. /package/src/runtime/{live-control-realtime.ts → live-session/live-control-realtime.ts} +0 -0
  288. /package/src/runtime/{live-extension-bridge.ts → live-session/live-extension-bridge.ts} +0 -0
  289. /package/src/runtime/{live-irc.ts → live-session/live-irc.ts} +0 -0
  290. /package/src/runtime/{live-session-health.ts → live-session/live-session-health.ts} +0 -0
  291. /package/src/runtime/{model-resolver.ts → model/model-resolver.ts} +0 -0
  292. /package/src/runtime/{model-scope.ts → model/model-scope.ts} +0 -0
  293. /package/src/runtime/{output-validator.ts → output/output-validator.ts} +0 -0
  294. /package/src/runtime/{pi-json-output.ts → output/pi-json-output.ts} +0 -0
  295. /package/src/runtime/{progress-event-coalescer.ts → output/progress-event-coalescer.ts} +0 -0
  296. /package/src/runtime/{cancellation-token.ts → process/cancellation-token.ts} +0 -0
  297. /package/src/runtime/{zombie-scanner.ts → process/zombie-scanner.ts} +0 -0
  298. /package/src/runtime/{crash-classification.ts → recovery/crash-classification.ts} +0 -0
  299. /package/src/runtime/{batch-barrier.ts → scheduling/batch-barrier.ts} +0 -0
  300. /package/src/runtime/{global-worker-cap.ts → scheduling/global-worker-cap.ts} +0 -0
  301. /package/src/runtime/{parallel-utils.ts → scheduling/parallel-utils.ts} +0 -0
  302. /package/src/runtime/{scheduler.ts → scheduling/scheduler.ts} +0 -0
  303. /package/src/runtime/{semaphore.ts → scheduling/semaphore.ts} +0 -0
  304. /package/src/runtime/{task-graph.ts → scheduling/task-graph.ts} +0 -0
  305. /package/src/runtime/{verification-worktree.ts → verification/verification-worktree.ts} +0 -0
  306. /package/src/state/{event-reconstructor.ts → event-log/event-reconstructor.ts} +0 -0
  307. /package/src/state/{worker-atomic-writer.ts → event-log/worker-atomic-writer.ts} +0 -0
@@ -1,25 +1,31 @@
1
1
  import { loadConfig } from "../../config/config.ts";
2
2
  import { applyAttentionState, formatActivityAge, resolveCrewControlConfig } from "../../runtime/agent-control.ts";
3
3
  import { extractCommandTrace } from "../../runtime/command-trace.ts";
4
- import { verifyTaskCompletion } from "../../runtime/completion-guard.ts";
5
4
  import { readCrewAgents } from "../../runtime/crew-agent-records.ts";
6
5
  import { evaluateRunEffectiveness } from "../../runtime/effectiveness.ts";
7
6
  import { computePhaseProgress } from "../../runtime/phase-progress.ts";
8
7
  import { checkProcessLiveness, isActiveRunStatus } from "../../runtime/process-status.ts";
9
8
  import { formatTaskGraphLines, waitingReason } from "../../runtime/task-display.ts";
9
+ import { verifyTaskCompletion } from "../../runtime/verification/completion-guard.ts";
10
10
  import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
11
- import { appendEvent, readEvents } from "../../state/event-log.ts";
12
- import { readDeliveryState, readMailbox } from "../../state/mailbox.ts";
13
- import { loadRunManifestById, saveRunTasks, updateRunStatus } from "../../state/state-store.ts";
11
+ import { readDeliveryState, readMailbox } from "../../state/coordination/mailbox.ts";
12
+ import { appendEvent, readEvents } from "../../state/event-log/event-log.ts";
13
+ import { loadRunManifestById, saveRunTasks, updateRunStatus } from "../../state/stores/state-store.ts";
14
14
  import { aggregateUsage, formatCost, formatUsage } from "../../state/usage.ts";
15
15
  import { formatDuration } from "../../ui/format-helpers.ts";
16
16
  import { locateRunCwd } from "../team-tool.ts";
17
17
  import type { PiTeamsToolResult } from "../tool-result.ts";
18
18
  import { result, type TeamContext } from "./context.ts";
19
+ import { paramRequired } from "./param-error.ts";
19
20
  import { RUN_NOT_FOUND_HINT } from "./run-not-found.ts";
20
21
 
21
22
  export function handleStatus(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
22
- if (!params.runId) return result("Status requires runId.", { action: "status", status: "error" }, true);
23
+ if (!params.runId)
24
+ return result(
25
+ paramRequired("status", "runId", "{ action: 'status', runId: 'team_...' }"),
26
+ { action: "status", status: "error" },
27
+ true,
28
+ );
23
29
  const runCwd = locateRunCwd(params.runId, ctx.cwd);
24
30
  if (!runCwd) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "status", status: "error" }, true);
25
31
  const loaded = loadRunManifestById(runCwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
@@ -7,12 +7,12 @@ import { loadConfig } from "../config/config.ts";
7
7
  // executeTeamRun is only called when a team run actually executes.
8
8
  import type { executeTeamRun as _executeTeamRunFn } from "../runtime/team-runner.ts";
9
9
  import type { TeamToolParamsValue } from "../schema/team-tool-schema.ts";
10
- import { writeArtifact } from "../state/artifact-store.ts";
11
10
  import { TEAM_TERMINAL_TASK_STATUSES } from "../state/contracts.ts";
12
- import { appendEvent, appendEventFireAndForget } from "../state/event-log.ts";
13
- import { withRunLock } from "../state/locks.ts";
14
- import { replayPendingMailboxMessages } from "../state/mailbox.ts";
15
- import { loadRunManifestById, saveRunManifestAsync, saveRunTasks, updateRunStatus } from "../state/state-store.ts";
11
+ import { withRunLock } from "../state/coordination/locks.ts";
12
+ import { replayPendingMailboxMessages } from "../state/coordination/mailbox.ts";
13
+ import { appendEvent, appendEventFireAndForget } from "../state/event-log/event-log.ts";
14
+ import { writeArtifact } from "../state/stores/artifact-store.ts";
15
+ import { loadRunManifestById, saveRunManifestAsync, saveRunTasks, updateRunStatus } from "../state/stores/state-store.ts";
16
16
  import type { ArtifactDescriptor, TeamRunManifest, TeamTaskState } from "../state/types.ts";
17
17
  import { allTeams, discoverTeams } from "../teams/discover-teams.ts";
18
18
  import { resolveRealContainedPath } from "../utils/safe-paths.ts";
@@ -32,8 +32,8 @@ async function executeTeamRun(...args: Parameters<ExecuteTeamRunFn>): Promise<Aw
32
32
  }
33
33
 
34
34
  import { directTeamAndWorkflowFromRun } from "../runtime/direct-run.ts";
35
- import { parsePiJsonOutput } from "../runtime/pi-json-output.ts";
36
- import { resolveCrewRuntime, runtimeResolutionState } from "../runtime/runtime-resolver.ts";
35
+ import { resolveCrewRuntime, runtimeResolutionState } from "../runtime/model/runtime-resolver.ts";
36
+ import { parsePiJsonOutput } from "../runtime/output/pi-json-output.ts";
37
37
  import { effectiveRunConfig } from "./team-tool/config-patch.ts";
38
38
  import { buildParentContext, formatScoped, result, type TeamContext } from "./team-tool/context.ts";
39
39
  // Lazy-loaded: run.ts pulls in spawnBackgroundTeamRun, resolveCrewRuntime, etc.
@@ -51,6 +51,7 @@ async function handleRun(...args: Parameters<HandleRunFn>): Promise<Awaited<Retu
51
51
  return _cachedHandleRun(...args);
52
52
  }
53
53
 
54
+ import { t } from "../i18n.ts";
54
55
  import { waitForRun } from "../runtime/run-tracker.ts";
55
56
  import { normalizeSkillOverride } from "../runtime/skill-instructions.ts";
56
57
  import { formatActionSuggestion } from "./action-suggestions.ts";
@@ -638,10 +639,9 @@ export async function handleTeamTool(params: TeamToolParamsValue, ctx: TeamConte
638
639
  return handleManageDomain(params, ctx);
639
640
  case "automate":
640
641
  return handleAutomateDomain(params, ctx);
641
- case undefined:
642
642
  default:
643
643
  return result(
644
- `Unknown action: ${action}${formatActionSuggestion(String(action))}`,
644
+ t("team.unknownAction", { action: String(action) }) + formatActionSuggestion(String(action)),
645
645
  { action: "unknown", status: "error" },
646
646
  true,
647
647
  );
@@ -649,11 +649,15 @@ export async function handleTeamTool(params: TeamToolParamsValue, ctx: TeamConte
649
649
  }
650
650
 
651
651
  /**
652
- * Global RPC registry for cross-extension access to pi-crew's team orchestrator.
653
- * Uses Symbol.for() for cross-package singleton pattern (same as OpenTelemetry).
654
- * Extensions can access via: const reg = globalThis[Symbol.for("pi-crew:registry")];
652
+ * Module-scoped RPC registry for access to pi-crew's team orchestrator.
653
+ *
654
+ * EXT-9: Previously this used a `globalThis[Symbol.for("pi-crew:registry")]`
655
+ * singleton — fragile (cross-realm, no lifecycle, peer extensions could
656
+ * read/overwrite it). It is now a module-level variable: exactly one instance
657
+ * per extension load (one per pi session), invisible to peer extensions.
658
+ * Cross-extension consumers should use the `pi.events` RPC channel
659
+ * (`registerPiCrewRpc`) instead of poking globalThis.
655
660
  */
656
- const CREW_REGISTRY_KEY = Symbol.for("pi-crew:registry");
657
661
  interface CrewRegistry {
658
662
  version: 2;
659
663
  getRecord: (runId: string) => TeamRunManifest | undefined;
@@ -674,13 +678,16 @@ interface CrewRegistry {
674
678
  // discovery results with highest priority. The CrewRegistry interface exposes
675
679
  // registerAgent/unregisterAgent/listDynamicAgents for cross-extension access.
676
680
 
681
+ // Module-scoped singleton instance — one per extension load (EXT-9).
682
+ let crewRegistryInstance: CrewRegistry | undefined;
683
+
677
684
  export function registerCrewGlobalRegistry(registry: CrewRegistry): void {
678
- (globalThis as Record<symbol | string, unknown>)[CREW_REGISTRY_KEY] = registry;
685
+ crewRegistryInstance = registry;
679
686
  }
680
687
 
681
- /** @internal */
682
- function getCrewGlobalRegistry(): CrewRegistry | undefined {
683
- return (globalThis as Record<symbol | string, unknown>)[CREW_REGISTRY_KEY] as CrewRegistry | undefined;
688
+ /** @internal — exported for lifecycle tests. */
689
+ export function getCrewGlobalRegistry(): CrewRegistry | undefined {
690
+ return crewRegistryInstance;
684
691
  }
685
692
 
686
693
  /** Manifest cache shape needed to construct the global registry's read-side. */
@@ -744,7 +751,7 @@ export function installCrewGlobalRegistry(deps?: { manifestCache: ManifestCacheF
744
751
  registerCrewGlobalRegistry(registry);
745
752
  }
746
753
 
747
- /** Remove the global CrewRegistry singleton. Call during session cleanup. */
754
+ /** Remove the CrewRegistry singleton. Call during session cleanup. */
748
755
  export function uninstallCrewGlobalRegistry(): void {
749
- delete (globalThis as Record<symbol | string, unknown>)[CREW_REGISTRY_KEY];
756
+ crewRegistryInstance = undefined;
750
757
  }
@@ -1,4 +1,4 @@
1
- import { appendEvent } from "../state/event-log.ts";
1
+ import { appendEvent } from "../state/event-log/event-log.ts";
2
2
  import type { TeamRunManifest } from "../state/types.ts";
3
3
  import { runEventBus } from "../ui/run-event-bus.ts";
4
4
  import type { HookContext, HookDefinition, HookExecutionReport, HookName, HookResult } from "./types.ts";
package/src/i18n.ts CHANGED
@@ -24,6 +24,13 @@ const fallback = {
24
24
  "steer.noted": "Steering request noted for {id}.",
25
25
  "steer.unavailable": "Current default pi-crew backend is child-process, so mid-turn session.steer is not available yet.",
26
26
  "steer.cancelHint": "Use team cancel runId={runId} if the agent must be interrupted.",
27
+ // PR-F12 (EXT-12): team tool user-facing strings routed through t() for
28
+ // consistency with the subagent tools (Agent / get_subagent_result).
29
+ "team.run.created": "Created pi-crew run {runId}.",
30
+ "team.run.completed": "pi-crew run {status}: {runId} ({team})",
31
+ "team.run.allCompleted": "All tasks completed successfully.",
32
+ "team.run.tasksFailed": "{count} task(s) failed: {ids}. Consider retrying.",
33
+ "team.unknownAction": "Unknown action: {action}",
27
34
  } as const;
28
35
 
29
36
  type Key = keyof typeof fallback;
@@ -50,6 +57,11 @@ const translations: Record<string, Partial<Record<Key, string>>> = {
50
57
  "steer.unavailable":
51
58
  "El backend predeterminado actual de pi-crew es child-process, así que session.steer a mitad de turno aún no está disponible.",
52
59
  "steer.cancelHint": "Usa team cancel runId={runId} si hay que interrumpir el agente.",
60
+ "team.run.created": "Ejecución de pi-crew creada {runId}.",
61
+ "team.run.completed": "Ejecución de pi-crew {status}: {runId} ({team})",
62
+ "team.run.allCompleted": "Todas las tareas se completaron con éxito.",
63
+ "team.run.tasksFailed": "{count} tarea(s) fallaron: {ids}. Considera reintentar.",
64
+ "team.unknownAction": "Acción desconocida: {action}",
53
65
  },
54
66
  fr: {
55
67
  "agent.requiresPrompt": "Agent nécessite un prompt.",
@@ -71,6 +83,11 @@ const translations: Record<string, Partial<Record<Key, string>>> = {
71
83
  "steer.unavailable":
72
84
  "Le backend pi-crew par défaut actuel est child-process, donc session.steer en milieu de tour n'est pas encore disponible.",
73
85
  "steer.cancelHint": "Utilisez team cancel runId={runId} si l'agent doit être interrompu.",
86
+ "team.run.created": "Exécution pi-crew créée {runId}.",
87
+ "team.run.completed": "Exécution pi-crew {status} : {runId} ({team})",
88
+ "team.run.allCompleted": "Toutes les tâches ont été effectuées avec succès.",
89
+ "team.run.tasksFailed": "{count} tâche(s) ont échoué : {ids}. Envisagez de réessayer.",
90
+ "team.unknownAction": "Action inconnue : {action}",
74
91
  },
75
92
  "pt-BR": {
76
93
  "agent.requiresPrompt": "Agent requer prompt.",
@@ -92,6 +109,11 @@ const translations: Record<string, Partial<Record<Key, string>>> = {
92
109
  "steer.unavailable":
93
110
  "O backend padrão atual do pi-crew é child-process, então session.steer no meio do turno ainda não está disponível.",
94
111
  "steer.cancelHint": "Use team cancel runId={runId} se o agente precisar ser interrompido.",
112
+ "team.run.created": "Execução do pi-crew criada {runId}.",
113
+ "team.run.completed": "Execução do pi-crew {status}: {runId} ({team})",
114
+ "team.run.allCompleted": "Todas as tarefas foram concluídas com sucesso.",
115
+ "team.run.tasksFailed": "{count} tarefa(s) falharam: {ids}. Considere tentar novamente.",
116
+ "team.unknownAction": "Ação desconhecida: {action}",
95
117
  },
96
118
  };
97
119
 
@@ -1,4 +1,4 @@
1
- import type { AgentProgress } from "../runtime/progress-tracker.ts";
1
+ import type { AgentProgress } from "../runtime/output/progress-tracker.ts";
2
2
  import { logInternalError } from "../utils/internal-error.ts";
3
3
 
4
4
  export type CrewEventType = "agent:progress" | "agent:complete" | "agent:error" | "run:start" | "run:complete";
@@ -1,7 +1,7 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
4
- import { startChildBrokerClient } from "../runtime/crew-broker-child.ts";
4
+ import { startChildBrokerClient } from "../runtime/broker/crew-broker-child.ts";
5
5
  import { logInternalError } from "../utils/internal-error.ts";
6
6
  import { resolveRealContainedPath } from "../utils/safe-paths.ts";
7
7
 
@@ -362,7 +362,7 @@ export default function registerPiTeamsPromptRuntime(pi: ExtensionAPI): void {
362
362
  // already .unref()'d so it never blocks event-loop exit; errors are
363
363
  // swallowed because teardown failures during shutdown are harmless.
364
364
  pi.on("session_shutdown", () => {
365
- void brokerHandle.close().catch(() => {});
365
+ void brokerHandle.close().catch(() => undefined);
366
366
  });
367
367
 
368
368
  // ── Prompt rewriting (existing) ────────────────────────────────────────
@@ -0,0 +1,35 @@
1
+ # src/runtime/ — runtime cluster map
2
+
3
+ This directory holds the team-run execution machinery. After the v0.9.x reorg, the largest
4
+ clusters are extracted into subdirectories; the remaining files stay at the root.
5
+
6
+ ## Extracted subdirectories (navigable clusters)
7
+
8
+ | Subdir | Phase | Cluster | Key files |
9
+ |--------|-------|---------|-----------|
10
+ | [`child-pi/`](./child-pi/) | B-1 | child Pi worker spawn/lifecycle/steering/transcript | `child-pi.ts`, `child-pi-spawn.ts`, `child-pi-kill.ts`, `child-pi-constants.ts`, `child-pi-steering.ts`, `child-pi-streams.ts`, `child-pi-transcript.ts`, `child-pi-pool.ts` |
11
+ | [`broker/`](./broker/) | B-2 | crew broker server/client/auth (child-pi ↔ parent IPC) | `crew-broker.ts`, `crew-broker-client.ts`, `crew-broker-child.ts`, `crew-broker-tokens.ts`, `broker-issuer.ts` |
12
+ | [`task-runner/`](./task-runner/) | (pre-existing) | per-task execution (pre-execution, child-executor) | `child-executor.ts`, `pre-execution.ts`, ... |
13
+ | [`live-session/`](./live-session/) | 3 | live agent control/manager, session runtime, IRC, health, extension bridge | `live-session-runtime.ts`, `live-agent-manager.ts`, `live-agent-control.ts`, `live-control-realtime.ts`, `live-irc.ts`, `live-session-health.ts`, `live-extension-bridge.ts`, `intercom-bridge.ts` |
14
+ | [`recovery/`](./recovery/) | 4 | crash recovery, retry, checkpoint | `crash-recovery.ts`, `crash-classification.ts`, `recovery-recipes.ts`, `overflow-recovery.ts`, `retry-executor.ts`, `retry-runner.ts`, `checkpoint.ts` |
15
+ | [`scheduling/`](./scheduling/) | 5 | scheduler, concurrency, task-graph, batch-barrier, parallel utils | `scheduler.ts`, `semaphore.ts`, `concurrency.ts`, `task-graph.ts`, `task-graph-scheduler.ts`, `batch-barrier.ts`, `coalesce-tasks.ts`, `run-coalesced-task-group.ts`, `global-worker-cap.ts`, `parallel-research.ts`, `parallel-utils.ts` |
16
+ | [`verification/`](./verification/) | 6a | verification gates, green-contract, post-checks, completion-guard | `verification-gates.ts`, `verification-integrity.ts`, `verification-worktree.ts`, `green-contract.ts`, `post-checks.ts`, `completion-guard.ts` |
17
+ | [`model/`](./model/) | 6b | model fallback/resolver/scope, pi-args, runtime policy/resolver/warmup | `model-fallback.ts`, `model-resolver.ts`, `model-scope.ts`, `pi-args.ts`, `runtime-policy.ts`, `runtime-resolver.ts`, `runtime-warmup.ts` |
18
+ | [`output/`](./output/) | 6c | streaming output, progress tracking, sidechain, result extraction | `streaming-output.ts`, `stream-preview.ts`, `output-validator.ts`, `pi-json-output.ts`, `tool-progress.ts`, `progress-event-coalescer.ts`, `progress-tracker.ts`, `result-extractor.ts`, `sidechain-output.ts` |
19
+ | [`heartbeat/`](./heartbeat/) | 6d | heartbeat gradient/watcher, worker heartbeat/startup | `heartbeat-gradient.ts`, `heartbeat-watcher.ts`, `worker-heartbeat.ts`, `worker-startup.ts` |
20
+ | [`process/`](./process/) | 6e | cancellation, process lifecycle, zombie scanner, stdio guard | `cancellation-token.ts`, `cancellation.ts`, `process-lifecycle.ts`, `zombie-scanner.ts`, `post-exit-stdio-guard.ts` |
21
+ | [`goal-workflow/`](./goal-workflow/) | 6f | goal achievement/evaluation/loop, dynamic-workflow, adaptive plan | `goal-achievement.ts`, `goal-evaluator.ts`, `goal-loop-runner.ts`, `goal-state-store.ts`, `dynamic-workflow-context.ts`, `dynamic-workflow-runner.ts`, `adaptive-plan.ts`, `plan-templates.ts` |
22
+ | [`compaction/`](./compaction/) | 6g | compaction pipeline, tool-output-pruner, important-line-classifier, compact-stages | `compact-pipeline.ts`, `compaction-summary.ts`, `tool-output-pruner.ts`, `important-line-classifier.ts`, [`compact-stages/`](./compaction/compact-stages/) |
23
+ | [`custom-tools/`](./custom-tools/) | (pre-existing) | custom tool definitions | `irc-tool.ts`, `submit-result-tool.ts`, ... |
24
+ | [`errors/`](./errors/) | (pre-existing) | error types | ... |
25
+
26
+ ## Remaining flat files at root (~77)
27
+
28
+ - **team-runner** — `team-runner.ts` (the orchestrator) + `run-worker.ts`, `run-tracker.ts`
29
+ - **chain/pipeline runners** — `chain-parser.ts`, `chain-runner.ts`, `pipeline-runner.ts`, `direct-run.ts`
30
+ - **foreground/background runners** — `foreground-control.ts`, `foreground-watchdog.ts`, `async-runner.ts`, `background-runner.ts`
31
+ - **crew agent** — `crew-agent-records.ts`, `crew-agent-runtime.ts`, `crew-hooks.ts`, `single-agent-compose.ts`
32
+ - **observability** — `effectiveness.ts`, `agent-observability.ts`, `command-trace.ts`, `metric-parser.ts`
33
+ - **misc** — `stale-reconciler.ts`, `parent-guard.ts`, `manifest-cache.ts`, `event-stream-bridge.ts`, `policy-engine.ts`, `role-permission.ts`, `workspace-lock.ts`, `workspace-tree.ts`, `session-*.ts`, ...
34
+
35
+ See `docs/COVERAGE-ASSESSMENT-2026-08-01.md` § "Source reorganization" for the reorg history + remaining-cluster plan.
@@ -32,7 +32,7 @@ export function resolveCrewControlConfig(config: PiTeamsConfig | undefined): Cre
32
32
  })
33
33
  | undefined;
34
34
  return {
35
- enabled: raw?.control?.enabled === false ? false : true,
35
+ enabled: raw?.control?.enabled !== false,
36
36
  needsAttentionAfterMs: positiveInt(raw?.control?.needsAttentionAfterMs) ?? DEFAULT_NEEDS_ATTENTION_MS,
37
37
  consecutiveFailureThreshold: positiveInt(raw?.control?.consecutiveFailureThreshold) ?? DEFAULT_CONSECUTIVE_FAILURE_THRESHOLD,
38
38
  longRunningMinutes: positiveInt(raw?.control?.longRunningMinutes) ?? DEFAULT_LONG_RUNNING_MINUTES,
@@ -16,8 +16,6 @@ const MAX_HANDOFFS_PER_ANCHOR = 100;
16
16
  * - accumulateHandoff() adds handoffs to the anchor
17
17
  * - clearAnchor() finalizes and returns accumulated summaries
18
18
  * - getAnchorHandoff() retrieves accumulated summary without clearing
19
- *
20
- * @see docs/pi-boomerang-integration-plan.md
21
19
  */
22
20
 
23
21
  import type { HandoffSummary } from "./handoff-manager.ts";
@@ -3,7 +3,7 @@ import * as fs from "node:fs";
3
3
  import { createRequire } from "node:module";
4
4
  import * as path from "node:path";
5
5
  import { fileURLToPath, pathToFileURL } from "node:url";
6
- import { appendEventAsync } from "../state/event-log.ts";
6
+ import { appendEventAsync } from "../state/event-log/event-log.ts";
7
7
  import type { TeamRunManifest } from "../state/types.ts";
8
8
  import { WINDOWS_ESSENTIAL_ENV_VARS } from "../utils/env-allowlist.ts";
9
9
  import { sanitizeEnvSecrets } from "../utils/env-filter.ts";
@@ -1,4 +1,4 @@
1
- import { appendEvent, type TeamEvent } from "../state/event-log.ts";
1
+ import { appendEvent, type TeamEvent } from "../state/event-log/event-log.ts";
2
2
  import type { CrewAttentionEventData, TeamRunManifest } from "../state/types.ts";
3
3
  import { readJsonlTail } from "../utils/incremental-reader.ts";
4
4
 
@@ -5,8 +5,6 @@
5
5
  * - toggle() enables/disables auto-summarization
6
6
  * - shouldAutoSummarize() checks if task should auto-summarize
7
7
  * - Token and tool thresholds control when summarization triggers
8
- *
9
- * @see docs/pi-boomerang-integration-plan.md
10
8
  */
11
9
 
12
10
  import type { TaskPacket, TaskResult } from "./handoff-manager.ts";
@@ -3,9 +3,9 @@ import * as path from "node:path";
3
3
  import { allAgents, discoverAgents } from "../agents/discover-agents.ts";
4
4
  import { loadConfig } from "../config/config.ts";
5
5
  import { atomicWriteFile } from "../state/atomic-write.ts";
6
- import { appendEvent } from "../state/event-log.ts";
7
- import { withRunLockSync } from "../state/locks.ts";
8
- import { createRunPaths, loadRunManifestById, saveRunManifestAsync, updateRunStatus } from "../state/state-store.ts";
6
+ import { withRunLockSync } from "../state/coordination/locks.ts";
7
+ import { appendEvent, appendEventFireAndForget } from "../state/event-log/event-log.ts";
8
+ import { createRunPaths, loadRunManifestById, saveRunManifestAsync, updateRunStatus } from "../state/stores/state-store.ts";
9
9
  import type { TeamRunManifest, TeamTaskState } from "../state/types.ts";
10
10
  import { allTeams, discoverTeams } from "../teams/discover-teams.ts";
11
11
  import { errorMessage } from "../utils/guards.ts";
@@ -35,7 +35,7 @@ async function executeTeamRun(...args: Parameters<typeof ExecuteTeamRunFn>): Pro
35
35
  // FIX (split-scope install): prime the ESM peer dep BEFORE team-runner is
36
36
  // imported, so its transitive skill-instructions.ts can read getAgentDir()
37
37
  // from the primed cache instead of crashing on `Cannot find module`.
38
- await primePeerDep().catch(() => {});
38
+ await primePeerDep().catch(() => undefined);
39
39
  // LAZY: avoid pulling team-runner into background-runner at module load time.
40
40
  const mod = await import("./team-runner.ts");
41
41
  _cachedExecuteTeamRun = mod.executeTeamRun;
@@ -45,12 +45,12 @@ async function executeTeamRun(...args: Parameters<typeof ExecuteTeamRunFn>): Pro
45
45
 
46
46
  import { logInternalError } from "../utils/internal-error.ts";
47
47
  import { writeAsyncStartMarker } from "./async-marker.ts";
48
- import { terminateActiveChildPiProcesses } from "./child-pi.ts";
48
+ import { terminateActiveChildPiProcesses } from "./child-pi/child-pi.ts";
49
49
  import { directTeamAndWorkflowFromRun } from "./direct-run.ts";
50
+ import { resolveCrewRuntime, runtimeResolutionState } from "./model/runtime-resolver.ts";
50
51
  import { unregisterWorker } from "./orphan-worker-registry.ts";
51
- import { expandParallelResearchWorkflow } from "./parallel-research.ts";
52
52
  import { startParentGuard, stopParentGuard } from "./parent-guard.ts";
53
- import { resolveCrewRuntime, runtimeResolutionState } from "./runtime-resolver.ts";
53
+ import { expandParallelResearchWorkflow } from "./scheduling/parallel-research.ts";
54
54
 
55
55
  /**
56
56
  * Debug logger gated behind PI_CREW_DEBUG env var. Writes to background.log
@@ -110,7 +110,47 @@ function argValue(name: string): string | undefined {
110
110
  return process.argv[index + 1];
111
111
  }
112
112
 
113
- function startInterruptGuard(
113
+ /**
114
+ * Fire-and-forget event log for signal handlers. Extracted to module level
115
+ * (from inside main()) so the exported SIGINT handler installer (test seam)
116
+ * and the inline signal-handler loop inside main() can both use it.
117
+ * Pure function of its arguments — no closure captures from main().
118
+ */
119
+ function signalLog(sig: string, eventsPath: string): void {
120
+ const runId = argValue("--run-id");
121
+ if (runId && eventsPath) {
122
+ appendEventFireAndForget(eventsPath, {
123
+ type: "async.failed",
124
+ runId,
125
+ message: `Background runner received ${sig} — exiting.`,
126
+ data: { signal: sig, pid: process.pid },
127
+ });
128
+ }
129
+ }
130
+
131
+ /**
132
+ * RT-2 SIGINT handler installer — exported as a test seam so integration tests
133
+ * can exercise the REAL handler logic (process.exitCode = 130, NOT
134
+ * process.exit(130)) without re-implementing it in a harness copy.
135
+ *
136
+ * Behavior is IDENTICAL to the previous inline handler in main() — pure
137
+ * extraction, zero logic change.
138
+ */
139
+ export function installBackgroundRunnerSigintHandler(abortController: AbortController, eventsPath: string): void {
140
+ process.on("SIGINT", () => {
141
+ signalLog("SIGINT", eventsPath);
142
+ // RT-2 FIX: Mirror the CORE-7 pattern at the interrupt guard (:146-151).
143
+ // Do NOT call process.exit(130) — it bypasses the finally/runCleanup block
144
+ // in main(), orphaning child-pi workers (they have no parent-guard, see
145
+ // RT-19). Setting exitCode lets the event loop drain naturally so main()'s
146
+ // finally block runs terminateActiveChildPiProcesses + unregisterWorker.
147
+ abortController.abort();
148
+ stopParentGuard();
149
+ process.exitCode = 130;
150
+ });
151
+ }
152
+
153
+ export function startInterruptGuard(
114
154
  manifest: { runId: string; stateRoot: string; eventsPath: string },
115
155
  abortController: AbortController,
116
156
  stopParentGuard: () => void,
@@ -119,6 +159,13 @@ function startInterruptGuard(
119
159
  // FIX: Made configurable via PI_CREW_INTERRUPT_GUARD_INTERVAL_MS env var.
120
160
  // Default 250ms balances fast SIGINT response against filesystem overhead.
121
161
  const interruptGuardInterval = Number(process.env.PI_CREW_INTERRUPT_GUARD_INTERVAL_MS) || 250;
162
+ // RT-4 FIX: Module-local gate so the interrupt body runs only once per
163
+ // interrupt request. Without this, the guard re-fires every
164
+ // interruptGuardInterval (250ms) — each tick does a full
165
+ // terminateActiveChildPiProcesses sweep + sync appendEvent = ~4×/s steady
166
+ // state. The ack write stops the re-fire; this gate is defense-in-depth if
167
+ // the ack write fails (e.g. transient fs error).
168
+ let interruptHandled = false;
122
169
  const interval = setInterval(() => {
123
170
  try {
124
171
  if (!fs.existsSync(controlPath)) return;
@@ -127,6 +174,25 @@ function startInterruptGuard(
127
174
  };
128
175
  const last = parsed.requests?.at(-1);
129
176
  if (last?.type === "interrupt" && last?.acknowledged !== true) {
177
+ // RT-4 FIX: Gate ensures the interrupt body runs only once even if
178
+ // the synchronous ack write below fails.
179
+ if (interruptHandled) return;
180
+ interruptHandled = true;
181
+
182
+ // RT-4 FIX: Write acknowledged:true back to foreground-control.json
183
+ // SYNCHRONOUSLY. This stops the guard from re-firing on the next tick
184
+ // (250ms). Must be sync because this is a setInterval polling callback
185
+ // — we cannot await in a polling callback.
186
+ try {
187
+ const reqs = parsed.requests ?? [];
188
+ if (reqs.length > 0) {
189
+ reqs[reqs.length - 1].acknowledged = true;
190
+ atomicWriteFile(controlPath, JSON.stringify(parsed, null, 2));
191
+ }
192
+ } catch {
193
+ /* best-effort ack — interruptHandled gate prevents re-fire */
194
+ }
195
+
130
196
  appendEvent(manifest.eventsPath, {
131
197
  type: "async.interrupt_detected",
132
198
  runId: manifest.runId,
@@ -335,19 +401,8 @@ async function main(): Promise<void> {
335
401
 
336
402
  // Scrub macOS malloc vars BEFORE anything else — must be clean for all child processes
337
403
  scrubProcessEnv();
338
- // Install signal handlers EARLY — log events before exiting so we can distinguish
339
- // OOM/SIGKILL (no event) from SIGTERM/SIGINT (event written).
340
- const signalLog = (sig: string, eventsPath: string): void => {
341
- const runId = argValue("--run-id");
342
- if (runId && eventsPath) {
343
- appendEvent(eventsPath, {
344
- type: "async.failed",
345
- runId,
346
- message: `Background runner received ${sig} — exiting.`,
347
- data: { signal: sig, pid: process.pid },
348
- });
349
- }
350
- };
404
+ // signalLog is now defined at module level (shared by the exported SIGINT
405
+ // handler installer and the inline signal-handler loop below).
351
406
  // BUG #17 FIX: Compute exitCodePath at module load time using args,
352
407
  // NOT by referencing `manifest` (declared inside main() and not in scope at module load).
353
408
  const exitCodePath = ((): string | undefined => {
@@ -422,10 +477,7 @@ async function main(): Promise<void> {
422
477
  // Trigger graceful shutdown via abort signal so finally block runs
423
478
  abortController.abort();
424
479
  });
425
- process.on("SIGINT", () => {
426
- signalLog("SIGINT", manifest.eventsPath);
427
- process.exit(130);
428
- });
480
+ installBackgroundRunnerSigintHandler(abortController, manifest.eventsPath);
429
481
  // BUG #17: Catch ALL signals to identify what kills the background runner
430
482
  for (const sig of [
431
483
  "SIGHUP",
@@ -527,7 +579,7 @@ async function main(): Promise<void> {
527
579
  // compilation of team-runner.ts, the event loop must not drain prematurely.
528
580
  // The interval is always cleared in the finally block, so the delay is
529
581
  // bounded by the 5s interval. The event loop exit is deferred at most 5s.
530
- const keepAlive = setInterval(() => {}, 5000);
582
+ const keepAlive = setInterval(() => undefined, 5000);
531
583
 
532
584
  // WATCHDOG (anti-zombie): if the run exceeds MAX_BACKGROUND_RUN_MS without
533
585
  // completing, abort it and force-exit. Without this, a hung team run
@@ -598,9 +650,9 @@ async function main(): Promise<void> {
598
650
  debugLog(`[background-runner] short-circuiting ${manifest.runKind} (synthetic team/workflow)`);
599
651
  if (manifest.runKind === "goal-loop") {
600
652
  // LAZY: defer dynamic import of ./goal-loop-runner.ts to its call site.
601
- const { runGoalLoop } = await import("./goal-loop-runner.ts");
653
+ const { runGoalLoop } = await import("./goal-workflow/goal-loop-runner.ts");
602
654
  // LAZY: defer dynamic import of ./goal-state-store.ts to its call site.
603
- const { GoalStore } = await import("./goal-state-store.ts");
655
+ const { GoalStore } = await import("./goal-workflow/goal-state-store.ts");
604
656
  // LAZY: defer dynamic import of ../agents/discover-agents.ts to its call site.
605
657
  const { discoverAgents, allAgents } = await import("../agents/discover-agents.ts");
606
658
  const store = new GoalStore(manifest.cwd);
@@ -639,7 +691,7 @@ async function main(): Promise<void> {
639
691
  };
640
692
  } else {
641
693
  // LAZY: defer dynamic import of ./dynamic-workflow-runner.ts to its call site.
642
- const { runDynamicWorkflow } = await import("./dynamic-workflow-runner.ts");
694
+ const { runDynamicWorkflow } = await import("./goal-workflow/dynamic-workflow-runner.ts");
643
695
  // LAZY: defer dynamic import of ../workflows/discover-workflows.ts to its call site.
644
696
  const { allWorkflows, discoverWorkflows } = await import("../workflows/discover-workflows.ts");
645
697
  const wf = allWorkflows(discoverWorkflows(manifest.cwd)).find((w) => w.name === manifest.workflow);
@@ -774,7 +826,7 @@ async function main(): Promise<void> {
774
826
  const manifestToUse = loaded?.manifest ?? manifest;
775
827
  if (manifestToUse) {
776
828
  // LAZY: live-agent-manager only needed on failure cleanup path; avoid module load at hot path.
777
- const { terminateLiveAgentsForRun } = await import("./live-agent-manager.ts");
829
+ const { terminateLiveAgentsForRun } = await import("./live-session/live-agent-manager.ts");
778
830
  void terminateLiveAgentsForRun(manifestToUse.runId, "failed", appendEvent, manifestToUse.eventsPath).catch((error) =>
779
831
  logInternalError("background-runner.terminate", error, `runId=${manifestToUse.runId}`),
780
832
  );
@@ -832,6 +884,27 @@ try {
832
884
  // called process.exit(1) directly, bypassing the finally block and leaving
833
885
  // orphaned child processes.
834
886
  exitDueToRejection = true;
887
+ // RT-3 FIX: Startup failures (lock-fail, missing manifest, pre-try throws)
888
+ // previously wrote NO event and left exitCode at 0. The run stayed 'queued'
889
+ // until the stale reconciler reaped it. Now write async.failed so the
890
+ // notifier/foreground detects the failure immediately, and set exitCode=1
891
+ // so the process exits non-zero.
892
+ try {
893
+ const mCwd = argValue("--cwd");
894
+ const mRunId = argValue("--run-id");
895
+ if (mCwd && mRunId) {
896
+ const mEventsPath = createRunPaths(mCwd, mRunId).eventsPath;
897
+ appendEvent(mEventsPath, {
898
+ type: "async.failed",
899
+ runId: mRunId,
900
+ message: errorMessage(err),
901
+ data: { stack: err instanceof Error ? err.stack : undefined },
902
+ });
903
+ }
904
+ } catch {
905
+ /* best-effort — don't let event-write failure mask the original error */
906
+ }
907
+ process.exitCode = 1;
835
908
  // FIX: Call stopParentGuard directly here as a safety net in case the
836
909
  // finally block (which calls runCleanup→stopParentGuard) does not complete.
837
910
  // This ensures the parent guard is stopped in ALL exit paths: normal
@@ -41,7 +41,7 @@ export interface StartChildBrokerClientOptions {
41
41
 
42
42
  const NOOP_HANDLE: ChildBrokerClientHandle = {
43
43
  active: false,
44
- close: async () => {},
44
+ close: async () => undefined,
45
45
  };
46
46
 
47
47
  export function startChildBrokerClient(options: StartChildBrokerClientOptions = {}): ChildBrokerClientHandle {
@@ -75,7 +75,7 @@ export function startChildBrokerClient(options: StartChildBrokerClientOptions =
75
75
  // Establish the persistent connection so the broker can push events. This
76
76
  // is fire-and-forget: on any failure the client becomes sticky-fallback and
77
77
  // the file-poll steering path remains fully functional.
78
- void client.reconnect().catch(() => {});
78
+ void client.reconnect().catch(() => undefined);
79
79
 
80
80
  return {
81
81
  get active() {
@@ -24,9 +24,9 @@
24
24
  import { randomUUID } from "node:crypto";
25
25
  import * as net from "node:net";
26
26
 
27
- import { logInternalError } from "../utils/internal-error.ts";
28
- import { BrokerError, encodeBrokerFrame, NdjsonDecoder } from "../utils/ndjson.ts";
29
- import { redactSecretString } from "../utils/redaction.ts";
27
+ import { logInternalError } from "../../utils/internal-error.ts";
28
+ import { BrokerError, encodeBrokerFrame, NdjsonDecoder } from "../../utils/ndjson.ts";
29
+ import { redactSecretString } from "../../utils/redaction.ts";
30
30
 
31
31
  /** Shape of an unsolicited event frame pushed by the broker (mailbox.message,
32
32
  * team.event, etc.). */
@@ -95,7 +95,6 @@ export class CrewBrokerClient {
95
95
  private socket: net.Socket | null = null;
96
96
  private decoder: NdjsonDecoder | null = null;
97
97
  private readonly pending = new Map<string, PendingRequest>();
98
- private attempts = 0;
99
98
  /** Listeners attached to the current socket; kept for explicit close(). */
100
99
  private readonly socketListeners: Array<{
101
100
  event: string;
@@ -234,7 +233,6 @@ export class CrewBrokerClient {
234
233
  async reconnect(): Promise<boolean> {
235
234
  // Close the current socket if any.
236
235
  this.teardownSocket();
237
- this.attempts = 0;
238
236
  this._mode = "unstarted";
239
237
  const res = await this.request("ping", null);
240
238
  return res.ok;
@@ -309,7 +307,6 @@ export class CrewBrokerClient {
309
307
  if (this.closed) {
310
308
  return { ok: false, fallback: true, errorCode: "closed" };
311
309
  }
312
- this.attempts = attempt + 1;
313
310
  const result = await this.attemptHello(netModule);
314
311
  if (result.ok) {
315
312
  // Belt-and-suspenders: a successful hello can still race
@@ -460,7 +457,7 @@ export class CrewBrokerClient {
460
457
  return;
461
458
  }
462
459
  // Hello ack: must include `result.ok === true` and matching id.
463
- if (frame.id && frame.id.startsWith("hello-")) {
460
+ if (frame.id?.startsWith("hello-")) {
464
461
  if (frame.error) {
465
462
  const code = (frame.error as { code?: string }).code ?? "auth";
466
463
  finish({ ok: false, fallback: true, errorCode: code });