pi-crew 0.9.16 → 0.9.17

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 (432) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/README.md +19 -0
  3. package/dist/build-meta.json +21790 -0
  4. package/dist/index.mjs +83070 -0
  5. package/dist/index.mjs.map +7 -0
  6. package/docs/A +358 -0
  7. package/docs/M-A +357 -0
  8. package/docs/REVIEW-FINDINGS-2026-06 +357 -0
  9. package/docs/Y +357 -0
  10. package/docs/a +357 -0
  11. package/docs/aA +358 -0
  12. package/docs/archive/README.md +91 -0
  13. package/docs/patterns/command-agent-skill.md +1 -1
  14. package/docs/skills/REFERENCE.md +0 -17
  15. package/docs//303/242mmaAAA/303/242 +357 -0
  16. package/index.bundle.ts +25 -0
  17. package/index.ts +95 -4
  18. package/package.json +15 -4
  19. package/skills/iterative-audit/SKILL.md +0 -1
  20. package/skills/widget-rendering/SKILL.md +17 -0
  21. package/src/adapters/claude-adapter.ts +1 -3
  22. package/src/adapters/export-util.ts +16 -16
  23. package/src/adapters/index.ts +5 -5
  24. package/src/agents/agent-config.ts +20 -14
  25. package/src/agents/agent-serializer.ts +1 -1
  26. package/src/agents/discover-agents.ts +83 -39
  27. package/src/benchmark/benchmark-runner.ts +51 -51
  28. package/src/benchmark/feedback-loop.ts +1 -1
  29. package/src/config/config.ts +166 -590
  30. package/src/config/defaults.ts +28 -2
  31. package/src/config/drift-detector.ts +11 -14
  32. package/src/config/markers.ts +201 -203
  33. package/src/config/resilient-parser.ts +14 -6
  34. package/src/config/role-tools.ts +3 -3
  35. package/src/config/suggestions.ts +5 -12
  36. package/src/config/types.ts +9 -25
  37. package/src/errors.ts +151 -157
  38. package/src/extension/action-suggestions.ts +54 -9
  39. package/src/extension/async-notifier.ts +43 -13
  40. package/src/extension/autonomous-policy.ts +77 -37
  41. package/src/extension/command-completions.ts +9 -8
  42. package/src/extension/context-status-injection.ts +14 -12
  43. package/src/extension/crew-autocomplete.ts +8 -16
  44. package/src/extension/crew-cleanup.ts +2 -1
  45. package/src/extension/crew-shortcuts.ts +9 -6
  46. package/src/extension/cross-extension-rpc.ts +136 -42
  47. package/src/extension/help.ts +1 -1
  48. package/src/extension/import-index.ts +10 -5
  49. package/src/extension/knowledge-injection.ts +88 -15
  50. package/src/extension/management.ts +89 -349
  51. package/src/extension/message-renderers.ts +3 -4
  52. package/src/extension/notification-router.ts +22 -5
  53. package/src/extension/notification-sink.ts +6 -3
  54. package/src/extension/pi-api.ts +17 -8
  55. package/src/extension/plan-orchestrate.ts +8 -27
  56. package/src/extension/project-init.ts +21 -6
  57. package/src/extension/register.ts +329 -975
  58. package/src/extension/registration/artifact-cleanup.ts +9 -4
  59. package/src/extension/registration/command-utils.ts +5 -1
  60. package/src/extension/registration/commands.ts +806 -314
  61. package/src/extension/registration/compaction-guard.ts +15 -15
  62. package/src/extension/registration/lifecycle.ts +259 -0
  63. package/src/extension/registration/observability.ts +293 -0
  64. package/src/extension/registration/subagent-helpers.ts +29 -7
  65. package/src/extension/registration/subagent-tools.ts +253 -44
  66. package/src/extension/registration/team-tool.ts +19 -84
  67. package/src/extension/registration/ui.ts +168 -0
  68. package/src/extension/registration/viewers.ts +64 -24
  69. package/src/extension/result-watcher.ts +18 -7
  70. package/src/extension/run-bundle-schema.ts +21 -6
  71. package/src/extension/run-export.ts +15 -6
  72. package/src/extension/run-import.ts +64 -29
  73. package/src/extension/run-index.ts +28 -9
  74. package/src/extension/run-maintenance.ts +32 -12
  75. package/src/extension/session-summary.ts +1 -1
  76. package/src/extension/team-manager-command.ts +64 -7
  77. package/src/extension/team-onboard.ts +151 -150
  78. package/src/extension/team-recommendation.ts +121 -21
  79. package/src/extension/team-tool/anchor.ts +31 -64
  80. package/src/extension/team-tool/api.ts +929 -141
  81. package/src/extension/team-tool/auto-summarize.ts +14 -26
  82. package/src/extension/team-tool/cache-control.ts +1 -5
  83. package/src/extension/team-tool/cancel.ts +138 -38
  84. package/src/extension/team-tool/chain-dispatch.ts +5 -13
  85. package/src/extension/team-tool/chain-executor.ts +29 -51
  86. package/src/extension/team-tool/config-patch.ts +1 -1
  87. package/src/extension/team-tool/context.ts +40 -20
  88. package/src/extension/team-tool/destructive-gate.ts +10 -5
  89. package/src/extension/team-tool/doctor.ts +170 -51
  90. package/src/extension/team-tool/explain.ts +228 -214
  91. package/src/extension/team-tool/failure-patterns.ts +3 -9
  92. package/src/extension/team-tool/goal-wrap.ts +71 -29
  93. package/src/extension/team-tool/goal.ts +185 -35
  94. package/src/extension/team-tool/handle-schedule.ts +34 -15
  95. package/src/extension/team-tool/handle-settings.ts +94 -56
  96. package/src/extension/team-tool/health-monitor.ts +27 -108
  97. package/src/extension/team-tool/inspect.ts +42 -9
  98. package/src/extension/team-tool/intent-policy.ts +4 -1
  99. package/src/extension/team-tool/lifecycle-actions.ts +244 -48
  100. package/src/extension/team-tool/orchestrate.ts +7 -18
  101. package/src/extension/team-tool/parallel-dispatch.ts +51 -29
  102. package/src/extension/team-tool/plan.ts +29 -5
  103. package/src/extension/team-tool/respond.ts +49 -16
  104. package/src/extension/team-tool/run-not-found.ts +3 -8
  105. package/src/extension/team-tool/run.ts +80 -317
  106. package/src/extension/team-tool/status.ts +135 -43
  107. package/src/extension/team-tool/workflow-manage.ts +92 -25
  108. package/src/extension/team-tool-types.ts +8 -1
  109. package/src/extension/team-tool.ts +142 -551
  110. package/src/extension/validate-resources.ts +39 -8
  111. package/src/hooks/registry.ts +66 -17
  112. package/src/hooks/types.ts +1 -1
  113. package/src/i18n.ts +25 -11
  114. package/src/observability/correlation.ts +17 -3
  115. package/src/observability/event-bus.ts +51 -56
  116. package/src/observability/event-to-metric.ts +117 -15
  117. package/src/observability/exporters/otlp-exporter.ts +56 -17
  118. package/src/observability/exporters/prometheus-exporter.ts +1 -1
  119. package/src/observability/metric-registry.ts +16 -4
  120. package/src/observability/metric-retention.ts +8 -2
  121. package/src/observability/metric-sink.ts +11 -3
  122. package/src/observability/metrics-primitives.ts +42 -9
  123. package/src/plugins/plugin-define.ts +2 -2
  124. package/src/plugins/plugin-registry.ts +25 -25
  125. package/src/plugins/plugins/index.ts +1 -1
  126. package/src/plugins/plugins/nextjs.ts +16 -16
  127. package/src/plugins/plugins/vite.ts +7 -11
  128. package/src/plugins/plugins/vitest.ts +6 -11
  129. package/src/runtime/adaptive-plan.ts +225 -40
  130. package/src/runtime/agent-control.ts +58 -15
  131. package/src/runtime/agent-memory.ts +15 -9
  132. package/src/runtime/agent-observability.ts +10 -2
  133. package/src/runtime/anchor-manager.ts +27 -25
  134. package/src/runtime/async-marker.ts +7 -1
  135. package/src/runtime/async-runner.ts +27 -23
  136. package/src/runtime/auto-summarize.ts +7 -13
  137. package/src/runtime/background-runner.ts +189 -251
  138. package/src/runtime/batch-barrier.ts +18 -16
  139. package/src/runtime/cancellation-token.ts +16 -6
  140. package/src/runtime/cancellation.ts +46 -8
  141. package/src/runtime/capability-inventory.ts +6 -4
  142. package/src/runtime/chain-parser.ts +44 -11
  143. package/src/runtime/chain-runner.ts +63 -69
  144. package/src/runtime/checkpoint.ts +12 -56
  145. package/src/runtime/child-pi.ts +343 -78
  146. package/src/runtime/coalesce-tasks.ts +268 -0
  147. package/src/runtime/code-summary.ts +71 -26
  148. package/src/runtime/compact-stages/index.ts +15 -5
  149. package/src/runtime/compact-stages/tail-capture-stage.ts +7 -2
  150. package/src/runtime/compact-stages/truncation-stage.ts +4 -1
  151. package/src/runtime/compaction-summary.ts +17 -10
  152. package/src/runtime/completion-guard.ts +33 -16
  153. package/src/runtime/crash-classification.ts +28 -7
  154. package/src/runtime/crash-recovery.ts +177 -37
  155. package/src/runtime/crew-agent-records.ts +145 -47
  156. package/src/runtime/crew-hooks.ts +9 -24
  157. package/src/runtime/cross-extension-rpc.ts +25 -23
  158. package/src/runtime/custom-tools/irc-tool.ts +43 -15
  159. package/src/runtime/custom-tools/submit-result-tool.ts +16 -5
  160. package/src/runtime/delivery-coordinator.ts +34 -7
  161. package/src/runtime/delta-conflict.ts +9 -21
  162. package/src/runtime/deterministic-ast.ts +1 -1
  163. package/src/runtime/diagnostic-export.ts +53 -20
  164. package/src/runtime/direct-run.ts +12 -2
  165. package/src/runtime/dwf-state-store.ts +1 -1
  166. package/src/runtime/dynamic-workflow-context.ts +186 -58
  167. package/src/runtime/dynamic-workflow-runner.ts +42 -20
  168. package/src/runtime/effectiveness.ts +16 -8
  169. package/src/runtime/errors/crew-errors.ts +7 -11
  170. package/src/runtime/event-stream-bridge.ts +9 -3
  171. package/src/runtime/foreground-control.ts +54 -14
  172. package/src/runtime/foreground-watchdog.ts +9 -6
  173. package/src/runtime/goal-achievement.ts +27 -10
  174. package/src/runtime/goal-evaluator.ts +54 -19
  175. package/src/runtime/goal-loop-runner.ts +280 -99
  176. package/src/runtime/goal-state-store.ts +27 -17
  177. package/src/runtime/green-contract.ts +11 -2
  178. package/src/runtime/group-join.ts +64 -31
  179. package/src/runtime/handoff-manager.ts +37 -42
  180. package/src/runtime/heartbeat-gradient.ts +10 -2
  181. package/src/runtime/heartbeat-watcher.ts +32 -6
  182. package/src/runtime/hidden-handoff.ts +12 -30
  183. package/src/runtime/important-line-classifier.ts +12 -2
  184. package/src/runtime/iteration-hooks.ts +25 -15
  185. package/src/runtime/live-agent-control.ts +55 -7
  186. package/src/runtime/live-agent-manager.ts +130 -27
  187. package/src/runtime/live-control-realtime.ts +23 -3
  188. package/src/runtime/live-irc.ts +4 -1
  189. package/src/runtime/live-session-health.ts +12 -4
  190. package/src/runtime/live-session-runtime.ts +379 -117
  191. package/src/runtime/manifest-cache.ts +28 -12
  192. package/src/runtime/mcp-proxy.ts +8 -16
  193. package/src/runtime/metric-parser.ts +1 -5
  194. package/src/runtime/model-fallback.ts +55 -18
  195. package/src/runtime/model-resolver.ts +2 -6
  196. package/src/runtime/model-scope.ts +19 -3
  197. package/src/runtime/notebook-helpers.ts +60 -62
  198. package/src/runtime/orphan-worker-registry.ts +37 -26
  199. package/src/runtime/output-validator.ts +18 -3
  200. package/src/runtime/overflow-recovery.ts +5 -4
  201. package/src/runtime/parallel-research.ts +29 -5
  202. package/src/runtime/parallel-utils.ts +9 -11
  203. package/src/runtime/path-overlap.ts +150 -0
  204. package/src/runtime/peer-dep.ts +12 -17
  205. package/src/runtime/per-write-validator.ts +1 -3
  206. package/src/runtime/phase-tracker.ts +342 -330
  207. package/src/runtime/pi-args.ts +26 -8
  208. package/src/runtime/pi-json-output.ts +1 -1
  209. package/src/runtime/pi-spawn.ts +30 -19
  210. package/src/runtime/pipeline-runner.ts +56 -55
  211. package/src/runtime/plan-templates.ts +5 -6
  212. package/src/runtime/policy-engine.ts +43 -7
  213. package/src/runtime/post-checks.ts +12 -4
  214. package/src/runtime/post-exit-stdio-guard.ts +2 -2
  215. package/src/runtime/process-lifecycle.ts +20 -10
  216. package/src/runtime/process-status.ts +16 -5
  217. package/src/runtime/progress-event-coalescer.ts +2 -1
  218. package/src/runtime/progress-tracker.ts +103 -103
  219. package/src/runtime/prose-compressor.ts +9 -11
  220. package/src/runtime/recovery-recipes.ts +118 -24
  221. package/src/runtime/replace.ts +25 -10
  222. package/src/runtime/resilient-edit.ts +10 -25
  223. package/src/runtime/result-extractor.ts +1 -2
  224. package/src/runtime/retry-executor.ts +20 -4
  225. package/src/runtime/retry-runner.ts +26 -50
  226. package/src/runtime/role-permission.ts +6 -1
  227. package/src/runtime/run-coalesced-task-group.ts +256 -0
  228. package/src/runtime/run-drift.ts +14 -15
  229. package/src/runtime/run-tracker.ts +6 -28
  230. package/src/runtime/runtime-policy.ts +1 -6
  231. package/src/runtime/runtime-resolver.ts +80 -15
  232. package/src/runtime/scheduler.ts +47 -18
  233. package/src/runtime/semaphore.ts +5 -7
  234. package/src/runtime/sensitive-paths.ts +2 -1
  235. package/src/runtime/session-usage.ts +1 -1
  236. package/src/runtime/settings-store.ts +16 -12
  237. package/src/runtime/sidechain-output.ts +6 -2
  238. package/src/runtime/single-agent-compose.ts +1 -4
  239. package/src/runtime/skill-effectiveness.ts +29 -97
  240. package/src/runtime/skill-instructions.ts +40 -83
  241. package/src/runtime/stale-reconciler.ts +73 -197
  242. package/src/runtime/stream-preview.ts +1 -1
  243. package/src/runtime/streaming-output.ts +1 -1
  244. package/src/runtime/subagent-manager.ts +44 -169
  245. package/src/runtime/subprocess-tool-registry.ts +4 -1
  246. package/src/runtime/supervisor-contact.ts +10 -5
  247. package/src/runtime/task-display.ts +19 -5
  248. package/src/runtime/task-graph-scheduler.ts +95 -21
  249. package/src/runtime/task-graph.ts +5 -11
  250. package/src/runtime/task-health.ts +54 -47
  251. package/src/runtime/task-id.ts +11 -18
  252. package/src/runtime/task-output-context.ts +265 -81
  253. package/src/runtime/task-packet.ts +12 -20
  254. package/src/runtime/task-quality.ts +6 -14
  255. package/src/runtime/task-runner/context-retrieval.ts +4 -13
  256. package/src/runtime/task-runner/live-executor.ts +114 -36
  257. package/src/runtime/task-runner/output-splitter.ts +152 -0
  258. package/src/runtime/task-runner/progress.ts +50 -12
  259. package/src/runtime/task-runner/prompt-builder.ts +31 -7
  260. package/src/runtime/task-runner/prompt-pipeline.ts +31 -7
  261. package/src/runtime/task-runner/result-utils.ts +3 -1
  262. package/src/runtime/task-runner/retrieval-orchestrator.ts +310 -0
  263. package/src/runtime/task-runner/run-projection.ts +27 -8
  264. package/src/runtime/task-runner/state-helpers.ts +29 -8
  265. package/src/runtime/task-runner/tail-read.ts +2 -6
  266. package/src/runtime/task-runner.ts +180 -326
  267. package/src/runtime/team-runner-artifacts.ts +13 -0
  268. package/src/runtime/team-runner.ts +456 -974
  269. package/src/runtime/tool-output-pruner.ts +6 -9
  270. package/src/runtime/tool-progress.ts +11 -21
  271. package/src/runtime/verification-gates.ts +33 -24
  272. package/src/runtime/verification-integrity.ts +1 -4
  273. package/src/runtime/verification-worktree.ts +62 -12
  274. package/src/runtime/worker-heartbeat.ts +5 -1
  275. package/src/runtime/worker-startup.ts +29 -5
  276. package/src/runtime/workflow-state.ts +17 -9
  277. package/src/runtime/workspace-lock.ts +30 -35
  278. package/src/runtime/workspace-tree.ts +20 -32
  279. package/src/runtime/yield-handler.ts +43 -9
  280. package/src/runtime/zombie-scanner.ts +5 -4
  281. package/src/schema/config-schema.ts +266 -172
  282. package/src/schema/team-tool-schema.ts +29 -74
  283. package/src/schema/validation-types.ts +25 -17
  284. package/src/skills/discover-skills.ts +35 -10
  285. package/src/skills/skill-templates.ts +109 -27
  286. package/src/skills/validate.ts +26 -8
  287. package/src/state/active-run-registry.ts +87 -28
  288. package/src/state/artifact-store.ts +9 -5
  289. package/src/state/atomic-write-v2.ts +85 -63
  290. package/src/state/atomic-write.ts +105 -26
  291. package/src/state/blob-store.ts +47 -20
  292. package/src/state/contracts.ts +20 -5
  293. package/src/state/crew-init.ts +5 -22
  294. package/src/state/decision-ledger.ts +19 -73
  295. package/src/state/event-log-rotation.ts +41 -15
  296. package/src/state/event-log.ts +168 -53
  297. package/src/state/event-reconstructor.ts +11 -1
  298. package/src/state/gitignore-manager.ts +2 -8
  299. package/src/state/health-store.ts +57 -57
  300. package/src/state/hook-instinct-bridge.ts +1 -1
  301. package/src/state/hook-integrations.ts +1 -1
  302. package/src/state/instinct-store.ts +17 -5
  303. package/src/state/jsonl-writer.ts +1 -1
  304. package/src/state/locks.ts +23 -9
  305. package/src/state/mailbox.ts +151 -28
  306. package/src/state/observation-store.ts +20 -14
  307. package/src/state/run-cache.ts +142 -135
  308. package/src/state/run-graph.ts +6 -15
  309. package/src/state/run-metrics.ts +5 -18
  310. package/src/state/schedule.ts +15 -9
  311. package/src/state/state-store.ts +129 -45
  312. package/src/state/task-claims.ts +12 -2
  313. package/src/state/tiered-eval.ts +52 -43
  314. package/src/state/types-eval.ts +2 -2
  315. package/src/state/types.ts +24 -20
  316. package/src/state/usage.ts +20 -4
  317. package/src/state/worker-atomic-writer.ts +6 -3
  318. package/src/subagents/index.ts +2 -2
  319. package/src/teams/discover-teams.ts +21 -6
  320. package/src/tools/safe-bash-extension.ts +5 -6
  321. package/src/tools/safe-bash.ts +10 -11
  322. package/src/types/new-api-types.ts +6 -10
  323. package/src/ui/agent-management-overlay.ts +52 -40
  324. package/src/ui/card-colors.ts +13 -4
  325. package/src/ui/crew-footer.ts +8 -7
  326. package/src/ui/crew-select-list.ts +1 -1
  327. package/src/ui/dashboard-panes/agents-pane.ts +41 -25
  328. package/src/ui/dashboard-panes/cancellation-pane.ts +1 -1
  329. package/src/ui/dashboard-panes/capability-pane.ts +32 -15
  330. package/src/ui/dashboard-panes/health-pane.ts +2 -1
  331. package/src/ui/dashboard-panes/metrics-pane.ts +4 -1
  332. package/src/ui/dashboard-panes/progress-pane.ts +12 -9
  333. package/src/ui/heartbeat-aggregator.ts +15 -4
  334. package/src/ui/keybinding-map.ts +40 -7
  335. package/src/ui/live-conversation-overlay.ts +36 -20
  336. package/src/ui/live-duration.ts +1 -4
  337. package/src/ui/live-run-sidebar.ts +88 -25
  338. package/src/ui/loaders.ts +2 -8
  339. package/src/ui/mascot.ts +20 -36
  340. package/src/ui/overlays/agent-picker-overlay.ts +11 -3
  341. package/src/ui/overlays/confirm-overlay.ts +4 -2
  342. package/src/ui/overlays/help-overlay.ts +25 -14
  343. package/src/ui/overlays/mailbox-compose-overlay.ts +48 -11
  344. package/src/ui/overlays/mailbox-compose-preview.ts +20 -5
  345. package/src/ui/overlays/mailbox-detail-overlay.ts +27 -6
  346. package/src/ui/pi-ui-compat.ts +7 -7
  347. package/src/ui/powerbar-publisher.ts +120 -42
  348. package/src/ui/render-diff.ts +10 -3
  349. package/src/ui/render-scheduler.ts +12 -4
  350. package/src/ui/run-action-dispatcher.ts +81 -18
  351. package/src/ui/run-dashboard.ts +172 -76
  352. package/src/ui/run-event-bus.ts +59 -37
  353. package/src/ui/run-snapshot-cache.ts +276 -86
  354. package/src/ui/settings-overlay.ts +361 -74
  355. package/src/ui/status-colors.ts +12 -1
  356. package/src/ui/syntax-highlight.ts +1 -1
  357. package/src/ui/theme-adapter.ts +16 -14
  358. package/src/ui/theme-discovery.ts +13 -2
  359. package/src/ui/tool-progress-formatter.ts +7 -7
  360. package/src/ui/tool-render.ts +128 -56
  361. package/src/ui/tool-renderers/brief-mode.ts +45 -27
  362. package/src/ui/tool-renderers/index.ts +109 -43
  363. package/src/ui/transcript-cache.ts +32 -6
  364. package/src/ui/transcript-entries.ts +25 -23
  365. package/src/ui/transcript-viewer.ts +78 -29
  366. package/src/ui/widget/index.ts +99 -40
  367. package/src/ui/widget/widget-formatters.ts +13 -6
  368. package/src/ui/widget/widget-model.ts +19 -8
  369. package/src/ui/widget/widget-renderer.ts +23 -13
  370. package/src/ui/widget/widget-types.ts +1 -1
  371. package/src/utils/bm25-search.ts +199 -199
  372. package/src/utils/conflict-detect.ts +22 -21
  373. package/src/utils/env-filter.ts +14 -7
  374. package/src/utils/file-coalescer.ts +5 -1
  375. package/src/utils/fingerprint.ts +3 -6
  376. package/src/utils/frontmatter.ts +3 -1
  377. package/src/utils/fs-watch.ts +2 -6
  378. package/src/utils/gh-protocol.ts +119 -44
  379. package/src/utils/git.ts +13 -15
  380. package/src/utils/guards.ts +2 -5
  381. package/src/utils/ids.ts +9 -2
  382. package/src/utils/incremental-reader.ts +14 -3
  383. package/src/utils/internal-error.ts +2 -1
  384. package/src/utils/names.ts +12 -3
  385. package/src/utils/paths.ts +49 -5
  386. package/src/utils/project-detector.ts +2 -2
  387. package/src/utils/redaction.ts +29 -19
  388. package/src/utils/resolve-shell.ts +9 -7
  389. package/src/utils/run-watcher-registry.ts +19 -31
  390. package/src/utils/safe-paths.ts +45 -24
  391. package/src/utils/scan-cache.ts +9 -2
  392. package/src/utils/session-utils.ts +2 -4
  393. package/src/utils/sleep.ts +12 -5
  394. package/src/utils/sse-parser.ts +5 -17
  395. package/src/utils/visual.ts +52 -32
  396. package/src/workflows/discover-workflows.ts +41 -109
  397. package/src/workflows/intermediate-store.ts +5 -21
  398. package/src/workflows/preflight-validator.ts +6 -33
  399. package/src/workflows/topology-analyzer.ts +5 -21
  400. package/src/workflows/workflow-config.ts +7 -6
  401. package/src/worktree/branch-freshness.ts +66 -8
  402. package/src/worktree/cleanup.ts +130 -20
  403. package/src/worktree/worktree-manager.ts +212 -69
  404. package/skills/artifact-analysis-loop/SKILL.md +0 -303
  405. package/skills/detection-pipeline-design/SKILL.md +0 -286
  406. package/skills/hunting-investigation-loop/SKILL.md +0 -402
  407. package/skills/incident-playbook-construction/SKILL.md +0 -384
  408. package/skills/security-review/SKILL.md +0 -561
  409. package/skills/threat-hypothesis-framework/SKILL.md +0 -176
  410. package/skills/ui-render-performance/SKILL.md +0 -58
  411. /package/docs/{followup-review-round3-2026-05-12.md → archive/followup-review-round3-2026-05-12.md} +0 -0
  412. /package/docs/{followup-review-round4-2026-05-13.md → archive/followup-review-round4-2026-05-13.md} +0 -0
  413. /package/docs/{pi-crew-bugs.md → archive/pi-crew-bugs.md} +0 -0
  414. /package/docs/{pi-crew-test-final.md → archive/pi-crew-test-final.md} +0 -0
  415. /package/docs/{pi-crew-test-results.md → archive/pi-crew-test-results.md} +0 -0
  416. /package/docs/{pi-crew-test-round2.md → archive/pi-crew-test-round2.md} +0 -0
  417. /package/docs/{pi-crew-test-round4.md → archive/pi-crew-test-round4.md} +0 -0
  418. /package/docs/{pi-crew-test-round5.md → archive/pi-crew-test-round5.md} +0 -0
  419. /package/docs/{pi-crew-test-round6.md → archive/pi-crew-test-round6.md} +0 -0
  420. /package/docs/{pi-crew-v0.5.10-audit-fix-plan.md → archive/pi-crew-v0.5.10-audit-fix-plan.md} +0 -0
  421. /package/docs/{pi-crew-v0.5.11-audit-fix-plan.md → archive/pi-crew-v0.5.11-audit-fix-plan.md} +0 -0
  422. /package/docs/{pi-crew-v0.5.12-audit-fix-plan.md → archive/pi-crew-v0.5.12-audit-fix-plan.md} +0 -0
  423. /package/docs/{pi-crew-v0.5.13-audit-fix-plan.md → archive/pi-crew-v0.5.13-audit-fix-plan.md} +0 -0
  424. /package/docs/{pi-crew-v0.5.14-audit-fix-plan.md → archive/pi-crew-v0.5.14-audit-fix-plan.md} +0 -0
  425. /package/docs/{pi-crew-v0.5.16-audit-fix-plan.md → archive/pi-crew-v0.5.16-audit-fix-plan.md} +0 -0
  426. /package/docs/{pi-crew-v0.5.17-audit-fix-plan.md → archive/pi-crew-v0.5.17-audit-fix-plan.md} +0 -0
  427. /package/docs/{pi-crew-v0.5.5-audit-fix-plan.md → archive/pi-crew-v0.5.5-audit-fix-plan.md} +0 -0
  428. /package/docs/{pi-crew-v0.5.9-audit-fix-plan.md → archive/pi-crew-v0.5.9-audit-fix-plan.md} +0 -0
  429. /package/docs/{pi-mono-opportunities.md → archive/pi-mono-opportunities.md} +0 -0
  430. /package/docs/{pi-mono-review.md → archive/pi-mono-review.md} +0 -0
  431. /package/docs/{pi-subagent4-comparison.md → archive/pi-subagent4-comparison.md} +0 -0
  432. /package/docs/{pi-subagents3-deep-analysis.md → archive/pi-subagents3-deep-analysis.md} +0 -0
