@pugi/cli 0.1.0-beta.8 → 0.1.0-beta.88

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 (405) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/LICENSE +1 -1
  3. package/THIRD_PARTY_NOTICES.md +40 -0
  4. package/assets/pugi-prozr2-mascot.ansi +9 -0
  5. package/bin/run.js +33 -1
  6. package/dist/commands/deploy.js +40 -40
  7. package/dist/commands/flatten.js +191 -0
  8. package/dist/commands/jobs-watch.js +201 -0
  9. package/dist/commands/jobs.js +42 -27
  10. package/dist/commands/smoke.js +133 -0
  11. package/dist/core/agent-progress/cleanup.js +134 -0
  12. package/dist/core/agent-progress/schema.js +144 -0
  13. package/dist/core/agent-progress/writer.js +101 -0
  14. package/dist/core/agents/adaptive-router.js +330 -0
  15. package/dist/core/agents/query-decomposer.js +297 -0
  16. package/dist/core/agents/registry.js +3 -3
  17. package/dist/core/approvals/shortcut-resolver.js +98 -0
  18. package/dist/core/artifact-chain/dispatcher.js +148 -0
  19. package/dist/core/artifact-chain/exporter.js +164 -0
  20. package/dist/core/artifact-chain/state.js +243 -0
  21. package/dist/core/artifact-chain/steps.js +169 -0
  22. package/dist/core/ask-user/question.js +92 -0
  23. package/dist/core/audit/audit-trail.js +275 -0
  24. package/dist/core/auth/ensure-authenticated.js +129 -0
  25. package/dist/core/auth/env-provider.js +238 -0
  26. package/dist/core/auto-open-browser.js +4 -4
  27. package/dist/core/auto-update/channels.js +122 -0
  28. package/dist/core/auto-update/checker.js +241 -0
  29. package/dist/core/auto-update/state.js +235 -0
  30. package/dist/core/bare-mode/index.js +107 -0
  31. package/dist/core/bash/redirect.js +281 -0
  32. package/dist/core/bash-classifier.js +436 -40
  33. package/dist/core/checkpoint/resumer.js +149 -0
  34. package/dist/core/checkpoint/rewinder.js +291 -0
  35. package/dist/core/checkpoints/shadow-git.js +670 -0
  36. package/dist/core/citations/parser.js +109 -0
  37. package/dist/core/classifier/yolo-classifier.js +88 -0
  38. package/dist/core/codegraph/decision-store.js +248 -0
  39. package/dist/core/codegraph/detect-repo.js +459 -0
  40. package/dist/core/codegraph/install.js +134 -0
  41. package/dist/core/codegraph/offer-hook.js +220 -0
  42. package/dist/core/compact/auto-trigger.js +96 -0
  43. package/dist/core/compact/buffer-rewriter.js +115 -0
  44. package/dist/core/compact/summarizer.js +208 -0
  45. package/dist/core/compact/token-counter.js +108 -0
  46. package/dist/core/consensus/anvil-fanout.js +25 -25
  47. package/dist/core/consensus/diff-capture.js +121 -12
  48. package/dist/core/consensus/rubric.js +21 -21
  49. package/dist/core/context/builder.js +6 -6
  50. package/dist/core/context/compaction-events.js +8 -8
  51. package/dist/core/context/compaction.js +31 -31
  52. package/dist/core/context/index.js +15 -8
  53. package/dist/core/context/invariants.js +51 -51
  54. package/dist/core/context/markdown-loader.js +28 -10
  55. package/dist/core/context/markdown-traverse.js +255 -0
  56. package/dist/core/context/pugiignore.js +41 -41
  57. package/dist/core/context/repo-skeleton.js +37 -37
  58. package/dist/core/context/tool-eviction.js +55 -0
  59. package/dist/core/context/watcher.js +32 -32
  60. package/dist/core/context/working-set.js +23 -23
  61. package/dist/core/coordinator/agent-tools.js +77 -0
  62. package/dist/core/coordinator/agent-toolset.js +65 -0
  63. package/dist/core/coordinator/fsm.js +73 -0
  64. package/dist/core/coordinator/mode-fsm.js +70 -0
  65. package/dist/core/cost/rate-card.js +129 -0
  66. package/dist/core/cost/tracker.js +221 -0
  67. package/dist/core/credentials.js +12 -12
  68. package/dist/core/cron/scheduler.js +138 -0
  69. package/dist/core/denial-tracking/index.js +8 -0
  70. package/dist/core/denial-tracking/state.js +264 -0
  71. package/dist/core/diagnostics/probe-runner.js +93 -0
  72. package/dist/core/diagnostics/probes/api.js +46 -0
  73. package/dist/core/diagnostics/probes/auth.js +93 -0
  74. package/dist/core/diagnostics/probes/bare-mode.js +42 -0
  75. package/dist/core/diagnostics/probes/cli-version.js +127 -0
  76. package/dist/core/diagnostics/probes/config.js +72 -0
  77. package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
  78. package/dist/core/diagnostics/probes/disk.js +81 -0
  79. package/dist/core/diagnostics/probes/engine-live.js +46 -0
  80. package/dist/core/diagnostics/probes/git.js +65 -0
  81. package/dist/core/diagnostics/probes/hooks.js +118 -0
  82. package/dist/core/diagnostics/probes/mcp.js +75 -0
  83. package/dist/core/diagnostics/probes/node.js +59 -0
  84. package/dist/core/diagnostics/probes/pnpm.js +36 -0
  85. package/dist/core/diagnostics/probes/pugi-md.js +89 -0
  86. package/dist/core/diagnostics/probes/sandbox.js +40 -0
  87. package/dist/core/diagnostics/probes/session.js +74 -0
  88. package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
  89. package/dist/core/diagnostics/probes/workspace.js +63 -0
  90. package/dist/core/diagnostics/types.js +70 -0
  91. package/dist/core/dispatch/cache-cleanup.js +197 -0
  92. package/dist/core/dispatch/cache-handoff.js +295 -0
  93. package/dist/core/edits/apply-patch-layer-e.js +189 -0
  94. package/dist/core/edits/dispatch.js +293 -7
  95. package/dist/core/edits/format-matrix.js +26 -0
  96. package/dist/core/edits/fuzzy-ladder.js +650 -0
  97. package/dist/core/edits/index.js +3 -1
  98. package/dist/core/edits/journal.js +199 -0
  99. package/dist/core/edits/layer-a-apply.js +15 -15
  100. package/dist/core/edits/layer-a-fuzzy-apply.js +198 -0
  101. package/dist/core/edits/layer-b-apply.js +9 -9
  102. package/dist/core/edits/layer-c-apply.js +6 -6
  103. package/dist/core/edits/layer-d-ast.js +557 -14
  104. package/dist/core/edits/marker-parser.js +12 -12
  105. package/dist/core/edits/security-gate.js +27 -27
  106. package/dist/core/edits/verify-hook.js +273 -0
  107. package/dist/core/edits/worktree.js +322 -0
  108. package/dist/core/engine/anvil-client.js +151 -26
  109. package/dist/core/engine/auto-compact.js +179 -0
  110. package/dist/core/engine/budgets.js +186 -0
  111. package/dist/core/engine/context-prefix.js +155 -0
  112. package/dist/core/engine/index.js +1 -1
  113. package/dist/core/engine/intensity.js +158 -0
  114. package/dist/core/engine/intent.js +260 -0
  115. package/dist/core/engine/native-pugi.js +1295 -227
  116. package/dist/core/engine/prompts.js +134 -16
  117. package/dist/core/engine/strip-internal-fields.js +124 -0
  118. package/dist/core/engine/tool-bridge.js +1295 -59
  119. package/dist/core/evaluation/golden-dataset.js +293 -0
  120. package/dist/core/feedback/queue.js +177 -0
  121. package/dist/core/feedback/submitter.js +145 -0
  122. package/dist/core/file-cache.js +113 -1
  123. package/dist/core/flatten/flatten-repo.js +439 -0
  124. package/dist/core/format/osc8-link.js +28 -0
  125. package/dist/core/hook-chains.js +392 -0
  126. package/dist/core/hooks/citation-verify-hook.js +138 -0
  127. package/dist/core/hooks/citation-verify.js +112 -0
  128. package/dist/core/hooks/events.js +44 -0
  129. package/dist/core/hooks/index.js +15 -0
  130. package/dist/core/hooks/registry.js +213 -0
  131. package/dist/core/hooks/runner.js +236 -0
  132. package/dist/core/hooks/v2/event-emitter.js +115 -0
  133. package/dist/core/hooks/v2/executor.js +282 -0
  134. package/dist/core/hooks/v2/index.js +25 -0
  135. package/dist/core/hooks/v2/lifecycle.js +104 -0
  136. package/dist/core/hooks/v2/loader.js +216 -0
  137. package/dist/core/hooks/v2/matcher.js +125 -0
  138. package/dist/core/hooks/v2/trust.js +143 -0
  139. package/dist/core/hooks/v2/types.js +86 -0
  140. package/dist/core/image/renderer.js +71 -0
  141. package/dist/core/init/detector.js +582 -0
  142. package/dist/core/init/template-renderer.js +242 -0
  143. package/dist/core/jobs/registry.js +18 -18
  144. package/dist/core/ledger/results-tsv.js +142 -0
  145. package/dist/core/log-discipline/stdout-redirect.js +51 -0
  146. package/dist/core/lsp/cache.js +105 -0
  147. package/dist/core/lsp/client.js +776 -0
  148. package/dist/core/lsp/language-detect.js +66 -0
  149. package/dist/core/lsp/post-edit-diagnostics.js +171 -0
  150. package/dist/core/lsp/symbol-tools.js +372 -0
  151. package/dist/core/mcp/client.js +97 -28
  152. package/dist/core/mcp/http-server.js +553 -0
  153. package/dist/core/mcp/orchestrator-tools.js +662 -0
  154. package/dist/core/mcp/permission.js +190 -0
  155. package/dist/core/mcp/registry.js +39 -17
  156. package/dist/core/mcp/server-tools.js +219 -0
  157. package/dist/core/mcp/server.js +397 -0
  158. package/dist/core/mcp/trust.js +10 -10
  159. package/dist/core/memory/dual-write.js +416 -0
  160. package/dist/core/memory/passive-extract.js +130 -0
  161. package/dist/core/memory/phase1-kinds.js +20 -0
  162. package/dist/core/memory/secret-scanner.js +304 -0
  163. package/dist/core/memory-sync/queue.js +170 -0
  164. package/dist/core/metrics/extract.js +113 -0
  165. package/dist/core/modes/roo-modes.js +68 -0
  166. package/dist/core/onboarding/ensure-initialized.js +133 -0
  167. package/dist/core/onboarding/marker.js +111 -0
  168. package/dist/core/onboarding/telemetry-state.js +108 -0
  169. package/dist/core/output-style/presets.js +176 -0
  170. package/dist/core/output-style/state.js +185 -0
  171. package/dist/core/path-security.js +287 -5
  172. package/dist/core/permission.js +82 -22
  173. package/dist/core/permissions/auto-classifier.js +124 -0
  174. package/dist/core/permissions/bash-parser.js +371 -0
  175. package/dist/core/permissions/circuit-breaker.js +83 -0
  176. package/dist/core/permissions/constrained-edit.js +91 -0
  177. package/dist/core/permissions/gate.js +278 -0
  178. package/dist/core/permissions/index.js +20 -0
  179. package/dist/core/permissions/mode.js +174 -0
  180. package/dist/core/permissions/network-egress.js +137 -0
  181. package/dist/core/permissions/state.js +241 -0
  182. package/dist/core/permissions/tool-class.js +93 -0
  183. package/dist/core/plan-mode/ui-state.js +51 -0
  184. package/dist/core/plans/plan-artifact.js +721 -0
  185. package/dist/core/policy-limits/etag-store.js +122 -0
  186. package/dist/core/prd-check/parser.js +215 -0
  187. package/dist/core/prd-check/reporter.js +127 -0
  188. package/dist/core/prd-check/session-review.js +557 -0
  189. package/dist/core/prd-check/verifiers.js +223 -0
  190. package/dist/core/prompt-cache/client-cache.js +99 -0
  191. package/dist/core/prompts/assembly.js +29 -0
  192. package/dist/core/prompts/registry.js +364 -0
  193. package/dist/core/pugi-md/cc-compat-rules.js +735 -0
  194. package/dist/core/pugi-md/context-injector.js +76 -0
  195. package/dist/core/pugi-md/walk-up.js +207 -0
  196. package/dist/core/python/uv-installer.js +270 -0
  197. package/dist/core/python/uv-resolver.js +83 -0
  198. package/dist/core/rate-limit/narrator.js +146 -0
  199. package/dist/core/recipes/cli-types.js +20 -0
  200. package/dist/core/recipes/loader.js +103 -0
  201. package/dist/core/recipes/runner.js +345 -0
  202. package/dist/core/recipes/schema.js +587 -0
  203. package/dist/core/release-notes/parser.js +241 -0
  204. package/dist/core/release-notes/state.js +116 -0
  205. package/dist/core/repl/ask.js +37 -37
  206. package/dist/core/repl/cancellation.js +26 -26
  207. package/dist/core/repl/cap-warning.js +4 -4
  208. package/dist/core/repl/clipboard-read.js +11 -11
  209. package/dist/core/repl/dispatch-fsm.js +12 -12
  210. package/dist/core/repl/history-search.js +15 -15
  211. package/dist/core/repl/history.js +28 -18
  212. package/dist/core/repl/kill-ring.js +5 -5
  213. package/dist/core/repl/model-pricing.js +135 -0
  214. package/dist/core/repl/privacy-banner.js +22 -22
  215. package/dist/core/repl/session.js +2157 -214
  216. package/dist/core/repl/slash-commands.js +533 -40
  217. package/dist/core/repl/store/index.js +1 -1
  218. package/dist/core/repl/store/jsonl-log.js +22 -22
  219. package/dist/core/repl/store/lockfile.js +10 -10
  220. package/dist/core/repl/store/session-store.js +136 -107
  221. package/dist/core/repl/store/types.js +15 -15
  222. package/dist/core/repl/store/uuid-v7.js +12 -12
  223. package/dist/core/repl/workspace-context.js +43 -21
  224. package/dist/core/repo-map/build.js +125 -0
  225. package/dist/core/repo-map/cache.js +185 -0
  226. package/dist/core/repo-map/extractor.js +254 -0
  227. package/dist/core/repo-map/formatter.js +145 -0
  228. package/dist/core/repo-map/page-rank.js +105 -0
  229. package/dist/core/repo-map/scanner.js +211 -0
  230. package/dist/core/retry-budget/budget.js +284 -0
  231. package/dist/core/retry-budget/index.js +5 -0
  232. package/dist/core/retry-budget/retry-cap.js +74 -0
  233. package/dist/core/routing/lead-worker.js +43 -0
  234. package/dist/core/routing/pre-flight-estimator.js +108 -0
  235. package/dist/core/runs/run-tree.js +103 -0
  236. package/dist/core/security/injection-scanner.js +367 -0
  237. package/dist/core/security/output-filter.js +418 -0
  238. package/dist/core/session/env-file.js +105 -0
  239. package/dist/core/session/section-budgets.js +140 -0
  240. package/dist/core/session.js +92 -0
  241. package/dist/core/settings.js +298 -5
  242. package/dist/core/share/formatter.js +271 -0
  243. package/dist/core/share/redactor.js +221 -0
  244. package/dist/core/share/uploader.js +267 -0
  245. package/dist/core/skills/defaults.js +457 -0
  246. package/dist/core/skills/loader.js +22 -22
  247. package/dist/core/skills/sources.js +27 -27
  248. package/dist/core/smoke/headless-driver.js +174 -0
  249. package/dist/core/smoke/orchestrator.js +194 -0
  250. package/dist/core/smoke/runner.js +238 -0
  251. package/dist/core/smoke/scenario-parser.js +316 -0
  252. package/dist/core/statusline.js +99 -0
  253. package/dist/core/subagents/dispatcher-real.js +600 -0
  254. package/dist/core/subagents/dispatcher.js +132 -43
  255. package/dist/core/subagents/index.js +19 -6
  256. package/dist/core/subagents/isolation-matrix.js +213 -0
  257. package/dist/core/subagents/spawn.js +19 -4
  258. package/dist/core/telemetry/emitter.js +229 -0
  259. package/dist/core/telemetry/queue.js +251 -0
  260. package/dist/core/theme/context.js +91 -0
  261. package/dist/core/theme/presets.js +228 -0
  262. package/dist/core/theme/state.js +181 -0
  263. package/dist/core/todos/invariant.js +10 -0
  264. package/dist/core/todos/state.js +177 -0
  265. package/dist/core/tool-schema/compressor.js +89 -0
  266. package/dist/core/transport/version-interceptor.js +166 -0
  267. package/dist/core/trust.js +2 -2
  268. package/dist/core/tui/thinking-block.js +64 -0
  269. package/dist/core/vim/keymap.js +288 -0
  270. package/dist/core/vim/state.js +92 -0
  271. package/dist/core/watch-markers/marker-watcher.js +133 -0
  272. package/dist/core/worktree-manager/cleanup.js +123 -0
  273. package/dist/core/worktree-manager/manager.js +303 -0
  274. package/dist/index.js +36 -0
  275. package/dist/runtime/bootstrap.js +190 -0
  276. package/dist/runtime/cli.js +4203 -493
  277. package/dist/runtime/commands/agents.js +30 -30
  278. package/dist/runtime/commands/budget.js +5 -5
  279. package/dist/runtime/commands/cancel.js +231 -0
  280. package/dist/runtime/commands/chain.js +489 -0
  281. package/dist/runtime/commands/codegraph-status.js +227 -0
  282. package/dist/runtime/commands/compact.js +297 -0
  283. package/dist/runtime/commands/config.js +73 -39
  284. package/dist/runtime/commands/cost.js +199 -0
  285. package/dist/runtime/commands/delegate.js +244 -13
  286. package/dist/runtime/commands/dispatch.js +126 -0
  287. package/dist/runtime/commands/doctor.js +579 -0
  288. package/dist/runtime/commands/feedback.js +184 -0
  289. package/dist/runtime/commands/hooks.js +184 -0
  290. package/dist/runtime/commands/init.js +254 -0
  291. package/dist/runtime/commands/lsp.js +368 -0
  292. package/dist/runtime/commands/mcp.js +879 -0
  293. package/dist/runtime/commands/memory.js +582 -0
  294. package/dist/runtime/commands/model.js +237 -0
  295. package/dist/runtime/commands/onboarding.js +275 -0
  296. package/dist/runtime/commands/patch.js +128 -0
  297. package/dist/runtime/commands/permissions.js +112 -0
  298. package/dist/runtime/commands/plan.js +143 -0
  299. package/dist/runtime/commands/prd-check.js +285 -0
  300. package/dist/runtime/commands/privacy.js +17 -17
  301. package/dist/runtime/commands/recipe.js +325 -0
  302. package/dist/runtime/commands/redo-blob-store.js +92 -0
  303. package/dist/runtime/commands/redo.js +361 -0
  304. package/dist/runtime/commands/release-notes.js +229 -0
  305. package/dist/runtime/commands/repo-map.js +95 -0
  306. package/dist/runtime/commands/report.js +299 -0
  307. package/dist/runtime/commands/resume.js +118 -0
  308. package/dist/runtime/commands/review-consensus.js +68 -53
  309. package/dist/runtime/commands/rewind.js +333 -0
  310. package/dist/runtime/commands/roster.js +14 -14
  311. package/dist/runtime/commands/sessions.js +163 -0
  312. package/dist/runtime/commands/share.js +316 -0
  313. package/dist/runtime/commands/skills.js +31 -31
  314. package/dist/runtime/commands/status.js +186 -0
  315. package/dist/runtime/commands/stickers.js +82 -0
  316. package/dist/runtime/commands/style.js +194 -0
  317. package/dist/runtime/commands/theme.js +196 -0
  318. package/dist/runtime/commands/undo.js +54 -22
  319. package/dist/runtime/commands/update.js +289 -0
  320. package/dist/runtime/commands/vim.js +140 -0
  321. package/dist/runtime/commands/worktree.js +177 -0
  322. package/dist/runtime/commands/worktrees.js +155 -0
  323. package/dist/runtime/headless-repl.js +195 -0
  324. package/dist/runtime/headless.js +543 -0
  325. package/dist/runtime/load-hooks-or-exit.js +71 -0
  326. package/dist/runtime/plan-decompose.js +531 -0
  327. package/dist/runtime/sigint-guard.js +272 -0
  328. package/dist/runtime/update-check.js +28 -28
  329. package/dist/runtime/version.js +65 -0
  330. package/dist/skills/bundled/batch.js +617 -0
  331. package/dist/skills/bundled/index.js +45 -0
  332. package/dist/skills/bundled/loop.js +358 -0
  333. package/dist/skills/bundled/remember.js +383 -0
  334. package/dist/skills/bundled/simplify.js +289 -0
  335. package/dist/skills/bundled/skillify.js +373 -0
  336. package/dist/skills/bundled/stuck.js +558 -0
  337. package/dist/skills/bundled/verify.js +439 -0
  338. package/dist/testing/vcr.js +486 -0
  339. package/dist/tools/agent-tool.js +229 -0
  340. package/dist/tools/apply-patch.js +556 -0
  341. package/dist/tools/ask-user-question.js +288 -0
  342. package/dist/tools/ask-user.js +115 -0
  343. package/dist/tools/bash.js +624 -46
  344. package/dist/tools/brief.js +224 -0
  345. package/dist/tools/enter-worktree.js +250 -0
  346. package/dist/tools/exit-worktree.js +147 -0
  347. package/dist/tools/file-tools.js +161 -44
  348. package/dist/tools/lsp-tools.js +189 -0
  349. package/dist/tools/mcp-tool.js +260 -0
  350. package/dist/tools/multi-edit.js +361 -0
  351. package/dist/tools/powershell.js +268 -0
  352. package/dist/tools/registry.js +85 -0
  353. package/dist/tools/skill-tool.js +96 -0
  354. package/dist/tools/sleep.js +99 -0
  355. package/dist/tools/synthetic-output.js +133 -0
  356. package/dist/tools/tasks.js +208 -0
  357. package/dist/tools/todo-write.js +184 -0
  358. package/dist/tools/verify-plan-execution.js +295 -0
  359. package/dist/tools/web-fetch-injection-scanner.js +207 -0
  360. package/dist/tools/web-fetch.js +195 -10
  361. package/dist/tools/web-search.js +458 -0
  362. package/dist/tui/agent-progress-card.js +111 -0
  363. package/dist/tui/agent-tree.js +11 -1
  364. package/dist/tui/ask-modal.js +14 -14
  365. package/dist/tui/ask-user-question-chips.js +257 -0
  366. package/dist/tui/ask-user-question-prompt.js +203 -0
  367. package/dist/tui/compact-banner.js +81 -0
  368. package/dist/tui/conversation-pane.js +85 -11
  369. package/dist/tui/cost-table.js +111 -0
  370. package/dist/tui/device-flow.js +2 -2
  371. package/dist/tui/doctor-table.js +46 -0
  372. package/dist/tui/feedback-prompt.js +156 -0
  373. package/dist/tui/input-box.js +247 -32
  374. package/dist/tui/login-picker.js +3 -3
  375. package/dist/tui/markdown-render.js +6 -6
  376. package/dist/tui/onboarding-wizard.js +240 -0
  377. package/dist/tui/permissions-picker.js +86 -0
  378. package/dist/tui/render.js +35 -0
  379. package/dist/tui/repl-render.js +332 -54
  380. package/dist/tui/repl-splash-art.js +16 -16
  381. package/dist/tui/repl-splash-mascot.js +48 -24
  382. package/dist/tui/repl-splash.js +22 -22
  383. package/dist/tui/repl.js +124 -44
  384. package/dist/tui/slash-palette.js +6 -6
  385. package/dist/tui/splash.js +2 -2
  386. package/dist/tui/status-bar.js +109 -31
  387. package/dist/tui/status-table.js +7 -0
  388. package/dist/tui/stickers-art.js +136 -0
  389. package/dist/tui/style-table.js +28 -0
  390. package/dist/tui/theme-table.js +29 -0
  391. package/dist/tui/thinking-spinner.js +123 -0
  392. package/dist/tui/tool-stream-pane.js +53 -4
  393. package/dist/tui/update-banner.js +27 -2
  394. package/dist/tui/vim-input.js +267 -0
  395. package/dist/tui/welcome-banner.js +107 -0
  396. package/dist/tui/welcome-data.js +293 -0
  397. package/dist/tui/workspace-context.js +2 -2
  398. package/docs/examples/codegraph.mcp.json +10 -0
  399. package/package.json +25 -7
  400. package/test/scenarios/codegen-create-file.scenario.txt +13 -0
  401. package/test/scenarios/compact-force.scenario.txt +11 -0
  402. package/test/scenarios/identity.scenario.txt +11 -0
  403. package/test/scenarios/persona-handoff.scenario.txt +11 -0
  404. package/test/scenarios/walkback.scenario.txt +12 -0
  405. package/dist/core/engine/compaction-hook.js +0 -154
