@pugi/cli 0.1.0-beta.1 → 0.1.0-beta.100

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 (448) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/LICENSE +1 -1
  3. package/README.md +53 -11
  4. package/THIRD_PARTY_NOTICES.md +40 -0
  5. package/assets/pugi-mascot.ansi +15 -40
  6. package/assets/pugi-prozr2-mascot.ansi +9 -0
  7. package/bin/run.js +33 -1
  8. package/dist/commands/deploy.js +40 -40
  9. package/dist/commands/flatten.js +191 -0
  10. package/dist/commands/jobs-watch.js +201 -0
  11. package/dist/commands/jobs.js +42 -27
  12. package/dist/commands/retro.js +210 -0
  13. package/dist/commands/smoke.js +133 -0
  14. package/dist/core/agent-progress/cleanup.js +134 -0
  15. package/dist/core/agent-progress/schema.js +144 -0
  16. package/dist/core/agent-progress/writer.js +101 -0
  17. package/dist/core/agents/adaptive-router.js +330 -0
  18. package/dist/core/agents/query-decomposer.js +297 -0
  19. package/dist/core/agents/registry.js +3 -3
  20. package/dist/core/approvals/shortcut-resolver.js +98 -0
  21. package/dist/core/artifact-chain/dispatcher.js +148 -0
  22. package/dist/core/artifact-chain/exporter.js +164 -0
  23. package/dist/core/artifact-chain/state.js +243 -0
  24. package/dist/core/artifact-chain/steps.js +169 -0
  25. package/dist/core/ask-user/question.js +92 -0
  26. package/dist/core/audit/audit-trail.js +275 -0
  27. package/dist/core/auth/ensure-authenticated.js +129 -0
  28. package/dist/core/auth/env-provider.js +238 -0
  29. package/dist/core/auto-open-browser.js +4 -4
  30. package/dist/core/auto-update/channels.js +122 -0
  31. package/dist/core/auto-update/checker.js +241 -0
  32. package/dist/core/auto-update/state.js +235 -0
  33. package/dist/core/bare-mode/index.js +107 -0
  34. package/dist/core/bash/redirect.js +281 -0
  35. package/dist/core/bash-classifier.js +436 -40
  36. package/dist/core/checkpoint/resumer.js +149 -0
  37. package/dist/core/checkpoint/rewinder.js +291 -0
  38. package/dist/core/checkpoints/shadow-git.js +670 -0
  39. package/dist/core/citations/parser.js +109 -0
  40. package/dist/core/classifier/yolo-classifier.js +88 -0
  41. package/dist/core/codegraph/db.js +506 -0
  42. package/dist/core/codegraph/decision-store.js +248 -0
  43. package/dist/core/codegraph/detect-repo.js +459 -0
  44. package/dist/core/codegraph/install.js +134 -0
  45. package/dist/core/codegraph/offer-hook.js +220 -0
  46. package/dist/core/codegraph/parser.js +71 -0
  47. package/dist/core/codegraph/types.js +34 -0
  48. package/dist/core/compact/auto-trigger.js +96 -0
  49. package/dist/core/compact/buffer-rewriter.js +115 -0
  50. package/dist/core/compact/summarizer.js +208 -0
  51. package/dist/core/compact/token-counter.js +108 -0
  52. package/dist/core/consensus/anvil-fanout.js +25 -25
  53. package/dist/core/consensus/diff-capture.js +121 -12
  54. package/dist/core/consensus/rubric.js +21 -21
  55. package/dist/core/context/builder.js +6 -6
  56. package/dist/core/context/compaction-events.js +8 -8
  57. package/dist/core/context/compaction.js +31 -31
  58. package/dist/core/context/index.js +15 -8
  59. package/dist/core/context/invariants.js +51 -51
  60. package/dist/core/context/markdown-loader.js +28 -10
  61. package/dist/core/context/markdown-traverse.js +255 -0
  62. package/dist/core/context/pugiignore.js +41 -41
  63. package/dist/core/context/repo-skeleton.js +37 -37
  64. package/dist/core/context/tool-eviction.js +55 -0
  65. package/dist/core/context/watcher.js +32 -32
  66. package/dist/core/context/working-set.js +23 -23
  67. package/dist/core/coordinator/agent-tools.js +77 -0
  68. package/dist/core/coordinator/agent-toolset.js +65 -0
  69. package/dist/core/coordinator/fsm.js +73 -0
  70. package/dist/core/coordinator/mode-fsm.js +70 -0
  71. package/dist/core/cost/rate-card.js +129 -0
  72. package/dist/core/cost/tracker.js +221 -0
  73. package/dist/core/credentials.js +13 -13
  74. package/dist/core/cron/scheduler.js +138 -0
  75. package/dist/core/denial-tracking/index.js +8 -0
  76. package/dist/core/denial-tracking/state.js +264 -0
  77. package/dist/core/diagnostics/probe-runner.js +93 -0
  78. package/dist/core/diagnostics/probes/api.js +46 -0
  79. package/dist/core/diagnostics/probes/auth.js +93 -0
  80. package/dist/core/diagnostics/probes/bare-mode.js +42 -0
  81. package/dist/core/diagnostics/probes/cli-version.js +127 -0
  82. package/dist/core/diagnostics/probes/config.js +72 -0
  83. package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
  84. package/dist/core/diagnostics/probes/disk.js +81 -0
  85. package/dist/core/diagnostics/probes/engine-live.js +46 -0
  86. package/dist/core/diagnostics/probes/git.js +65 -0
  87. package/dist/core/diagnostics/probes/hooks.js +118 -0
  88. package/dist/core/diagnostics/probes/mcp.js +75 -0
  89. package/dist/core/diagnostics/probes/node.js +59 -0
  90. package/dist/core/diagnostics/probes/pnpm.js +36 -0
  91. package/dist/core/diagnostics/probes/pugi-md.js +89 -0
  92. package/dist/core/diagnostics/probes/sandbox.js +72 -0
  93. package/dist/core/diagnostics/probes/session.js +74 -0
  94. package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
  95. package/dist/core/diagnostics/probes/workspace.js +63 -0
  96. package/dist/core/diagnostics/types.js +70 -0
  97. package/dist/core/dispatch/cache-cleanup.js +197 -0
  98. package/dist/core/dispatch/cache-handoff.js +295 -0
  99. package/dist/core/edits/apply-patch-layer-e.js +189 -0
  100. package/dist/core/edits/dispatch.js +333 -7
  101. package/dist/core/edits/format-detector.js +260 -0
  102. package/dist/core/edits/format-matrix.js +26 -0
  103. package/dist/core/edits/fuzzy-ladder.js +650 -0
  104. package/dist/core/edits/index.js +5 -1
  105. package/dist/core/edits/journal.js +199 -0
  106. package/dist/core/edits/layer-a-apply.js +15 -15
  107. package/dist/core/edits/layer-a-fuzzy-apply.js +198 -0
  108. package/dist/core/edits/layer-b-apply.js +9 -9
  109. package/dist/core/edits/layer-c-apply.js +6 -6
  110. package/dist/core/edits/layer-d-ast.js +557 -14
  111. package/dist/core/edits/marker-parser.js +12 -12
  112. package/dist/core/edits/security-gate.js +27 -27
  113. package/dist/core/edits/verify-hook.js +273 -0
  114. package/dist/core/edits/worktree.js +322 -0
  115. package/dist/core/engine/anvil-client.js +214 -26
  116. package/dist/core/engine/auto-compact.js +247 -0
  117. package/dist/core/engine/budgets.js +220 -0
  118. package/dist/core/engine/compact-llm-summarizer.js +124 -0
  119. package/dist/core/engine/context-prefix.js +155 -0
  120. package/dist/core/engine/index.js +1 -1
  121. package/dist/core/engine/intensity.js +163 -0
  122. package/dist/core/engine/intent.js +260 -0
  123. package/dist/core/engine/native-pugi.js +1559 -227
  124. package/dist/core/engine/prompts.js +192 -16
  125. package/dist/core/engine/strip-internal-fields.js +124 -0
  126. package/dist/core/engine/tool-bridge.js +1887 -59
  127. package/dist/core/engine/verification-patterns.js +195 -0
  128. package/dist/core/evaluation/golden-dataset.js +293 -0
  129. package/dist/core/feedback/queue.js +177 -0
  130. package/dist/core/feedback/submitter.js +145 -0
  131. package/dist/core/file-cache.js +113 -1
  132. package/dist/core/flatten/flatten-repo.js +439 -0
  133. package/dist/core/format/osc8-link.js +28 -0
  134. package/dist/core/hook-chains.js +392 -0
  135. package/dist/core/hooks/citation-verify-hook.js +138 -0
  136. package/dist/core/hooks/citation-verify.js +112 -0
  137. package/dist/core/hooks/events.js +46 -0
  138. package/dist/core/hooks/index.js +15 -0
  139. package/dist/core/hooks/registry.js +216 -0
  140. package/dist/core/hooks/runner.js +236 -0
  141. package/dist/core/hooks/v2/event-emitter.js +115 -0
  142. package/dist/core/hooks/v2/executor.js +282 -0
  143. package/dist/core/hooks/v2/index.js +25 -0
  144. package/dist/core/hooks/v2/lifecycle.js +104 -0
  145. package/dist/core/hooks/v2/loader.js +216 -0
  146. package/dist/core/hooks/v2/matcher.js +125 -0
  147. package/dist/core/hooks/v2/trust.js +143 -0
  148. package/dist/core/hooks/v2/types.js +86 -0
  149. package/dist/core/hooks/worktree-events.js +158 -0
  150. package/dist/core/image/renderer.js +71 -0
  151. package/dist/core/init/detector.js +582 -0
  152. package/dist/core/init/template-renderer.js +242 -0
  153. package/dist/core/jobs/registry.js +18 -18
  154. package/dist/core/ledger/results-tsv.js +142 -0
  155. package/dist/core/log-discipline/stdout-redirect.js +51 -0
  156. package/dist/core/lsp/cache.js +105 -0
  157. package/dist/core/lsp/client.js +1229 -0
  158. package/dist/core/lsp/language-detect.js +66 -0
  159. package/dist/core/lsp/post-edit-diagnostics.js +171 -0
  160. package/dist/core/lsp/server-detect.js +173 -0
  161. package/dist/core/lsp/symbol-cache.js +162 -0
  162. package/dist/core/lsp/symbol-tools.js +664 -0
  163. package/dist/core/mcp/client.js +97 -28
  164. package/dist/core/mcp/http-server.js +553 -0
  165. package/dist/core/mcp/orchestrator-config.js +192 -0
  166. package/dist/core/mcp/orchestrator-tools.js +806 -0
  167. package/dist/core/mcp/permission.js +190 -0
  168. package/dist/core/mcp/registry.js +39 -17
  169. package/dist/core/mcp/server-tools.js +219 -0
  170. package/dist/core/mcp/server.js +397 -0
  171. package/dist/core/mcp/trust.js +10 -10
  172. package/dist/core/memory/dual-write.js +416 -0
  173. package/dist/core/memory/passive-extract.js +130 -0
  174. package/dist/core/memory/phase1-kinds.js +20 -0
  175. package/dist/core/memory/secret-scanner.js +304 -0
  176. package/dist/core/memory-sync/queue.js +170 -0
  177. package/dist/core/metrics/extract.js +113 -0
  178. package/dist/core/modes/roo-modes.js +68 -0
  179. package/dist/core/notes/notes-paths.js +113 -0
  180. package/dist/core/notes/notes-recorder.js +140 -0
  181. package/dist/core/notes/notes-writer.js +53 -0
  182. package/dist/core/notes/renderers.js +0 -0
  183. package/dist/core/notes/slug.js +105 -0
  184. package/dist/core/onboarding/ensure-initialized.js +133 -0
  185. package/dist/core/onboarding/marker.js +111 -0
  186. package/dist/core/onboarding/telemetry-state.js +108 -0
  187. package/dist/core/output-style/presets.js +176 -0
  188. package/dist/core/output-style/state.js +185 -0
  189. package/dist/core/path-security.js +287 -5
  190. package/dist/core/permission.js +82 -22
  191. package/dist/core/permissions/auto-classifier.js +124 -0
  192. package/dist/core/permissions/bash-parser.js +371 -0
  193. package/dist/core/permissions/circuit-breaker.js +83 -0
  194. package/dist/core/permissions/constrained-edit.js +91 -0
  195. package/dist/core/permissions/gate.js +278 -0
  196. package/dist/core/permissions/index.js +20 -0
  197. package/dist/core/permissions/mode.js +174 -0
  198. package/dist/core/permissions/network-egress.js +137 -0
  199. package/dist/core/permissions/state.js +241 -0
  200. package/dist/core/permissions/tool-class.js +107 -0
  201. package/dist/core/plan-mode/ui-state.js +51 -0
  202. package/dist/core/plans/plan-artifact.js +721 -0
  203. package/dist/core/policy-limits/etag-store.js +122 -0
  204. package/dist/core/prd-check/parser.js +215 -0
  205. package/dist/core/prd-check/reporter.js +127 -0
  206. package/dist/core/prd-check/session-review.js +557 -0
  207. package/dist/core/prd-check/verifiers.js +223 -0
  208. package/dist/core/prompt-cache/client-cache.js +99 -0
  209. package/dist/core/prompts/assembly.js +29 -0
  210. package/dist/core/prompts/registry.js +364 -0
  211. package/dist/core/pugi-gitignore.js +52 -0
  212. package/dist/core/pugi-md/cc-compat-rules.js +735 -0
  213. package/dist/core/pugi-md/context-injector.js +76 -0
  214. package/dist/core/pugi-md/walk-up.js +207 -0
  215. package/dist/core/python/uv-installer.js +270 -0
  216. package/dist/core/python/uv-resolver.js +83 -0
  217. package/dist/core/rate-limit/narrator.js +146 -0
  218. package/dist/core/recipes/cli-types.js +20 -0
  219. package/dist/core/recipes/loader.js +103 -0
  220. package/dist/core/recipes/runner.js +345 -0
  221. package/dist/core/recipes/schema.js +587 -0
  222. package/dist/core/release-notes/parser.js +241 -0
  223. package/dist/core/release-notes/state.js +116 -0
  224. package/dist/core/repl/ask.js +37 -37
  225. package/dist/core/repl/cancellation.js +26 -26
  226. package/dist/core/repl/cap-warning.js +4 -4
  227. package/dist/core/repl/clipboard-read.js +11 -11
  228. package/dist/core/repl/dispatch-fsm.js +12 -12
  229. package/dist/core/repl/engine-bridge.js +303 -0
  230. package/dist/core/repl/history-search.js +15 -15
  231. package/dist/core/repl/history.js +28 -18
  232. package/dist/core/repl/kill-ring.js +5 -5
  233. package/dist/core/repl/model-pricing.js +135 -0
  234. package/dist/core/repl/privacy-banner.js +22 -22
  235. package/dist/core/repl/session.js +2714 -228
  236. package/dist/core/repl/slash-commands.js +572 -40
  237. package/dist/core/repl/store/index.js +1 -1
  238. package/dist/core/repl/store/jsonl-log.js +22 -22
  239. package/dist/core/repl/store/lockfile.js +10 -10
  240. package/dist/core/repl/store/session-store.js +136 -107
  241. package/dist/core/repl/store/types.js +15 -15
  242. package/dist/core/repl/store/uuid-v7.js +12 -12
  243. package/dist/core/repl/tool-route.js +382 -0
  244. package/dist/core/repl/workspace-context.js +43 -21
  245. package/dist/core/repo-map/build.js +125 -0
  246. package/dist/core/repo-map/cache.js +185 -0
  247. package/dist/core/repo-map/extractor.js +254 -0
  248. package/dist/core/repo-map/formatter.js +145 -0
  249. package/dist/core/repo-map/page-rank.js +105 -0
  250. package/dist/core/repo-map/scanner.js +211 -0
  251. package/dist/core/retro/git-collector.js +251 -0
  252. package/dist/core/retro/health-card.js +25 -0
  253. package/dist/core/retro/metrics.js +342 -0
  254. package/dist/core/retro/narrative.js +249 -0
  255. package/dist/core/retro/plane-collector.js +274 -0
  256. package/dist/core/retro/pr-issue-link.js +65 -0
  257. package/dist/core/retro/types.js +16 -0
  258. package/dist/core/retry-budget/budget.js +284 -0
  259. package/dist/core/retry-budget/index.js +5 -0
  260. package/dist/core/retry-budget/retry-cap.js +74 -0
  261. package/dist/core/routing/lead-worker.js +43 -0
  262. package/dist/core/routing/pre-flight-estimator.js +108 -0
  263. package/dist/core/runs/run-tree.js +103 -0
  264. package/dist/core/sandboxing/adapter.js +29 -0
  265. package/dist/core/sandboxing/index.js +49 -0
  266. package/dist/core/sandboxing/none.js +19 -0
  267. package/dist/core/sandboxing/seatbelt.js +183 -0
  268. package/dist/core/security/injection-scanner.js +367 -0
  269. package/dist/core/security/output-filter.js +418 -0
  270. package/dist/core/session/env-file.js +105 -0
  271. package/dist/core/session/section-budgets.js +140 -0
  272. package/dist/core/session.js +119 -0
  273. package/dist/core/settings.js +378 -5
  274. package/dist/core/share/formatter.js +271 -0
  275. package/dist/core/share/redactor.js +221 -0
  276. package/dist/core/share/uploader.js +267 -0
  277. package/dist/core/skills/defaults.js +457 -0
  278. package/dist/core/skills/loader.js +22 -22
  279. package/dist/core/skills/sources.js +27 -27
  280. package/dist/core/smoke/headless-driver.js +174 -0
  281. package/dist/core/smoke/orchestrator.js +194 -0
  282. package/dist/core/smoke/runner.js +238 -0
  283. package/dist/core/smoke/scenario-parser.js +316 -0
  284. package/dist/core/statusline.js +99 -0
  285. package/dist/core/subagents/dispatcher-real.js +600 -0
  286. package/dist/core/subagents/dispatcher.js +146 -52
  287. package/dist/core/subagents/index.js +19 -6
  288. package/dist/core/subagents/isolation-matrix.js +213 -0
  289. package/dist/core/subagents/spawn.js +19 -4
  290. package/dist/core/telemetry/emitter.js +229 -0
  291. package/dist/core/telemetry/queue.js +251 -0
  292. package/dist/core/theme/context.js +91 -0
  293. package/dist/core/theme/presets.js +228 -0
  294. package/dist/core/theme/state.js +181 -0
  295. package/dist/core/todos/invariant.js +10 -0
  296. package/dist/core/todos/state.js +177 -0
  297. package/dist/core/tool-schema/compressor.js +89 -0
  298. package/dist/core/transport/version-interceptor.js +166 -0
  299. package/dist/core/trust.js +2 -2
  300. package/dist/core/tui/thinking-block.js +64 -0
  301. package/dist/core/vim/keymap.js +288 -0
  302. package/dist/core/vim/state.js +92 -0
  303. package/dist/core/watch-markers/marker-watcher.js +133 -0
  304. package/dist/core/worktree/include-parser.js +249 -0
  305. package/dist/core/worktree-manager/cleanup.js +123 -0
  306. package/dist/core/worktree-manager/manager.js +303 -0
  307. package/dist/index.js +36 -0
  308. package/dist/runtime/bootstrap.js +190 -0
  309. package/dist/runtime/cli.js +4536 -477
  310. package/dist/runtime/commands/agents.js +31 -31
  311. package/dist/runtime/commands/budget.js +5 -5
  312. package/dist/runtime/commands/cancel.js +231 -0
  313. package/dist/runtime/commands/chain.js +489 -0
  314. package/dist/runtime/commands/codegraph-status.js +227 -0
  315. package/dist/runtime/commands/compact.js +297 -0
  316. package/dist/runtime/commands/config.js +74 -40
  317. package/dist/runtime/commands/cost.js +199 -0
  318. package/dist/runtime/commands/delegate.js +312 -0
  319. package/dist/runtime/commands/dispatch.js +126 -0
  320. package/dist/runtime/commands/doctor.js +579 -0
  321. package/dist/runtime/commands/feedback.js +184 -0
  322. package/dist/runtime/commands/hooks.js +187 -0
  323. package/dist/runtime/commands/index-cmd.js +353 -0
  324. package/dist/runtime/commands/init.js +254 -0
  325. package/dist/runtime/commands/lsp.js +368 -0
  326. package/dist/runtime/commands/mcp.js +935 -0
  327. package/dist/runtime/commands/memory.js +582 -0
  328. package/dist/runtime/commands/model.js +237 -0
  329. package/dist/runtime/commands/onboarding.js +275 -0
  330. package/dist/runtime/commands/patch.js +128 -0
  331. package/dist/runtime/commands/permissions.js +112 -0
  332. package/dist/runtime/commands/plan.js +143 -0
  333. package/dist/runtime/commands/prd-check.js +285 -0
  334. package/dist/runtime/commands/privacy.js +17 -17
  335. package/dist/runtime/commands/recipe.js +325 -0
  336. package/dist/runtime/commands/redo-blob-store.js +92 -0
  337. package/dist/runtime/commands/redo.js +361 -0
  338. package/dist/runtime/commands/release-notes.js +229 -0
  339. package/dist/runtime/commands/repo-map.js +95 -0
  340. package/dist/runtime/commands/report.js +299 -0
  341. package/dist/runtime/commands/resume.js +118 -0
  342. package/dist/runtime/commands/review-consensus.js +68 -53
  343. package/dist/runtime/commands/rewind.js +333 -0
  344. package/dist/runtime/commands/roster.js +117 -0
  345. package/dist/runtime/commands/servers.js +236 -0
  346. package/dist/runtime/commands/sessions.js +163 -0
  347. package/dist/runtime/commands/share.js +316 -0
  348. package/dist/runtime/commands/skills.js +31 -31
  349. package/dist/runtime/commands/status.js +186 -0
  350. package/dist/runtime/commands/stickers.js +82 -0
  351. package/dist/runtime/commands/style.js +194 -0
  352. package/dist/runtime/commands/theme.js +196 -0
  353. package/dist/runtime/commands/undo.js +54 -22
  354. package/dist/runtime/commands/update.js +289 -0
  355. package/dist/runtime/commands/vim.js +140 -0
  356. package/dist/runtime/commands/worktree.js +177 -0
  357. package/dist/runtime/commands/worktrees.js +155 -0
  358. package/dist/runtime/deprecation-warning.js +69 -0
  359. package/dist/runtime/engine-exit-code.js +50 -0
  360. package/dist/runtime/headless-repl.js +195 -0
  361. package/dist/runtime/headless.js +548 -0
  362. package/dist/runtime/load-hooks-or-exit.js +71 -0
  363. package/dist/runtime/plan-decompose.js +531 -0
  364. package/dist/runtime/sigint-guard.js +272 -0
  365. package/dist/runtime/stream-renderer.js +195 -0
  366. package/dist/runtime/update-check.js +28 -28
  367. package/dist/runtime/version.js +65 -0
  368. package/dist/runtime/worktree-bootstrap.js +579 -0
  369. package/dist/skills/bundled/batch.js +617 -0
  370. package/dist/skills/bundled/index.js +45 -0
  371. package/dist/skills/bundled/loop.js +358 -0
  372. package/dist/skills/bundled/remember.js +383 -0
  373. package/dist/skills/bundled/simplify.js +289 -0
  374. package/dist/skills/bundled/skillify.js +373 -0
  375. package/dist/skills/bundled/stuck.js +558 -0
  376. package/dist/skills/bundled/verify.js +439 -0
  377. package/dist/testing/vcr.js +486 -0
  378. package/dist/tools/agent-tool.js +229 -0
  379. package/dist/tools/apply-patch.js +556 -0
  380. package/dist/tools/ask-user-question.js +337 -0
  381. package/dist/tools/ask-user.js +115 -0
  382. package/dist/tools/bash.js +624 -46
  383. package/dist/tools/brief.js +224 -0
  384. package/dist/tools/cron.js +433 -0
  385. package/dist/tools/enter-worktree.js +250 -0
  386. package/dist/tools/exit-worktree.js +147 -0
  387. package/dist/tools/file-tools.js +161 -44
  388. package/dist/tools/http-request.js +336 -0
  389. package/dist/tools/lsp-tools.js +565 -0
  390. package/dist/tools/mcp-tool.js +260 -0
  391. package/dist/tools/multi-edit.js +361 -0
  392. package/dist/tools/powershell.js +268 -0
  393. package/dist/tools/registry.js +142 -1
  394. package/dist/tools/server-tools.js +892 -0
  395. package/dist/tools/skill-tool.js +96 -0
  396. package/dist/tools/sleep.js +99 -0
  397. package/dist/tools/synthetic-output.js +133 -0
  398. package/dist/tools/tasks.js +208 -0
  399. package/dist/tools/todo-write.js +184 -0
  400. package/dist/tools/verify-plan-execution.js +295 -0
  401. package/dist/tools/web-fetch-injection-scanner.js +207 -0
  402. package/dist/tools/web-fetch.js +195 -10
  403. package/dist/tools/web-search.js +458 -0
  404. package/dist/tui/agent-progress-card.js +111 -0
  405. package/dist/tui/agent-tree.js +22 -1
  406. package/dist/tui/ask-modal.js +14 -14
  407. package/dist/tui/ask-user-question-chips.js +315 -0
  408. package/dist/tui/ask-user-question-prompt.js +203 -0
  409. package/dist/tui/compact-banner.js +81 -0
  410. package/dist/tui/conversation-pane.js +85 -11
  411. package/dist/tui/cost-table.js +111 -0
  412. package/dist/tui/device-flow.js +2 -2
  413. package/dist/tui/doctor-table.js +46 -0
  414. package/dist/tui/feedback-prompt.js +156 -0
  415. package/dist/tui/input-box.js +247 -32
  416. package/dist/tui/login-picker.js +3 -3
  417. package/dist/tui/markdown-render.js +6 -6
  418. package/dist/tui/multi-file-diff-approval.js +375 -0
  419. package/dist/tui/onboarding-wizard.js +240 -0
  420. package/dist/tui/permissions-picker.js +86 -0
  421. package/dist/tui/render.js +36 -1
  422. package/dist/tui/repl-render.js +405 -32
  423. package/dist/tui/repl-splash-art.js +16 -16
  424. package/dist/tui/repl-splash-mascot.js +48 -24
  425. package/dist/tui/repl-splash.js +22 -22
  426. package/dist/tui/repl.js +136 -43
  427. package/dist/tui/slash-palette.js +6 -6
  428. package/dist/tui/splash.js +2 -2
  429. package/dist/tui/status-bar.js +109 -31
  430. package/dist/tui/status-table.js +7 -0
  431. package/dist/tui/stickers-art.js +136 -0
  432. package/dist/tui/style-table.js +28 -0
  433. package/dist/tui/theme-table.js +29 -0
  434. package/dist/tui/thinking-spinner.js +123 -0
  435. package/dist/tui/tool-stream-pane.js +53 -4
  436. package/dist/tui/update-banner.js +27 -2
  437. package/dist/tui/vim-input.js +267 -0
  438. package/dist/tui/welcome-banner.js +107 -0
  439. package/dist/tui/welcome-data.js +293 -0
  440. package/dist/tui/workspace-context.js +2 -2
  441. package/docs/examples/codegraph.mcp.json +10 -0
  442. package/package.json +25 -7
  443. package/test/scenarios/codegen-create-file.scenario.txt +13 -0
  444. package/test/scenarios/compact-force.scenario.txt +12 -0
  445. package/test/scenarios/identity.scenario.txt +11 -0
  446. package/test/scenarios/persona-handoff.scenario.txt +12 -0
  447. package/test/scenarios/walkback.scenario.txt +12 -0
  448. package/dist/core/engine/compaction-hook.js +0 -154
