pi-crew 0.9.55 → 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 (309) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +58 -0
  3. package/README.md +53 -5
  4. package/dist/index.mjs +5666 -4370
  5. package/docs/README.md +54 -0
  6. package/package.json +12 -13
  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 +109 -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 +138 -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 +17 -6
  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 +3 -2
  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} +23 -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} +47 -78
  87. package/src/runtime/compaction/compact-stages/bounded-tail.ts +84 -0
  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/crew-agent-records.ts +48 -2
  92. package/src/runtime/custom-tools/irc-tool.ts +2 -2
  93. package/src/runtime/delivery-coordinator.ts +0 -3
  94. package/src/runtime/diagnostic-export.ts +5 -4
  95. package/src/runtime/foreground-control.ts +1 -1
  96. package/src/runtime/foreground-watchdog.ts +1 -1
  97. package/src/runtime/{adaptive-plan.ts → goal-workflow/adaptive-plan.ts} +8 -8
  98. package/src/runtime/{dynamic-workflow-context.ts → goal-workflow/dynamic-workflow-context.ts} +16 -16
  99. package/src/runtime/{dynamic-workflow-runner.ts → goal-workflow/dynamic-workflow-runner.ts} +10 -10
  100. package/src/runtime/{goal-achievement.ts → goal-workflow/goal-achievement.ts} +3 -3
  101. package/src/runtime/{goal-evaluator.ts → goal-workflow/goal-evaluator.ts} +8 -8
  102. package/src/runtime/{goal-loop-runner.ts → goal-workflow/goal-loop-runner.ts} +27 -25
  103. package/src/runtime/{goal-state-store.ts → goal-workflow/goal-state-store.ts} +8 -8
  104. package/src/runtime/{plan-templates.ts → goal-workflow/plan-templates.ts} +1 -1
  105. package/src/runtime/group-join.ts +3 -3
  106. package/src/runtime/handoff-manager.ts +0 -2
  107. package/src/runtime/{heartbeat-watcher.ts → heartbeat/heartbeat-watcher.ts} +7 -7
  108. package/src/runtime/iteration-hooks.ts +1 -1
  109. package/src/runtime/{live-agent-control.ts → live-session/live-agent-control.ts} +2 -2
  110. package/src/runtime/{live-agent-manager.ts → live-session/live-agent-manager.ts} +4 -4
  111. package/src/runtime/{live-session-runtime.ts → live-session/live-session-runtime.ts} +39 -41
  112. package/src/runtime/manifest-cache.ts +6 -2
  113. package/src/runtime/{model-fallback.ts → model/model-fallback.ts} +1 -1
  114. package/src/runtime/{pi-args.ts → model/pi-args.ts} +20 -5
  115. package/src/runtime/model/provider-extensions.ts +116 -0
  116. package/src/runtime/{runtime-policy.ts → model/runtime-policy.ts} +2 -2
  117. package/src/runtime/{runtime-resolver.ts → model/runtime-resolver.ts} +3 -3
  118. package/src/runtime/{runtime-warmup.ts → model/runtime-warmup.ts} +8 -8
  119. package/src/runtime/orphan-worker-registry.ts +1 -1
  120. package/src/runtime/{progress-tracker.ts → output/progress-tracker.ts} +1 -1
  121. package/src/runtime/{result-extractor.ts → output/result-extractor.ts} +4 -4
  122. package/src/runtime/{sidechain-output.ts → output/sidechain-output.ts} +2 -2
  123. package/src/runtime/{stream-preview.ts → output/stream-preview.ts} +1 -1
  124. package/src/runtime/{streaming-output.ts → output/streaming-output.ts} +2 -2
  125. package/src/runtime/{tool-progress.ts → output/tool-progress.ts} +1 -1
  126. package/src/runtime/parent-guard.ts +30 -10
  127. package/src/runtime/pipeline-runner.ts +2 -2
  128. package/src/runtime/policy-engine.ts +2 -2
  129. package/src/runtime/{cancellation.ts → process/cancellation.ts} +1 -1
  130. package/src/runtime/{post-exit-stdio-guard.ts → process/post-exit-stdio-guard.ts} +1 -1
  131. package/src/runtime/{process-lifecycle.ts → process/process-lifecycle.ts} +3 -3
  132. package/src/runtime/{checkpoint.ts → recovery/checkpoint.ts} +4 -4
  133. package/src/runtime/{crash-recovery.ts → recovery/crash-recovery.ts} +93 -21
  134. package/src/runtime/{overflow-recovery.ts → recovery/overflow-recovery.ts} +1 -1
  135. package/src/runtime/{recovery-recipes.ts → recovery/recovery-recipes.ts} +1 -1
  136. package/src/runtime/{retry-executor.ts → recovery/retry-executor.ts} +2 -2
  137. package/src/runtime/{retry-runner.ts → recovery/retry-runner.ts} +2 -8
  138. package/src/runtime/run-tracker.ts +1 -1
  139. package/src/runtime/run-worker.ts +3 -3
  140. package/src/runtime/{coalesce-tasks.ts → scheduling/coalesce-tasks.ts} +3 -3
  141. package/src/runtime/{concurrency.ts → scheduling/concurrency.ts} +9 -3
  142. package/src/runtime/{parallel-research.ts → scheduling/parallel-research.ts} +4 -2
  143. package/src/runtime/{run-coalesced-task-group.ts → scheduling/run-coalesced-task-group.ts} +95 -36
  144. package/src/runtime/{semaphore.ts → scheduling/semaphore.ts} +4 -1
  145. package/src/runtime/{task-graph-scheduler.ts → scheduling/task-graph-scheduler.ts} +1 -1
  146. package/src/runtime/session-resources.ts +1 -1
  147. package/src/runtime/settings-store.ts +1 -1
  148. package/src/runtime/single-agent-compose.ts +1 -0
  149. package/src/runtime/stale-reconciler.ts +1 -1
  150. package/src/runtime/subagent-manager.ts +1 -1
  151. package/src/runtime/supervisor-contact.ts +28 -13
  152. package/src/runtime/task-output-context.ts +7 -5
  153. package/src/runtime/task-runner/child-executor.ts +67 -31
  154. package/src/runtime/task-runner/live-executor.ts +8 -8
  155. package/src/runtime/task-runner/post-execution.ts +12 -12
  156. package/src/runtime/task-runner/pre-execution.ts +6 -6
  157. package/src/runtime/task-runner/progress.ts +1 -1
  158. package/src/runtime/task-runner/run-projection.ts +1 -1
  159. package/src/runtime/task-runner/scaffold-executor.ts +1 -1
  160. package/src/runtime/task-runner/state-helpers.ts +2 -2
  161. package/src/runtime/task-runner.ts +4 -4
  162. package/src/runtime/team-runner.ts +441 -175
  163. package/src/runtime/{completion-guard.ts → verification/completion-guard.ts} +1 -1
  164. package/src/runtime/{green-contract.ts → verification/green-contract.ts} +1 -1
  165. package/src/runtime/{post-checks.ts → verification/post-checks.ts} +4 -4
  166. package/src/runtime/{verification-gates.ts → verification/verification-gates.ts} +5 -5
  167. package/src/runtime/{verification-integrity.ts → verification/verification-integrity.ts} +1 -1
  168. package/src/schema/config-schema.ts +1 -0
  169. package/src/schema/team-tool-schema.ts +149 -185
  170. package/src/state/README.md +44 -0
  171. package/src/state/atomic-write.ts +24 -3
  172. package/src/state/{locks.ts → coordination/locks.ts} +118 -38
  173. package/src/state/{mailbox.ts → coordination/mailbox.ts} +14 -8
  174. package/src/state/{schedule.ts → coordination/schedule.ts} +3 -3
  175. package/src/state/{task-claims.ts → coordination/task-claims.ts} +1 -1
  176. package/src/state/decision-ledger.ts +1 -1
  177. package/src/state/{event-log-rotation.ts → event-log/event-log-rotation.ts} +189 -31
  178. package/src/state/{event-log.ts → event-log/event-log.ts} +77 -39
  179. package/src/state/{jsonl-writer.ts → event-log/jsonl-writer.ts} +14 -6
  180. package/src/state/hook-instinct-bridge.ts +2 -2
  181. package/src/state/{active-run-registry.ts → stores/active-run-registry.ts} +7 -7
  182. package/src/state/{artifact-store.ts → stores/artifact-store.ts} +62 -4
  183. package/src/state/{blob-store.ts → stores/blob-store.ts} +3 -3
  184. package/src/state/{health-store.ts → stores/health-store.ts} +3 -3
  185. package/src/state/{instinct-store.ts → stores/instinct-store.ts} +3 -3
  186. package/src/state/{observation-store.ts → stores/observation-store.ts} +2 -2
  187. package/src/state/{run-cache.ts → stores/run-cache.ts} +4 -4
  188. package/src/state/{run-graph.ts → stores/run-graph.ts} +4 -4
  189. package/src/state/{run-metrics.ts → stores/run-metrics.ts} +3 -3
  190. package/src/state/{state-store.ts → stores/state-store.ts} +254 -21
  191. package/src/state/types.ts +27 -3
  192. package/src/ui/component.ts +55 -0
  193. package/src/ui/crew-select-list.ts +3 -1
  194. package/src/ui/dashboard-panes/agents-pane.ts +1 -1
  195. package/src/ui/dwf-phase-display.ts +1 -1
  196. package/src/ui/heartbeat-aggregator.ts +1 -1
  197. package/src/ui/keybinding-map.ts +179 -6
  198. package/src/ui/layout-primitives.ts +9 -5
  199. package/src/ui/live-conversation-overlay.ts +1 -1
  200. package/src/ui/live-run-sidebar.ts +1 -1
  201. package/src/ui/overlay-stack.ts +148 -0
  202. package/src/ui/overlays/agent-picker-overlay.ts +1 -1
  203. package/src/ui/overlays/mailbox-compose-overlay.ts +1 -1
  204. package/src/ui/overlays/mailbox-detail-overlay.ts +2 -2
  205. package/src/ui/powerbar-publisher.ts +1 -1
  206. package/src/ui/render-scheduler.ts +1 -1
  207. package/src/ui/run-action-dispatcher.ts +3 -3
  208. package/src/ui/run-dashboard.ts +5 -33
  209. package/src/ui/run-event-bus.ts +3 -3
  210. package/src/ui/run-snapshot-cache.ts +37 -18
  211. package/src/ui/settings-overlay.ts +13 -21
  212. package/src/ui/snapshot-types.ts +1 -1
  213. package/src/ui/status-colors.ts +0 -2
  214. package/src/ui/terminal-status.ts +1 -1
  215. package/src/ui/theme-adapter.ts +33 -13
  216. package/src/ui/tool-renderers/index.ts +8 -0
  217. package/src/ui/transcript-viewer.ts +37 -13
  218. package/src/ui/widget/index.ts +32 -9
  219. package/src/ui/widget/widget-formatters.ts +62 -4
  220. package/src/ui/widget/widget-model.ts +2 -2
  221. package/src/ui/widget/widget-renderer.ts +1 -1
  222. package/src/utils/conflict-detect.ts +58 -5
  223. package/src/utils/ndjson.ts +2 -2
  224. package/src/utils/redaction.ts +39 -0
  225. package/src/utils/socket-path.ts +1 -1
  226. package/src/workflows/workflow-config.ts +1 -1
  227. package/src/worktree/cleanup.ts +1 -1
  228. package/src/worktree/worktree-manager.ts +111 -47
  229. package/workflows/chain.workflow.md +2 -2
  230. package/dist/build-meta.json +0 -16807
  231. package/index.bundle.ts +0 -25
  232. package/scripts/bench-check.mjs +0 -96
  233. package/scripts/bench-cold-start.mjs +0 -216
  234. package/scripts/build-bundle.mjs +0 -92
  235. package/scripts/check-all-skills.ts +0 -294
  236. package/scripts/check-bundle-size.mjs +0 -38
  237. package/scripts/check-bundle-staleness.mjs +0 -97
  238. package/scripts/check-conflict-markers.mjs +0 -91
  239. package/scripts/check-lazy-imports.mjs +0 -28
  240. package/scripts/dev-runner.mjs +0 -106
  241. package/scripts/profile-startup.mjs +0 -125
  242. package/scripts/release-smoke.mjs +0 -74
  243. package/scripts/run-bench.mjs +0 -47
  244. package/scripts/run-real-chain.ts +0 -41
  245. package/scripts/test-issue-29-crash.ts +0 -111
  246. package/scripts/test-issue-29-e2e.ts +0 -183
  247. package/scripts/test-issue-29-real-runtime.ts +0 -330
  248. package/scripts/test-issue-29-real-tasks.ts +0 -387
  249. package/scripts/test-issue-29-team-tool.ts +0 -105
  250. package/scripts/test-runner.mjs +0 -84
  251. package/scripts/verify-flicker-fix.ts +0 -109
  252. package/scripts/verify-skill.ts +0 -550
  253. package/scripts/watch-bundle.mjs +0 -259
  254. package/scripts/watchdog-harness.ts +0 -119
  255. package/src/adapters/claude-adapter.ts +0 -23
  256. package/src/adapters/codex-adapter.ts +0 -21
  257. package/src/adapters/cursor-adapter.ts +0 -17
  258. package/src/adapters/export-util.ts +0 -143
  259. package/src/adapters/index.ts +0 -15
  260. package/src/adapters/registry.ts +0 -18
  261. package/src/adapters/types.ts +0 -23
  262. package/src/runtime/code-summary.ts +0 -292
  263. package/src/runtime/cross-extension-rpc.ts +0 -143
  264. package/src/runtime/hidden-handoff.ts +0 -407
  265. package/src/runtime/prose-compressor.ts +0 -162
  266. package/src/subagents/async-entry.ts +0 -1
  267. package/src/subagents/index.ts +0 -3
  268. package/src/subagents/live/control.ts +0 -1
  269. package/src/subagents/live/manager.ts +0 -1
  270. package/src/subagents/live/realtime.ts +0 -1
  271. package/src/subagents/live/session-runtime.ts +0 -1
  272. package/src/subagents/manager.ts +0 -1
  273. package/src/subagents/spawn.ts +0 -1
  274. package/test-integration-check.ts +0 -118
  275. /package/src/runtime/{broker-issuer.ts → broker/broker-issuer.ts} +0 -0
  276. /package/src/runtime/{crew-broker-tokens.ts → broker/crew-broker-tokens.ts} +0 -0
  277. /package/src/runtime/{child-pi-pool.ts → child-pi/child-pi-pool.ts} +0 -0
  278. /package/src/runtime/{compact-pipeline.ts → compaction/compact-pipeline.ts} +0 -0
  279. /package/src/runtime/{compact-stages → compaction/compact-stages}/ansi-strip-stage.ts +0 -0
  280. /package/src/runtime/{compact-stages → compaction/compact-stages}/blank-collapse-stage.ts +0 -0
  281. /package/src/runtime/{compact-stages → compaction/compact-stages}/deduplicate-stage.ts +0 -0
  282. /package/src/runtime/{compact-stages → compaction/compact-stages}/head-snap-stage.ts +0 -0
  283. /package/src/runtime/{compact-stages → compaction/compact-stages}/tail-capture-stage.ts +0 -0
  284. /package/src/runtime/{compact-stages → compaction/compact-stages}/truncation-stage.ts +0 -0
  285. /package/src/runtime/{important-line-classifier.ts → compaction/important-line-classifier.ts} +0 -0
  286. /package/src/runtime/{heartbeat-gradient.ts → heartbeat/heartbeat-gradient.ts} +0 -0
  287. /package/src/runtime/{worker-heartbeat.ts → heartbeat/worker-heartbeat.ts} +0 -0
  288. /package/src/runtime/{worker-startup.ts → heartbeat/worker-startup.ts} +0 -0
  289. /package/src/runtime/{intercom-bridge.ts → live-session/intercom-bridge.ts} +0 -0
  290. /package/src/runtime/{live-control-realtime.ts → live-session/live-control-realtime.ts} +0 -0
  291. /package/src/runtime/{live-extension-bridge.ts → live-session/live-extension-bridge.ts} +0 -0
  292. /package/src/runtime/{live-irc.ts → live-session/live-irc.ts} +0 -0
  293. /package/src/runtime/{live-session-health.ts → live-session/live-session-health.ts} +0 -0
  294. /package/src/runtime/{model-resolver.ts → model/model-resolver.ts} +0 -0
  295. /package/src/runtime/{model-scope.ts → model/model-scope.ts} +0 -0
  296. /package/src/runtime/{output-validator.ts → output/output-validator.ts} +0 -0
  297. /package/src/runtime/{pi-json-output.ts → output/pi-json-output.ts} +0 -0
  298. /package/src/runtime/{progress-event-coalescer.ts → output/progress-event-coalescer.ts} +0 -0
  299. /package/src/runtime/{cancellation-token.ts → process/cancellation-token.ts} +0 -0
  300. /package/src/runtime/{zombie-scanner.ts → process/zombie-scanner.ts} +0 -0
  301. /package/src/runtime/{crash-classification.ts → recovery/crash-classification.ts} +0 -0
  302. /package/src/runtime/{batch-barrier.ts → scheduling/batch-barrier.ts} +0 -0
  303. /package/src/runtime/{global-worker-cap.ts → scheduling/global-worker-cap.ts} +0 -0
  304. /package/src/runtime/{parallel-utils.ts → scheduling/parallel-utils.ts} +0 -0
  305. /package/src/runtime/{scheduler.ts → scheduling/scheduler.ts} +0 -0
  306. /package/src/runtime/{task-graph.ts → scheduling/task-graph.ts} +0 -0
  307. /package/src/runtime/{verification-worktree.ts → verification/verification-worktree.ts} +0 -0
  308. /package/src/state/{event-reconstructor.ts → event-log/event-reconstructor.ts} +0 -0
  309. /package/src/state/{worker-atomic-writer.ts → event-log/worker-atomic-writer.ts} +0 -0