@@ -6,13 +6,20 @@
6
6
  * handlers table) does not need a try/catch wrapper.
7
7
  */
8
8
  export async function runDelegateCommand(args, ctx) {
9
- const slug = args[0];
10
- const brief = args.slice(1).join(' ').trim();
9
+ // Extract the optional `--wait` flag from positional args. Accept it
10
+ // in any position so `pugi delegate --wait dev "..."` and
11
+ // `pugi delegate dev "..." --wait` both work; positional ordering of
12
+ // slug + brief is preserved by filtering the flag out before the
13
+ // slug/brief split (Claude P2 fix).
14
+ const wait = args.some((a) => a === '--wait');
15
+ const positional = args.filter((a) => a !== '--wait');
16
+ const slug = positional[0];
17
+ const brief = positional.slice(1).join(' ').trim();
11
18
  if (!slug || !brief) {
12
19
  ctx.writeOutput({
13
20
  ok: false,
14
- error: 'Usage: pugi delegate <persona-slug> "<one-sentence brief>"',
15
- }, 'Usage: pugi delegate <persona-slug> "<one-sentence brief>"');
21
+ error: 'Usage: pugi delegate [--wait] <persona-slug> "<one-sentence brief>"',
22
+ }, 'Usage: pugi delegate [--wait] <persona-slug> "<one-sentence brief>"');
16
23
  process.exitCode = 2;
