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
@@ -341,11 +341,20 @@ export function parseConflictUri(raw: string): ParsedConflictUri | null {
341
341
  * Works by locating the recorded marker block by content (anchored to
342
342
  * `entry.startLine` as the preferred match), so out-of-band edits earlier
343
343
  * in the file that shift line numbers don't break resolution.
344
+ *
345
+ * EOL preservation: lines are split keeping each line's original ending
346
+ * bytes (CRLF / LF / none). Only the conflicting region is rewritten; every
347
+ * other line is round-tripped byte-for-byte, so a mixed-EOL file produces a
348
+ * minimal git diff (previously every line ending was normalised, rewriting
349
+ * the whole file even when only a few lines conflicted).
344
350
  */
345
351
  export function spliceConflict(originalText: string, entry: ConflictEntry, replacement: string): string {
346
- // Preserve the original line ending (CRLF or LF) for a byte-accurate round-trip.
347
- const eol = originalText.includes("\r\n") ? "\r\n" : "\n";
348
- const lines = originalText.split(/\r?\n/);
352
+ // Split preserving each line's original EOL so non-conflicting lines are
353
+ // round-tripped byte-for-byte (minimal git diff on mixed-EOL files).
354
+ const segments = splitPreservingEol(originalText);
355
+ // Content-only view (CR stripped) — identical to the old `split(/\r?\n/)`,
356
+ // so conflict detection / region matching behaviour is unchanged.
357
+ const lines = segments.map((s) => s.content);
349
358
  const expected = buildRecordedRegion(entry);
350
359
  const match = locateRegion(lines, expected, entry.startLine - 1);
351
360
  if (!match) {
@@ -356,8 +365,52 @@ export function spliceConflict(originalText: string, entry: ConflictEntry, repla
356
365
 
357
366
  const trimmed = normalizeTrailingNewline(replacement);
358
367
  const replacementLines = trimmed.split("\n");
359
- const next = [...lines.slice(0, match.startIdx), ...replacementLines, ...lines.slice(match.endIdx + 1)];
360
- return next.join(eol);
368
+ // EOL for the inserted lines: prefer the EOL that originally terminated the
369
+ // conflict region (local style); fall back to the file's dominant EOL.
370
+ const regionEol = segments[match.endIdx]?.eol ?? "";
371
+ const interEol = regionEol || (originalText.includes("\r\n") ? "\r\n" : "\n");
372
+
373
+ const out: string[] = [];
374
+ // Lines before the conflict — verbatim (original content + original EOL).
375
+ for (let i = 0; i < match.startIdx; i++) out.push(segments[i].content, segments[i].eol);
376
+ // Replacement lines — intermediate ones use the local EOL; the final one
377
+ // reuses the boundary EOL that originally separated the region from the
378
+ // following line, preserving that line's leading boundary exactly.
379
+ for (let i = 0; i < replacementLines.length; i++) {
380
+ out.push(replacementLines[i]);
381
+ out.push(i < replacementLines.length - 1 ? interEol : regionEol);
382
+ }
383
+ // Lines after the conflict — verbatim.
384
+ for (let i = match.endIdx + 1; i < segments.length; i++) out.push(segments[i].content, segments[i].eol);
385
+ return out.join("");
386
+ }
387
+
388
+ /**
389
+ * Split `text` into `{ content, eol }` segments keeping each line's exact
390
+ * ending bytes. The `content` view equals `text.split(/\r?\n/)`, but the
391
+ * original EOL (`"\r\n"`, `"\n"`, or `""` for the final line) is retained
392
+ * so callers can reconstruct the text byte-for-byte.
393
+ */
394
+ function splitPreservingEol(text: string): { content: string; eol: string }[] {
395
+ const segments: { content: string; eol: string }[] = [];
396
+ const n = text.length;
397
+ let i = 0;
398
+ while (i <= n) {
399
+ const nl = text.indexOf("\n", i);
400
+ if (nl === -1) {
401
+ segments.push({ content: text.slice(i), eol: "" });
402
+ break;
403
+ }
404
+ let contentEnd = nl;
405
+ let eol = "\n";
406
+ if (nl > 0 && text.charCodeAt(nl - 1) === 13 /* \r */) {
407
+ contentEnd = nl - 1;
408
+ eol = "\r\n";
409
+ }
410
+ segments.push({ content: text.slice(i, contentEnd), eol });
411
+ i = nl + 1;
412
+ }
413
+ return segments;
361
414
  }
362
415
 
363
416
  /** Reconstruct the recorded marker block as it should appear in the file. */
@@ -2,7 +2,7 @@
2
2
  * ndjson.ts — Canonical broker NDJSON framing primitives (encoder + decoder
3
3
  * + typed errors). Newline-delimited JSON, one frame per `\\n`.
4
4
  *
5
- * Moved out of the parallel-work stub `src/runtime/crew-broker-deps.ts`.
5
+ * Moved out of the parallel-work stub `src/runtime/broker/crew-broker-deps.ts`.
6
6
  * The public surface (MAX_BROKER_FRAME_BYTES, BrokerError, BrokerErrorCode,
7
7
  * encodeBrokerFrame, NdjsonDecoder) is preserved verbatim so importers
8
8
  * can be updated with a single import-path change.
@@ -112,4 +112,4 @@ export class NdjsonDecoder {
112
112
  // External re-exports
113
113
  // ============================================================================
114
114
  // Re-exported here for callers that import all broker primitives from ndjson.ts.
115
- export { newBrokerToken } from "../runtime/crew-broker-tokens.ts";
115
+ export { newBrokerToken } from "../runtime/broker/crew-broker-tokens.ts";
@@ -222,7 +222,46 @@ function isRecord(value: unknown): value is Record<string, unknown> {
222
222
  return true;
223
223
  }
224
224
 
225
+ // P1-6: cheap pre-filter. The common clean case (plain output, JSON event
226
+ // lines without secret-like key names) bails after one sweep instead of running
227
+ // all ~14 redaction passes. The marker set is the NECESSARY substring for every
228
+ // redactable pattern below — a string containing none of them cannot hold a
229
+ // redactable secret, so skipping is safe. Any marker present → full redaction.
230
+ // NOTE: keep this set in sync with the patterns in redactSecretString; the
231
+ // redaction-corpus test asserts every known secret type trips the pre-filter.
232
+ const SECRET_MARKERS_CASE_SENSITIVE = [
233
+ "-----BEGIN",
234
+ "eyJ",
235
+ "AKIA",
236
+ "AIza",
237
+ "sk_live_",
238
+ "xox",
239
+ // GitHub PAT prefixes (gh[pousr]_) — exact, not the over-broad "gh" which
240
+ // matched "though"/"highlight"/"might" and defeated the pre-filter skip.
241
+ "ghp_",
242
+ "gho_",
243
+ "ghu_",
244
+ "ghs_",
245
+ "ghr_",
246
+ ];
247
+ const SECRET_MARKERS_LOWER = ["bearer", "authorization", "token", "api", "key", "password", "passwd", "secret", "credential", "private"];
248
+
249
+ function mayContainSecret(value: string): boolean {
250
+ for (const m of SECRET_MARKERS_CASE_SENSITIVE) {
251
+ if (value.includes(m)) return true;
252
+ }
253
+ // Case-insensitive markers (Bearer/auth headers + inline-secret key names).
254
+ // toLowerCase is a full pass, so only pay it after the case-sensitive misses.
255
+ const lower = value.toLowerCase();
256
+ for (const m of SECRET_MARKERS_LOWER) {
257
+ if (lower.includes(m)) return true;
258
+ }
259
+ return false;
260
+ }
261
+
225
262
  export function redactSecretString(value: string): string {
263
+ // P1-6: skip the ~14 redaction passes when no secret marker is present.
264
+ if (!mayContainSecret(value)) return value;
226
265
  let result = value;
227
266
 
228
267
  // Replace PEM private keys. Skip the regex entirely on very large inputs —
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * socket-path.ts — Canonical broker Unix-socket / named-pipe path utilities.
3
3
  *
4
- * Moved out of the parallel-work stub `src/runtime/crew-broker-deps.ts`.
4
+ * Moved out of the parallel-work stub `src/runtime/broker/crew-broker-deps.ts`.
5
5
  * The public surface (hashSessionId, getBrokerSocketPath,
6
6
  * prepareBrokerSocketDir, removeStaleBrokerSocket) is preserved verbatim
7
7
  * so importers can be updated with a single import-path change.
@@ -63,7 +63,7 @@ export interface WorkflowConfig {
63
63
  * multiple ready tasks sharing role + cwd are grouped into a single
64
64
  * multi-task worker prompt to reduce per-task cold-start cost. Disabled
65
65
  * in v0.9.17 unless the workflow author opts in. See
66
- * src/runtime/coalesce-tasks.ts. */
66
+ * src/runtime/scheduling/coalesce-tasks.ts. */
67
67
  coalesceMicroTasks?: boolean;
68
68
  }
69
69
 
@@ -2,7 +2,7 @@ import { execFileSync } from "node:child_process";
2
2
  import * as fs from "node:fs";
3
3
  import * as path from "node:path";
4
4
  import { DEFAULT_PATHS } from "../config/defaults.ts";
5
- import { writeArtifact } from "../state/artifact-store.ts";
5
+ import { writeArtifact } from "../state/stores/artifact-store.ts";
6
6
  import type { TeamRunManifest } from "../state/types.ts";
7
7
  import { WINDOWS_ESSENTIAL_ENV_VARS } from "../utils/env-allowlist.ts";
8
8
  import { sanitizeEnvSecrets } from "../utils/env-filter.ts";
@@ -5,7 +5,7 @@ import * as path from "node:path";
5
5
  import { promisify } from "node:util";
6
6
  import { loadConfig } from "../config/config.ts";
7
7
  import { DEFAULT_PATHS } from "../config/defaults.ts";
8
- import { writeArtifact } from "../state/artifact-store.ts";
8
+ import { writeArtifact } from "../state/stores/artifact-store.ts";
9
9
  import type { TeamRunManifest, TeamTaskState } from "../state/types.ts";
10
10
  import { WINDOWS_ESSENTIAL_ENV_VARS } from "../utils/env-allowlist.ts";
11
11
  import { sanitizeEnvSecrets } from "../utils/env-filter.ts";
@@ -463,15 +463,30 @@ async function branchExistsAsync(repoRoot: string, branch: string): Promise<{ lo
463
463
  }
464
464
  }
465
465
 
466
+ // P1-11: `git worktree prune` is a repo-level write that cleans ALL stale
467
+ // worktrees — running it per task is pure waste. Coalesce concurrent calls
468
+ // (N tasks in a batch → 1 prune) and memoize per repo per process (within a
469
+ // run no new stale worktrees appear, so one prune suffices).
470
+ const _prunedRepos = new Set<string>();
471
+ const _pruneInFlight = new Map<string, Promise<void>>();
466
472
  async function pruneStaleWorktreesAsync(repoRoot: string): Promise<void> {
467
- try {
468
- await execFileAsync("git", ["worktree", "prune"], {
469
- cwd: repoRoot,
470
- windowsHide: true,
471
- });
472
- } catch {
473
- /* best-effort */
474
- }
473
+ if (_prunedRepos.has(repoRoot)) return;
474
+ const inFlight = _pruneInFlight.get(repoRoot);
475
+ if (inFlight) return inFlight;
476
+ const p = (async () => {
477
+ try {
478
+ await execFileAsync("git", ["worktree", "prune"], {
479
+ cwd: repoRoot,
480
+ windowsHide: true,
481
+ });
482
+ } catch {
483
+ /* best-effort */
484
+ }
485
+ _prunedRepos.add(repoRoot);
486
+ _pruneInFlight.delete(repoRoot);
487
+ })();
488
+ _pruneInFlight.set(repoRoot, p);
489
+ return p;
475
490
  }
476
491
 
477
492
  /**
@@ -568,7 +583,7 @@ export function overlaySeedPaths(repoRoot: string, worktreePath: string, seedPat
568
583
  * recovered via `git apply` / manual restore. Best-effort: a snapshot failure
569
584
  * only logs (it must not block the clean-slate reuse flow).
570
585
  */
571
- function snapshotDirtyWorktree(manifest: TeamRunManifest, task: TeamTaskState, worktreePath: string, dirtyStatus: string): boolean {
586
+ export function snapshotDirtyWorktree(manifest: TeamRunManifest, task: TeamTaskState, worktreePath: string, dirtyStatus: string): boolean {
572
587
  try {
573
588
  const parts: string[] = [
574
589
  `# Worktree recovery snapshot`,
@@ -576,15 +591,18 @@ function snapshotDirtyWorktree(manifest: TeamRunManifest, task: TeamTaskState, w
576
591
  `capturedAt: ${new Date().toISOString()}`,
577
592
  "",
578
593
  ];
594
+ // ST-1: use --binary so tracked binary modifications are recoverable via `git apply`.
579
595
  let trackedDiff = "";
580
596
  try {
581
- trackedDiff = git(worktreePath, ["diff", "HEAD"]);
597
+ trackedDiff = git(worktreePath, ["diff", "HEAD", "--binary"]);
582
598
  } catch {
583
599
  trackedDiff = "";
584
600
  }
585
601
  if (trackedDiff.trim()) {
586
- parts.push("## Tracked changes (`git diff HEAD`)", "```diff", trackedDiff, "```", "");
602
+ parts.push("## Tracked changes (`git diff HEAD --binary`)", "```diff", trackedDiff, "```", "");
587
603
  }
604
+ // ST-1: per-file byte cap — skip/truncate larger files with a note to avoid OOM.
605
+ const MAX_FILE_BYTES = 256 * 1024;
588
606
  for (const line of dirtyStatus.split("\n")) {
589
607
  if (!line.startsWith("?? ")) continue;
590
608
  // Strip the "?? " prefix and surrounding git quotes.
@@ -593,8 +611,27 @@ function snapshotDirtyWorktree(manifest: TeamRunManifest, task: TeamTaskState, w
593
611
  try {
594
612
  const abs = path.join(worktreePath, rel);
595
613
  if (!fs.existsSync(abs) || fs.statSync(abs).isDirectory()) continue;
596
- const content = fs.readFileSync(abs, "utf-8");
597
- parts.push(`## Untracked file: ${rel}`, "```", content, "```", "");
614
+ // ST-1: read raw bytes (not utf-8) so binary files are not corrupted.
615
+ const buf = fs.readFileSync(abs);
616
+ const originalSize = buf.byteLength;
617
+ let data: Buffer = buf;
618
+ let note = "";
619
+ if (originalSize > MAX_FILE_BYTES) {
620
+ data = buf.subarray(0, MAX_FILE_BYTES);
621
+ note = ` (truncated: ${originalSize} → ${MAX_FILE_BYTES} bytes)`;
622
+ }
623
+ // ST-1: detect non-UTF-8 via fatal TextDecoder; base64-encode binary files.
624
+ let isUtf8 = true;
625
+ try {
626
+ new TextDecoder("utf-8", { fatal: true }).decode(data);
627
+ } catch {
628
+ isUtf8 = false;
629
+ }
630
+ if (isUtf8) {
631
+ parts.push(`## Untracked file: ${rel}${note}`, "```", data.toString("utf-8"), "```", "");
632
+ } else {
633
+ parts.push(`## Untracked file: ${rel}${note} (base64-encoded binary)`, "```base64", data.toString("base64"), "```", "");
634
+ }
598
635
  } catch {
599
636
  /* skip unreadable/unstat-able entry */
600
637
  }
@@ -729,8 +766,8 @@ export function prepareTaskWorkspace(manifest: TeamRunManifest, task: TeamTaskSt
729
766
  if (currentBranch !== branch) {
730
767
  throw new Error(`Existing worktree branch mismatch at ${worktreePath}: expected '${branch}', got '${currentBranch}'.`);
731
768
  }
732
- // Check for uncommitted changes from previous run before reusing
733
- const dirtyStatus = git(worktreePath, ["status", "--porcelain"]);
769
+ // ST-1: use -uall so untracked directories are expanded to individual files.
770
+ const dirtyStatus = git(worktreePath, ["status", "--porcelain", "-uall"]);
734
771
  if (dirtyStatus.trim()) {
735
772
  // Snapshot uncommitted work to a recovery artifact BEFORE discarding, so the
736
773
  // previous run's changes are never silently destroyed on reuse.
@@ -889,7 +926,8 @@ export async function prepareTaskWorkspaceAsync(
889
926
  if (currentBranch !== branch) {
890
927
  throw new Error(`Existing worktree branch mismatch at ${worktreePath}: expected '${branch}', got '${currentBranch}'.`);
891
928
  }
892
- const dirtyStatus = await gitAsync(worktreePath, ["status", "--porcelain"]);
929
+ // ST-1: use -uall so untracked directories are expanded to individual files.
930
+ const dirtyStatus = await gitAsync(worktreePath, ["status", "--porcelain", "-uall"]);
893
931
  if (dirtyStatus.trim()) {
894
932
  const snapshotOk = snapshotDirtyWorktree(manifest, task, worktreePath, dirtyStatus);
895
933
  if (snapshotOk) {
@@ -1045,52 +1083,78 @@ export async function captureWorktreeDiffAsync(worktreePath: string): Promise<st
1045
1083
  * assertCleanLeader, pruneStaleWorktrees, sanitizeBranchPart,
1046
1084
  * linkNodeModulesIfPresent) but with a minimal, task-free signature.
1047
1085
  *
1048
- * Returns `undefined` when worktree creation is unavailable (no git repo, dirty
1049
- * leader, git error) so the caller (`ctx.agent`) can fall back gracefully.
1086
+ * Returns `undefined` when worktree isolation is genuinely unavailable (no git
1087
+ * repo, dirty leader) so the caller (`ctx.agent`) can fall back gracefully.
1088
+ * ST-15: when creation was attempted but failed (e.g. disk full), this THROWS
1089
+ * instead of returning undefined so the caller never silently runs in the
1090
+ * leader repo. The branch + path suffix is non-deterministic so a 2nd call for
1091
+ * the same agentId always produces a distinct worktree.
1050
1092
  */
1051
1093
  export function prepareAgentWorktree(manifest: TeamRunManifest, agentId: string): PreparedTaskWorkspace | undefined {
1094
+ // ST-15: Split preconditions from worktree creation.
1095
+ // Precondition failures (no git repo, dirty leader) → return undefined so the
1096
+ // caller falls back gracefully (worktree isolation is genuinely unavailable).
1097
+ let repoRoot: string;
1098
+ let loadedConfig: ReturnType<typeof loadConfig>;
1052
1099
  try {
1053
- const repoRoot = findGitRoot(manifest.cwd);
1054
- const loadedConfig = loadConfig(manifest.cwd);
1100
+ repoRoot = findGitRoot(manifest.cwd);
1101
+ loadedConfig = loadConfig(manifest.cwd);
1055
1102
  if (loadedConfig.config.requireCleanWorktreeLeader !== false) assertCleanLeader(repoRoot);
1056
- const sanitizedRunId = manifest.runId.replace(/[^a-zA-Z0-9._-]/g, "-").replace(/^-+|-+$/g, "") || "run";
1057
- const worktreeRoot = path.join(projectCrewRoot(manifest.cwd), DEFAULT_PATHS.state.worktreesSubdir, sanitizedRunId);
1058
- fs.mkdirSync(worktreeRoot, { recursive: true });
1059
- const sanitizedAgentId = sanitizeBranchPart(agentId);
1060
- const worktreePath = path.join(worktreeRoot, sanitizedAgentId);
1061
- const branch = `pi-crew/${sanitizedRunId}/${sanitizedAgentId}`;
1062
- pruneStaleWorktrees(repoRoot);
1063
- git(repoRoot, ["worktree", "add", "-b", branch, worktreePath, "HEAD"]);
1064
- const nodeModulesLinked =
1065
- loadedConfig.config.worktree?.linkNodeModules === true ? linkNodeModulesIfPresent(repoRoot, worktreePath) : false;
1066
- return { cwd: worktreePath, worktreePath, branch, nodeModulesLinked };
1067
1103
  } catch {
1068
- // Graceful fallback: no git repo, dirty leader, or git error → run normally.
1104
+ // Graceful fallback: no git repo or dirty leader → run normally in cwd.
1069
1105
  return undefined;
1070
1106
  }
1107
+
1108
+ // ST-15: NON-DETERMINISTIC branch + path suffix. The OLD deterministic name
1109
+ // (`pi-crew/<runId>/<agentId>`) made a 2nd call for the same agent collide
1110
+ // ("already exists") → catch → returned undefined → the run silently fell
1111
+ // back to the leader repo (isolation lost, no error). The timestamp +
1112
+ // short-uuid suffix makes every call produce a distinct worktree.
1113
+ // Creation failures here THROW (not undefined) so callers never silently lose
1114
+ // isolation when worktree creation was requested but failed.
1115
+ const sanitizedRunId = manifest.runId.replace(/[^a-zA-Z0-9._-]/g, "-").replace(/^-+|-+$/g, "") || "run";
1116
+ const worktreeRoot = path.join(projectCrewRoot(manifest.cwd), DEFAULT_PATHS.state.worktreesSubdir, sanitizedRunId);
1117
+ fs.mkdirSync(worktreeRoot, { recursive: true });
1118
+ const sanitizedAgentId = sanitizeBranchPart(agentId);
1119
+ const stamp = `${Date.now()}-${randomBytes(4).toString("hex")}`;
1120
+ const worktreePath = path.join(worktreeRoot, `${sanitizedAgentId}-${stamp}`);
1121
+ const branch = `pi-crew/${sanitizedRunId}/${sanitizedAgentId}-${stamp}`;
1122
+ pruneStaleWorktrees(repoRoot);
1123
+ git(repoRoot, ["worktree", "add", "-b", branch, worktreePath, "HEAD"]);
1124
+ const nodeModulesLinked =
1125
+ loadedConfig.config.worktree?.linkNodeModules === true ? linkNodeModulesIfPresent(repoRoot, worktreePath) : false;
1126
+ return { cwd: worktreePath, worktreePath, branch, nodeModulesLinked };
1071
1127
  }
1072
1128
 
1073
1129
  /** Async version of prepareAgentWorktree — yields the event loop during git operations. */
1074
1130
  export async function prepareAgentWorktreeAsync(manifest: TeamRunManifest, agentId: string): Promise<PreparedTaskWorkspace | undefined> {
1131
+ // ST-15: Split preconditions from worktree creation (see prepareAgentWorktree).
1132
+ let repoRoot: string;
1133
+ let loadedConfig: ReturnType<typeof loadConfig>;
1075
1134
  try {
1076
- const repoRoot = await findGitRootAsync(manifest.cwd);
1077
- const loadedConfig = loadConfig(manifest.cwd);
1135
+ repoRoot = await findGitRootAsync(manifest.cwd);
1136
+ loadedConfig = loadConfig(manifest.cwd);
1078
1137
  if (loadedConfig.config.requireCleanWorktreeLeader !== false) await assertCleanLeaderAsync(repoRoot);
1079
- const sanitizedRunId = manifest.runId.replace(/[^a-zA-Z0-9._-]/g, "-").replace(/^-+|-+$/g, "") || "run";
1080
- const worktreeRoot = path.join(projectCrewRoot(manifest.cwd), DEFAULT_PATHS.state.worktreesSubdir, sanitizedRunId);
1081
- fs.mkdirSync(worktreeRoot, { recursive: true });
1082
- const sanitizedAgentId = sanitizeBranchPart(agentId);
1083
- const worktreePath = path.join(worktreeRoot, sanitizedAgentId);
1084
- const branch = `pi-crew/${sanitizedRunId}/${sanitizedAgentId}`;
1085
- await pruneStaleWorktreesAsync(repoRoot);
1086
- await gitAsync(repoRoot, ["worktree", "add", "-b", branch, worktreePath, "HEAD"]);
1087
- const nodeModulesLinked =
1088
- loadedConfig.config.worktree?.linkNodeModules === true ? linkNodeModulesIfPresent(repoRoot, worktreePath) : false;
1089
- return { cwd: worktreePath, worktreePath, branch, nodeModulesLinked };
1090
1138
  } catch {
1091
- // Graceful fallback: no git repo, dirty leader, or git error → run normally.
1139
+ // Graceful fallback: no git repo or dirty leader → run normally in cwd.
1092
1140
  return undefined;
1093
1141
  }
1142
+
1143
+ // ST-15: NON-DETERMINISTIC branch + path suffix — a 2nd call for the same
1144
+ // agentId creates a DISTINCT worktree instead of colliding. Creation failures
1145
+ // here THROW so callers never silently fall back to the leader repo.
1146
+ const sanitizedRunId = manifest.runId.replace(/[^a-zA-Z0-9._-]/g, "-").replace(/^-+|-+$/g, "") || "run";
1147
+ const worktreeRoot = path.join(projectCrewRoot(manifest.cwd), DEFAULT_PATHS.state.worktreesSubdir, sanitizedRunId);
1148
+ fs.mkdirSync(worktreeRoot, { recursive: true });
1149
+ const sanitizedAgentId = sanitizeBranchPart(agentId);
1150
+ const stamp = `${Date.now()}-${randomBytes(4).toString("hex")}`;
1151
+ const worktreePath = path.join(worktreeRoot, `${sanitizedAgentId}-${stamp}`);
1152
+ const branch = `pi-crew/${sanitizedRunId}/${sanitizedAgentId}-${stamp}`;
1153
+ await pruneStaleWorktreesAsync(repoRoot);
1154
+ await gitAsync(repoRoot, ["worktree", "add", "-b", branch, worktreePath, "HEAD"]);
1155
+ const nodeModulesLinked =
1156
+ loadedConfig.config.worktree?.linkNodeModules === true ? linkNodeModulesIfPresent(repoRoot, worktreePath) : false;
1157
+ return { cwd: worktreePath, worktreePath, branch, nodeModulesLinked };
1094
1158
  }
1095
1159
 
1096
1160
  /**
@@ -6,7 +6,7 @@ topology: dynamic
6
6
 
7
7
  # Chain Workflow - Sequential execution with context passing
8
8
 
9
- **Source:** `docs/pi-boomerang-integration-plan.md`
9
+ **Source:** pi-boomerang integration plan
10
10
  **Syntax:** `step1 -> step2 -> step3`
11
11
  **Version:** 1.0.0
12
12
 
@@ -255,4 +255,4 @@ pi team run --chain "@step1 -> @step2" --continue-on-error
255
255
 
256
256
  ---
257
257
 
258
- *Generated from pi-boomerang integration plan. See `docs/pi-boomerang-integration-plan.md` for full specification.*
258
+ *Generated from pi-boomerang integration plan.*