@@ -1,31 +1,36 @@
1
1
  /**
2
- * Subagent dispatcher (Sprint a5.4 M1 gap remediation D).
2
+ * Subagent dispatcher (β2 S1 + S4 ).
3
3
  *
4
4
  * The dispatcher is the runtime side of the @pugi/sdk subagent contracts.
5
5
  * Given a SubagentTask, it:
6
6
  *
7
- * 1. Resolves the role to a Cyber-Zoo persona via the local registry
8
- * (apps/pugi-cli/src/core/agents/registry.ts, which itself sources
9
- * @pugi/personas).
10
- * 2. Classifies isolation per the M1 matrix (see isolationForRole).
11
- * 3. Builds the dispatch-time permission overrides (Vera as reviewer
12
- * or verifier loses every edit/write/bash class — see
13
- * permissionOverridesForRole).
14
- * 4. Emits subagent.spawned into the session events log.
15
- * 5. Runs the dispatch (M1: stub returning shipped immediately so the
16
- * contract surface is exercisable; M2+ swaps the body for
17
- * worktree-isolated execution backed by runEngineLoop).
18
- * 6. Emits subagent.completed | blocked | failed into the session
19
- * events log.
20
- * 7. Returns the typed SubagentResult.
7
+ * 1. Resolves the role to a Cyber-Zoo persona via the local registry
8
+ * (apps/pugi-cli/src/core/agents/registry.ts, which itself sources
9
+ * @pugi/personas).
10
+ * 2. Classifies isolation per the matrix (see isolationForRole).
11
+ * 3. Builds the dispatch-time permission overrides (Vera as reviewer
12
+ * or verifier loses every edit/write/bash class — see
13
+ * permissionOverridesForRole).
14
+ * 4. Emits subagent.spawned into the session events log.
15
+ * 5. Drives the dispatch via one of two backends:
16
+ * - REAL (β2 S1): when ctx carries an EngineLoopClient, the child
17
+ * runs a genuine `runEngineLoop` against Anvil with a per-child
18
+ * tools schema gated by the isolation-matrix capability map
19
+ * (β2 S4). See `dispatcher-real.ts::runRealDispatch`.
20
+ * - STUB (M1 legacy): when no engine client is supplied, the
21
+ * dispatcher returns a `shipped` result with zero metrics so
22
+ * the legacy `inMemoryDispatcherContext` test path stays green.
23
+ * This is the back-compat door for the M1 spec coverage.
24
+ * 6. Emits subagent.completed | blocked | failed into the session
25
+ * events log (real backend emits richer details; stub emits the
26
+ * M1-compatible shape).
27
+ * 7. Returns the typed SubagentResult.
21
28
  *
22
- * Why a stub at M1: the contract surface itself, the event emission, the
23
- * isolation classification, and the permission overrides are real
24
- * load-bearing pieces the cabinet UI, audit replay, and triple-review
25
- * gating all read these events. The model-driven loop that actually
26
- * spawns a separate Anvil session is alpha-5.7 work (REPL-by-default).
27
- * The stub returns a shipped result with the correct persona slug + role
28
- * pair so downstream consumers can wire against the real shape.
29
+ * Why we kept the stub path: the existing M1 spec coverage exercises
30
+ * the dispatcher's contract surface (role-to-persona, isolation tier,
31
+ * permission overrides, event ordering) without any HTTP transport.
32
+ * β2 must not regress that surface every existing assertion still
33
+ * holds for in-memory contexts. The real backend is a strict superset.
29
34
  *
30
35
  * The dispatcher is the only place that knows the isolation matrix and
31
36
  * the permission overrides. Both surfaces are exported so engine adapter
@@ -36,10 +41,10 @@ import { randomUUID } from 'node:crypto';
36
41
  import { subagentTaskSchema } from '@pugi/sdk';
37
42
  import { getPersonaForRole } from '../agents/registry.js';
38
43
  /* ------------------------------------------------------------------ */
