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
@@ -1,10 +1,10 @@
1
1
  import type { AgentConfig } from "../agents/agent-config.ts";
2
+ import type { SkillDescriptor } from "../skills/discover-skills.ts";
2
3
  import type { TeamConfig } from "../teams/team-config.ts";
4
+ import { resolveContainedPath } from "../utils/safe-paths.ts";
3
5
  import type { WorkflowConfig } from "../workflows/workflow-config.ts";
4
- import type { SkillDescriptor } from "../skills/discover-skills.ts";
5
- import type { ExportContent } from "./types.ts";
6
6
  import { adapterRegistry } from "./registry.ts";
7
- import { resolveContainedPath } from "../utils/safe-paths.ts";
7
+ import type { ExportContent } from "./types.ts";
8
8
 
9
9
  function slugify(value: string): string {
10
10
  return value
@@ -30,9 +30,7 @@ export function agentToExportContent(agent: AgentConfig): ExportContent {
30
30
  export function teamToExportContent(team: TeamConfig): ExportContent {
31
31
  const category = team.routing?.category ?? "team";
32
32
  const tags = team.routing?.triggers ?? [];
33
- const rolesDesc = team.roles
34
- .map((role) => `- **${role.name}**: ${role.description ?? role.agent}`)
35
- .join("\n");
33
+ const rolesDesc = team.roles.map((role) => `- **${role.name}**: ${role.description ?? role.agent}`).join("\n");
36
34
  const body = `${team.description}\n\n### Roles\n${rolesDesc}`;
37
35
  return {
38
36
  id: slugify(team.name),
@@ -46,9 +44,7 @@ export function teamToExportContent(team: TeamConfig): ExportContent {
46
44
  }
47
45
 
48
46
  export function workflowToExportContent(workflow: WorkflowConfig): ExportContent {
49
- const stepsDesc = workflow.steps
50
- .map((step) => `- **${step.id}** (${step.role}): ${step.task}`)
51
- .join("\n");
47
+ const stepsDesc = workflow.steps.map((step) => `- **${step.id}** (${step.role}): ${step.task}`).join("\n");
52
48
  const body = `${workflow.description}\n\n### Steps\n${stepsDesc}`;
53
49
  return {
54
50
  id: slugify(workflow.name),
@@ -105,14 +101,15 @@ export interface ToolExportResult {
105
101
  files: Array<{ path: string; content: string }>;
106
102
  }
107
103
 
108
- export function generateToolExport(
109
- toolId: string,
110
- resources: ExportableResource[],
111
- projectRoot?: string,
112
- ): ToolExportResult {
104
+ export function generateToolExport(toolId: string, resources: ExportableResource[], projectRoot?: string): ToolExportResult {
113
105
  const adapter = adapterRegistry.get(toolId);
114
106
  if (!adapter) {
115
- throw new Error(`Unknown export adapter: ${toolId}. Available: ${adapterRegistry.getAll().map((a) => a.toolId).join(", ")}`);
107
+ throw new Error(
108
+ `Unknown export adapter: ${toolId}. Available: ${adapterRegistry
109
+ .getAll()
110
+ .map((a) => a.toolId)
111
+ .join(", ")}`,
112
+ );
116
113
  }
117
114
  const contents = resourcesToExportContent(resources);
118
115
  const files = contents.map((content): { path: string; content: string } => {
@@ -138,6 +135,9 @@ export function generateToolExport(
138
135
  const existing = merged.get(f.path);
139
136
  merged.set(f.path, existing ? `${existing}\n\n${f.content}` : f.content);
140
137
  }
141
- const mergedFiles = [...merged.entries()].map(([p, content]) => ({ path: p, content }));
138
+ const mergedFiles = [...merged.entries()].map(([p, content]) => ({
139
+ path: p,
140
+ content,
141
+ }));
142
142
  return { toolId, files: mergedFiles };
143
143
  }
@@ -1,14 +1,14 @@
1
- export type { ExportContent, ExportAdapter, AdapterRegistry } from "./types.ts";
2
- export { createAdapterRegistry, adapterRegistry } from "./registry.ts";
3
1
  export { claudeAdapter } from "./claude-adapter.ts";
4
- export { cursorAdapter } from "./cursor-adapter.ts";
5
2
  export { codexAdapter } from "./codex-adapter.ts";
3
+ export { cursorAdapter } from "./cursor-adapter.ts";
6
4
  export { generateToolExport, resourcesToExportContent } from "./export-util.ts";
5
+ export { adapterRegistry, createAdapterRegistry } from "./registry.ts";
6
+ export type { AdapterRegistry, ExportAdapter, ExportContent } from "./types.ts";
7
7
 
8
- import { adapterRegistry } from "./registry.ts";
9
8
  import { claudeAdapter } from "./claude-adapter.ts";
10
- import { cursorAdapter } from "./cursor-adapter.ts";
11
9
  import { codexAdapter } from "./codex-adapter.ts";
10
+ import { cursorAdapter } from "./cursor-adapter.ts";
11
+ import { adapterRegistry } from "./registry.ts";
12
12
 
13
13
  adapterRegistry.register(claudeAdapter);
14
14
  adapterRegistry.register(cursorAdapter);
@@ -9,15 +9,7 @@ import { getToolConfig } from "../config/role-tools.ts";
9
9
  * the wildcard expansion will pick it up. The 7 names below are stable
10
10
  * across pi v0.77+ and cover read, edit, write, bash, grep, find, ls.
11
11
  */
12
- export const BUILTIN_TOOL_NAMES: readonly string[] = [
13
- "read",
14
- "edit",
15
- "write",
16
- "bash",
17
- "grep",
18
- "find",
19
- "ls",
20
- ];
12
+ export const BUILTIN_TOOL_NAMES: readonly string[] = ["read", "edit", "write", "bash", "grep", "find", "ls"];
21
13
 
22
14
  /**
23
15
  * F1 (v0.7.9): normalize the raw `tools:` frontmatter CSV into a `string[]`.
@@ -41,7 +33,10 @@ export function parseToolsField(raw: unknown): string[] | undefined {
41
33
  const lowered = s.toLowerCase();
42
34
  if (lowered === "none" || lowered === "[]") return [];
43
35
  if (lowered === "*" || lowered === "all") return [...BUILTIN_TOOL_NAMES];
44
- const items = s.split(",").map((t) => t.trim()).filter(Boolean);
36
+ const items = s
37
+ .split(",")
38
+ .map((t) => t.trim())
39
+ .filter(Boolean);
45
40
  return items;
46
41
  }
47
42
 
@@ -160,12 +155,23 @@ function uniqueToolMerge(...lists: Array<string[] | undefined>): string[] | unde
160
155
  export function resolveToolPolicy(agent: AgentConfig, role?: string): ResolvedToolPolicy {
161
156
  const roleConfig = role ? getToolConfig(role) : {};
162
157
  // allowlist: source-aware precedence (see doc above).
163
- const explicitTools = agent.source === "builtin"
164
- ? (roleConfig.tools ?? agent.tools)
165
- : (agent.tools ?? roleConfig.tools);
158
+ const explicitTools = agent.source === "builtin" ? (roleConfig.tools ?? agent.tools) : (agent.tools ?? roleConfig.tools);
159
+ // L5: when the agent opts into `loadMode: "lean"` AND provides a
160
+ // non-empty `defaultTools` list, merge that list into the resolved
161
+ // allowlist. The merge is additive (union, dedup, order-preserving) so
162
+ // the existing source-aware precedence is preserved and a lean agent
163
+ // gets a focused-but-non-empty tool set. Signal flow:
164
+ // agent YAML frontmatter (loadMode, defaultTools)
165
+ // → parsed into AgentConfig
166
+ // → resolveToolPolicy(agent, role) here
167
+ // → policy.tools returned to buildPiWorkerArgs
168
+ // → `args.push("--tools", policy.tools.join(","))` in pi-args.ts
169
+ // → child pi process sees the merged allowlist
170
+ const tools =
171
+ agent.loadMode === "lean" && agent.defaultTools?.length ? uniqueToolMerge(explicitTools, agent.defaultTools) : explicitTools;
166
172
  // denylist: additive merge of role excludeTools + agent disallowedTools.
167
173
  const excludeTools = uniqueToolMerge(roleConfig.excludeTools, agent.disallowedTools);
168
- return { tools: explicitTools, excludeTools };
174
+ return { tools, excludeTools };
169
175
  }
170
176
 
171
177
  /**
@@ -15,7 +15,7 @@ export function serializeAgent(agent: AgentConfig): string {
15
15
  line("fallbackModels", agent.fallbackModels),
16
16
  line("thinking", agent.thinking),
17
17
  line("tools", agent.tools),
18
- agent.extensions !== undefined ? line("extensions", agent.extensions) ?? "extensions:" : undefined,
18
+ agent.extensions !== undefined ? (line("extensions", agent.extensions) ?? "extensions:") : undefined,
19
19
  line("skills", agent.skills),
20
20
  line("systemPromptMode", agent.systemPromptMode),
21
21
  line("inheritProjectContext", agent.inheritProjectContext),
@@ -1,11 +1,11 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
- import type { AgentConfig, ResourceSource } from "./agent-config.ts";
4
- import { parseToolsField } from "./agent-config.ts";
5
- import { loadConfig, type LoadedPiTeamsConfig } from "../config/config.ts";
3
+ import { type LoadedPiTeamsConfig, loadConfig } from "../config/config.ts";
6
4
  import { parseCsv, parseFrontmatter } from "../utils/frontmatter.ts";
7
5
  import { logInternalError } from "../utils/internal-error.ts";
8
- import { packageRoot, projectCrewRoot, userPiRoot, findRepoRoot } from "../utils/paths.ts";
6
+ import { findRepoRoot, packageRoot, projectCrewRoot, userPiRoot } from "../utils/paths.ts";
7
+ import type { AgentConfig, ResourceSource } from "./agent-config.ts";
8
+ import { parseToolsField } from "./agent-config.ts";
9
9
 
10
10
  // ═══════════════════════════════════════════════════════════════════════════
11
11
  // SEC-001 Fix: Protected Agent Names Blocklist
@@ -21,7 +21,6 @@ import { packageRoot, projectCrewRoot, userPiRoot, findRepoRoot } from "../utils
21
21
  // See: SECURITY-ISSUES.md SEC-005
22
22
  // ═══════════════════════════════════════════════════════════════════════════
23
23
 
24
-
25
24
  /** Version counter for atomic cache invalidation. Incremented on every mutation. */
26
25
  let cacheVersion = 0;
27
26
 
@@ -69,14 +68,23 @@ const PROTECTED_AGENT_PATTERNS: Array<{ pattern: RegExp; example: string }> = [
69
68
  { pattern: /^explorer[-_]/i, example: "explorer-debug" },
70
69
  { pattern: /^planner[-_]/i, example: "planner-v3" },
71
70
  // Generic prefixes that could impersonate builtins
72
- { pattern: /^(my|custom|new|local)[-_](executor|test[-_]?engineer|explorer|planner)$/i, example: "my-executor" },
73
- { pattern: /^(executor|test[-_]?engineer|explorer|planner)[-_]?(proxy|hook|override)$/i, example: "executor-override" },
71
+ {
72
+ pattern: /^(my|custom|new|local)[-_](executor|test[-_]?engineer|explorer|planner)$/i,
73
+ example: "my-executor",
74
+ },
75
+ {
76
+ pattern: /^(executor|test[-_]?engineer|explorer|planner)[-_]?(proxy|hook|override)$/i,
77
+ example: "executor-override",
78
+ },
74
79
  // Common typosquatting patterns (intentional misspellings)
75
80
  { pattern: /^exec[au]t[o0]r$/i, example: "execator" },
76
81
  { pattern: /^expl[o0]rer$/i, example: "explorer" },
77
82
  { pattern: /^plann[ae]r$/i, example: "plannar" },
78
83
  // Suffixes that indicate override意图
79
- { pattern: /^(executor|test[-_]?engineer|explorer|planner)[-_]?(override|replacement|shadow)$/i, example: "executor-override" },
84
+ {
85
+ pattern: /^(executor|test[-_]?engineer|explorer|planner)[-_]?(override|replacement|shadow)$/i,
86
+ example: "executor-override",
87
+ },
80
88
  ];
81
89
 
82
90
  /**
@@ -123,11 +131,7 @@ function logSecurityEvent(event: SecurityEvent): void {
123
131
  }
124
132
 
125
133
  // Log security events via structured logger
126
- logInternalError(
127
- `security.${event.type}`,
128
- undefined,
129
- `agent="${event.name}" reason="${event.reason}"`,
130
- );
134
+ logInternalError(`security.${event.type}`, undefined, `agent="${event.name}" reason="${event.reason}"`);
131
135
  }
132
136
 
133
137
  /**
@@ -167,7 +171,7 @@ function assertAgentNameAllowed(name: string): void {
167
171
  });
168
172
  throw new Error(
169
173
  `SECURITY: Cannot register agent '${name}': protected builtin name. ` +
170
- `Dynamic agents cannot shadow builtin agents (executor, explorer, planner, etc.) to prevent privilege escalation.`
174
+ `Dynamic agents cannot shadow builtin agents (executor, explorer, planner, etc.) to prevent privilege escalation.`,
171
175
  );
172
176
  }
173
177
 
@@ -182,7 +186,7 @@ function assertAgentNameAllowed(name: string): void {
182
186
  });
183
187
  throw new Error(
184
188
  `SECURITY: Cannot register agent '${name}': name matches protected pattern (${matchedPattern}). ` +
185
- `This pattern is blocked to prevent privilege escalation via similar-named agents.`
189
+ `This pattern is blocked to prevent privilege escalation via similar-named agents.`,
186
190
  );
187
191
  }
188
192
  }
@@ -284,7 +288,7 @@ function sourceToTrustLevel(source: ResourceSource): TrustLevel {
284
288
  case "user":
285
289
  return "user";
286
290
  case "project":
287
- return "project";
291
+ return "project";
288
292
  default:
289
293
  return "project";
290
294
  }
@@ -305,10 +309,7 @@ function sourceToTrustLevel(source: ResourceSource): TrustLevel {
305
309
  * - user: Standard sanitization
306
310
  * - project: Strict sanitization (untrusted source)
307
311
  */
308
- export function sanitizeAgentSystemPrompt(
309
- content: string,
310
- source: ResourceSource
311
- ): string {
312
+ export function sanitizeAgentSystemPrompt(content: string, source: ResourceSource): string {
312
313
  const trustLevel = sourceToTrustLevel(source);
313
314
  let sanitized = content;
314
315
 
@@ -323,7 +324,7 @@ export function sanitizeAgentSystemPrompt(
323
324
  // Strip lines that look like system directives
324
325
  sanitized = sanitized.replace(
325
326
  /^\s*(?:SYSTEM|INSTRUCTION|IGNORE(?:\s+ALL)?\s+(?:PREVIOUS|INSTRUCTIONS)?|OVERRIDE|YOUR\s+ROLE\s+IS|MALICIOUS|BACKDOOR)\s*:.*$/gim,
326
- ""
327
+ "",
327
328
  );
328
329
 
329
330
  // Strip embedded instruction patterns in brackets
@@ -357,6 +358,17 @@ export function sanitizeAgentSystemPrompt(
357
358
  return sanitized.trim();
358
359
  }
359
360
 
361
+ /**
362
+ * M4: per-process dedup set of agent filePaths for which we've already
363
+ * emitted the `contextMode: fork` warn-only notice. Avoids spam when
364
+ * the discovery cache reloads or the same agent is parsed multiple
365
+ * times in a session. Exported for test reset.
366
+ */
367
+ const warnedForkAgents = new Set<string>();
368
+ export function __test_resetForkWarnings(): void {
369
+ warnedForkAgents.clear();
370
+ }
371
+
360
372
  function parseAgentFile(filePath: string, source: ResourceSource): AgentConfig | undefined {
361
373
  try {
362
374
  const content = fs.readFileSync(filePath, "utf-8");
@@ -373,6 +385,27 @@ function parseAgentFile(filePath: string, source: ResourceSource): AgentConfig |
373
385
  const rawSystemPrompt = body.trim();
374
386
  const systemPrompt = sanitizeAgentSystemPrompt(rawSystemPrompt, source);
375
387
 
388
+ const contextMode = parseContextMode(frontmatter.contextMode);
389
+
390
+ // M4: warn-only when contextMode=fork is configured but the
391
+ // runtime is the default child-process path. `contextMode: fork`
392
+ // is only effective in the live-session runtime (the experimental
393
+ // path that runs the agent IN the parent pi's session). The
394
+ // default child-process path (runChildPi in src/runtime/child-pi.ts)
395
+ // spawns a NEW pi process and has no parent session to inherit,
396
+ // so the agent will behave as `fresh` regardless of the setting.
397
+ // We warn (not throw) so existing configs that predate live-session
398
+ // keep working. Deduped per-filePath so we don't spam on cache
399
+ // reload. Use console.warn (no logger hook here yet; a future
400
+ // refactor could pipe through the same log channel as
401
+ // logInternalError below).
402
+ if (contextMode === "fork" && !warnedForkAgents.has(filePath)) {
403
+ console.warn(
404
+ "contextMode: 'fork' is only effective in live-session runtime; current default child-process will behave as 'fresh'. See docs/runtime-modes.md.",
405
+ );
406
+ warnedForkAgents.add(filePath);
407
+ }
408
+
376
409
  return {
377
410
  name,
378
411
  description,
@@ -389,15 +422,21 @@ function parseAgentFile(filePath: string, source: ResourceSource): AgentConfig |
389
422
  skills: parseCsv(frontmatter.skills ?? frontmatter.skill),
390
423
  systemPromptMode: frontmatter.systemPromptMode === "append" ? "append" : "replace",
391
424
  inheritProjectContext: frontmatter.inheritProjectContext === "true",
392
- inheritSkills: frontmatter.inheritSkills === "true",
393
- memory: parseMemory(frontmatter.memory),
394
- loadMode: parseLoadMode(frontmatter.loadMode),
395
- defaultTools: frontmatter.defaultTools !== undefined ? parseCsv(frontmatter.defaultTools) ?? null : undefined,
396
- contextMode: parseContextMode(frontmatter.contextMode),
397
- maxTurns: (() => { const n = Number.parseInt(frontmatter.maxTurns, 10); return Number.isFinite(n) && n > 0 ? n : undefined; })(),
398
- effort: frontmatter.effort === "low" || frontmatter.effort === "medium" || frontmatter.effort === "high" ? frontmatter.effort : undefined,
399
- disabled: frontmatter.disabled === "true" || frontmatter.enabled === "false",
400
- routing: triggers || useWhen || avoidWhen || cost || category ? { triggers, useWhen, avoidWhen, cost, category } : undefined,
425
+ inheritSkills: frontmatter.inheritSkills === "true",
426
+ memory: parseMemory(frontmatter.memory),
427
+ loadMode: parseLoadMode(frontmatter.loadMode),
428
+ defaultTools: frontmatter.defaultTools !== undefined ? (parseCsv(frontmatter.defaultTools) ?? null) : undefined,
429
+ contextMode,
430
+ maxTurns: (() => {
431
+ const n = Number.parseInt(frontmatter.maxTurns, 10);
432
+ return Number.isFinite(n) && n > 0 ? n : undefined;
433
+ })(),
434
+ effort:
435
+ frontmatter.effort === "low" || frontmatter.effort === "medium" || frontmatter.effort === "high"
436
+ ? frontmatter.effort
437
+ : undefined,
438
+ disabled: frontmatter.disabled === "true" || frontmatter.enabled === "false",
439
+ routing: triggers || useWhen || avoidWhen || cost || category ? { triggers, useWhen, avoidWhen, cost, category } : undefined,
401
440
  };
402
441
  } catch (error) {
403
442
  logInternalError("discoverAgents.parseAgentFile", error, `filePath=${filePath}`);
@@ -407,7 +446,8 @@ function parseAgentFile(filePath: string, source: ResourceSource): AgentConfig |
407
446
 
408
447
  function readAgentDir(dir: string, source: ResourceSource): AgentConfig[] {
409
448
  if (!fs.existsSync(dir)) return [];
410
- const agents = fs.readdirSync(dir)
449
+ const agents = fs
450
+ .readdirSync(dir)
411
451
  .filter((entry) => entry.endsWith(".md") && !entry.endsWith(".team.md") && !entry.endsWith(".workflow.md"))
412
452
  .map((entry) => parseAgentFile(path.join(dir, entry), source))
413
453
  .filter((agent): agent is AgentConfig => agent !== undefined)
@@ -436,11 +476,11 @@ function applyAgentOverrides(agents: AgentConfig[], cwd: string, loadedConfig?:
436
476
  return {
437
477
  ...agent,
438
478
  disabled: override.disabled ?? agent.disabled,
439
- model: override.model === false ? undefined : override.model ?? agent.model,
440
- fallbackModels: override.fallbackModels === false ? undefined : override.fallbackModels ?? agent.fallbackModels,
441
- thinking: override.thinking === false ? undefined : override.thinking ?? agent.thinking,
442
- tools: override.tools === false ? undefined : override.tools ?? agent.tools,
443
- skills: override.skills === false ? undefined : override.skills ?? agent.skills,
479
+ model: override.model === false ? undefined : (override.model ?? agent.model),
480
+ fallbackModels: override.fallbackModels === false ? undefined : (override.fallbackModels ?? agent.fallbackModels),
481
+ thinking: override.thinking === false ? undefined : (override.thinking ?? agent.thinking),
482
+ tools: override.tools === false ? undefined : (override.tools ?? agent.tools),
483
+ skills: override.skills === false ? undefined : (override.skills ?? agent.skills),
444
484
  override: { source: "config", path: loaded.path },
445
485
  };
446
486
  });
@@ -454,7 +494,7 @@ const DISCOVERY_CACHE_TTL_MS = 500;
454
494
  interface CachedDiscoveryEntry {
455
495
  result: AgentDiscoveryResult;
456
496
  expiresAt: number;
457
- cacheVersion: number; // SEC-005: Version stamp for atomic invalidation
497
+ cacheVersion: number; // SEC-005: Version stamp for atomic invalidation
458
498
  }
459
499
  const discoveryCache = new Map<string, CachedDiscoveryEntry>();
460
500
  const DISCOVERY_CACHE_MAX_ENTRIES = 32;
@@ -500,7 +540,11 @@ export function discoverAgents(cwd: string): AgentDiscoveryResult {
500
540
  projectPi: applyAgentOverrides(readAgentDir(path.join(findRepoRoot(cwd) ?? cwd, ".pi", "agents"), "project-pi"), cwd, loaded),
501
541
  };
502
542
  // SEC-005: Store with current version stamp
503
- discoveryCache.set(cwd, { result, expiresAt: Date.now() + DISCOVERY_CACHE_TTL_MS, cacheVersion: currentVersion });
543
+ discoveryCache.set(cwd, {
544
+ result,
545
+ expiresAt: Date.now() + DISCOVERY_CACHE_TTL_MS,
546
+ cacheVersion: currentVersion,
547
+ });
504
548
  while (discoveryCache.size > DISCOVERY_CACHE_MAX_ENTRIES) {
505
549
  const oldest = discoveryCache.keys().next().value;
506
550
  if (oldest !== undefined) discoveryCache.delete(oldest);
@@ -522,7 +566,7 @@ export function registerDynamicAgent(config: AgentConfig): void {
522
566
  if (dynamicAgents.has(key)) {
523
567
  throw new Error(`Agent already registered: ${config.name}`);
524
568
  }
525
- dynamicAgents.set(key, { ...config, source: "dynamic" }); // Always "dynamic" — cannot be spoofed
569
+ dynamicAgents.set(key, { ...config, source: "dynamic" }); // Always "dynamic" — cannot be spoofed
526
570
  invalidateAgentDiscoveryCache();
527
571
  }
528
572
 
@@ -41,42 +41,42 @@ export interface BenchmarkResult {
41
41
  * Uses comprehensive shell metacharacter blocking similar to safe-bash.ts.
42
42
  */
43
43
  function validateCommand(command: string): void {
44
- // Basic allowlist - must start with an allowed command.
45
- // SECURITY (H-7): `npx`/`node` were removed because they enable arbitrary code
46
- // execution without any shell metacharacter (e.g. `npx --yes evil-package`
47
- // or `node -e "require('fs')…"`). Use `npm test`/`npm run …` instead of raw
48
- // `node`/`npx` in benchmark task definitions.
49
- // `echo` is allowed because the metachar blocker (validateGateCommand) rejects
50
- // command substitution (`$(...)`, backticks), so `echo $(evil)` cannot run;
51
- // bare `echo …` only prints. It's the canonical exit-0 command used in
52
- // benchmark fixtures across Linux/macOS/Windows(sh).
53
- const allowlist = /^(pytest|grep|npm test|cargo test|cargo clippy|echo) /;
54
- if (!allowlist.test(command)) {
55
- throw new Error(`Command not allowed: ${command}. Only pytest, grep, npm test, cargo test/clippy, echo allowed.`);
56
- }
57
-
58
- // Block shell metacharacters after command name
59
- const afterCommand = command.substring(command.indexOf(" ") + 1);
60
-
61
- // Block dangerous shell metacharacters
62
- const dangerousPatterns = [
63
- /[;&|`$(){}[\]<>\\]/, // Shell metacharacters
64
- /\$\([^)]*\)/, // Command substitution $(...)
65
- /`[^`]*`/, // Backtick command substitution
66
- /\|/, // Pipe
67
- /&&/, // And
68
- /\|\|/, // Or
69
- />>/, // Append redirect
70
- /2>&1/, // stderr redirect
71
- />/, // Output redirect
72
- /</, // Input redirect
73
- ];
74
-
75
- for (const pattern of dangerousPatterns) {
76
- if (pattern.test(afterCommand)) {
77
- throw new Error(`Shell metacharacters not allowed in command arguments`);
78
- }
79
- }
44
+ // Basic allowlist - must start with an allowed command.
45
+ // SECURITY (H-7): `npx`/`node` were removed because they enable arbitrary code
46
+ // execution without any shell metacharacter (e.g. `npx --yes evil-package`
47
+ // or `node -e "require('fs')…"`). Use `npm test`/`npm run …` instead of raw
48
+ // `node`/`npx` in benchmark task definitions.
49
+ // `echo` is allowed because the metachar blocker (validateGateCommand) rejects
50
+ // command substitution (`$(...)`, backticks), so `echo $(evil)` cannot run;
51
+ // bare `echo …` only prints. It's the canonical exit-0 command used in
52
+ // benchmark fixtures across Linux/macOS/Windows(sh).
53
+ const allowlist = /^(pytest|grep|npm test|cargo test|cargo clippy|echo) /;
54
+ if (!allowlist.test(command)) {
55
+ throw new Error(`Command not allowed: ${command}. Only pytest, grep, npm test, cargo test/clippy, echo allowed.`);
56
+ }
57
+
58
+ // Block shell metacharacters after command name
59
+ const afterCommand = command.substring(command.indexOf(" ") + 1);
60
+
61
+ // Block dangerous shell metacharacters
62
+ const dangerousPatterns = [
63
+ /[;&|`$(){}[\]<>\\]/, // Shell metacharacters
64
+ /\$\([^)]*\)/, // Command substitution $(...)
65
+ /`[^`]*`/, // Backtick command substitution
66
+ /\|/, // Pipe
67
+ /&&/, // And
68
+ /\|\|/, // Or
69
+ />>/, // Append redirect
70
+ /2>&1/, // stderr redirect
71
+ />/, // Output redirect
72
+ /</, // Input redirect
73
+ ];
74
+
75
+ for (const pattern of dangerousPatterns) {
76
+ if (pattern.test(afterCommand)) {
77
+ throw new Error(`Shell metacharacters not allowed in command arguments`);
78
+ }
79
+ }
80
80
  }
81
81
 
82
82
  /**
@@ -143,10 +143,18 @@ export async function runBenchmark(task: BenchmarkTask): Promise<BenchmarkResult
143
143
  passed = true; // Command succeeded = pass
144
144
  }
145
145
 
146
- judgeResults.push({ description: judge.description, passed: passed ?? false, output });
146
+ judgeResults.push({
147
+ description: judge.description,
148
+ passed: passed ?? false,
149
+ output,
150
+ });
147
151
  } catch (e: unknown) {
148
152
  const error = e as { message?: string };
149
- judgeResults.push({ description: judge.description, passed: false, output: error.message ?? String(e) });
153
+ judgeResults.push({
154
+ description: judge.description,
155
+ passed: false,
156
+ output: error.message ?? String(e),
157
+ });
150
158
  }
151
159
  }
152
160
 
@@ -200,9 +208,7 @@ export async function runBenchmarkSuite(
200
208
  totalDurationMs: number;
201
209
  totalCost: number;
202
210
  }> {
203
- const filtered = taskTypes
204
- ? tasks.filter((t) => t.taskType && taskTypes.includes(t.taskType))
205
- : tasks;
211
+ const filtered = taskTypes ? tasks.filter((t) => t.taskType && taskTypes.includes(t.taskType)) : tasks;
206
212
 
207
213
  const results: BenchmarkResult[] = [];
208
214
 
@@ -241,8 +247,7 @@ export function aggregateBenchmarkMetrics(results: BenchmarkResult[]): Aggregate
241
247
  const totalTasks = group.length;
242
248
  const passedTasks = group.filter((r) => r.passed).length;
243
249
  const passRate = totalTasks > 0 ? passedTasks / totalTasks : 0;
244
- const avgTimeMs =
245
- totalTasks > 0 ? group.reduce((s, r) => s + r.durationMs, 0) / totalTasks : 0;
250
+ const avgTimeMs = totalTasks > 0 ? group.reduce((s, r) => s + r.durationMs, 0) / totalTasks : 0;
246
251
  const totalCost = group.reduce((s, r) => s + r.cost, 0);
247
252
  const avgCost = totalTasks > 0 ? totalCost / totalTasks : 0;
248
253
 
@@ -266,10 +271,7 @@ export function aggregateBenchmarkMetrics(results: BenchmarkResult[]): Aggregate
266
271
  * @param results - Benchmark results to report.
267
272
  * @param includeTaskTypeComparison - When true (default), appends a per-task-type aggregate table.
268
273
  */
269
- export function generateBenchmarkReport(
270
- results: BenchmarkResult[],
271
- includeTaskTypeComparison = true,
272
- ): string {
274
+ export function generateBenchmarkReport(results: BenchmarkResult[], includeTaskTypeComparison = true): string {
273
275
  const lines: string[] = ["# Benchmark Results", ""];
274
276
 
275
277
  lines.push("| Task | Type | Status | Duration | Cost |");
@@ -298,9 +300,7 @@ export function generateBenchmarkReport(
298
300
  const m = metrics[t];
299
301
  const passRatePct = `${(m.passRate * 100).toFixed(1)}%`;
300
302
  const avgCostStr = m.avgCost > 0 ? `$${m.avgCost.toFixed(4)}` : "—";
301
- lines.push(
302
- `| ${m.taskType} | ${m.totalTasks} | ${m.passedTasks} | ${passRatePct} | ${m.avgTimeMs}ms | ${avgCostStr} |`,
303
- );
303
+ lines.push(`| ${m.taskType} | ${m.totalTasks} | ${m.passedTasks} | ${passRatePct} | ${m.avgTimeMs}ms | ${avgCostStr} |`);
304
304
  }
305
305
  }
306
306
  }
@@ -310,4 +310,4 @@ export function generateBenchmarkReport(
310
310
  lines.push(`**Total: ${passed}/${results.length} passed**`);
311
311
 
312
312
  return lines.join("\n");
313
- }
313
+ }
@@ -70,4 +70,4 @@ class FeedbackLoop {
70
70
  clear(): void {
71
71
  this.runs = [];
72
72
  }
73
- }
73
+ }