17
24
  return;
18
25
  }
@@ -47,14 +54,66 @@ export async function runDelegateCommand(args, ctx) {
47
54
  brief,
48
55
  });
49
56
  switch (result.status) {
50
- case 'ok':
51
- ctx.writeOutput({
52
- ok: true,
53
- sessionId: opened.sessionId,
54
- dispatchId: result.response.dispatchId,
55
- personaSlug: result.response.personaSlug,
56
- }, `dispatched ${result.response.personaSlug} (dispatchId=${result.response.dispatchId}); stream via GET /sessions/${opened.sessionId}/stream.`);
57
+ case 'ok': {
58
+ const ok = result.response;
59
+ if (!wait) {
60
+ ctx.writeOutput({
61
+ ok: true,
62
+ sessionId: opened.sessionId,
63
+ dispatchId: ok.dispatchId,
64
+ personaSlug: ok.personaSlug,
65
+ }, `dispatched ${ok.personaSlug} (dispatchId=${ok.dispatchId}); stream via GET /sessions/${opened.sessionId}/stream.`);
66
+ return;
67
+ }
68
+ // --wait: subscribe to SSE until the persona reaches a terminal
69
+ // event. The waiter contract is provider-shaped so tests can pass
70
+ // a fake without standing up fetch.
71
+ const waiter = ctx.waitForTerminal ?? waitForDelegateTerminal;
72
+ const outcome = await waiter(config, opened.sessionId, ok.personaSlug);
73
+ switch (outcome.kind) {
74
+ case 'completed':
75
+ ctx.writeOutput({
76
+ ok: true,
77
+ sessionId: opened.sessionId,
78
+ dispatchId: ok.dispatchId,
79
+ personaSlug: outcome.personaSlug,
80
+ status: 'completed',
81
+ }, `completed ${outcome.personaSlug} (dispatchId=${ok.dispatchId}).`);
82
+ return;
83
+ case 'blocked':
84
+ ctx.writeOutput({
85
+ ok: false,
86
+ sessionId: opened.sessionId,
87
+ dispatchId: ok.dispatchId,
88
+ personaSlug: outcome.personaSlug,
89
+ status: 'blocked',
90
+ detail: outcome.detail,
91
+ }, `blocked ${outcome.personaSlug}: ${outcome.detail}`);
92
+ process.exitCode = 5;
93
+ return;
94
+ case 'failed':
95
+ ctx.writeOutput({
96
+ ok: false,
97
+ sessionId: opened.sessionId,
98
+ dispatchId: ok.dispatchId,
99
+ personaSlug: outcome.personaSlug,
100
+ status: 'failed',
101
+ error: outcome.error,
102
+ }, `failed ${outcome.personaSlug}: ${outcome.error}`);
103
+ process.exitCode = 5;
104
+ return;
105
+ case 'stream_error':
106
+ ctx.writeOutput({
107
+ ok: false,
108
+ sessionId: opened.sessionId,
109
+ dispatchId: ok.dispatchId,
110
+ error: outcome.error,
111
+ }, `pugi delegate --wait: ${outcome.error}`);
112
+ process.exitCode = 1;
113
+ return;
114
+ }
57
115
  return;
116
+ }
58
117
  case 'unknown_persona':
59
118
  ctx.writeOutput({ ok: false, error: result.message, code: result.code }, `pugi delegate: ${result.message}`);
60
119
  process.exitCode = 3;
@@ -66,9 +125,9 @@ export async function runDelegateCommand(args, ctx) {
66
125
  case 'endpoint_missing':
67
126
  ctx.writeOutput({
68
127
  ok: false,
69
- error: 'runtime does not expose POST /api/pugi/sessions/:id/delegate (upgrade admin-api to α7.5+)',
128
+ error: 'runtime does not expose POST /api/pugi/sessions/:id/delegate (upgrade admin-api to +)',
70
129
  code: result.code,
71
- }, 'pugi delegate: runtime does not expose the delegate endpoint. Upgrade admin-api to α7.5+.');
130
+ }, 'pugi delegate: runtime does not expose the delegate endpoint. Upgrade admin-api to +.');
72
131
  process.exitCode = 1;