package/docs/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # docs/ — documentation index
2
+
3
+ pi-crew's documentation. After the v0.9.x reorg the **living/active** docs
4
+ stay at the root of this directory; historical/retired docs live in
5
+ [`archive/`](./archive/). Cluster maps for the code live in
6
+ [`src/runtime/README.md`](../src/runtime/README.md) and
7
+ [`src/state/README.md`](../src/state/README.md).
8
+
9
+ ## Living docs (root)
10
+
11
+ | Doc | Contents |
12
+ |-----|----------|
13
+ | [`usage.md`](./usage.md) | Usage patterns + config examples |
14
+ | [`commands-reference.md`](./commands-reference.md) | Slash commands + `/team-api` |
15
+ | [`actions-reference.md`](./actions-reference.md) | Full tool actions + examples |
16
+ | [`resource-formats.md`](./resource-formats.md) | Agent/team/workflow file formats |
17
+ | [`architecture.md`](./architecture.md) | Internal architecture + run flow |
18
+ | [`runtime-flow.md`](./runtime-flow.md) | Runtime execution details |
19
+ | [`dynamic-workflows.md`](./dynamic-workflows.md) | `.dwf.ts` script runtime + trust model |
20
+ | [`goals.md`](./goals.md) | Autonomous goal loops (`team action='goal'`) |
21
+ | [`live-mailbox-runtime.md`](./live-mailbox-runtime.md) | Mailbox + live-session runtime |
22
+ | [`troubleshooting.md`](./troubleshooting.md) | Common errors, recovery, error-code reference (E001–E012) |
23
+ | [`publishing.md`](./publishing.md) | Release & publish process |
24
+ | [`migration-v0.4-v0.5.md`](./migration-v0.4-v0.5.md) | Migration guide: v0.4 → v0.5 |
25
+ | [`HARNESS.md`](./HARNESS.md) | Agent-testing harness operating model |
26
+ | [`HARNESS_BACKLOG.md`](./HARNESS_BACKLOG.md) | Harness capability backlog |
27
+ | [`FEATURE_INTAKE.md`](./FEATURE_INTAKE.md) | Feature-intake gate for implementation prompts |
28
+ | [`TEST_MATRIX.md`](./TEST_MATRIX.md) | Behavior→proof mapping (every row needs real evidence) |
29
+ | [`TEST-STRATEGY-2026-07-30.md`](./TEST-STRATEGY-2026-07-30.md) | v0.9.56 test strategy (coverage × test type) |
30
+ | [`COVERAGE-ASSESSMENT-2026-08-01.md`](./COVERAGE-ASSESSMENT-2026-08-01.md) | v0.9.56 coverage assessment + source-reorg history |
31
+ | [`AUDIT-2026-07-30.md`](./AUDIT-2026-07-30.md) | v0.9.56 comprehensive audit (6 parallel streams) |
32
+ | [`REMEDIATION-PLAN-2026-07-30.md`](./REMEDIATION-PLAN-2026-07-30.md) | v0.9.56 remediation plan |
33
+
34
+ ## Subdirectories
35
+
36
+ | Subdir | Contents |
37
+ |--------|----------|
38
+ | [`archive/`](./archive/) | Historical/retired docs (flat; ~59 files — audits, research, superseded plans) |
39
+ | [`bugs/`](./bugs/) | Bug write-ups + security audit/issues |
40
+ | [`decisions/`](./decisions/) | Architecture decision records (ADRs, numbered) |
41
+ | [`distillation/`](./distillation/) | Distilled pattern/skill references |
42
+ | [`fixes/`](./fixes/) | Bug-fix reports |
43
+ | [`migration/`](./migration/) | Migration guides (e.g. atomic-write v2) |
44
+ | [`patterns/`](./patterns/) | Reusable pattern references |
45
+ | [`perf/`](./perf/) | Performance audits, sprint reports, optimization plans |
46
+ | [`product/`](./product/) | Product-domain docs |
47
+ | [`skills/`](./skills/) | pi-crew skills reference |
48
+ | [`stories/`](./stories/) | Story-sized work packets |
49
+ | [`superpowers/`](./superpowers/) | Fallow-patterns adoption plans |
50
+ | [`templates/`](./templates/) | Decision / story / validation-report templates |
51
+
52
+ See also the top-level [README.md](../README.md) and the source cluster maps
53
+ ([`src/runtime/README.md`](../src/runtime/README.md),
54
+ [`src/state/README.md`](../src/state/README.md)).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-crew",
3
- "version": "0.9.55",
3
+ "version": "0.9.57",
4
4
  "description": "Pi extension for coordinated AI teams, workflows, worktrees, and async task orchestration",