@@ -30,7 +30,7 @@ export const DEFAULT_CHILD_PI: Readonly<{
30
30
 
31
31
  export const DEFAULT_LIVE_SESSION = {
32
32
  /** Maximum wall-clock time for a single live-session task before abort (ms). */
33
- responseTimeoutMs: 10 * 60_000, // 10 minutes - increased from 5min for complex verification
33
+ responseTimeoutMs: 10 * 60_000, // 10 minutes - increased from 5min for complex verification
34
34
  /** Maximum yield reminder attempts before accepting no-yield. */
35
35
  maxYieldRetries: 3,
36
36
  /** Polling interval for session idle check during yield enforcement (ms). */
@@ -56,13 +56,39 @@ export const DEFAULT_CONCURRENCY = {
56
56
  };
57
57
 
58
58
  export const DEFAULT_EVENT_LOG = {
59
- terminalEventTypes: ["run.blocked", "run.completed", "run.failed", "run.cancelled", "task.completed", "task.failed", "task.skipped", "task.cancelled", "task.needs_attention"],
59
+ terminalEventTypes: [
60
+ "run.blocked",
61
+ "run.completed",
62
+ "run.failed",
63
+ "run.cancelled",
64
+ "task.completed",
65
+ "task.failed",
66
+ "task.skipped",
67
+ "task.cancelled",
68
+ "task.needs_attention",
69
+ ],
60
70
  };
61
71
 
62
72
  export const DEFAULT_ARTIFACT_CLEANUP = {
63
73
  maxAgeDays: 7,
64
74
  };
65
75
 
76
+ /** Round 25 (L6): thresholds for task-output-context inline-bytes budget.
77
+ * Single source of truth for the per-dep cap, total dep cap, and tee
78
+ * recovery multiplier. Previously hardcoded in
79
+ * src/runtime/task-output-context.ts; moved here so that operators can
80
+ * override them via config (Phase 5 ship) without touching runtime code. */
81
+ export const DEFAULT_OUTPUT_CONTEXT = {
82
+ /** Per-dep inline-bytes cap (chars). Set by plan §5 L4 (96 KB total). */
83
+ maxResultInlineBytes: 32_000,
84
+ /** Total inline-bytes budget across all deps for one downstream worker. */
85
+ maxTotalDepInlineBytes: 96_000,
86
+ /** Tee recovery threshold: only when file > TEE_THRESHOLD_MULTIPLIER *
87
+ * maxResultInlineBytes, the truncated inline is also written to a
88
+ * tee file (R2: 1.25x = 40 KB). */
89
+ teeThresholdMultiplier: 1.25,
90
+ } as const;
91
+
66
92
  export const DEFAULT_PATHS = {
67
93
  state: {
68
94
  runsSubdir: "state/runs",
@@ -1,5 +1,5 @@
1
- import type { PiTeamsConfig } from "./config.ts";
2
1
  import { PiTeamsConfigSchema } from "../schema/config-schema.ts";
2
+ import type { PiTeamsConfig } from "./config.ts";
3
3
 
4
4
  /**
5
5
  * A single drift finding between discovered resources and config expectations.
@@ -53,9 +53,7 @@ export interface ConfigReferences {
53
53
  /**
54
54
  * Known top-level config keys allowed by the schema.
55
55
  */
56
- const SCHEMA_KEYS: ReadonlySet<string> = new Set<string>(
57
- Object.keys(PiTeamsConfigSchema.properties ?? {}),
58
- );
56
+ const SCHEMA_KEYS: ReadonlySet<string> = new Set<string>(Object.keys(PiTeamsConfigSchema.properties ?? {}));
59
57
 
60
58
  /**
61
59
  * Extract all agent, team, and workflow names referenced in a raw config object.
@@ -70,13 +68,15 @@ function extractConfigReferences(config: Record<string, unknown>): ConfigReferen
70
68
  const workflows = new Set<string>();
71
69
 
72
70
  // agents.overrides keys are explicit agent references
73
- const agentsObj = typeof config.agents === "object" && config.agents !== null && !Array.isArray(config.agents)
74
- ? config.agents as Record<string, unknown>
75
- : undefined;
76
- if (agentsObj) {
77
- const overrides = typeof agentsObj.overrides === "object" && agentsObj.overrides !== null && !Array.isArray(agentsObj.overrides)
78
- ? agentsObj.overrides as Record<string, unknown>
71
+ const agentsObj =
72
+ typeof config.agents === "object" && config.agents !== null && !Array.isArray(config.agents)
73
+ ? (config.agents as Record<string, unknown>)
79
74
  : undefined;
75
+ if (agentsObj) {
76
+ const overrides =
77
+ typeof agentsObj.overrides === "object" && agentsObj.overrides !== null && !Array.isArray(agentsObj.overrides)
78
+ ? (agentsObj.overrides as Record<string, unknown>)
79
+ : undefined;
80
80
  if (overrides) {
81
81
  for (const name of Object.keys(overrides)) {
82
82
  agents.add(name);
@@ -103,10 +103,7 @@ function extractConfigReferences(config: Record<string, unknown>): ConfigReferen
103
103
  * For teams/workflows: the config currently doesn't have explicit team/workflow references,
104
104
  * so missing/extra checks rely solely on what resources reference each other.
105
105
  */
106
- export function detectDrift(
107
- discovered: DiscoveredResources,
108
- config: PiTeamsConfig,
109
- ): DriftReport {
106
+ export function detectDrift(discovered: DiscoveredResources, config: PiTeamsConfig): DriftReport {
110
107
  const items: DriftItem[] = [];
111
108
 
112
109
  const configRaw = config as Record<string, unknown>;
@@ -10,21 +10,21 @@ export const MARKER_END = "<!-- PI-CREW:GUIDANCE:END -->";
10
10
 
11
11
  /** A single guidance section to inject between markers. */
12
12
  export interface GuidanceBlock {
13
- /**
14
- * Unique identifier for this guidance section (e.g. "team-tool-usage").
15
- * Must match `/^[a-zA-Z0-9_-]+$/`.
16
- */
17
- id: string;
18
- /**
19
- * Markdown content to inject.
20
- *
21
- * **WARNING:** Content must be from trusted sources only. Guidance blocks
22
- * are injected into markdown files that AI agents read. Untrusted content
23
- * could contain prompt-injection payloads that manipulate agent behavior.
24
- */
25
- content: string;
26
- /** Higher priority = appears first. Default 0. */
27
- priority?: number;
13
+ /**
14
+ * Unique identifier for this guidance section (e.g. "team-tool-usage").
15
+ * Must match `/^[a-zA-Z0-9_-]+$/`.
16
+ */
17
+ id: string;
18
+ /**
19
+ * Markdown content to inject.
20
+ *
21
+ * **WARNING:** Content must be from trusted sources only. Guidance blocks
22
+ * are injected into markdown files that AI agents read. Untrusted content
23
+ * could contain prompt-injection payloads that manipulate agent behavior.
24
+ */
25
+ content: string;
26
+ /** Higher priority = appears first. Default 0. */
27
+ priority?: number;
28
28
  }
29
29
 
30
30
  /** Regex for valid guidance block IDs. */
@@ -45,26 +45,26 @@ const VALID_BLOCK_ID = /^[a-zA-Z0-9_-]+$/;
45
45
  * prevent all bypasses (e.g., base64, ROT13, semantic tricks).
46
46
  */
47
47
  export function sanitizeGuidanceContent(content: string): string {
48
- let sanitized = content;
49
- // Strip zero-width and invisible Unicode characters (potential bypass vectors)
50
- sanitized = sanitized.replace(/[\u200B-\u200F\u2028-\u202F\u2060-\u206F\uFEFF]/g, "");
51
- // Strip HTML comments (potential instruction hiding)
52
- sanitized = sanitized.replace(/<!--[\s\S]*?-->/g, "");
53
- // Strip lines that look like system directives (e.g. "SYSTEM:", "INSTRUCTION:", "IGNORE PREVIOUS")
54
- sanitized = sanitized.replace(/^\s*(?:SYSTEM|INSTRUCTION|IGNORE\s+PREVIOUS|OVERRIDE)\s*:.*$/gim, "");
55
- // Collapse multiple blank lines left by removals
56
- sanitized = sanitized.replace(/\n{3,}/g, "\n\n");
57
- return sanitized.trim();
48
+ let sanitized = content;
49
+ // Strip zero-width and invisible Unicode characters (potential bypass vectors)
50
+ sanitized = sanitized.replace(/[\u200B-\u200F\u2028-\u202F\u2060-\u206F\uFEFF]/g, "");
51
+ // Strip HTML comments (potential instruction hiding)
52
+ sanitized = sanitized.replace(/<!--[\s\S]*?-->/g, "");
53
+ // Strip lines that look like system directives (e.g. "SYSTEM:", "INSTRUCTION:", "IGNORE PREVIOUS")
54
+ sanitized = sanitized.replace(/^\s*(?:SYSTEM|INSTRUCTION|IGNORE\s+PREVIOUS|OVERRIDE)\s*:.*$/gim, "");
55
+ // Collapse multiple blank lines left by removals
56
+ sanitized = sanitized.replace(/\n{3,}/g, "\n\n");
57
+ return sanitized.trim();
58
58
  }
59
59
 
60
60
  /** Result of an injection or removal operation. */
61
61
  export interface InjectionResult {
62
- path: string;
63
- modified: boolean;
64
- /** Block IDs that were added or updated. */
65
- added: string[];
66
- /** Block IDs that were removed (content was empty). */
67
- removed: string[];
62
+ path: string;
63
+ modified: boolean;
64
+ /** Block IDs that were added or updated. */
65
+ added: string[];
66
+ /** Block IDs that were removed (content was empty). */
67
+ removed: string[];
68
68
  }
69
69
 
70
70
  /**
@@ -75,10 +75,8 @@ export interface InjectionResult {
75
75
  * parse individual blocks back out.
76
76
  */
77
77
  function renderBlocks(blocks: GuidanceBlock[]): string {
78
- const sorted = [...blocks].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
79
- return sorted
80
- .map((block) => `<!-- PI-CREW:BLOCK:${block.id} -->\n${block.content}\n<!-- PI-CREW:/BLOCK:${block.id} -->`)
81
- .join("\n\n");
78
+ const sorted = [...blocks].sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
79
+ return sorted.map((block) => `<!-- PI-CREW:BLOCK:${block.id} -->\n${block.content}\n<!-- PI-CREW:/BLOCK:${block.id} -->`).join("\n\n");
82
80
  }
83
81
 
84
82
  /**
@@ -101,8 +99,7 @@ export function extractGuidanceIds(content: string): string[] {
101
99
  */
102
100
  function parseExistingBlocks(inner: string): Map<string, GuidanceBlock> {
103
101
  const map = new Map<string, GuidanceBlock>();
104
- const regex =
105
- /<!-- PI-CREW:BLOCK:([^\s>]+) -->\n([\s\S]*?)<!-- PI-CREW:\/BLOCK:\1 -->/g;
102
+ const regex = /<!-- PI-CREW:BLOCK:([^\s>]+) -->\n([\s\S]*?)<!-- PI-CREW:\/BLOCK:\1 -->/g;
106
103
  let match: RegExpExecArray | null = regex.exec(inner);
107
104
  while (match !== null) {
108
105
  const id = match[1];
@@ -119,8 +116,8 @@ function parseExistingBlocks(inner: string): Map<string, GuidanceBlock> {
119
116
  * Build the full marker section string.
120
117
  */
121
118
  function buildMarkerSection(blocks: GuidanceBlock[]): string {
122
- const body = renderBlocks(blocks);
123
- return `\n${MARKER_START}\n${body}\n${MARKER_END}\n`;
119
+ const body = renderBlocks(blocks);
120
+ return `\n${MARKER_START}\n${body}\n${MARKER_END}\n`;
124
121
  }
125
122
 
126
123
  /**
@@ -137,87 +134,88 @@ function buildMarkerSection(blocks: GuidanceBlock[]): string {
137
134
  * - Content outside the markers is preserved exactly.
138
135
  */
139
136
  export function injectGuidance(filePath: string, blocks: GuidanceBlock[]): InjectionResult {
140
- // Validate block IDs before processing (M1)
141
- for (const block of blocks) {
142
- if (!VALID_BLOCK_ID.test(block.id)) {
143
- throw new Error(
144
- `Invalid guidance block ID '${block.id}': must match /^[a-zA-Z0-9_-]+$/.`,
145
- );
146
- }
147
- }
148
-
149
- const original = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf-8") : "";
150
-
151
- const startIdx = original.indexOf(MARKER_START);
152
- const endIdx = original.indexOf(MARKER_END);
153
-
154
- let existingBlocks = new Map<string, GuidanceBlock>();
155
- let before = original;
156
- let after = "";
157
-
158
- if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
159
- // Extract content around markers
160
- before = original.slice(0, startIdx);
161
- after = original.slice(endIdx + MARKER_END.length);
162
-
163
- const inner = original.slice(startIdx + MARKER_START.length, endIdx);
164
- existingBlocks = parseExistingBlocks(inner);
165
- } else {
166
- // No markers: whole file is "before"
167
- before = original;
168
- after = "";
169
- }
170
-
171
- // Merge: apply new blocks on top of existing
172
- const added: string[] = [];
173
- const removed: string[] = [];
174
-
175
- for (const block of blocks) {
176
- if (block.content === "") {
177
- // Empty content signals removal
178
- if (existingBlocks.has(block.id)) {
179
- existingBlocks.delete(block.id);
180
- removed.push(block.id);
181
- }
182
- } else {
183
- existingBlocks.set(block.id, { ...block, content: sanitizeGuidanceContent(block.content) });
184
- added.push(block.id);
185
- }
186
- }
187
-
188
- const merged = [...existingBlocks.values()];
189
-
190
- // Nothing to write if there are no blocks and no markers existed
191
- const hadMarkers = startIdx !== -1;
192
- if (merged.length === 0 && !hadMarkers) {
193
- return { path: filePath, modified: false, added: [], removed: [] };
194
- }
195
-
196
- // If all blocks removed and markers existed, remove the whole section
197
- if (merged.length === 0 && hadMarkers) {
198
- const newContent = trimTrailingNewlines(before) + after;
199
- if (newContent === original) {
200
- return { path: filePath, modified: false, added: [], removed };
201
- }
202
- fs.writeFileSync(filePath, newContent, "utf-8");
203
- return { path: filePath, modified: true, added: [], removed };
204
- }
205
-
206
- const section = buildMarkerSection(merged);
207
- const newContent = trimTrailingNewlines(before) + section + trimLeadingNewlines(after);
208
-
209
- if (newContent === original) {
210
- return { path: filePath, modified: false, added: [], removed };
211
- }
212
-
213
- // Ensure parent directory exists
214
- const dir = filePath.substring(0, Math.max(filePath.lastIndexOf("/"), filePath.lastIndexOf("\\")));
215
- if (dir && !fs.existsSync(dir)) {
216
- fs.mkdirSync(dir, { recursive: true });
217
- }
218
-
219
- fs.writeFileSync(filePath, newContent, "utf-8");
220
- return { path: filePath, modified: true, added, removed };
137
+ // Validate block IDs before processing (M1)
138
+ for (const block of blocks) {
139
+ if (!VALID_BLOCK_ID.test(block.id)) {
140
+ throw new Error(`Invalid guidance block ID '${block.id}': must match /^[a-zA-Z0-9_-]+$/.`);
141
+ }
142
+ }
143
+
144
+ const original = fs.existsSync(filePath) ? fs.readFileSync(filePath, "utf-8") : "";
145
+
146
+ const startIdx = original.indexOf(MARKER_START);
147
+ const endIdx = original.indexOf(MARKER_END);
148
+
149
+ let existingBlocks = new Map<string, GuidanceBlock>();
150
+ let before = original;
151
+ let after = "";
152
+
153
+ if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
154
+ // Extract content around markers
155
+ before = original.slice(0, startIdx);
156
+ after = original.slice(endIdx + MARKER_END.length);
157
+
158
+ const inner = original.slice(startIdx + MARKER_START.length, endIdx);
159
+ existingBlocks = parseExistingBlocks(inner);
160
+ } else {
161
+ // No markers: whole file is "before"
162
+ before = original;
163
+ after = "";
164
+ }
165
+
166
+ // Merge: apply new blocks on top of existing
167
+ const added: string[] = [];
168
+ const removed: string[] = [];
169
+
170
+ for (const block of blocks) {
171
+ if (block.content === "") {
172
+ // Empty content signals removal
173
+ if (existingBlocks.has(block.id)) {
174
+ existingBlocks.delete(block.id);
175
+ removed.push(block.id);
176
+ }
177
+ } else {
178
+ existingBlocks.set(block.id, {
179
+ ...block,
180
+ content: sanitizeGuidanceContent(block.content),
181
+ });
182
+ added.push(block.id);
183
+ }
184
+ }
185
+
186
+ const merged = [...existingBlocks.values()];
187
+
188
+ // Nothing to write if there are no blocks and no markers existed
189
+ const hadMarkers = startIdx !== -1;
190
+ if (merged.length === 0 && !hadMarkers) {
191
+ return { path: filePath, modified: false, added: [], removed: [] };
192
+ }
193
+
194
+ // If all blocks removed and markers existed, remove the whole section
195
+ if (merged.length === 0 && hadMarkers) {
196
+ const newContent = trimTrailingNewlines(before) + after;
197
+ if (newContent === original) {
198
+ return { path: filePath, modified: false, added: [], removed };
199
+ }
200
+ fs.writeFileSync(filePath, newContent, "utf-8");
201
+ return { path: filePath, modified: true, added: [], removed };
202
+ }
203
+
204
+ const section = buildMarkerSection(merged);
205
+ const newContent = trimTrailingNewlines(before) + section + trimLeadingNewlines(after);
206
+
207
+ if (newContent === original) {
208
+ return { path: filePath, modified: false, added: [], removed };
209
+ }
210
+
211
+ // Ensure parent directory exists
212
+ const dir = filePath.substring(0, Math.max(filePath.lastIndexOf("/"), filePath.lastIndexOf("\\")));
213
+ if (dir && !fs.existsSync(dir)) {
214
+ fs.mkdirSync(dir, { recursive: true });
215
+ }
216
+
217
+ fs.writeFileSync(filePath, newContent, "utf-8");
218
+ return { path: filePath, modified: true, added, removed };
221
219
  }
222
220
 
223
221
  /**
@@ -229,58 +227,58 @@ export function injectGuidance(filePath: string, blocks: GuidanceBlock[]): Injec
229
227
  * - Content outside markers is preserved exactly.
230
228
  */
231
229
  export function removeGuidance(filePath: string, ids?: string[]): InjectionResult {
232
- if (!fs.existsSync(filePath)) {
233
- return { path: filePath, modified: false, added: [], removed: [] };
234
- }
235
-
236
- const original = fs.readFileSync(filePath, "utf-8");
237
- const startIdx = original.indexOf(MARKER_START);
238
- const endIdx = original.indexOf(MARKER_END);
239
-
240
- if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx) {
241
- return { path: filePath, modified: false, added: [], removed: [] };
242
- }
243
-
244
- const before = original.slice(0, startIdx);
245
- const after = original.slice(endIdx + MARKER_END.length);
246
- const inner = original.slice(startIdx + MARKER_START.length, endIdx);
247
-
248
- if (ids === undefined) {
249
- // Remove entire marker section
250
- const allIds = extractGuidanceIds(inner);
251
- const newContent = trimTrailingNewlines(before) + after;
252
- if (newContent === original) {
253
- return { path: filePath, modified: false, added: [], removed: [] };
254
- }
255
- fs.writeFileSync(filePath, newContent, "utf-8");
256
- return { path: filePath, modified: true, added: [], removed: allIds };
257
- }
258
-
259
- // Remove specific block IDs
260
- const existingBlocks = parseExistingBlocks(inner);
261
- const removed: string[] = [];
262
- for (const id of ids) {
263
- if (existingBlocks.delete(id)) {
264
- removed.push(id);
265
- }
266
- }
267
-
268
- if (removed.length === 0) {
269
- return { path: filePath, modified: false, added: [], removed: [] };
270
- }
271
-
272
- const merged = [...existingBlocks.values()];
273
-
274
- if (merged.length === 0) {
275
- const newContent = trimTrailingNewlines(before) + after;
276
- fs.writeFileSync(filePath, newContent, "utf-8");
277
- return { path: filePath, modified: true, added: [], removed };
278
- }
279
-
280
- const section = buildMarkerSection(merged);
281
- const newContent = trimTrailingNewlines(before) + section + trimLeadingNewlines(after);
282
- fs.writeFileSync(filePath, newContent, "utf-8");
283
- return { path: filePath, modified: true, added: [], removed };
230
+ if (!fs.existsSync(filePath)) {
231
+ return { path: filePath, modified: false, added: [], removed: [] };
232
+ }
233
+
234
+ const original = fs.readFileSync(filePath, "utf-8");
235
+ const startIdx = original.indexOf(MARKER_START);
236
+ const endIdx = original.indexOf(MARKER_END);
237
+
238
+ if (startIdx === -1 || endIdx === -1 || endIdx <= startIdx) {
239
+ return { path: filePath, modified: false, added: [], removed: [] };
240
+ }
241
+
242
+ const before = original.slice(0, startIdx);
243
+ const after = original.slice(endIdx + MARKER_END.length);
244
+ const inner = original.slice(startIdx + MARKER_START.length, endIdx);
245
+
246
+ if (ids === undefined) {
247
+ // Remove entire marker section
248
+ const allIds = extractGuidanceIds(inner);
249
+ const newContent = trimTrailingNewlines(before) + after;
250
+ if (newContent === original) {
251
+ return { path: filePath, modified: false, added: [], removed: [] };
252
+ }
253
+ fs.writeFileSync(filePath, newContent, "utf-8");
254
+ return { path: filePath, modified: true, added: [], removed: allIds };
255
+ }
256
+
257
+ // Remove specific block IDs
258
+ const existingBlocks = parseExistingBlocks(inner);
259
+ const removed: string[] = [];
260
+ for (const id of ids) {
261
+ if (existingBlocks.delete(id)) {
262
+ removed.push(id);
263
+ }
264
+ }
265
+
266
+ if (removed.length === 0) {
267
+ return { path: filePath, modified: false, added: [], removed: [] };
268
+ }
269
+
270
+ const merged = [...existingBlocks.values()];
271
+
272
+ if (merged.length === 0) {
273
+ const newContent = trimTrailingNewlines(before) + after;
274
+ fs.writeFileSync(filePath, newContent, "utf-8");
275
+ return { path: filePath, modified: true, added: [], removed };
276
+ }
277
+
278
+ const section = buildMarkerSection(merged);
279
+ const newContent = trimTrailingNewlines(before) + section + trimLeadingNewlines(after);
280
+ fs.writeFileSync(filePath, newContent, "utf-8");
281
+ return { path: filePath, modified: true, added: [], removed };
284
282
  }
285
283
 
286
284
  /**
@@ -290,43 +288,43 @@ export function removeGuidance(filePath: string, ids?: string[]): InjectionResul
290
288
  * @param version — current pi-crew package version for version-aware updates
291
289
  */
292
290
  export function standardGuidanceBlocks(version: string): GuidanceBlock[] {
293
- return [
294
- {
295
- id: "pi-crew-overview",
296
- priority: 10,
297
- content: [
298
- "## pi-crew",
299
- "",
300
- `> Managed by **pi-crew v${version}** — do not edit this section manually.`,
301
- "",
302
- "pi-crew is a Pi extension for coordinated AI agent teams, workflows,",
303
- "worktrees, and async task orchestration.",
304
- ].join("\n"),
305
- },
306
- {
307
- id: "pi-crew-commands",
308
- priority: 5,
309
- content: [
310
- "### Quick Commands",
311
- "",
312
- "| Command | Description |",
313
- "|---|---|",
314
- "| `team action='init'` | Initialize pi-crew for this project |",
315
- "| `team action='run'` | Start a team run |",
316
- "| `team action='status'` | Check run status |",
317
- "| `team action='list'` | List available teams/agents/workflows |",
318
- "| `team action='recommend'` | Get team/workflow recommendations |",
319
- ].join("\n"),
320
- },
321
- ];
291
+ return [
292
+ {
293
+ id: "pi-crew-overview",
294
+ priority: 10,
295
+ content: [
296
+ "## pi-crew",
297
+ "",
298
+ `> Managed by **pi-crew v${version}** — do not edit this section manually.`,
299
+ "",
300
+ "pi-crew is a Pi extension for coordinated AI agent teams, workflows,",
301
+ "worktrees, and async task orchestration.",
302
+ ].join("\n"),
303
+ },
304
+ {
305
+ id: "pi-crew-commands",
306
+ priority: 5,
307
+ content: [
308
+ "### Quick Commands",
309
+ "",
310
+ "| Command | Description |",
311
+ "|---|---|",
312
+ "| `team action='init'` | Initialize pi-crew for this project |",
313
+ "| `team action='run'` | Start a team run |",
314
+ "| `team action='status'` | Check run status |",
315
+ "| `team action='list'` | List available teams/agents/workflows |",
316
+ "| `team action='recommend'` | Get team/workflow recommendations |",
317
+ ].join("\n"),
318
+ },
319
+ ];
322
320
  }
323
321
 
324
322
  /** Remove trailing newlines from a string, ensuring at most one trailing newline. */
325
323
  function trimTrailingNewlines(s: string): string {
326
- return s.replace(/\n+$/, "");
324
+ return s.replace(/\n+$/, "");
327
325
  }
328
326
 
329
327
  /** Remove leading newlines from a string. */
330
328
  function trimLeadingNewlines(s: string): string {
331
- return s.replace(/^\n+/, "");
329
+ return s.replace(/^\n+/, "");
332
330
  }
@@ -2,14 +2,11 @@
2
2
  * Per-field resilient config parsing — continues on error, collects all field-level issues.
3
3
  */
4
4
 
5
- import { PiTeamsConfigSchema } from "../schema/config-schema.ts";
6
5
  import type { TSchema } from "@sinclair/typebox";
7
6
  import { Value } from "@sinclair/typebox/value";
7
+ import { PiTeamsConfigSchema } from "../schema/config-schema.ts";
8
+ import { type PiTeamsConfig, parseConfig } from "./config.ts";
8
9
  import { suggestConfigKey } from "./suggestions.ts";
9
- import {
10
- parseConfig,
11
- type PiTeamsConfig,
12
- } from "./config.ts";
13
10
 
14
11
  // ---------------------------------------------------------------------------
15
12
  // Types
@@ -56,7 +53,18 @@ export function parseConfigResilient(raw: unknown): ResilientParseResult {
56
53
  const warnings: string[] = [];
57
54
 
58
55
  if (!isObject(raw)) {
59
- return { config: {}, errors: [{ field: "config", message: "config must be an object", value: raw }], warnings, valid: false };
56
+ return {
57
+ config: {},
58
+ errors: [
59
+ {
60
+ field: "config",
61
+ message: "config must be an object",
62
+ value: raw,
63
+ },
64
+ ],
65
+ warnings,
66
+ valid: false,
67
+ };
60
68
  }
61
69
 
62
70
  // Collect unknown top-level keys with suggestions
@@ -102,7 +102,7 @@ export function getToolConfig(role: string): RoleToolConfig {
102
102
  */
103
103
  export function hasToolRestrictions(role: string): boolean {
104
104
  const config = getToolConfig(role);
105
- return (config.tools !== undefined) || (config.excludeTools !== undefined);
105
+ return config.tools !== undefined || config.excludeTools !== undefined;
106
106
  }
107
107
 
108
108
  /**
@@ -110,6 +110,6 @@ export function hasToolRestrictions(role: string): boolean {
110
110
  */
111
111
  export function getRestrictedRoles(): string[] {
112
112
  return Object.entries(ROLE_TOOL_CONFIGS)
113
- .filter(([, config]) => (config.tools !== undefined) || (config.excludeTools !== undefined))
113
+ .filter(([, config]) => config.tools !== undefined || config.excludeTools !== undefined)
114
114
  .map(([role]) => role);
115
- }
115
+ }