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
@@ -19,14 +19,14 @@
19
19
 
20
20
  import { loadConfig } from "../../config/config.ts";
21
21
  import type { GoalWrapWorkflowConfig } from "../../config/types.ts";
22
- import { GoalStore } from "../../runtime/goal-state-store.ts";
23
- import { snapshotManifests } from "../../runtime/verification-integrity.ts";
22
+ import { spawnBackgroundTeamRun } from "../../runtime/async-runner.ts";
23
+ import { GoalStore } from "../../runtime/goal-workflow/goal-state-store.ts";
24
+ import { snapshotManifests } from "../../runtime/verification/verification-integrity.ts";
24
25
  import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
25
26
  import { atomicWriteJson } from "../../state/atomic-write.ts";
26
- import { appendEvent } from "../../state/event-log.ts";
27
- import { createRunPaths, saveRunManifestAsync } from "../../state/state-store.ts";
27
+ import { appendEvent } from "../../state/event-log/event-log.ts";
28
+ import { createRunPaths, saveRunManifestAsync } from "../../state/stores/state-store.ts";
28
29
  import type { GoalLoopState, TeamRunManifest } from "../../state/types.ts";
29
- import { spawnBackgroundTeamRun } from "../../subagents/async-entry.ts";
30
30
  import { logInternalError } from "../../utils/internal-error.ts";
31
31
  import type { WorkflowConfig } from "../../workflows/workflow-config.ts";
32
32
  import { result, type TeamContext } from "./context.ts";
@@ -14,16 +14,17 @@
14
14
  * §0c C11 (control path: cooperative flag + handleCancel(currentRunId) via abortOwned).
15
15
  */
16
16
 
17
- import { GoalStore } from "../../runtime/goal-state-store.ts";
18
- import { snapshotManifests } from "../../runtime/verification-integrity.ts";
17
+ import { spawnBackgroundTeamRun } from "../../runtime/async-runner.ts";
18
+ import { GoalStore } from "../../runtime/goal-workflow/goal-state-store.ts";
19
+ import { snapshotManifests } from "../../runtime/verification/verification-integrity.ts";
19
20
  import { isWorkspaceBusy } from "../../runtime/workspace-lock.ts";
20
21
  import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
21
- import { appendEvent } from "../../state/event-log.ts";
22
- import { createRunPaths, saveRunManifestAsync } from "../../state/state-store.ts";
22
+ import { appendEvent } from "../../state/event-log/event-log.ts";
23
+ import { createRunPaths, saveRunManifestAsync } from "../../state/stores/state-store.ts";
23
24
  import type { GoalLoopState, GoalLoopStatus, TeamRunManifest } from "../../state/types.ts";
24
- import { spawnBackgroundTeamRun } from "../../subagents/async-entry.ts";
25
25
  import { logInternalError } from "../../utils/internal-error.ts";
26
26
  import { result, type TeamContext } from "./context.ts";
27
+ import { paramRequired } from "./param-error.ts";
27
28
 
28
29
  const MAX_GOAL_OBJECTIVE_CHARS = 4000;
29
30
 