5
5
  "author": "baphuongna",
6
6
  "license": "MIT",
@@ -29,11 +29,10 @@
29
29
  "orchestration"
30
30
  ],
31
31
  "files": [
32
- "*.ts",
33
- "*.mjs",
34
32
  "src/",
35
33
  "dist/index.mjs",
36
- "dist/build-meta.json",
34
+ "index.ts",
35
+ "install.mjs",
37
36
  "agents/",
38
37
  "teams/",
39
38
  "workflows/",
@@ -72,12 +71,12 @@
72
71
  "check:bundle-size": "node scripts/check-bundle-size.mjs",
73
72
  "check:conflict-markers": "node scripts/check-conflict-markers.mjs",
74
73
  "typecheck": "tsc --noEmit && node --experimental-strip-types -e \"await import('./index.ts'); console.log('strip-types import ok')\"",
75
- "lint": "biome check --linter-enabled=true --formatter-enabled=false --max-diagnostics=50 --diagnostic-level=error .",
74
+ "lint": "biome check --linter-enabled=true --formatter-enabled=false --max-diagnostics=50 .",
76
75
  "format:check": "biome format .",
77
76
  "test": "npm run test:unit && npm run test:integration",
78
- "test:unit": "node scripts/test-runner.mjs --test-concurrency=4 --test-timeout=180000 --test-force-exit test/unit/*.test.ts",
79
- "test:critical": "node scripts/test-runner.mjs --test-concurrency=4 --test-timeout=30000 --test-force-exit test/unit/crew-broker-handshake.test.ts test/unit/crew-broker-stale-socket.test.ts test/unit/crew-broker-feature-flag.test.ts test/unit/crew-broker-server-gate.test.ts test/unit/crew-broker-client-fallback.test.ts test/unit/crew-broker-mailbox-observer.test.ts test/unit/crew-broker-close-during-reconnect.test.ts test/unit/crew-broker-steer-dedup.test.ts test/unit/crew-broker-symlink-steering.test.ts test/unit/keybinding-map.parity.test.ts test/unit/pi-tui-dispatch-probe.test.ts test/unit/session-utils-extract.test.ts test/unit/config-schema-sync.test.ts test/unit/child-pi-env-spread.test.ts",
80
- "test:watch": "tsx --watch --test --test-concurrency=4 --test-timeout=30000 --test-force-exit test/unit/*.test.ts",
77
+ "test:unit": "node scripts/test-runner.mjs --test-concurrency=4 --test-timeout=180000 --test-force-exit 'test/unit/**/*.test.ts'",
78
+ "test:critical": "node scripts/test-runner.mjs --test-concurrency=4 --test-timeout=30000 --test-force-exit test/unit/runtime/broker/crew-broker-handshake.test.ts test/unit/runtime/broker/crew-broker-stale-socket.test.ts test/unit/runtime/broker/crew-broker-feature-flag.test.ts test/unit/runtime/broker/crew-broker-server-gate.test.ts test/unit/runtime/broker/crew-broker-client-fallback.test.ts test/unit/runtime/broker/crew-broker-mailbox-observer.test.ts test/unit/runtime/broker/crew-broker-close-during-reconnect.test.ts test/unit/runtime/broker/crew-broker-steer-dedup.test.ts test/unit/runtime/broker/crew-broker-symlink-steering.test.ts test/unit/ui/keybinding-map.parity.test.ts test/unit/ui/pi-tui-dispatch-probe.test.ts test/unit/utils/session-utils-extract.test.ts test/unit/config/config-schema-sync.test.ts test/unit/runtime/child-pi/child-pi-env-spread.test.ts",
79
+ "test:watch": "tsx --watch --test --test-concurrency=4 --test-timeout=30000 --test-force-exit 'test/unit/**/*.test.ts'",
81
80
  "test:integration": "node scripts/test-runner.mjs --test-concurrency=1 --test-timeout=300000 test/integration/*.test.ts",
82
81
  "test:smoke": "node scripts/test-runner.mjs --test-concurrency=1 --test-timeout=180000 test/smoke/*.smoke.ts",
83
82
  "build:bundle": "node scripts/build-bundle.mjs",
@@ -90,7 +89,7 @@
90
89
  "build:crew-font": "python scripts/build-crew-vibes-font.py",
91
90
  "bench": "node scripts/run-bench.mjs",
92
91
  "bench:check": "node scripts/bench-check.mjs",
93
- "test:new": "tsx --test --test-concurrency=4 --test-timeout=30000 --test-force-exit test/unit/*.test.ts",
92
+ "test:new": "tsx --test --test-concurrency=4 --test-timeout=30000 --test-force-exit 'test/unit/**/*.test.ts'",
94
93
  "test:changed": "node scripts/test-changed.mjs",
95
94
  "bench:capture": "node scripts/run-bench.mjs && node -e \"require('node:fs').copyFileSync('test/bench/results.json','test/bench/baseline.json')\"",
96
95
  "profile:startup": "node scripts/profile-startup.mjs",
@@ -130,10 +129,10 @@
130
129
  },