39
- /* Isolation matrix */
44
+ /* Isolation matrix */
40
45
  /* ------------------------------------------------------------------ */
41
46
  /**
42
- * M1 isolation matrix (ADR-0056 Sprint a5.4 acceptance #2).
47
+ * M1 isolation matrix .
43
48
  *
44
49
  * The function is pure (same role in, same isolation out) and exported
45
50
  * separately so consumers (tests, REPL UI) can introspect without
@@ -62,11 +67,11 @@ export function isolationForRole(role) {
62
67
  }
63
68
  }
64
69
  /* ------------------------------------------------------------------ */
65
- /* Permission overrides */
70
+ /* Permission overrides */
66
71
  /* ------------------------------------------------------------------ */
67
72
  /**
68
73
  * Per-role permission overrides applied at dispatch time. The dominant
69
- * case is Vera's dual-role rule (ADR-0056 Sprint a5.4 acceptance #4):
74
+ * case is Vera's dual-role rule :
70
75
  * when dispatched as verifier OR reviewer, Vera gets edit: deny (which
71
76
  * we generalize to deny edit + write + bash, the three classes that can
72
77
  * mutate the workspace) so a review pass cannot accidentally patch what
@@ -81,7 +86,7 @@ export function isolationForRole(role) {
81
86
  * Write-capable roles (coder, release, devops, design_qa) get no
82
87
  * override; they inherit the workspace permission settings as-is.
83
88
  *
84
- * orchestrator also gets no override; Mira runs inside the parent
89
+ * orchestrator also gets no override; Pugi runs inside the parent
85
90
  * context, so the parent's permission settings already govern her.
86
91
  */