73
132
  return;
74
133
  case 'unauthenticated':
@@ -78,4 +137,176 @@ export async function runDelegateCommand(args, ctx) {
78
137
  return;
79
138
  }
80
139
  }
140
+ /* ------------------------------------------------------------------ */
141
+ /* --wait waiter */
142
+ /* ------------------------------------------------------------------ */
143
+ /**
144
+ * Subscribe to the session SSE stream and resolve when the named
145
+ * persona reaches a terminal event (agent.completed / agent.blocked /
146
+ * agent.failed). Falls back to a `stream_error` outcome when the
147
+ * stream closes before any terminal event arrives or when the
148
+ * underlying fetch fails.
149
+ *
150
+ * The waiter is intentionally a single-call helper (not a long-lived
151
+ * subscriber) - the scripted `pugi delegate --wait` caller wants to
152
+ * exit on the first terminal event for THIS persona, not maintain a
153
+ * persistent connection.
154
+ *
155
+ * Why we parse the lifecycle in this file (not via the repl-render
156
+ * subscribe helper): repl-render carries Ink/React deps the
157
+ * non-interactive delegate path does not want to load. Duplicating the
158
+ * minimal SSE-line parser here keeps the command lean (this is the same
159
+ * shape `apps/admin-api/src/pugi/sessions.controller.ts` writes to the
160
+ * wire).
161
+ */
162
+ export async function waitForDelegateTerminal(config, sessionId, targetPersonaSlug) {
163
+ const url = `${config.apiUrl.replace(/\/+$/, '')}/api/pugi/sessions/${encodeURIComponent(sessionId)}/stream`;
164
+ const controller = new AbortController();
165
+ // Hard-cap the waiter at 5 minutes so a stalled server cannot keep
166
+ // a scripted caller hanging forever; the dispatcher's per-turn budget
167
+ // is well under this.
168
+ const timeout = setTimeout(() => controller.abort(), 5 * 60 * 1000);
169
+ try {
170
+ const response = await fetch(url, {
171
+ method: 'GET',
172
+ headers: {
173
+ Accept: 'text/event-stream',
174
+ Authorization: `Bearer ${config.apiKey}`,
175
+ },
176
+ signal: controller.signal,
177
+ });
178
+ if (!response.ok) {
179
+ return { kind: 'stream_error', error: `HTTP ${response.status}` };
180
+ }
181
+ if (!response.body) {
182
+ return { kind: 'stream_error', error: 'no response body' };
183
+ }
184
+ // Track the most-recent persona slug seen on agent.spawned so the
185
+ // terminal event (which carries only taskId) can be matched to the
186
+ // delegate target without parsing the random nonce suffix.
187
+ const taskToPersona = new Map();
188
+ // Buffer `agent.message` frames per taskId so the terminal event can
189
+ // surface the persona's full reply (Gemini P1 fix, PR). Keyed by
190
+ // taskId so a session producing multiple parallel persona dispatches
191
+ // does not cross-contaminate transcripts.
192
+ const transcriptByTask = new Map();
193
+ const reader = response.body.getReader();
194
+ const decoder = new TextDecoder('utf-8');
195
+ let buffer = '';
196
+ let currentData = '';
197
+ while (true) {
198
+ const { value, done } = await reader.read();
199
+ if (done) {
200
+ return { kind: 'stream_error', error: 'stream ended without terminal event' };
201
+ }
202
+ buffer += decoder.decode(value, { stream: true });
203
+ let newlineIndex;
204
+ while ((newlineIndex = buffer.indexOf('\n')) !== -1) {
205
+ const rawLine = buffer.slice(0, newlineIndex).replace(/\r$/, '');
206
+ buffer = buffer.slice(newlineIndex + 1);
207
+ if (rawLine.length === 0) {
208
+ if (currentData.length > 0) {
209
+ const parsed = parseDelegateFrame(currentData);
210
+ if (parsed) {
211
+ if (parsed.type === 'agent.spawned') {
212
+ taskToPersona.set(parsed.taskId, parsed.personaSlug);
213
+ }
214
+ else if (parsed.type === 'agent.message') {
215
+ // Buffer the unfiltered reply by taskId. The terminal
216
+ // event below joins these into the `transcript` field
217
+ // when the matched persona reaches `agent.completed`.
218
+ const existing = transcriptByTask.get(parsed.taskId);
219
+ if (existing) {
220
+ existing.push(parsed.content);
221
+ }
222
+ else {
223
+ transcriptByTask.set(parsed.taskId, [parsed.content]);
224
+ }
225
+ }
226
+ else if (parsed.type === 'agent.completed' ||
227
+ parsed.type === 'agent.blocked' ||
228
+ parsed.type === 'agent.failed') {
229
+ const slug = taskToPersona.get(parsed.taskId) ?? targetPersonaSlug;
230
+ if (slug === targetPersonaSlug) {
231
+ controller.abort();
232
+ if (parsed.type === 'agent.completed') {
233
+ const frames = transcriptByTask.get(parsed.taskId) ?? [];
234
+ const transcript = frames.join('\n\n');
235
+ return {
236
+ kind: 'completed',
237
+ personaSlug: slug,
238
+ taskId: parsed.taskId,
239
+ transcript,
240
+ };
241
+ }
242
+ if (parsed.type === 'agent.blocked') {
243
+ return {
244
+ kind: 'blocked',
245
+ personaSlug: slug,
246
+ taskId: parsed.taskId,
247
+ detail: parsed.detail,
248
+ };
249
+ }
250
+ return {
251
+ kind: 'failed',
252
+ personaSlug: slug,
253
+ taskId: parsed.taskId,
254
+ error: parsed.error,
255
+ };
256
+ }
257
+ }
258
+ }
259
+ }
260
+ currentData = '';
261
+ continue;
262
+ }
263
+ if (rawLine.startsWith(':'))
264
+ continue;
265
+ const colonIndex = rawLine.indexOf(':');
266
+ const field = colonIndex === -1 ? rawLine : rawLine.slice(0, colonIndex);
267
+ const value = colonIndex === -1 ? '' : rawLine.slice(colonIndex + 1).replace(/^ /, '');
268
+ if (field === 'data') {
269
+ currentData = currentData.length === 0 ? value : `${currentData}\n${value}`;
270
+ }
271
+ }
272
+ }
273
+ }
274
+ catch (err) {
275
+ if (controller.signal.aborted) {
276
+ return { kind: 'stream_error', error: 'wait timed out' };
277
+ }
278
+ return { kind: 'stream_error', error: err.message };
279
+ }
280
+ finally {
281
+ clearTimeout(timeout);
282
+ }
283
+ }
284
+ function parseDelegateFrame(data) {
285
+ try {
286
+ const raw = JSON.parse(data);
287
+ const type = raw.type;
288
+ const taskId = typeof raw.taskId === 'string' ? raw.taskId : null;
289
+ if (!taskId)
290
+ return null;
291
+ if (type === 'agent.spawned' && typeof raw.personaSlug === 'string') {
292
+ return { type, taskId, personaSlug: raw.personaSlug };
293
+ }
294
+ if (type === 'agent.message' && typeof raw.content === 'string') {
295
+ return { type, taskId, content: raw.content };
296
+ }
297
+ if (type === 'agent.completed') {
298
+ return { type, taskId };
299
+ }
300
+ if (type === 'agent.blocked') {
301
+ return { type, taskId, detail: typeof raw.detail === 'string' ? raw.detail : '' };
302
+ }
303
+ if (type === 'agent.failed') {
304
+ return { type, taskId, error: typeof raw.error === 'string' ? raw.error : '' };
305
+ }
306
+ return null;
307
+ }
308
+ catch {
309
+ return null;
310
+ }
311
+ }
81
312
  //# sourceMappingURL=delegate.js.map