131
130
  "devDependencies": {
132
131
  "@biomejs/biome": "^2.5.3",
133
- "@earendil-works/pi-agent-core": "^0.82.0",
134
- "@earendil-works/pi-ai": "^0.82.0",
135
- "@earendil-works/pi-coding-agent": "^0.82.0",
136
- "@earendil-works/pi-tui": "^0.82.0",
132
+ "@earendil-works/pi-agent-core": "^0.83.0",
133
+ "@earendil-works/pi-ai": "^0.83.0",
134
+ "@earendil-works/pi-coding-agent": "^0.83.0",
135
+ "@earendil-works/pi-tui": "^0.83.0",
137
136
  "@types/node": "^25.9.5",
138
137
  "tsx": "^4.23.0",
139
138
  "typescript": "^7.0.2"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: real-test-pi-crew
3
- description: "End-to-end verification for pi-crew changes: fast critical tests, 3-path kill-switch proof, bundle md5 sync, live TUI probing, and smoke team runs."
3
+ description: "End-to-end verification for pi-crew changes: fast critical tests, 3-path kill-switch proof, bundle md5 sync, live TUI probing, smoke team runs, and a live feature-action battery (team tool + subagent tools)."
4
4
  origin: pi-crew
5
5
  triggers:
6
6
  - "test the change"
@@ -17,14 +17,20 @@ triggers:
17
17
  - "worker timeout"
18
18
  - "verifier hangs"
19
19
  - "rebuild and retry"
20
- - "tier 1 / tier 2 / tier 3 / tier 4 / tier 5 / tier 6 / tier 7 / tier 8"
20
+ - "unknown type" tool error
21
+ - "validation failed for tool"
22
+ - "team tool broken"
23
+ - "schema fix"
24
+ - "feature battery"
25
+ - "full features of pi-crew"
26
+ - "tier 1 / tier 2 / tier 3 / tier 4 / tier 5 / tier 6 / tier 7 / tier 8 / tier 9"
21
27
  ---
22
28
 
23
29
  # real-test-pi-crew
24
30
 
25
31
  End-to-end verification discipline for pi-crew changes. Distilled from the broker Phase-4 rollout (commits `1cb2dca` → `d599578` → `612e18b` → `4186284`, July 2026). The pain this skill prevents: shipping code that compiles + unit-tests-green but breaks in the user's live Pi session, or hangs the verifier worker.
26
32
 
27
- **When to use**: after any change to `src/runtime/crew-broker*.ts`, `src/ui/`, `src/config/`, `src/extension/registration/lifecycle-handlers.ts`, `src/runtime/child-pi-spawn.ts`, `src/runtime/plan-templates.ts`, `workflows/*.workflow.md`, or before any commit touching these paths.
33
+ **When to use**: after any change to `src/runtime/crew-broker*.ts`, `src/ui/`, `src/config/`, `src/extension/registration/lifecycle-handlers.ts`, `src/runtime/child-pi-spawn.ts`, `src/runtime/plan-templates.ts`, `src/schema/team-tool-schema.ts` (or any `Type.Unsafe({...})` schema definition), `src/extension/registration/team-tool.ts`, `workflows/*.workflow.md`, or before any commit touching these paths. Schema changes additionally require Tier 9 (feature battery) because the team tool's TypeBox schema is validated by pi-ai BEFORE the handler runs — a too-strict or malformed schema breaks every action silently.
28
34
 
29
35
  ## Core principle: disk ≠ live Pi
30
36
 
@@ -407,6 +413,8 @@ readlink ../node_modules/pi-crew/dist/index.mjs 2>/dev/null \
407
413
 
408
414
  If the two md5s match → session is on the latest code. If not → user must `/quit` + reopen Pi.
409
415
 
416
+ > **Agent-inside-session caveat**: when the agent *doing the testing* runs inside the very Pi session under test, the agent **cannot restart its own session** — only the user can. Pattern that works: (1) edit source + rebuild bundle, (2) ask the user to `/quit` + reopen, (3) on resume, re-check `md5sum dist/index.mjs` then issue a probe tool call (e.g. `team action='list'`). If the probe returns the *old* error (e.g. `Unknown type`, `Validation failed for tool team`), the session did NOT reload — there may be multiple `pi` PIDs and the user reopened a different one. Verify with `ps -eo pid,lstart,tty,args | grep pi` which PID is yours (the one whose session log is being appended to right now).
417
+
410
418
  **References**:
411
419
 
412
420
  | What | Where |
@@ -416,6 +424,74 @@ If the two md5s match → session is on the latest code. If not → user must `/
416
424
 
417
425
  ---
418
426
 
427
+ ## Tier 9 — Feature battery (live action coverage)
428
+
429
+ **What**: drive the team tool + subagent tools through a spread of actions from the parent Pi session to prove the full surface works end-to-end, not just one smoke run.
430
+
431
+ **Why this exists**: Tier 7 proves one team run completes. But pi-crew has ~50 `team` actions plus 4 subagent tools (`Agent`, `crew_agent`, `get_subagent_result`, `crew_agent_steer`), dispatched through several code paths (sync run, async run, chain, parallel, direct subagent). A schema or registration regression can break *some* paths while others still pass. The battery catches path-specific breakage.
432
+
433
+ **When required**: any change to `src/schema/team-tool-schema.ts`, `src/extension/registration/team-tool.ts`, `src/extension/team-tool/*.ts` (handler dispatch), or the subagent-tool registration. Optional but cheap for any change — the read-only actions are free.
434
+
435
+ **How** (run from the parent Pi session — these are tool calls, not shell):
436
+
437
+ 1. **9a. Read-only actions** (free, no subagent spawn — run these first as a fast battery):
438
+ - `team action='list'` — teams/workflows/agents
439
+ - `team action='recommend' goal='...'` — planner routing
440
+ - `team action='health'` — run-state scan
441
+ - `team action='doctor' focus='zombies'` — orphan subagent scan (read-only)
442
+ - `team action='status' runId='<recent>' details=false` — compact
443
+ - `team action='events' runId='<recent>'` — full event lifecycle
444
+ - `team action='summary' runId='<recent>'` — cost/by-role report
445
+ - `team action='get' resource='workflow' team='implementation'` — resource inspect
446
+ - `team action='explain' runId='<recent>'` — markdown render
447
+ - `team action='worktrees' runId='<recent>'` — workspace listing
448
+ 2. **9b. Spawn paths** (cost tokens — one probe each is enough):
449
+ - `team action='run'` sync (fast-fix, trivial goal) — proves sync run + child-pi spawn + provider-extension loading
450
+ - `team action='run' async=true` — proves background dispatch
451
+ - `team action='run' chain='"A" -> "B"'` — proves sequential handoff (chain runner)
452
+ - `Agent` direct subagent — proves the direct-subagent tool
453
+ - `crew_agent` `run_in_background=true` then `get_subagent_result` — proves background subagent lifecycle
454
+ 3. **Acceptance**: every action returns without `Unknown type` / `Validation failed for tool team` / empty error text; every spawn path completes with `consistency=1` and the expected probe token in the agent output.
455
+
456
+ **Real measured outcome** (this session, after the v0.9.57 schema fix): 9a (15 team actions) + 9b (4 subagent tools / 3 run paths) exercised; all green; the two silent-failure modes that motivated this tier (`Unknown type` from `Type.Unsafe` without Kind, and `Validation failed for tool team` from empty-string-strict schema) were caught ONLY by this battery — Tier 1-8 all passed while the team tool was broken live. The session also surfaced the unauthorized-agent-edit anti-pattern (a chain-run agent edited `chain-runner.ts` mid-smoke) — see Anti-patterns.
457
+
458
+ **Not covered by the cheap battery above** — the actions below need extra setup, cost, or user confirmation. Run them only when the change touches their code path, and prefer a throwaway cwd / config so you don't mutate the user's real state. Organised by cost/safety:
459
+
460
+ **9c. Lifecycle / recovery** (needs a *running* run — start an async run, then exercise these against its runId):
461
+ - `team action='wait' runId='...'` — block until completion
462
+ - `team action='steer' runId='...' message='...'` — inject a steering note mid-run
463
+ - `team action='status' runId='...' details=true` — full dump mid-run
464
+ - `team action='cache' subAction='...' runId='...'` — snapshot cache ops
465
+ - `team action='checkpoint' runId='...'` — state checkpoint
466
+ - `team action='cancel' runId='...'` — ⚠️ destructive (kills the run); use a throwaway run
467
+ - `team action='invalidate' runId='...'` — cache invalidation
468
+ - `team action='resume' runId='...'` / `retry` — resume a completed/failed run
469
+ - `team action='respond' taskId='...' message='...'` — mailbox reply (needs a waiting task)
470
+ - subagent steering: `crew_agent run_in_background=true` a long task (e.g. `sleep 60`), then `crew_agent_steer` while it runs, then `get_subagent_result` — proves the steer arrived (timing-sensitive; assert the agent's output reflects the steer)
471
+
472
+ **9d. Destructive** (⚠️ **requires explicit user confirmation** per the delegation policy — never run unprompted):
473
+ - `team action='prune' keep=<N>` — delete old finished runs
474
+ - `team action='cleanup'` — sweep stale workspaces/state
475
+ - `team action='forget' runId='...'` — delete one run's state
476
+ - `team action='doctor' focus='zombies'` is READ-ONLY (safe) but the follow-up `kill <PID>` it suggests is destructive — confirm with the user before killing
477
+
478
+ **9e. Admin / mutation** (mutates config or workflow files — use a scratch project cwd or back up first):
479
+ - `team action='create' resource='team' ...` / `update` / `delete` — manage teams/agents/workflows
480
+ - `team action='init'` / `config` / `validate` / `autonomy` / `settings` — project setup
481
+ - `team action='workflow-create'` / `workflow-save` / `workflow-delete` / `workflow-get` / `workflow-list` — workflow CRUD
482
+ - `team action='import'` / `imports` / `export` — run data portability
483
+ - `team action='parallel' tasks=[...]` — parallel dispatch (spawn path, costs tokens per task)
484
+
485
+ **9f. Background / scheduled** (expensive or niche):
486
+ - `team action='run' runKind='goal-loop'` — the goal loop runs many turns judging an objective; smoke with a trivial objective + low `maxTurns` (e.g. 2) to prove dispatch without burning budget
487
+ - `team action='schedule' cron='...' ...` / `scheduled` / `subAction='remove'` — cron; assert the job registers then remove it (cleanup)
488
+ - `team action='auto-summarize'` / `anchor` / `auto_boomerang` — background features; assert no-throw on a completed run
489
+ - `team action='api'` — programmatic surface
490
+
491
+ **Acceptance for 9c–9f**: the action returns a structured result (not `Unknown type` / not an empty error), and for spawn/lifecycle paths the run reaches the expected terminal status. For 9d/9e, the mutation is reversible or confined to scratch state.
492
+
493
+ ---
494
+
419
495
  ## Anti-patterns (the cost is real, observed in this session)
420
496
 
421
497
  | Anti-pattern | Cost | Where fixed | Reference |
@@ -432,6 +508,9 @@ If the two md5s match → session is on the latest code. If not → user must `/
432
508
  | Test by reading code | Proves nothing about runtime | n/a (permanent) | All tiers above |
433
509
  | `makeFakeCtx({ flagOn: false })` without `brokerEnv: "0"` | `makeFakeCtx` deletes `PI_CREW_BROKER` env if `brokerEnv` is undefined | `612e18b` (test fix) | `test/unit/crew-broker-server-gate.test.ts:78` — pass `brokerEnv: "0"` to preserve env |
434
510
  | Trust green CI on one OS | macOS/Windows regressions slip through | n/a (permanent) | `.crew/knowledge.md` — "CI runs 3 OSes ... A flake on one OS IS a real bug" |
511
+ | Trusting a team-run agent not to edit the repo under test | Agents spawned by `team`/`Agent`/`crew_agent` inherit the session cwd and have `edit`/`write` tools — a proactive LLM (observed with deepseek) will make **unauthorized source edits** to pi-crew during a trivial smoke run (e.g. "improving" `chain-runner.ts` while parsing a chain string). The edit can be correct + green-tested yet still be unintended scope creep that silently lands in your commit. | n/a (permanent) | After EVERY team/subagent run: `git status` and verify each changed file was authored by you. Diff + review any surprise change before staging. Consider `workspaceMode: 'worktree'` for parallel/risky runs to isolate mutations. |
512
+ | `Type.Unsafe({ anyOf/type })` schema field **without** `[TypeBox.Kind]` symbol | `Value.Check` throws `Unknown type` the first time a model emits that field (e.g. `skill`, `config`) — every team action returns `isError:true` text `"Unknown type"`. Tier 1-8 stay green because unit tests never send the offending field. | v0.9.57 | `src/schema/team-tool-schema.ts` — `SkillOverride`/`FreeformConfig` switched from `Type.Unsafe` to TypeBox-native `Type.Union`/`Type.Record`. See Tier 9. |
513
+ | Schema too strict for model-emitted empty strings (`runId:""`, `workspaceMode:""`, `budgetTotal:0`) | pi-ai `validateToolArguments` runs BEFORE the pi-crew handler and rejects `""` against Literal unions / patterns → `Validation failed for tool team` → model loops. | v0.9.57 | `src/schema/team-tool-schema.ts` — added `Literal("")` to unions, `^$|` pattern for runId, `""` to action enum, `0`/Boolean allowances. Handler-side `normalizeTeamParams` drops the empties. |
435
514
 
436
515
  ---
437
516
 
@@ -452,6 +531,9 @@ When a tier fails, the recovery is usually quick. Match the symptom to the cause
452
531
  | Smoke team: worker times out at 300s | Either verifier command slow OR LLM thinking cap | Check `RESPONSE_TIMEOUT_MS` (300s); bump only if you verified the command itself finishes <300s |
453
532
  | `stale-ctx` error in worker output | Extension ctx is stale after session replacement | This is runtime noise, not a regression; ignore. (Source: `.crew/knowledge.md` "Process Safety" notes) |
454
533
  | Bundle md5 not changing after rebuild | Stale `dist/` cache or esbuild no-op | `rm -rf dist/ && npm run build:bundle`; verify new md5 |
534
+ | Team tool returns `Unknown type` (isError:true, short text) | `Value.Check` in the handler hit a `Type.Unsafe({...})` schema node with **no `[TypeBox.Kind]` symbol** — only triggered when the model actually sends that field. Tier 1-8 pass; only Tier 9 (feature battery) catches it. | Replace the `Type.Unsafe` with a TypeBox-native constructor (`Type.Union`, `Type.Record`, `Type.Any`). Reproduce with `node --input-type=module -e "import {Value} from '@sinclair/typebox/value'; import {TeamToolParams} from './src/schema/team-tool-schema.ts'; Value.Check(TeamToolParams, {action:'list', skill:'', config:{}})"` — a throw = the bug. |
535
+ | `Validation failed for tool "team": ... must be equal to constant` | pi-ai `validateToolArguments` (`@earendil-works/pi-ai/dist/utils/validation.js`) rejects model-emitted `""`/`0`/`false` defaults against Literal unions / patterns / minimums — it runs BEFORE the pi-crew handler, so handler-side normalization is too late. | Loosen the schema to accept the unset marker (`Literal("")`, pattern `^$|...`, `Literal(0)`, add `Boolean()` to unions). Verify with the pi-ai validator directly: `import {validateToolArguments} from '@earendil-works/pi-ai'; validateToolArguments({name:'team',parameters:TeamToolParams},{name:'team',arguments:{...fullModelBlob}})`. |
536
+ | User says "restarted" but the probe still shows the OLD error | Multiple `pi` PIDs open; the user reopened a different terminal than the one the agent runs in; the agent's session never reloaded the bundle. | `ps -eo pid,lstart,tty,args \| grep pi` to list PIDs; match the agent's session log (the `.jsonl` being appended right now) to its PID; have the user reopen THAT session, or move the work into the freshly-opened one. |
455
537
 
456
538
  ## Performance budget (per-tier soft limits)
457
539
 
@@ -465,6 +547,7 @@ When a tier fails, the recovery is usually quick. Match the symptom to the cause
465
547
  | 6 (pty probe) | 5s | 15s | `pi` not in PATH |
466
548
  | 7 (smoke team) | 60s (verifier only) | 300s (worker hard limit) | Worker killed by `RESPONSE_TIMEOUT_MS` |
467
549
  | 8 (final md5 sync) | <1s | 5s | Disk/symlink issue |
550
+ | 9 (feature battery) | 30s (read-only batch) + ~120s per spawn probe | 300s per spawn probe (worker hard limit) | Spawn probe hung or returned `Unknown type`/`Validation failed` — a schema or registration regression; see Tier 9 + Failure symptoms |
468
551
 
469
552
  If a tier runs over the hard limit, **stop and investigate** — don't bump the budget silently. The budget exists precisely so regressions in test runtime (which usually means a regression in test setup/teardown) are caught early.
470
553
 
@@ -589,6 +672,12 @@ python3 scripts/pty_probe.py 2>&1 | tee /tmp/diag.log
589
672
  md5sum dist/index.mjs
590
673
  md5sum "$(npm root -g)"/pi-crew/dist/index.mjs 2>/dev/null \
591
674
  || md5sum ../node_modules/pi-crew/dist/index.mjs
675
+ # Tier 9 (feature battery — from parent Pi session, tool calls not shell)
676
+ # read-only: team action=list / recommend / health / doctor / status / events / summary / get / explain / worktrees
677
+ # spawn: team action=run (sync) ; team action=run async=true ; team action=run chain='"A" -> "B"'
678
+ # Agent (direct) ; crew_agent run_in_background=true + get_subagent_result
679
+ # reproduce the two silent schema failures:
680
+ # node --input-type=module -e "import {Value} from '@sinclair/typebox/value'; import {TeamToolParams} from './src/schema/team-tool-schema.ts'; Value.Check(TeamToolParams, {action:'list', skill:'', config:{}})" # throws 'Unknown type' = Type.Unsafe-without-Kind bug
592
681
  ```
593
682
 
594
683
  ---
@@ -604,6 +693,7 @@ Before claiming "tested":
604
693
  - [ ] Tier 5/6: live TUI smoke for any `src/ui/` change — keystroke reached `handleInput`
605
694
  - [ ] Tier 7: smoke team run for any `src/runtime/plan-templates.ts` or `workflows/*.workflow.md` change — completed, no hang, verifier output under 60s
606
695
  - [ ] Tier 8: final md5 sync check passed
696
+ - [ ] Tier 9: feature battery — **required if you touched `src/schema/team-tool-schema.ts`, `src/extension/registration/team-tool.ts`, or any `Type.Unsafe({...})` schema**. 9a read-only batch all return clean; one probe per 9b spawn path (sync / async / chain / `Agent` / `crew_agent`+`get_subagent_result`) completes with `consistency=1`. Run 9c–9f only when the change touches their code path; 9d (destructive) requires explicit user confirmation. **After every run: `git status` to catch unauthorized agent edits.**
607
697
 
608
698
  If any required item is unchecked, the answer to "is it tested?" is **no**.
609
699
 
@@ -1,6 +1,7 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import { type LoadedPiTeamsConfig, loadConfig } from "../config/config.ts";
4
+ import { discoverProviderExtensionPaths } from "../runtime/model/provider-extensions.ts";
4
5
  import { parseCsv, parseFrontmatter } from "../utils/frontmatter.ts";
5
6
  import { logInternalError } from "../utils/internal-error.ts";
6
7
  import { findRepoRoot, packageRoot, projectCrewRoot, userPiRoot } from "../utils/paths.ts";
@@ -317,7 +318,9 @@ export function sanitizeAgentSystemPrompt(content: string, source: ResourceSourc
317
318
  sanitized = sanitized.replace(/[\u200B-\u200F\u2028-\u202F\u2060-\u206F\uFEFF]/g, "");
318
319
 
319
320
  // 2. Strip HTML/JS comments (instruction hiding) — all trust levels
320
- sanitized = sanitized.replace(/<!--[\s\S]*?-->|<\/?script[^>]*>/gi, "");
321
+ // SEC-4: bounded quantifier {0,8192} prevents polynomial O(n²) backtracking
322
+ // DoS on pathological inputs (e.g. an unclosed `<!--` with no matching `-->`).
323
+ sanitized = sanitized.replace(/<!--[\s\S]{0,8192}?-->|<\/?script[^>]*>/gi, "");
321
324
 
322
325
  // 3. Strip known prompt injection directive patterns — user and project
323
326
  if (trustLevel !== "builtin") {
@@ -337,7 +340,8 @@ export function sanitizeAgentSystemPrompt(content: string, source: ResourceSourc
337
340
  sanitized = sanitized.replace(/\b(eval|exec|spawn|subprocess)\s*\(\s*(?:base64|Buffer\.from)\s*\(/gi, "[suspicious-call-redacted]");
338
341
 
339
342
  // Strip markdown that attempts to hide instructions
340
- sanitized = sanitized.replace(/```\s*(?:system|instruction|prompt)\n[\s\S]*?```/gi, "");
343
+ // SEC-4: bounded quantifier {0,8192} prevents polynomial backtracking DoS.
344
+ sanitized = sanitized.replace(/```\s*(?:system|instruction|prompt)\n[\s\S]{0,8192}?```/gi, "");
341
345
  }
342
346
 
343
347
  // 4. Project-level strict sanitization
@@ -391,7 +395,7 @@ function parseAgentFile(filePath: string, source: ResourceSource): AgentConfig |
391
395
  // runtime is the default child-process path. `contextMode: fork`
392
396
  // is only effective in the live-session runtime (the experimental
393
397
  // path that runs the agent IN the parent pi's session). The
394
- // default child-process path (runChildPi in src/runtime/child-pi.ts)
398
+ // default child-process path (runChildPi in src/runtime/child-pi/child-pi.ts)
395
399
  // spawns a NEW pi process and has no parent session to inherit,
396
400
  // so the agent will behave as `fresh` regardless of the setting.
397
401
  // We warn (not throw) so existing configs that predate live-session
@@ -401,7 +405,7 @@ function parseAgentFile(filePath: string, source: ResourceSource): AgentConfig |
401
405
  // logInternalError below).
402
406
  if (contextMode === "fork" && !warnedForkAgents.has(filePath)) {
403
407
  console.warn(
404
- "contextMode: 'fork' is only effective in live-session runtime; current default child-process will behave as 'fresh'. See docs/runtime-modes.md.",
408
+ "contextMode: 'fork' is only effective in live-session runtime; current default child-process will behave as 'fresh'. See docs/runtime-flow.md.",
405
409
  );
406
410
  warnedForkAgents.add(filePath);
407
411
  }
@@ -417,8 +421,19 @@ function parseAgentFile(filePath: string, source: ResourceSource): AgentConfig |
417
421
  fallbackModels: parseCsv(frontmatter.fallbackModels),
418
422
  thinking: frontmatter.thinking === "false" ? undefined : frontmatter.thinking || undefined,
419
423
  tools: parseToolsField(frontmatter.tools),
420
- extensions: frontmatter.extensions === "" ? [] : parseCsv(frontmatter.extensions),
421
- excludeExtensions: parseCsv(frontmatter.excludeExtensions ?? frontmatter.exclude_extensions),
424
+ // SEC-1: Strip extensions/excludeExtensions for untrusted project-sourced
425
+ // agents (RCE prevention). Both `project` (.crew/agents/) and
426
+ // `project-pi` (.pi/agents/) are repo-adjacent / untrusted sources —
427
+ // their frontmatter `extensions:` could point to attacker-controlled
428
+ // code. Bypass only when PI_CREW_TRUST_PROJECT_AGENT_EXTENSIONS=1 is
429
+ // explicitly set. buildPiWorkerArgs also enforces this as
430
+ // defense-in-depth.
431
+ ...((source === "project" || source === "project-pi") && process.env.PI_CREW_TRUST_PROJECT_AGENT_EXTENSIONS !== "1"
432
+ ? { extensions: [], excludeExtensions: [] }
433
+ : {
434
+ extensions: frontmatter.extensions === "" ? [] : parseCsv(frontmatter.extensions),
435
+ excludeExtensions: parseCsv(frontmatter.excludeExtensions ?? frontmatter.exclude_extensions),
436
+ }),
422
437
  skills: parseCsv(frontmatter.skills ?? frontmatter.skill),
423
438
  systemPromptMode: frontmatter.systemPromptMode === "append" ? "append" : "replace",
424
439
  inheritProjectContext: frontmatter.inheritProjectContext === "true",
@@ -448,12 +463,31 @@ function parseAgentFile(filePath: string, source: ResourceSource): AgentConfig |
448
463
  }
449
464
  }
450
465
 
466
+ // SEC-4: Maximum agent file size. Files exceeding this are skipped to prevent
467
+ // resource-exhaustion DoS (a 10MB agent file would block the event loop during
468
+ // readFileSync + frontmatter parse + regex sanitization). 256KB is generous —
469
+ // the largest builtin agent file is ~2KB.
470
+ const MAX_AGENT_FILE_BYTES = 256 * 1024;
471
+
451
472
  function readAgentDir(dir: string, source: ResourceSource): AgentConfig[] {
452
473
  if (!fs.existsSync(dir)) return [];
453
474
  const agents = fs
454
475
  .readdirSync(dir)
455
476
  .filter((entry) => entry.endsWith(".md") && !entry.endsWith(".team.md") && !entry.endsWith(".workflow.md"))
456
- .map((entry) => parseAgentFile(path.join(dir, entry), source))
477
+ .map((entry) => {
478
+ const fullPath = path.join(dir, entry);
479
+ // SEC-4: Skip files exceeding the size cap before reading/parsing.
480
+ try {
481
+ const stat = fs.statSync(fullPath);
482
+ if (stat.size > MAX_AGENT_FILE_BYTES) {
483
+ console.warn(`[pi-crew] Skipping oversized agent file (${stat.size} > ${MAX_AGENT_FILE_BYTES} bytes): ${fullPath}`);
484
+ return undefined;
485
+ }
486
+ } catch {
487
+ return undefined;
488
+ }
489
+ return parseAgentFile(fullPath, source);
490
+ })
457
491
  .filter((agent): agent is AgentConfig => agent !== undefined)
458
492
  .sort((a, b) => a.name.localeCompare(b.name));
459
493
 
@@ -471,13 +505,37 @@ function applyAgentOverrides(agents: AgentConfig[], cwd: string, loadedConfig?:
471
505
  const loaded = loadedConfig ?? loadConfig(cwd);
472
506
  const agentsConfig = loaded.config.agents;
473
507
  const overrides = agentsConfig?.overrides ?? {};
508
+ // Provider extension allowlist (v0.9.57): auto-discovered from Pi's
509
+ // installed package registry (settings.json `packages` with `npm:` specs —
510
+ // e.g. pi-commandcode-provider). These are the sanctioned channels for
511
+ // provider extensions that register models, so provider models stay
512
+ // resolvable inside subagents despite `--no-extensions`. The explicit
513
+ // `runtime.agentExtensions` config list is merged on top for operators who
514
+ // want extra paths beyond installed packages. SEC-1 preserved: project /
515
+ // project-pi agents never receive any of these (env-gate unchanged).
516
+ const globalExtensions = [...discoverProviderExtensionPaths(), ...(loaded.config.runtime?.agentExtensions ?? [])];
517
+ const deduped = [...new Set(globalExtensions.map((p) => path.resolve(p)))];
518
+ // SEC-1 (defense-in-depth): do NOT merge the global extension allowlist into
519
+ // untrusted project / project-pi agents. Those agents already had their
520
+ // `extensions` stripped at parse time unless PI_CREW_TRUST_PROJECT_AGENT_EXTENSIONS=1;
521
+ // re-adding global extensions would bypass that gate. The global list is a
522
+ // user-trusted config knob (provider extensions like pi-commandcode-provider)
523
+ // and applies to builtin / user agents only.
524
+ const isUntrustedProject = (agent: AgentConfig) =>
525
+ (agent.source === "project" || agent.source === "project-pi") && process.env.PI_CREW_TRUST_PROJECT_AGENT_EXTENSIONS !== "1";
526
+ const withGlobalExtensions = (agent: AgentConfig): AgentConfig => {
527
+ if (isUntrustedProject(agent)) return agent;
528
+ return deduped.length > 0 || agent.extensions !== undefined
529
+ ? { ...agent, extensions: [...deduped, ...(agent.extensions ?? [])] }
530
+ : agent;
531
+ };
474
532
  return agents
475
533
  .filter((agent) => !(agentsConfig?.disableBuiltins && agent.source === "builtin"))
476
534
  .map((agent) => {
477
535
  const overrideEntry = Object.entries(overrides).find(([name]) => name.toLowerCase() === agent.name.toLowerCase());
478
- if (!overrideEntry) return agent;
536
+ if (!overrideEntry) return withGlobalExtensions(agent);
479
537
  const [, override] = overrideEntry;
480
- return {
538
+ return withGlobalExtensions({
481
539
  ...agent,
482
540
  disabled: override.disabled ?? agent.disabled,
483
541
  model: override.model === false ? undefined : (override.model ?? agent.model),
@@ -486,7 +544,7 @@ function applyAgentOverrides(agents: AgentConfig[], cwd: string, loadedConfig?:
486
544
  tools: override.tools === false ? undefined : (override.tools ?? agent.tools),
487
545
  skills: override.skills === false ? undefined : (override.skills ?? agent.skills),
488
546
  override: { source: "config", path: loaded.path },
489
- };
547
+ });
490
548
  });
491
549
  }
492
550
 
@@ -2,7 +2,7 @@
2
2
  * Feedback loop - continuous improvement cycle: evaluate → learn → apply → re-evaluate
3
3
  */
4
4
 
5
- import type { RunMetrics } from "../state/run-metrics.ts";
5
+ import type { RunMetrics } from "../state/stores/run-metrics.ts";
6
6
 
7
7
  /** @internal */
8
8
  interface FeedbackLoopStats {
@@ -5,7 +5,7 @@ import { type Static, type TSchema, Type } from "@sinclair/typebox";
5
5
  import { Value } from "@sinclair/typebox/value";
6
6
  import { PiTeamsAutonomyProfileSchema, PiTeamsConfigSchema } from "../schema/config-schema.ts";
7
7
  import { atomicWriteFile } from "../state/atomic-write.ts";
8
- import { withFileLockSync } from "../state/locks.ts";
8
+ import { withFileLockSync } from "../state/coordination/locks.ts";
9
9
  import { logInternalError } from "../utils/internal-error.ts";
10
10
  import { projectCrewRoot, projectPiRoot } from "../utils/paths.ts";
11
11
  import { DEFAULT_BROKER, resolveBrokerEnvOverride } from "./defaults.ts";
@@ -732,6 +732,7 @@ function parseRuntimeConfig(value: unknown): CrewRuntimeConfig | undefined {
732
732
  return Object.values(parsed).some((v) => v !== undefined) ? parsed : undefined;
733
733
  })(),
734
734
  excludeContextBash: parseWithSchema(Type.Boolean(), obj.excludeContextBash),
735
+ agentExtensions: parseStringList(obj.agentExtensions),
735
736
  isolationPolicy: parseIsolationPolicy(obj.isolationPolicy),
736
737
  };