87
92
  export function permissionOverridesForRole(role) {
@@ -104,17 +109,17 @@ const DENY_ALL_WRITES_VERA = Object.freeze([
104
109
  {
105
110
  toolClass: 'edit',
106
111
  allowedPaths: Object.freeze([]),
107
- reason: 'Vera dispatched as verifier/reviewer (ADR-0056 section a5.4 acceptance #4)',
112
+ reason: 'Vera dispatched as verifier/reviewer ',
108
113
  },
109
114
  {
110
115
  toolClass: 'write',
111
116
  allowedPaths: Object.freeze([]),
112
- reason: 'Vera dispatched as verifier/reviewer (ADR-0056 section a5.4 acceptance #4)',
117
+ reason: 'Vera dispatched as verifier/reviewer ',
113
118
  },
114
119
  {
115
120
  toolClass: 'bash',
116
121
  allowedPaths: Object.freeze([]),
117
- reason: 'Vera dispatched as verifier/reviewer (ADR-0056 section a5.4 acceptance #4)',
122
+ reason: 'Vera dispatched as verifier/reviewer ',
118
123
  },
119
124
  ]);
120
125
  const DENY_ALL_WRITES_READONLY = Object.freeze([
@@ -135,18 +140,23 @@ const DENY_ALL_WRITES_READONLY = Object.freeze([
135
140
  },
136
141
  ]);
137
142
  /* ------------------------------------------------------------------ */
138
- /* Default budgets */
143
+ /* Default budgets */
139
144
  /* ------------------------------------------------------------------ */
145
+ // CEO escalation 2026-06-05: 120K coder budget exhausted mid-React-
146
+ // build (120214 > 120000). Match the engine-level `code` task bump
147
+ // (apps/pugi-cli/src/core/engine/budgets.ts:149 — 400K). Subagent
148
+ // dispatches inherit the upstream caller's headroom, so this needs
149
+ // to track the engine envelope.
140
150
  const DEFAULT_BUDGETS = Object.freeze({
141
- orchestrator: { tokens: 200_000, dollars: 5, wallClockMs: 600_000 },
142
- architect: { tokens: 80_000, dollars: 2, wallClockMs: 300_000 },
143
- coder: { tokens: 120_000, dollars: 3, wallClockMs: 600_000 },
144
- verifier: { tokens: 60_000, dollars: 2, wallClockMs: 300_000 },
145
- reviewer: { tokens: 80_000, dollars: 2, wallClockMs: 300_000 },
146
- researcher: { tokens: 60_000, dollars: 1.5, wallClockMs: 300_000 },
147
- release: { tokens: 40_000, dollars: 1, wallClockMs: 180_000 },
148
- devops: { tokens: 60_000, dollars: 2, wallClockMs: 300_000 },
149
- design_qa: { tokens: 60_000, dollars: 1.5, wallClockMs: 300_000 },
151
+ orchestrator: { tokens: 400_000, dollars: 8, wallClockMs: 900_000 },
152
+ architect: { tokens: 200_000, dollars: 4, wallClockMs: 600_000 },
153
+ coder: { tokens: 400_000, dollars: 8, wallClockMs: 900_000 },
154
+ verifier: { tokens: 150_000, dollars: 3, wallClockMs: 600_000 },
155
+ reviewer: { tokens: 200_000, dollars: 4, wallClockMs: 600_000 },
156
+ researcher: { tokens: 150_000, dollars: 3, wallClockMs: 600_000 },
157
+ release: { tokens: 80_000, dollars: 2, wallClockMs: 300_000 },
158
+ devops: { tokens: 150_000, dollars: 3, wallClockMs: 600_000 },
159
+ design_qa: { tokens: 150_000, dollars: 3, wallClockMs: 600_000 },
150
160
  });
151
161
  /**
152
162
  * Resolve the effective budget for a dispatch by merging task overrides
@@ -164,19 +174,51 @@ export function budgetForRole(role, override) {
164
174
  };
165
175
  }
166
176
  /* ------------------------------------------------------------------ */
167
- /* Dispatch */
177
+ /* Real-backend lazy import (memoized) */
168
178
  /* ------------------------------------------------------------------ */
169
179
  /**
170
- * Spawn a subagent. M1 implementation is a stub that synchronously
171
- * returns a shipped result so the contract surface is exercised by
172
- * tests and the cabinet UI. M2+ replaces the body with an Anvil-side
173
- * dispatch over a per-task worktree (ADR-0057, deferred).
180
+ * β2a r1 (Backend Architect P1): cached lazy-import of
181
+ * the real dispatch backend. Hoisting the dynamic import to
182
+ * module scope (instead of running it on every dispatch call) means
183
+ * the first agent spawn does not pay 50-200ms cold-start latency.
174
184
  *
175
- * The function still emits real subagent.spawned and subagent.completed
176
- * events; downstream consumers (audit replay, cabinet activity feed,
177
- * eval harness) cannot tell the stub apart from a real dispatch on the
178
- * event surface alone, which is the property we want for forward-
179
- * compatibility testing.
185
+ * The cache is a Promise so concurrent first-callers share one
186
+ * import; ESM's own module cache also dedups but the Promise wrapper
187
+ * lets `prewarmRealDispatch` kick off the import without awaiting.
188
+ */
189
+ let realDispatchPromise = null;
190
+ function ensureRealDispatch() {
191
+ if (!realDispatchPromise) {
192
+ realDispatchPromise = import('./dispatcher-real.js');
193
+ }
194
+ return realDispatchPromise;
195
+ }
196
+ /**
197
+ * β2a r1: pre-warm the real dispatcher's module graph. Called by the
198
+ * engine adapter (`NativePugiEngineAdapter`) at construction time
199
+ * when an engine client is wired, so the first `dispatch()` call
200
+ * with `ctx.engineClient` set returns instantly. Safe to call
201
+ * multiple times — subsequent calls hit the cached promise.
202
+ */
203
+ export function prewarmRealDispatch() {
204
+ return ensureRealDispatch();
205
+ }
206
+ /**
207
+ * Spawn a subagent. Two backends:
208
+ *
209
+ * - REAL (β2 S1): when `ctx.engineClient` is set, the dispatcher
210
+ * spawns a genuine child engine loop. See `dispatcher-real.ts`.
211
+ * The child's tool surface is filtered by the isolation matrix
212
+ * (β2 S4) so a `researcher` role cannot see `write`/`edit`/`bash`
213
+ * in its tools schema and the executor refuses if the model
214
+ * fabricates a call.
215
+ *
216
+ * - STUB (M1 legacy): when no engine client is supplied, the
217
+ * dispatcher returns a `shipped` result with zero metrics. This
218
+ * is the back-compat door for the M1 spec coverage and for
219
+ * in-memory consumers that only want to assert the dispatcher's
220
+ * CONTRACT surface (role-to-persona, isolation tier, permission
221
+ * overrides, event ordering) without standing up Anvil.
180
222
  *
181
223
  * The function rejects with ZodError when the task fails schema
182
224
  * validation. Throwing rather than returning a failed result is the
@@ -186,6 +228,58 @@ export function budgetForRole(role, override) {
186
228
  */
187
229
  export async function dispatch(task, ctx) {
188
230
  const validated = subagentTaskSchema.parse(task);
231
+ if (ctx.engineClient) {
232
+ // β2a r1 (Backend Architect P1): the lazy import
233
+ // chain (worktree + engine SDK graph) cost 50-200ms on the FIRST
234
+ // dispatch call. `ensureRealDispatch` memoizes the promise so the
235
+ // import happens at most once per process; subsequent dispatches
236
+ // hit the cached promise instantly. Production callers should
237
+ // prewarm via `prewarmRealDispatch()` at engine adapter init so
238
+ // the operator never pays cold-start on the first agent call.
239
+ const { runRealDispatch } = await ensureRealDispatch();
240
+ const outcome = await runRealDispatch(validated, {
241
+ sessionId: ctx.sessionId,
242
+ workspaceRoot: ctx.workspaceRoot,
243
+ appendEvent: ctx.appendEvent,
244
+ ...(ctx.now ? { now: ctx.now } : {}),
245
+ engineClient: ctx.engineClient,
246
+ ...(ctx.commandKind ? { commandKind: ctx.commandKind } : {}),
247
+ ...(ctx.useWorktreeIsolation !== undefined
248
+ ? { useWorktreeIsolation: ctx.useWorktreeIsolation }
249
+ : {}),
250
+ ...(ctx.signal ? { signal: ctx.signal } : {}),
251
+ });
252
+ return outcome.result;
253
+ }
254
+ return runStubDispatch(validated, ctx);
255
+ }
256
+ /**
257
+ * Real-backend variant that also surfaces the optional worktree
258
+ * handle. Callers that need to promote/drop the scratch worktree
259
+ * (e.g. the REPL `/agent` surface, or the Agent tool dispatcher) use
260
+ * this entry point.
261
+ */
262
+ export async function dispatchWithOutcome(task, ctx) {
263
+ const validated = subagentTaskSchema.parse(task);
264
+ if (ctx.engineClient) {
265
+ const { runRealDispatch } = await ensureRealDispatch();
266
+ return runRealDispatch(validated, {
267
+ sessionId: ctx.sessionId,
268
+ workspaceRoot: ctx.workspaceRoot,
269
+ appendEvent: ctx.appendEvent,
270
+ ...(ctx.now ? { now: ctx.now } : {}),
271
+ engineClient: ctx.engineClient,
272
+ ...(ctx.commandKind ? { commandKind: ctx.commandKind } : {}),
273
+ ...(ctx.useWorktreeIsolation !== undefined
274
+ ? { useWorktreeIsolation: ctx.useWorktreeIsolation }
275
+ : {}),
276
+ ...(ctx.signal ? { signal: ctx.signal } : {}),
277
+ });
278
+ }
279
+ const result = await runStubDispatch(validated, ctx);
280
+ return { result };
281
+ }
282
+ async function runStubDispatch(validated, ctx) {
189
283
  const persona = getPersonaForRole(validated.role);
190
284
  const isolation = isolationForRole(validated.role);
191
285
  void budgetForRole(validated.role, validated.budget);
@@ -233,13 +327,13 @@ export async function dispatch(task, ctx) {
233
327
  return result;
234
328
  }
235
329
  function stubSummaryFor(role, personaName) {
236
- return `${personaName} (${role}) dispatched: stub returning shipped (M1 contract surface only; real dispatch in alpha-5.7)`;
330
+ return `${personaName} (${role}) dispatched: in-memory stub backend (no engine client supplied; production callers should pass DispatcherContext.engineClient)`;
237
331
  }
238
332
  function defaultNow() {
239
333
  return new Date().toISOString();
240
334
  }
241
335
  /* ------------------------------------------------------------------ */
242
- /* Convenience helpers */
336
+ /* Convenience helpers */
243
337
  /* ------------------------------------------------------------------ */
244
338
  /**
245
339
  * Build a dispatch context tied to an in-memory event sink. Useful for
@@ -6,7 +6,7 @@
6
6
  * engine adapter code, the REPL, and tests can pull in everything they
7
7
  * need with one import statement:
8
8
  *
9
- * import { dispatch, isolationForRole, ... } from '../core/subagents/index.js';
9
+ * import { dispatch, isolationForRole, ... } from '../core/subagents/index.js';
10
10
  *
11
11
  * The submodule index does not re-export persona types — those live in
12
12
  * @pugi/personas and are pulled in by core/agents/registry.ts. Mixing
@@ -14,13 +14,26 @@
14
14
  * would invite the kind of accidental drift the persona-registry
15
15
  * extraction was designed to prevent.
16
16
  */
17
- export { budgetForRole, dispatch, inMemoryDispatcherContext, isolationForRole, permissionOverridesForRole, } from './dispatcher.js';
17
+ export { budgetForRole, dispatch, dispatchWithOutcome, inMemoryDispatcherContext, isolationForRole, permissionOverridesForRole, } from './dispatcher.js';
18
+ /**
19
+ * β2 S4: per-role capability matrix. Surfaced via the barrel so
20
+ * engine adapter code, the Agent tool, and tests can introspect a
21
+ * role's allowed tool set without importing the matrix module
22
+ * directly.
23
+ */
24
+ export { allowedToolsForRole, capabilitiesForRole, roleHasToolAccess, ROLE_CAPABILITIES, } from './isolation-matrix.js';
25
+ /**
26
+ * β2 S1: real-backend entry point. Exposed for callers that want to
27
+ * drive the dispatch with the worktree handle in scope (e.g. the
28
+ * Agent tool, the REPL `/agent` surface). Most callers should prefer
29
+ * the `dispatch()` / `dispatchWithOutcome()` helpers above which
30
+ * route to this module when ctx.engineClient is set.
31
+ */
32
+ export { runRealDispatch } from './dispatcher-real.js';
18
33
  /**
19
34
  * Spawn a subagent from inside the engine adapter loop. Re-exported via
20
35
  * the barrel so engine code does not have to import the dispatcher
21
- * module directly. The actual task_dispatch tool that the model uses
22
- * to invoke a subagent lands in alpha-5.7 (REPL); for now the helper
23
- * exists so adapter code has a single seam to wire against.
36
+ * module directly.
24
37
  */
25
- export { spawnSubagent } from './spawn.js';
38
+ export { spawnSubagent, spawnSubagentWithOutcome } from './spawn.js';
26
39
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,213 @@
1
+ const CAP_READ_ONLY = new Set([
2
+ 'read',
3
+ 'task',
4
+ 'skill',
5
+ ]);
6
+ const CAP_VERIFIER = new Set([
7
+ 'read',
8
+ 'task',
9
+ 'skill',
10
+ // β2a r1 (Codex P1): verifier previously got the FULL
11
+ // `bash` capability. The class-aware bash tool defaults to
12
+ // permission mode `auto`, which permits `write_workspace` class
13
+ // commands (e.g. `echo x > src/file.ts`, `sed -i`, `rm`). That
14
+ // silently bypassed the no-edit/no-write contract — a verifier
15
+ // could mutate the workspace it was meant to read.
16
+ //
17
+ // The fix splits bash into two capabilities:
18
+ // - `bash` → full bash (writers only)
19
+ // - `bash_read_only` → bash gate that forces read-only classifier
20
+ // mode regardless of operator settings
21
+ // verifier needs the read-only flavor so test commands (pnpm test,
22
+ // jest --listFiles, typecheck) still work but a fabricated
23
+ // `echo x > file.ts` is refused at the executor layer.
24
+ 'bash_read_only',
25
+ ]);
26
+ const CAP_WRITER = new Set([
27
+ 'read',
28
+ 'write',
29
+ 'bash',
30
+ 'task',
31
+ 'skill',
32
+ 'ask_user',
33
+ ]);
34
+ const CAP_FULL = new Set([
35
+ 'read',
36
+ 'write',
37
+ 'bash',
38
+ 'task',
39
+ 'skill',
40
+ 'ask_user',
41
+ 'web_fetch',
42
+ 'agent',
43
+ ]);
44
+ /**
45
+ * Per-role capability map. Add a new role only when the matching
46
+ * isolation tier classification in dispatcher.ts agrees with the
47
+ * capability set here — drift would let a `coder` role get write
48
+ * privileges with `shared_fs_readonly` isolation, which would mean
49
+ * the dispatcher emits readonly-isolation events while the child
50
+ * actually writes. Always touch both files together.
51
+ */
52
+ export const ROLE_CAPABILITIES = new Map([
53
+ [
54
+ 'orchestrator',
55
+ {
56
+ role: 'orchestrator',
57
+ capabilities: CAP_FULL,
58
+ rationale: 'orchestrator (Pugi/Pugi) runs in parent context with full toolset; '
59
+ + 'parent permissions still gate any actual mutation',
60
+ },
61
+ ],
62
+ [
63
+ 'architect',
64
+ {
65
+ role: 'architect',
66
+ capabilities: CAP_READ_ONLY,
67
+ rationale: 'architect role is read-only by design (analysis + planning, no mutations)',
68
+ },
69
+ ],
70
+ [
71
+ 'coder',
72
+ {
73
+ role: 'coder',
74
+ capabilities: CAP_WRITER,
75
+ rationale: 'coder role mutates the workspace via write + edit + bash',
76
+ },
77
+ ],
78
+ [
79
+ 'verifier',
80
+ {
81
+ role: 'verifier',
82
+ capabilities: CAP_VERIFIER,
83
+ rationale: 'verifier role reads workspace + executes verification commands (tests, typecheck) '
84
+ + 'but never edits the code it is verifying',
85
+ },
86
+ ],
87
+ [
88
+ 'reviewer',
89
+ {
90
+ role: 'reviewer',
91
+ capabilities: CAP_READ_ONLY,
92
+ rationale: 'reviewer role is read-only by policy (no edits to code under review); '
93
+ + 'shell is denied because reviewer should not be re-running tests',
94
+ },
95
+ ],
96
+ [
97
+ 'researcher',
98
+ {
99
+ role: 'researcher',
100
+ capabilities: CAP_READ_ONLY,
101
+ rationale: 'researcher role is read-only (corpus search + summarization)',
102
+ },
103
+ ],
104
+ [
105
+ 'release',
106
+ {
107
+ role: 'release',
108
+ capabilities: CAP_WRITER,
109
+ rationale: 'release role needs write + bash for changelog edits + version bumps',
110
+ },
111
+ ],
112
+ [
113
+ 'devops',
114
+ {
115
+ role: 'devops',
116
+ capabilities: CAP_WRITER,
117
+ rationale: 'devops role needs write + bash for infra config + deploy scripts',
118
+ },
119
+ ],
120
+ [
121
+ 'design_qa',
122
+ {
123
+ role: 'design_qa',
124
+ capabilities: CAP_WRITER,
125
+ rationale: 'design_qa role needs write + bash for UI tweaks + screenshot scripts',
126
+ },
127
+ ],
128
+ ]);
129
+ /**
130
+ * Resolve the capability set for a role. Throws when the role is not
131
+ * registered — the closed SubagentRole union prevents that at compile
132
+ * time for typed callers, but the runtime guard catches dynamic dispatch
133
+ * paths (e.g. a tag parsed off Pugi's reply text).
134
+ */
135
+ export function capabilitiesForRole(role) {
136
+ const entry = ROLE_CAPABILITIES.get(role);
137
+ if (!entry) {
138
+ throw new Error(`capabilitiesForRole: unknown role '${role}'`);
139
+ }
140
+ return entry;
141
+ }
142
+ /**
143
+ * Map capability classes → concrete tool names (matches tool-bridge.ts
144
+ * WIRED_TOOLS). This is the bridge between the policy layer (this file)
145
+ * and the schema-shaping layer (tool-bridge buildToolsSchema). Keep in
146
+ * lockstep with WIRED_TOOLS — a new tool added to the bridge should
147
+ * be classified here so subagents see (or do not see) it consistently.
148
+ */
149
+ const CAPABILITY_TO_TOOLS = {
150
+ read: ['read', 'grep', 'glob'],
151
+ write: ['write', 'edit'],
152
+ bash: ['bash'],
153
+ // β2a r1 : `bash_read_only` maps to the same `bash`
154
+ // tool name so the model sees only one tool surface. The
155
+ // dispatcher-real executor wraps the verifier's bash calls with a
156
+ // forced read-only classifier mode (see `gatedExecutor` in
157
+ // dispatcher-real.ts) so a `write_workspace`-class command is
158
+ // rejected before the tool runs even though the capability set
159
+ // appears to advertise `bash`.
160
+ bash_read_only: ['bash'],
161
+ task: ['task_create', 'task_get', 'task_list', 'task_update'],
162
+ skill: ['skill', 'skills_list'],
163
+ ask_user: ['ask_user_question'],
164
+ web_fetch: ['web_fetch'],
165
+ // Agent tool is the subagent spawn primitive itself (S3). Only the
166
+ // orchestrator role gets it — child agents cannot recursively spawn
167
+ // grand-children, which keeps the spawn depth bounded at 1 and the
168
+ // budget rollup tractable.
169
+ agent: ['agent'],
170
+ };
171
+ /**
172
+ * Return the set of tool names a role is allowed to call. Used by the
173
+ * per-child tool-bridge to shape the OpenAI tools schema AND by the
174
+ * executor refusal gate.
175
+ *
176
+ * The function is pure — same role in, same set out — so the schema
177
+ * builder can call it from inside `buildToolsSchema`.
178
+ */
179
+ export function allowedToolsForRole(role) {
180
+ const caps = capabilitiesForRole(role);
181
+ const out = new Set();
182
+ for (const cap of caps.capabilities) {
183
+ for (const name of CAPABILITY_TO_TOOLS[cap]) {
184
+ out.add(name);
185
+ }
186
+ }
187
+ return out;
188
+ }
189
+ /**
190
+ * Predicate: is a tool name reachable by a role under the capability
191
+ * matrix? Used by the executor's pre-dispatch refusal gate.
192
+ *
193
+ * Returns true for orchestrator/full-capability roles and for every
194
+ * specific tool the role's capability set unlocks; false otherwise.
195
+ */
196
+ export function roleHasToolAccess(role, toolName) {
197
+ return allowedToolsForRole(role).has(toolName);
198
+ }
199
+ /**
200
+ * β2a r1 (Codex P1): predicate identifying roles whose
201
+ * bash access is restricted to read-only classifier mode. Used by
202
+ * dispatcher-real.ts's gatedExecutor to force-flag bash dispatches as
203
+ * read-only regardless of the workspace's permission settings.
204
+ *
205
+ * A role qualifies when it holds `bash_read_only` but NOT the
206
+ * full-power `bash` capability — orchestrators (which inherit both
207
+ * via CAP_FULL) keep full bash access through the regular path.
208
+ */
209
+ export function bashIsReadOnlyForRole(role) {
210
+ const caps = capabilitiesForRole(role).capabilities;
211
+ return caps.has('bash_read_only') && !caps.has('bash');
212
+ }
213
+ //# sourceMappingURL=isolation-matrix.js.map
@@ -1,5 +1,5 @@
1
1
  import { recordSubagentBlocked, recordSubagentCompleted, recordSubagentFailed, recordSubagentSpawned, recordSubagentToolCall, } from '../session.js';
2
- import { dispatch } from './dispatcher.js';
2
+ import { dispatch, dispatchWithOutcome, } from './dispatcher.js';
3
3
  /**
4
4
  * Spawn a subagent under an existing PugiSession. Events are routed
5
5
  * through the session module's recorder functions; if the session is
@@ -7,13 +7,28 @@ import { dispatch } from './dispatcher.js';
7
7
  * dispatch still runs — the contract is "dispatch always works, audit
8
8
  * is best-effort".
9
9
  */
10
- export async function spawnSubagent(task, session) {
11
- const ctx = {
10
+ export async function spawnSubagent(task, session, options = {}) {
11
+ return dispatch(task, buildContext(session, options));
12
+ }
13
+ /**
14
+ * β2 S1: spawnSubagent variant that surfaces the optional worktree
15
+ * handle so the caller can wire promote/drop follow-ups.
16
+ */
17
+ export async function spawnSubagentWithOutcome(task, session, options = {}) {
18
+ return dispatchWithOutcome(task, buildContext(session, options));
19
+ }
20
+ function buildContext(session, options) {
21
+ return {
12
22
  sessionId: session.id,
13
23
  workspaceRoot: session.root,
14
24
  appendEvent: (event) => routeEvent(event, session),
25
+ ...(options.engineClient ? { engineClient: options.engineClient } : {}),
26
+ ...(options.commandKind ? { commandKind: options.commandKind } : {}),
27
+ ...(options.useWorktreeIsolation !== undefined
28
+ ? { useWorktreeIsolation: options.useWorktreeIsolation }
29
+ : {}),
30
+ ...(options.signal ? { signal: options.signal } : {}),
15
31
  };
16
- return dispatch(task, ctx);
17
32
  }
18
33
  function routeEvent(event, session) {
19
34
  if (!isRecord(event))