@@ -296,7 +297,12 @@ function assertGoalOwnership(goal: GoalLoopState, ctx: TeamContext, action: stri
296
297
  function handleStateFlip(input: GoalSubActionInput, nextState: GoalLoopStatus, label: string): ReturnType<typeof result> {
297
298
  const { params, ctx, store } = input;
298
299
  const goalId = params.config?.goalId as string | undefined;
299
- if (!goalId) return result(`${label} requires config.goalId.`, { action: "goal", status: "error" }, true);
300
+ if (!goalId)
301
+ return result(
302
+ paramRequired(label, "config.goalId", "{ action: 'goal', config: { goalId: '...' } }"),
303
+ { action: "goal", status: "error" },
304
+ true,
305
+ );
300
306
  const existing = store.load(goalId);
301
307
  if (!existing) return result(`Goal '${goalId}' not found.`, { action: "goal", status: "error" }, true);
302
308
  if (params.force !== true) {
@@ -325,7 +331,12 @@ function handleStateFlip(input: GoalSubActionInput, nextState: GoalLoopStatus, l
325
331
  async function handleStop(input: GoalSubActionInput): Promise<ReturnType<typeof result>> {
326
332
  const { params, ctx, store } = input;
327
333
  const goalId = params.config?.goalId as string | undefined;
328
- if (!goalId) return result("stop requires config.goalId.", { action: "goal", status: "error" }, true);
334
+ if (!goalId)
335
+ return result(
336
+ paramRequired("stop", "config.goalId", "{ action: 'goal', config: { subAction: 'stop', goalId: '...' } }"),
337
+ { action: "goal", status: "error" },
338
+ true,
339
+ );
329
340
  const eventsPath = createRunPaths(ctx.cwd, goalId).eventsPath;
330
341
  const before = store.load(goalId);
331
342
  if (!before) return result(`Goal '${goalId}' not found.`, { action: "goal", status: "error" }, true);
@@ -386,7 +397,12 @@ async function handleStop(input: GoalSubActionInput): Promise<ReturnType<typeof
386
397
  async function handleResume(input: GoalSubActionInput): Promise<ReturnType<typeof result>> {
387
398
  const { params, ctx, store } = input;
388
399
  const goalId = params.config?.goalId as string | undefined;
389
- if (!goalId) return result("resume requires config.goalId.", { action: "goal", status: "error" }, true);
400
+ if (!goalId)
401
+ return result(
402
+ paramRequired("resume", "config.goalId", "{ action: 'goal', config: { subAction: 'resume', goalId: '...' } }"),
403
+ { action: "goal", status: "error" },
404
+ true,
405
+ );
390
406
  const existing = store.load(goalId);
391
407
  if (!existing) return result(`Goal '${goalId}' not found.`, { action: "goal", status: "error" }, true);
392
408
  if (params.force !== true) {
@@ -510,7 +526,12 @@ export async function handleGoal(params: TeamToolParamsValue, ctx: TeamContext):
510
526
  // Fix P1-3 + round-5 P2: remove the goal file. But refuse if the loop is still
511
527
  // running (would leave a zombie background process). Require stop first.
512
528
  const clearGoalId = params.config?.goalId as string | undefined;
513
- if (!clearGoalId) return result("clear requires config.goalId.", { action: "goal", status: "error" }, true);
529
+ if (!clearGoalId)
530
+ return result(
531
+ paramRequired("clear", "config.goalId", "{ action: 'goal', config: { subAction: 'clear', goalId: '...' } }"),
532
+ { action: "goal", status: "error" },
533
+ true,
534
+ );
514
535
  const existing = store.load(clearGoalId);
515
536
  if (!existing) return result(`Goal '${clearGoalId}' not found (already cleared?).`, { action: "goal", status: "error" }, true);
516
537
  if (params.force !== true) {
@@ -1,28 +1,39 @@
1
1
  import * as crypto from "node:crypto";
2
- import { humanizeSchedule, nextRunTime, parseSchedule } from "../../runtime/scheduler.ts";
2
+ import { humanizeSchedule, nextRunTime, parseSchedule } from "../../runtime/scheduling/scheduler.ts";
3
3
  import { type CrewSettings, updateCrewSettings } from "../../runtime/settings-store.ts";
4
4
  import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
5
5
  import type { PiTeamsToolResult } from "../tool-result.ts";
6
6
  import { result, type TeamContext } from "./context.ts";
7
+ import { paramRequired } from "./param-error.ts";
7
8
 
8
- // Global key for cross-module scheduler access.
9
- const CREW_SCHEDULER_KEY = Symbol.for("pi-crew:scheduler");
9
+ // Module-scoped scheduler reference — one per extension load (EXT-9).
10
+ // Previously this lived on `globalThis[Symbol.for("pi-crew:scheduler")]`, which
11
+ // was fragile (cross-realm, no lifecycle, peer extensions could overwrite it).
10
12
  type SchedulerRef = {
11
- add(job: import("../../runtime/scheduler.ts").ScheduledJob): void;
12
- list(): import("../../runtime/scheduler.ts").ScheduledJob[];
13
+ add(job: import("../../runtime/scheduling/scheduler.ts").ScheduledJob): void;
14
+ list(): import("../../runtime/scheduling/scheduler.ts").ScheduledJob[];
13
15
  remove(id: string): boolean;
14
16
  update(
15
17
  id: string,
16
- patch: Partial<import("../../runtime/scheduler.ts").ScheduledJob>,
17
- ): import("../../runtime/scheduler.ts").ScheduledJob | undefined;
18
+ patch: Partial<import("../../runtime/scheduling/scheduler.ts").ScheduledJob>,
19
+ ): import("../../runtime/scheduling/scheduler.ts").ScheduledJob | undefined;
18
20
  };
19
21
 
20
- function getCrewScheduler(): SchedulerRef | undefined {
21
- return (globalThis as Record<symbol | string, unknown>)[CREW_SCHEDULER_KEY] as SchedulerRef | undefined;
22
+ // Module-scoped scheduler instance — one per extension load (EXT-9).
23
+ let crewSchedulerInstance: SchedulerRef | undefined;
24
+
25
+ /** @internal — exported for lifecycle tests. */
26
+ export function getCrewScheduler(): SchedulerRef | undefined {
27
+ return crewSchedulerInstance;
22
28
  }
23
29
 
24
30
  export function registerCrewScheduler(scheduler: SchedulerRef): void {
25
- (globalThis as Record<symbol | string, unknown>)[CREW_SCHEDULER_KEY] = scheduler;
31
+ crewSchedulerInstance = scheduler;
32
+ }
33
+
34
+ /** Remove the scheduler singleton. Call during session cleanup. */
35
+ export function unregisterCrewScheduler(): void {
36
+ crewSchedulerInstance = undefined;
26
37
  }
27
38
 
28
39
  interface ScheduleParams {
@@ -35,9 +46,9 @@ interface ScheduleParams {
35
46
  }
36
47
 
37
48
  function buildScheduleSpec(params: ScheduleParams): {
38
- spec: import("../../runtime/scheduler.ts").ScheduleSpec;
49
+ spec: import("../../runtime/scheduling/scheduler.ts").ScheduleSpec;
39
50
  schedule: string;
40
- scheduleType: import("../../runtime/scheduler.ts").ScheduleType;
51
+ scheduleType: import("../../runtime/scheduling/scheduler.ts").ScheduleType;
41
52
  intervalMs?: number;
42
53
  } {
43
54
  // Priority: cron > interval > once
@@ -100,7 +111,12 @@ export function handleSchedule(params: TeamToolParamsValue, ctx: TeamContext): P
100
111
 
101
112
  const team = params.team ?? "default";
102
113
  const goal = params.goal ?? params.task ?? "";
103
- if (!goal) return result("Schedule requires goal or task.", { action: "schedule", status: "error" }, true);
114
+ if (!goal)
115
+ return result(
116
+ paramRequired("schedule", "goal or task", "{ action: 'schedule', goal: '...', cron: '0 9 * * *' }"),
117
+ { action: "schedule", status: "error" },
118
+ true,
119
+ );
104
120
 
105
121
  let specResult: ReturnType<typeof buildScheduleSpec>;
106
122
  try {
@@ -121,7 +137,7 @@ export function handleSchedule(params: TeamToolParamsValue, ctx: TeamContext): P
121
137
  if ("error" in next) return result(next.error, { action: "schedule", status: "error" }, true);
122
138
 
123
139
  // Build the ScheduledJob
124
- const job: import("../../runtime/scheduler.ts").ScheduledJob = {
140
+ const job: import("../../runtime/scheduling/scheduler.ts").ScheduledJob = {
125
141
  id: crypto.randomUUID(),
126
142
  name: `${team}: ${goal.slice(0, 60)}`,
127
143
  description: `Scheduled run for team '${team}'`,
@@ -190,11 +206,13 @@ export function handleSchedule(params: TeamToolParamsValue, ctx: TeamContext): P
190
206
  );
191
207
  }
192
208
 
193
- function scheduledJobsOf(settings: CrewSettings): import("../../runtime/scheduler.ts").ScheduledJob[] {
194
- return Array.isArray(settings.scheduledJobs) ? (settings.scheduledJobs as import("../../runtime/scheduler.ts").ScheduledJob[]) : [];
209
+ function scheduledJobsOf(settings: CrewSettings): import("../../runtime/scheduling/scheduler.ts").ScheduledJob[] {
210
+ return Array.isArray(settings.scheduledJobs)
211
+ ? (settings.scheduledJobs as import("../../runtime/scheduling/scheduler.ts").ScheduledJob[])
212
+ : [];
195
213
  }
196
214
 
197
- function persistScheduledJob(cwd: string, job: import("../../runtime/scheduler.ts").ScheduledJob): void {
215
+ function persistScheduledJob(cwd: string, job: import("../../runtime/scheduling/scheduler.ts").ScheduledJob): void {
198
216
  try {
199
217
  updateCrewSettings(cwd, (settings) => ({
200
218
  ...settings,
@@ -206,7 +224,7 @@ function persistScheduledJob(cwd: string, job: import("../../runtime/scheduler.t
206
224
  }
207
225
 
208
226
  /** Update an existing scheduled job in persistent settings. */
209
- export function persistScheduledJobUpdate(cwd: string, job: import("../../runtime/scheduler.ts").ScheduledJob): void {
227
+ export function persistScheduledJobUpdate(cwd: string, job: import("../../runtime/scheduling/scheduler.ts").ScheduledJob): void {
210
228
  try {
211
229
  updateCrewSettings(cwd, (settings) => ({
212
230
  ...settings,
@@ -309,7 +327,7 @@ export function handleUpdateScheduled(params: TeamToolParamsValue, ctx: TeamCont
309
327
  return result("Scheduler not running.", { action: "schedule", status: "error" }, true);
310
328
  }
311
329
 
312
- const patch: Partial<import("../../runtime/scheduler.ts").ScheduledJob> = {};
330
+ const patch: Partial<import("../../runtime/scheduling/scheduler.ts").ScheduledJob> = {};
313
331
  if (subAction === "disable") patch.enabled = false;
314
332
  if (subAction === "enable") patch.enabled = true;
315
333
  // For generic "update", allow patch of cron / interval / goal.
@@ -1,15 +1,21 @@
1
1
  import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
2
- import { readEvents } from "../../state/event-log.ts";
3
- import { loadRunManifestById } from "../../state/state-store.ts";
2
+ import { readEvents } from "../../state/event-log/event-log.ts";
3
+ import { loadRunManifestById } from "../../state/stores/state-store.ts";
4
4
  import { aggregateUsage, formatCostReport, formatUsage } from "../../state/usage.ts";
5
5
  import { locateRunCwd } from "../team-tool.ts";
6
6
  import type { PiTeamsToolResult } from "../tool-result.ts";
7
7
  import { result, type TeamContext } from "./context.ts";
8
8
  import { formatFailurePatterns } from "./failure-patterns.ts";
9
+ import { paramRequired } from "./param-error.ts";
9
10
  import { RUN_NOT_FOUND_HINT } from "./run-not-found.ts";
10
11
 
11
12
  export function handleEvents(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
12
- if (!params.runId) return result("Events requires runId.", { action: "events", status: "error" }, true);
13
+ if (!params.runId)
14
+ return result(
15
+ paramRequired("events", "runId", "{ action: 'events', runId: 'team_...' }"),
16
+ { action: "events", status: "error" },
17
+ true,
18
+ );
13
19
  const runCwd = locateRunCwd(params.runId, ctx.cwd);
14
20
  if (!runCwd) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "events", status: "error" }, true);
15
21
  const loaded = loadRunManifestById(runCwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
@@ -33,7 +39,12 @@ export function handleEvents(params: TeamToolParamsValue, ctx: TeamContext): PiT
33
39
  }
34
40
 
35
41
  export function handleArtifacts(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
36
- if (!params.runId) return result("Artifacts requires runId.", { action: "artifacts", status: "error" }, true);
42
+ if (!params.runId)
43
+ return result(
44
+ paramRequired("artifacts", "runId", "{ action: 'artifacts', runId: 'team_...' }"),
45
+ { action: "artifacts", status: "error" },
46
+ true,
47
+ );
37
48
  const runCwd = locateRunCwd(params.runId, ctx.cwd);
38
49
  if (!runCwd) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "artifacts", status: "error" }, true);
39
50
  const loaded = loadRunManifestById(runCwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
@@ -56,7 +67,12 @@ export function handleArtifacts(params: TeamToolParamsValue, ctx: TeamContext):
56
67
  }
57
68
 
58
69
  export function handleSummary(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
59
- if (!params.runId) return result("Summary requires runId.", { action: "summary", status: "error" }, true);
70
+ if (!params.runId)
71
+ return result(
72
+ paramRequired("summary", "runId", "{ action: 'summary', runId: 'team_...' }"),
73
+ { action: "summary", status: "error" },
74
+ true,
75
+ );
60
76
  const runCwd = locateRunCwd(params.runId, ctx.cwd);
61
77
  if (!runCwd) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "summary", status: "error" }, true);
62
78
  const loaded = loadRunManifestById(runCwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
@@ -2,11 +2,11 @@ import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import { removeGuidance } from "../../config/markers.ts";
4
4
  import { appendHookEvent, executeHook } from "../../hooks/registry.ts";
5
- import { killProcessPid } from "../../runtime/child-pi.ts";
6
- import { terminateLiveAgentsForRun } from "../../runtime/live-agent-manager.ts";
5
+ import { killProcessPid } from "../../runtime/child-pi/child-pi.ts";
6
+ import { terminateLiveAgentsForRun } from "../../runtime/live-session/live-agent-manager.ts";
7
7
  import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
8
- import { appendEvent } from "../../state/event-log.ts";
9
- import { loadRunManifestById } from "../../state/state-store.ts";
8
+ import { appendEvent } from "../../state/event-log/event-log.ts";
9
+ import { loadRunManifestById } from "../../state/stores/state-store.ts";
10
10
  import { logInternalError } from "../../utils/internal-error.ts";
11
11
  import { projectCrewRoot, userCrewRoot, userPiRoot } from "../../utils/paths.ts";
12
12
  import { resolveRealContainedPath } from "../../utils/safe-paths.ts";
@@ -18,10 +18,16 @@ import { pruneFinishedRuns } from "../run-maintenance.ts";
18
18
  import type { PiTeamsToolResult } from "../tool-result.ts";
19
19
  import { configRecord, result, type TeamContext } from "./context.ts";
20
20
  import { enforceDestructiveIntent, intentFromConfig } from "./intent-policy.ts";
21
+ import { paramRequired } from "./param-error.ts";
21
22
  import { RUN_NOT_FOUND_HINT } from "./run-not-found.ts";
22
23
 
23
24
  export function handleWorktrees(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
24
- if (!params.runId) return result("Worktrees requires runId.", { action: "worktrees", status: "error" }, true);
25
+ if (!params.runId)
26
+ return result(
27
+ paramRequired("worktrees", "runId", "{ action: 'worktrees', runId: 'team_...' }"),
28
+ { action: "worktrees", status: "error" },
29
+ true,
30
+ );
25
31
  const loaded = loadRunManifestById(ctx.cwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
26
32
  if (!loaded) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "worktrees", status: "error" }, true);
27
33
  const withWorktrees = loaded.tasks.filter((task) => task.worktree);
@@ -59,7 +65,16 @@ export function handleImports(_params: TeamToolParamsValue, ctx: TeamContext): P
59
65
  export function handleImport(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
60
66
  const cfg = configRecord(params.config);
61
67
  const bundlePath = typeof cfg.path === "string" ? cfg.path : typeof cfg.bundlePath === "string" ? cfg.bundlePath : undefined;
62
- if (!bundlePath) return result("Import requires config.path pointing at run-export.json.", { action: "import", status: "error" }, true);
68
+ if (!bundlePath)
69
+ return result(
70
+ paramRequired(
71
+ "import",
72
+ "config.path pointing at run-export.json",
73
+ "{ action: 'import', config: { path: '/path/to/run-export.json' } }",
74
+ ),
75
+ { action: "import", status: "error" },
76
+ true,
77
+ );
63
78
  const scope = cfg.scope === "user" ? "user" : "project";
64
79
  try {
65
80
  const imported = importRunBundle(ctx.cwd, bundlePath, scope);
@@ -74,7 +89,12 @@ export function handleImport(params: TeamToolParamsValue, ctx: TeamContext): PiT
74
89
  }
75
90
 
76
91
  export async function handleExport(params: TeamToolParamsValue, ctx: TeamContext): Promise<PiTeamsToolResult> {
77
- if (!params.runId) return result("Export requires runId.", { action: "export", status: "error" }, true);
92
+ if (!params.runId)
93
+ return result(
94
+ paramRequired("export", "runId", "{ action: 'export', runId: 'team_...' }"),
95
+ { action: "export", status: "error" },
96
+ true,
97
+ );
78
98
  const loaded = loadRunManifestById(ctx.cwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
79
99
  if (!loaded) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "export", status: "error" }, true);
80
100
 
@@ -126,7 +146,12 @@ export async function handleExport(params: TeamToolParamsValue, ctx: TeamContext
126
146
  export async function handlePrune(params: TeamToolParamsValue, ctx: TeamContext): Promise<PiTeamsToolResult> {
127
147
  const intentError = enforceDestructiveIntent("prune", params, ctx.config);
128
148
  if (intentError) return intentError;
129
- if (!params.confirm) return result("prune requires confirm: true.", { action: "prune", status: "error" }, true);
149
+ if (!params.confirm)
150
+ return result(
151
+ paramRequired("prune", "confirm: true", "{ action: 'prune', confirm: true }"),
152
+ { action: "prune", status: "error" },
153
+ true,
154
+ );
130
155
  const keep = params.keep ?? 20;
131
156
  if (keep < 0 || !Number.isInteger(keep)) return result("keep must be an integer >= 0.", { action: "prune", status: "error" }, true);
132
157
  const intent = intentFromConfig(params.config);
@@ -164,8 +189,18 @@ export async function handlePrune(params: TeamToolParamsValue, ctx: TeamContext)
164
189
  export async function handleForget(params: TeamToolParamsValue, ctx: TeamContext): Promise<PiTeamsToolResult> {
165
190
  const intentError = enforceDestructiveIntent("forget", params, ctx.config);
166
191
  if (intentError) return intentError;
167
- if (!params.runId) return result("Forget requires runId.", { action: "forget", status: "error" }, true);
168
- if (!params.confirm) return result("forget requires confirm: true.", { action: "forget", status: "error" }, true);
192
+ if (!params.runId)
193
+ return result(
194
+ paramRequired("forget", "runId", "{ action: 'forget', runId: 'team_...', confirm: true }"),
195
+ { action: "forget", status: "error" },
196
+ true,
197
+ );
198
+ if (!params.confirm)
199
+ return result(
200
+ paramRequired("forget", "confirm: true", "{ action: 'forget', runId: 'team_...', confirm: true }"),
201
+ { action: "forget", status: "error" },
202
+ true,
203
+ );
169
204
  const loaded = loadRunManifestById(ctx.cwd, params.runId); // NOTE: no withRunLock - best-effort only; concurrent writes may cause inconsistency
170
205
  if (!loaded) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "forget", status: "error" }, true);
171
206
 
@@ -269,6 +304,14 @@ export async function handleCleanup(params: TeamToolParamsValue, ctx: TeamContex
269
304
  // can stay focused on their own logic.
270
305
  const intentError = enforceDestructiveIntent("cleanup", params, ctx.config);
271
306
  if (intentError) return intentError;
307
+ // SEC-5: self-enforce confirm:true (defense-in-depth), matching handlePrune/handleForget.
308
+ // dryRun:true is a non-destructive preview and is always allowed.
309
+ if (params.confirm !== true && params.dryRun !== true)
310
+ return result(
311
+ paramRequired("cleanup", "confirm: true", "{ action: 'cleanup', confirm: true }"),
312
+ { action: "cleanup", status: "error" },
313
+ true,
314
+ );
272
315
  // Three cleanup modes:
273
316
  // 1. WITH runId → per-run worktree cleanup (existing behavior).
274
317
  // 2. WITHOUT runId, scope=project (default) → PROJECT-LEVEL uninstall:
@@ -8,11 +8,11 @@
8
8
  */
9
9
  import { discoverAgents } from "../../agents/discover-agents.ts";
10
10
  import { loadConfig } from "../../config/config.ts";
11
- import { resolveCrewRuntime } from "../../runtime/runtime-resolver.ts";
11
+ import { spawnBackgroundTeamRun } from "../../runtime/async-runner.ts";
12
+ import { resolveCrewRuntime } from "../../runtime/model/runtime-resolver.ts";
12
13
  import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
13
- import { appendEvent } from "../../state/event-log.ts";
14
- import { createRunManifest } from "../../state/state-store.ts";
15
- import { spawnBackgroundTeamRun } from "../../subagents/async-entry.ts";
14
+ import { appendEvent } from "../../state/event-log/event-log.ts";
15
+ import { createRunManifest } from "../../state/stores/state-store.ts";
16
16
  import { discoverTeams } from "../../teams/discover-teams.ts";
17
17
  import type { TeamConfig } from "../../teams/team-config.ts";
18
18
  import { discoverWorkflows } from "../../workflows/discover-workflows.ts";
@@ -20,6 +20,7 @@ import type { WorkflowConfig } from "../../workflows/workflow-config.ts";
20
20
  import { resolveCwdOverride } from "../registration/team-tool.ts";
21
21
  import type { PiTeamsToolResult } from "../tool-result.ts";
22
22
  import { result, type TeamContext } from "./context.ts";
23
+ import { paramRequired } from "./param-error.ts";
23
24
 
24
25
  const MAX_CONCURRENCY = 8;
25
26
  const DEFAULT_CONCURRENCY = 4;
@@ -29,7 +30,15 @@ const DEFAULT_AGENT = "explorer";
29
30
  export async function handleParallel(params: TeamToolParamsValue, ctx: TeamContext): Promise<PiTeamsToolResult> {
30
31
  const tasksParam = params.config?.tasks;
31
32
  if (!Array.isArray(tasksParam) || tasksParam.length === 0) {
32
- return result("parallel action requires config.tasks: [{goal, agent?}]", { action: "parallel", status: "error" }, true);
33
+ return result(
34
+ paramRequired(
35
+ "parallel",
36
+ "config.tasks: [{goal, agent?}]",
37
+ "{ action: 'parallel', config: { tasks: [{ goal: '...', agent: 'explorer' }] } }",
38
+ ),
39
+ { action: "parallel", status: "error" },
40
+ true,
41
+ );
33
42
  }
34
43
 
35
44
  const concurrency = Math.min(Math.max(1, Math.floor((params.config?.concurrency as number) ?? DEFAULT_CONCURRENCY)), MAX_CONCURRENCY);
@@ -112,3 +112,27 @@ export function formatTeamToolParamError(schema: TSchema, params: unknown): stri
112
112
  "as an array/object instead of a single string; params nested instead of flat.",
113
113
  ].join("\n");
114
114
  }
115
+
116
+ /**
117
+ * Build a runtime handler error string for a MISSING REQUIRED FIELD, including
118
+ * a concrete example shape so the calling agent (LLM) can self-correct instead
119
+ * of looping on the same malformed call.
120
+ *
121
+ * The schema-validation path (`formatTeamToolParamError` above) already
122
+ * provides rich examples, but runtime handler errors used to return a plain
123
+ * `"X requires Y."` with NO example — giving LLMs worse guidance for the MORE
124
+ * COMMON failure (valid action, missing field). This helper closes that
125
+ * two-tier error-quality gap (AUDIT-2026-07-30 EXT-2).
126
+ *
127
+ * @param action The team-tool action (e.g. "status", "cancel").
128
+ * @param field The required field/fields (e.g. "runId", "goal or task").
129
+ * @param example Optional concrete example shape,
130
+ * e.g. `{ action: 'status', runId: 'team_...' }`.
131
+ * @returns An error string like
132
+ * `"Status requires runId. Example: { action: 'status', runId: 'team_...' }"`.
133
+ */
134
+ export function paramRequired(action: string, field: string, example?: string): string {
135
+ const subject = action.charAt(0).toUpperCase() + action.slice(1);
136
+ const base = `${subject} requires ${field}.`;
137
+ return example ? `${base} Example: ${example}` : base;
138
+ }
@@ -1,13 +1,14 @@
1
1
  import { readCrewAgents, recordFromTask, saveCrewAgents } from "../../runtime/crew-agent-records.ts";
2
2
  import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
3
- import { appendEvent } from "../../state/event-log.ts";
4
- import { withRunLockSync } from "../../state/locks.ts";
5
- import { appendMailboxMessage, updateMailboxMessageReply } from "../../state/mailbox.ts";
6
- import { loadRunManifestById, saveRunTasks, updateRunStatus } from "../../state/state-store.ts";
3
+ import { withRunLockSync } from "../../state/coordination/locks.ts";
4
+ import { appendMailboxMessage, updateMailboxMessageReply } from "../../state/coordination/mailbox.ts";
5
+ import { appendEvent } from "../../state/event-log/event-log.ts";
6
+ import { loadRunManifestById, saveRunTasks, updateRunStatus } from "../../state/stores/state-store.ts";
7
7
  import { logInternalError } from "../../utils/internal-error.ts";
8
8
  import { locateRunCwd } from "../team-tool.ts";
9
9
  import type { PiTeamsToolResult } from "../tool-result.ts";
10
10
  import { result, type TeamContext } from "./context.ts";
11
+ import { paramRequired } from "./param-error.ts";
11
12
  import { RUN_NOT_FOUND_HINT } from "./run-not-found.ts";
12
13
 
13
14
  /**
@@ -16,9 +17,22 @@ import { RUN_NOT_FOUND_HINT } from "./run-not-found.ts";
16
17
  * mailbox and the task is re-queued for durable scheduler resume.
17
18
  */
18
19
  export function handleRespond(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
19
- if (!params.runId) return result("Respond requires runId.", { action: "respond", status: "error" }, true);
20
+ if (!params.runId)
21
+ return result(
22
+ paramRequired("respond", "runId", "{ action: 'respond', runId: 'team_...', message: '...' }"),
23
+ { action: "respond", status: "error" },
24
+ true,
25
+ );
20
26
  if (!params.message && !params.taskId)
21
- return result("Respond requires taskId and/or message.", { action: "respond", status: "error" }, true);
27
+ return result(
28
+ paramRequired(
29
+ "respond",
30
+ "taskId and/or message",
31
+ "{ action: 'respond', runId: 'team_...', taskId: '01_agent', message: '...' }",
32
+ ),
33
+ { action: "respond", status: "error" },
34
+ true,
35
+ );
22
36
 
23
37
  const runCwd = locateRunCwd(params.runId, ctx.cwd);
24
38
  if (!runCwd) return result(`Run '${params.runId}' not found.${RUN_NOT_FOUND_HINT}`, { action: "respond", status: "error" }, true);
@@ -4,10 +4,10 @@ import { sanitizeTaskText } from "../../runtime/task-packet.ts";
4
4
  // Heavy runtime — lazy-loaded to avoid 1.4s import cost at extension registration.
5
5
  import type { executeTeamRun as ExecuteTeamRunFn } from "../../runtime/team-runner.ts";
6
6
  import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
7
- import { registerActiveRun, unregisterActiveRun } from "../../state/active-run-registry.ts";
8
- import { writeArtifact } from "../../state/artifact-store.ts";
9
7
  import { atomicWriteJson } from "../../state/atomic-write.ts";
10
- import { createRunManifest, loadRunManifestById, updateRunStatus } from "../../state/state-store.ts";
8
+ import { registerActiveRun, unregisterActiveRun } from "../../state/stores/active-run-registry.ts";
9
+ import { writeArtifact } from "../../state/stores/artifact-store.ts";
10
+ import { createRunManifest, loadRunManifestById, updateRunStatus } from "../../state/stores/state-store.ts";
11
11
  import { allTeams, discoverTeams } from "../../teams/discover-teams.ts";
12
12
  import { allWorkflows, discoverWorkflows } from "../../workflows/discover-workflows.ts";
13
13
  import { assertCleanLeaderAsync, findGitRootAsync } from "../../worktree/worktree-manager.ts";
@@ -18,6 +18,7 @@ const _typeCheck: typeof ExecuteTeamRunFn = null as never as typeof ExecuteTeamR
18
18
  import { errorMessage } from "../../utils/guards.ts";
19
19
  import { logInternalError } from "../../utils/internal-error.ts";
20
20
  import { resolveRealContainedPath } from "../../utils/safe-paths.ts";
21
+ import { paramRequired } from "./param-error.ts";
21
22
 
22
23
  let _cachedExecuteTeamRun: typeof ExecuteTeamRunFn | undefined;
23
24
  async function executeTeamRun(...args: Parameters<typeof ExecuteTeamRunFn>): Promise<Awaited<ReturnType<typeof ExecuteTeamRunFn>>> {
@@ -29,11 +30,11 @@ async function executeTeamRun(...args: Parameters<typeof ExecuteTeamRunFn>): Pro
29
30
  return _cachedExecuteTeamRun(...args);
30
31
  }
31
32
 
32
- import { resolveCrewRuntime, runtimeResolutionState } from "../../runtime/runtime-resolver.ts";
33
- import { appendEventAsync, readEvents } from "../../state/event-log.ts";
34
- import type { RunMetrics } from "../../state/run-metrics.ts";
33
+ import { spawnBackgroundTeamRun } from "../../runtime/async-runner.ts";
34
+ import { resolveCrewRuntime, runtimeResolutionState } from "../../runtime/model/runtime-resolver.ts";
35
+ import { appendEventAsync, readEvents } from "../../state/event-log/event-log.ts";
36
+ import type { RunMetrics } from "../../state/stores/run-metrics.ts";
35
37
  import type { RuntimeResolutionState, TeamRunManifest, TeamTaskState } from "../../state/types.ts";
36
- import { spawnBackgroundTeamRun } from "../../subagents/async-entry.ts";
37
38
 
38
39
  /**
39
40
  * Module-scoped latch for the crew-init dynamic import.
@@ -72,10 +73,11 @@ function loadCrewInit(): Promise<typeof import("../../state/crew-init.ts")> {
72
73
 
73
74
  import * as fs from "node:fs";
74
75
  import * as path from "node:path";
76
+ import { t } from "../../i18n.ts";
75
77
  import { hasAsyncStartMarker } from "../../runtime/async-marker.ts";
76
78
  import { checkProcessLiveness, isActiveRunStatus } from "../../runtime/process-status.ts";
77
79
  import { waitForRun } from "../../runtime/run-tracker.ts";
78
- import { collectRunMetrics } from "../../state/run-metrics.ts";
80
+ import { collectRunMetrics } from "../../state/stores/run-metrics.ts";
79
81
  import type { PiTeamsToolResult } from "../tool-result.ts";
80
82
  import { effectiveRunConfig } from "./config-patch.ts";
81
83
  import { buildParentContext, result, type TeamContext } from "./context.ts";
@@ -256,7 +258,7 @@ function formatRunResult(manifest: TeamRunManifest, options: FormatRunResultOpti
256
258
  ? "Experimental live-session worker execution was enabled."
257
259
  : "Safe scaffold mode: child Pi workers were not launched because runtime.mode=scaffold or executeWorkers=false was configured.";
258
260
  const text = [
259
- `Created pi-crew run ${manifest.runId}.`,
261
+ t("team.run.created", { runId: manifest.runId }),
260
262
  `Team: ${team}`,
261
263
  `Workflow: ${workflow}`,
262
264
  `Status: ${manifest.status}`,
@@ -285,7 +287,10 @@ function formatRunResult(manifest: TeamRunManifest, options: FormatRunResultOpti
285
287
  }
286
288
 
287
289
  // mode === "waited" — detailed per-task summary.
288
- const lines: string[] = [`pi-crew run ${manifest.status}: ${manifest.runId} (${team})`, `Goal: ${goal.slice(0, 100)}`];
290
+ const lines: string[] = [
291
+ t("team.run.completed", { status: manifest.status, runId: manifest.runId, team }),
292
+ `Goal: ${goal.slice(0, 100)}`,
293
+ ];
289
294
  if (metrics) {
290
295
  lines.push("");
291
296
  lines.push(
@@ -346,10 +351,10 @@ function formatRunResult(manifest: TeamRunManifest, options: FormatRunResultOpti
346
351
 
347
352
  if (failedCount === 0) {
348
353
  lines.push("");
349
- lines.push("All tasks completed successfully.");
354
+ lines.push(t("team.run.allCompleted"));
350
355
  } else {
351
356
  lines.push("");
352
- lines.push(`${failedCount} task(s) failed: ${failedIds.join(", ")}. Consider retrying.`);
357
+ lines.push(t("team.run.tasksFailed", { count: failedCount, ids: failedIds.join(", ") }));
353
358
  }
354
359
  } else {
355
360
  lines.push(
@@ -385,7 +390,12 @@ export async function handleRun(params: TeamToolParamsValue, ctx: TeamContext):
385
390
  return handleChainRun(params, ctx, handleRun);
386
391
  }
387
392
  const goal = params.goal ?? params.task;
388
- if (!goal) return result("Run requires goal or task.", { action: "run", status: "error" }, true);
393
+ if (!goal)
394
+ return result(
395
+ paramRequired("run", "goal or task", "{ action: 'run', goal: '<what to achieve>' }"),
396
+ { action: "run", status: "error" },
397
+ true,
398
+ );
389
399
  const intentPrefix = goal.length > 60 ? `${goal.slice(0, 57)}...` : goal;
390
400
 
391
401
  // P0: Ensure .crew directory structure exists before creating any manifests.
@@ -494,7 +504,7 @@ export async function handleRun(params: TeamToolParamsValue, ctx: TeamContext):
494
504
  if (analysisParam.error) return result(analysisParam.error, { action: "run", status: "error" }, true);
495
505
 
496
506
  // LAZY: dodge the jiti ESM/CJS interop TDZ race on the static `import { expandParallelResearchWorkflow }` above (issue #28, RFC 17). At call time the module body has fully evaluated, so the dynamic import returns a live binding. Multi-line form breaks scripts/check-lazy-imports.mjs (which does `lines[lineNum - 2]`), so keep destructuring + await import on one line.
497
- const { expandParallelResearchWorkflow: expandParallelResearch } = await import("../../runtime/parallel-research.ts");
507
+ const { expandParallelResearchWorkflow: expandParallelResearch } = await import("../../runtime/scheduling/parallel-research.ts");
498
508
  const workflow = directAgent ? baseWorkflow : expandParallelResearch(baseWorkflow, resolvedCtx.cwd);
499
509
  const isDynamicWorkflow =
500
510
  !directAgent && (workflow as import("../../workflows/workflow-config.ts").WorkflowConfig).runtime === "dynamic";
@@ -623,8 +633,8 @@ export async function handleRun(params: TeamToolParamsValue, ctx: TeamContext):
623
633
  console.warn(
624
634
  `[pi-crew SECURITY] Dynamic workflow '${workflow.name}' executes as trusted Node.js code with full process/require/import access; run only reviewed .dwf.ts files.`,
625
635
  );
626
- // LAZY: defer dynamic import of ../../runtime/dynamic-workflow-runner.ts to its call site.
627
- const { runDynamicWorkflow } = await import("../../runtime/dynamic-workflow-runner.ts");
636
+ // LAZY: defer dynamic import of ../../runtime/goal-workflow/dynamic-workflow-runner.ts to its call site.
637
+ const { runDynamicWorkflow } = await import("../../runtime/goal-workflow/dynamic-workflow-runner.ts");
628
638
  // Re-synthesize a dynamic-team (§0c C9) for role resolution.
629
639
  const dwfTeam: import("../../teams/team-config.ts").TeamConfig = {
630
640
  name: `dwf-${manifest.runId.slice(-12)}`,
@@ -643,7 +653,7 @@ export async function handleRun(params: TeamToolParamsValue, ctx: TeamContext):
643
653
  // CORE-8: unified deadline — resolve params > config > 1h default.
644
654
  const dwfDeadline = resolveRunDeadline(ctx, params);
645
655
  try {
646
- let dwfResult: import("../../runtime/dynamic-workflow-runner.ts").RunDynamicWorkflowResult | undefined;
656
+ let dwfResult: import("../../runtime/goal-workflow/dynamic-workflow-runner.ts").RunDynamicWorkflowResult | undefined;
647
657
  try {
648
658
  dwfResult = await runDynamicWorkflow({
649
659
  manifest: dwfManifest,