737
738
  return Object.values(runtime).some((entry) => entry !== undefined) ? runtime : undefined;
@@ -44,6 +44,18 @@ export interface CrewRuntimeConfig {
44
44
  allowChildProcessFallback?: boolean;
45
45
  maxTurns?: number;
46
46
  graceTurns?: number;
47
+ /**
48
+ * Global extension allowlist (default: none). Paths (file paths or npm
49
+ * extension entry points) to load in EVERY spawned child-pi worker, on top
50
+ * of pi-crew's own prompt-runtime extension. Despite `--no-extensions`
51
+ * being set for child spawns (to prevent untrusted user extensions from
52
+ * auto-loading), Pi loads explicitly-passed `--extension <path>` entries.
53
+ * This is the sanctioned channel for provider extensions that register
54
+ * models (e.g. `pi-commandcode-provider`) so those models stay resolvable
55
+ * inside subagents. Applies to all agents; agent-level `extensions:`
56
+ * frontmatter (user sources) can still add per-agent extensions.
57
+ */
58
+ agentExtensions?: string[];
47
59
  /**
48
60
  * W2 fix — wall-clock timeout per task in milliseconds. When the task
49
61
  * exceeds this limit, input.signal is aborted which triggers the existing
@@ -7,75 +7,28 @@
7
7
  * (`src/config/suggestions.ts → suggestConfigKey`); this module applies it to
8
8
  * the known set of team actions.
9
9
  *
10
- * The known-action list mirrors the `action` enum in
11
- * `src/schema/team-tool-schema.ts`. Kept as a hand-maintained constant (not
12
- * derived from the TypeBox schema at runtime) so it is trivially testable and
13
- * avoids pulling the schema into low-level error paths.
10
+ * EXT-4/EXT-8: the known-action list is now derived from the single source of
11
+ * truth — `allActionLiterals` in `src/schema/team-tool-schema.ts` — so it can
12
+ * never drift from the schema's action enum. A drift test
13
+ * (`test/unit/action-list-single-source.test.ts`) guards against regression.
14
14
  */
15
15
 
16
16
  import { findClosestKey } from "../config/suggestions.ts";
17
+ import { allActionLiterals } from "../schema/team-tool-schema.ts";
17
18
 
18
19
  /**
19
- * The complete set of valid top-level `team` actions (mirrors the action enum
20
- * in `src/schema/team-tool-schema.ts`). Exported so callers and tests can use
21
- * the single source of truth.
20
+ * The complete set of valid top-level `team` actions. EXT-4/EXT-8: derived from
21
+ * `allActionLiterals` (the schema's single source of truth), not hand-maintained.
22
+ * Each `allActionLiterals` entry is a `{ const: string }` produced by the domain
23
+ * `stringEnum` schemas; we map to the raw string for use with the fuzzy matcher.
24
+ *
25
+ * Sorted by (length desc, then alphabetical) so `findClosestKey` tie-breaking
26
+ * is deterministic and prefers longer (more specific) matches on equal
27
+ * Levenshtein distance — e.g. "cancle" → "cancel" over "cache".
22
28
  */
23
- export const KNOWN_TEAM_ACTIONS = [
24
- "run",
25
- "parallel",
26
- "plan",
27
- "status",
28
- "wait",
29
- "list",
30
- "get",
31
- "cancel",
32
- "retry",
33
- "resume",
34
- "respond",
35
- "create",
36
- "update",
37
- "delete",
38
- "doctor",
39
- "cleanup",
40
- "events",
41
- "artifacts",
42
- "worktrees",
43
- "forget",
44
- "summary",
45
- "prune",
46
- "export",
47
- "import",
48
- "imports",
49
- "help",
50
- "validate",
51
- "config",
52
- "init",
53
- "recommend",
54
- "autonomy",
55
- "api",
56
- "settings",
57
- "steer",
58
- "invalidate",
59
- "health",
60
- "graph",
61
- "onboard",
62
- "explain",
63
- "cache",
64
- "checkpoint",
65
- "search",
66
- "orchestrate",
67
- "schedule",
68
- "scheduled",
69
- "anchor",
70
- "auto-summarize",
71
- "auto_boomerang",
72
- "goal",
73
- "workflow-create",
74
- "workflow-get",
75
- "workflow-list",
76
- "workflow-save",
77
- "workflow-delete",
78
- ] as const;
29
+ export const KNOWN_TEAM_ACTIONS: readonly string[] = allActionLiterals
30
+ .map((l) => (l as { const: string }).const)
31
+ .sort((a, b) => b.length - a.length || a.localeCompare(b));
79
32
 
80
33
  /**
81
34
  * Suggest the closest known team action for a (likely typo'd) input.
@@ -1,9 +1,9 @@
1
1
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
  import { readCrewAgents, saveCrewAgents } from "../runtime/crew-agent-records.ts";
3
3
  import { checkProcessLiveness, isActiveRunStatus } from "../runtime/process-status.ts";
4
- import { appendEvent, readEvents, type TeamEvent } from "../state/event-log.ts";
5
- import { withRunLockSync } from "../state/locks.ts";
6
- import { loadRunManifestById, saveRunTasks, updateRunStatus } from "../state/state-store.ts";
4
+ import { withRunLockSync } from "../state/coordination/locks.ts";
5
+ import { appendEvent, readEvents, type TeamEvent } from "../state/event-log/event-log.ts";
6
+ import { loadRunManifestById, saveRunTasks, updateRunStatus } from "../state/stores/state-store.ts";
7
7
  import type { TeamRunManifest, TeamTaskState } from "../state/types.ts";
8
8
  import { logInternalError } from "../utils/internal-error.ts";
9
9
  import { listRuns } from "./run-index.ts";
@@ -68,8 +68,8 @@ export function suggestRunIds(_prefix: string, cwd?: string): AutocompleteItem[]
68
68
  export async function suggestTaskIds(runId: string, prefix: string, cwd?: string): Promise<AutocompleteItem[] | null> {
69
69
  const resolvedCwd = cwd ?? process.cwd();
70
70
  // Dynamic import to avoid pulling state-store into the hot command-registration path.
71
- // LAZY: defer dynamic import of ../state/state-store.ts to its call site.
72
- const { loadRunManifestById } = await import("../state/state-store.ts");
71
+ // LAZY: defer dynamic import of ../state/stores/state-store.ts to its call site.
72
+ const { loadRunManifestById } = await import("../state/stores/state-store.ts");
73
73
  const loaded = loadRunManifestById(resolvedCwd, runId);
74
74
  if (!loaded) return null;
75
75
  const items: AutocompleteItem[] = loaded.tasks.map((task) => ({
@@ -1,11 +1,11 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
- import { cleanupAllTrackedTempDirs } from "../runtime/pi-args.ts";
2
+ import { cleanupAllTrackedTempDirs } from "../runtime/model/pi-args.ts";
3
3
  import { logInternalError } from "../utils/internal-error.ts";
4
4
 
5
5
  // NOTE: globalProgressTracker import kept for documentation but not directly used
6
6
  // since we don't have agent IDs to untrack. Actual progress clearing should be
7
7
  // handled by the progress tracker itself on shutdown.
8
- // import { globalProgressTracker } from "../runtime/progress-tracker.ts";
8
+ // import { globalProgressTracker } from "../runtime/output/progress-tracker.ts";
9
9
 
10
10
  /**
11
11
  * Registers cleanup handlers for graceful shutdown.
@@ -115,7 +115,7 @@ async function cleanupChildProcesses(): Promise<void> {
115
115
  // extension load path (check-lazy-imports) AND to avoid a static import cycle
116
116
  // (child-pi.ts already imports registerChildProcess from this module).
117
117
  // LAZY: defer child-pi.ts load (heavy runtime chain) + avoid static import cycle.
118
- const { killProcessPid } = await import("../runtime/child-pi.ts");
118
+ const { killProcessPid } = await import("../runtime/child-pi/child-pi.ts");
119
119
  for (const pid of pids) {
120
120
  // killProcessPid signals the whole process GROUP (-pid on POSIX, taskkill /T on
121
121
  // Windows) and escalates to SIGKILL after HARD_KILL_MS. A bare