@@ -0,0 +1,126 @@
1
+ /**
2
+ * `pugi dispatch <sub>` — fork-subagent cache-handoff surface (—).
3
+ *
4
+ * Sub-commands:
5
+ *
6
+ * - `pugi dispatch list-cache-refs` — show active cache-inherit refs
7
+ * persisted under `.pugi/cache-refs/`. Renders an aligned table or
8
+ * JSON depending on `--json`.
9
+ *
10
+ * - `pugi dispatch clear-cache-refs [--older-than 1h] [-v]` — GC stale
11
+ * refs. Without `--older-than`, defaults to 24h (the same cutoff
12
+ * the REPL boot-time auto-sweep uses). The flag accepts duration
13
+ * strings the `parseDuration` helper recognises (`1h`, `30m`,
14
+ * `7d`, `500ms`, ...).
15
+ *
16
+ * The command lives in its own module (not inline in cli.ts) so the
17
+ * dispatch table stays narrow and tests can drive it without spinning
18
+ * up the full CLI.
19
+ */
20
+ import { cleanupStaleCacheRefs, parseDuration, } from '../../core/dispatch/cache-cleanup.js';
21
+ import { listCacheRefs } from '../../core/dispatch/cache-handoff.js';
22
+ const USAGE = [
23
+ 'Usage:',
24
+ ' pugi dispatch list-cache-refs',
25
+ ' Show every active subagent cache-inherit',
26
+ ' reference persisted under .pugi/cache-refs/.',
27
+ '',
28
+ ' pugi dispatch clear-cache-refs [--older-than <duration>] [-v]',
29
+ ' Evict stale refs. Accepts 500ms / 30s / 5m /',
30
+ ' 1h / 7d. Default --older-than 24h.',
31
+ ].join('\n');
32
+ export async function runDispatchCommand(args, ctx) {
33
+ const sub = args[0];
34
+ if (!sub || sub === '--help' || sub === '-h') {
35
+ ctx.writeOutput({ command: 'dispatch', usage: USAGE.split('\n') }, USAGE);
36
+ return;
37
+ }
38
+ switch (sub) {
39
+ case 'list-cache-refs':
40
+ return runListCacheRefs(ctx);
41
+ case 'clear-cache-refs':
42
+ return runClearCacheRefs(args.slice(1), ctx);
43
+ default:
44
+ ctx.writeOutput({
45
+ ok: false,
46
+ error: `unknown subcommand: ${sub}`,
47
+ usage: USAGE.split('\n'),
48
+ }, `pugi dispatch: unknown subcommand '${sub}'\n\n${USAGE}`);
49
+ process.exitCode = 2;
50
+ return;
51
+ }
52
+ }
53
+ function runListCacheRefs(ctx) {
54
+ const refs = listCacheRefs(ctx.workspaceRoot);
55
+ if (ctx.json) {
56
+ ctx.writeOutput({ ok: true, count: refs.length, refs }, '');
57
+ return;
58
+ }
59
+ if (refs.length === 0) {
60
+ ctx.writeOutput({ ok: true, count: 0, refs: [] }, 'No active cache-inherit refs under .pugi/cache-refs/.');
61
+ return;
62
+ }
63
+ // Aligned column table. Widths derived from the data — no hardcoded
64
+ // sizes so a long childAgentId does not overflow the layout.
65
+ const header = ['CHILD AGENT', 'CACHE ID', 'PARENT SESSION', 'CREATED'];
66
+ const rows = refs.map((r) => [
67
+ r.childAgentId,
68
+ r.cacheId,
69
+ r.parentSessionId,
70
+ r.createdAt,
71
+ ]);
72
+ const widths = header.map((h, i) => Math.max(h.length, ...rows.map((row) => (row[i] ?? '').length)));
73
+ const lines = [];
74
+ lines.push(header.map((h, i) => h.padEnd(widths[i] ?? 0)).join(' '));
75
+ lines.push(widths.map((w) => '-'.repeat(w)).join(' '));
76
+ for (const row of rows) {
77
+ lines.push(row.map((cell, i) => (cell ?? '').padEnd(widths[i] ?? 0)).join(' '));
78
+ }
79
+ ctx.writeOutput({ ok: true, count: refs.length, refs }, lines.join('\n'));
80
+ }
81
+ function runClearCacheRefs(args, ctx) {
82
+ let olderThanArg;
83
+ let verbose = false;
84
+ for (let i = 0; i < args.length; i++) {
85
+ const arg = args[i];
86
+ if (arg === '--older-than') {
87
+ olderThanArg = args[i + 1];
88
+ i++;
89
+ continue;
90
+ }
91
+ if (arg && arg.startsWith('--older-than=')) {
92
+ olderThanArg = arg.slice('--older-than='.length);
93
+ continue;
94
+ }
95
+ if (arg === '-v' || arg === '--verbose') {
96
+ verbose = true;
97
+ continue;
98
+ }
99
+ }
100
+ // Default 24h matches the REPL boot-time auto-sweep cutoff.
101
+ const olderThanMs = olderThanArg ? parseDuration(olderThanArg) : 24 * 60 * 60 * 1000;
102
+ if (olderThanMs === null) {
103
+ ctx.writeOutput({
104
+ ok: false,
105
+ error: `invalid --older-than value: ${olderThanArg ?? '(missing)'}`,
106
+ usage: USAGE.split('\n'),
107
+ }, `pugi dispatch clear-cache-refs: invalid --older-than '${olderThanArg ?? '(missing)'}'\n\n${USAGE}`);
108
+ process.exitCode = 2;
109
+ return;
110
+ }
111
+ const result = cleanupStaleCacheRefs(ctx.workspaceRoot, {
112
+ olderThanMs,
113
+ verbose,
114
+ });
115
+ const summary = `Removed ${result.removedCount} ref(s) (${result.corruptCount} corrupt), kept ${result.keptCount}.`;
116
+ ctx.writeOutput({
117
+ ok: true,
118
+ olderThanMs,
119
+ removedCount: result.removedCount,
120
+ keptCount: result.keptCount,
121
+ corruptCount: result.corruptCount,
122
+ removed: result.removed,
123
+ corrupt: result.corrupt,
124
+ }, summary);
125
+ }
126
+ //# sourceMappingURL=dispatch.js.map