@pugi/cli 0.1.0-beta.9 → 0.1.0-beta.91

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 (411) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/LICENSE +1 -1
  3. package/assets/pugi-prozr2-mascot.ansi +9 -0
  4. package/bin/run.js +33 -1
  5. package/dist/commands/deploy.js +40 -40
  6. package/dist/commands/flatten.js +191 -0
  7. package/dist/commands/jobs-watch.js +201 -0
  8. package/dist/commands/jobs.js +42 -27
  9. package/dist/commands/smoke.js +133 -0
  10. package/dist/core/agent-progress/cleanup.js +134 -0
  11. package/dist/core/agent-progress/schema.js +144 -0
  12. package/dist/core/agent-progress/writer.js +101 -0
  13. package/dist/core/agents/adaptive-router.js +330 -0
  14. package/dist/core/agents/query-decomposer.js +297 -0
  15. package/dist/core/agents/registry.js +3 -3
  16. package/dist/core/approvals/shortcut-resolver.js +98 -0
  17. package/dist/core/artifact-chain/dispatcher.js +148 -0
  18. package/dist/core/artifact-chain/exporter.js +164 -0
  19. package/dist/core/artifact-chain/state.js +243 -0
  20. package/dist/core/artifact-chain/steps.js +169 -0
  21. package/dist/core/ask-user/question.js +92 -0
  22. package/dist/core/audit/audit-trail.js +275 -0
  23. package/dist/core/auth/ensure-authenticated.js +129 -0
  24. package/dist/core/auth/env-provider.js +238 -0
  25. package/dist/core/auto-open-browser.js +4 -4
  26. package/dist/core/auto-update/channels.js +122 -0
  27. package/dist/core/auto-update/checker.js +241 -0
  28. package/dist/core/auto-update/state.js +235 -0
  29. package/dist/core/bare-mode/index.js +107 -0
  30. package/dist/core/bash/redirect.js +281 -0
  31. package/dist/core/bash-classifier.js +436 -40
  32. package/dist/core/checkpoint/resumer.js +149 -0
  33. package/dist/core/checkpoint/rewinder.js +291 -0
  34. package/dist/core/checkpoints/shadow-git.js +670 -0
  35. package/dist/core/citations/parser.js +109 -0
  36. package/dist/core/classifier/yolo-classifier.js +88 -0
  37. package/dist/core/codegraph/decision-store.js +248 -0
  38. package/dist/core/codegraph/detect-repo.js +459 -0
  39. package/dist/core/codegraph/install.js +134 -0
  40. package/dist/core/codegraph/offer-hook.js +220 -0
  41. package/dist/core/compact/auto-trigger.js +96 -0
  42. package/dist/core/compact/buffer-rewriter.js +115 -0
  43. package/dist/core/compact/summarizer.js +208 -0
  44. package/dist/core/compact/token-counter.js +108 -0
  45. package/dist/core/consensus/anvil-fanout.js +25 -25
  46. package/dist/core/consensus/diff-capture.js +121 -12
  47. package/dist/core/consensus/rubric.js +21 -21
  48. package/dist/core/context/builder.js +6 -6
  49. package/dist/core/context/compaction-events.js +8 -8
  50. package/dist/core/context/compaction.js +31 -31
  51. package/dist/core/context/index.js +15 -8
  52. package/dist/core/context/invariants.js +51 -51
  53. package/dist/core/context/markdown-loader.js +28 -10
  54. package/dist/core/context/markdown-traverse.js +255 -0
  55. package/dist/core/context/pugiignore.js +41 -41
  56. package/dist/core/context/repo-skeleton.js +37 -37
  57. package/dist/core/context/tool-eviction.js +55 -0
  58. package/dist/core/context/watcher.js +32 -32
  59. package/dist/core/context/working-set.js +23 -23
  60. package/dist/core/coordinator/agent-tools.js +77 -0
  61. package/dist/core/coordinator/agent-toolset.js +65 -0
  62. package/dist/core/coordinator/fsm.js +73 -0
  63. package/dist/core/coordinator/mode-fsm.js +70 -0
  64. package/dist/core/cost/rate-card.js +129 -0
  65. package/dist/core/cost/tracker.js +221 -0
  66. package/dist/core/credentials.js +13 -13
  67. package/dist/core/cron/scheduler.js +138 -0
  68. package/dist/core/denial-tracking/index.js +8 -0
  69. package/dist/core/denial-tracking/state.js +264 -0
  70. package/dist/core/diagnostics/probe-runner.js +93 -0
  71. package/dist/core/diagnostics/probes/api.js +46 -0
  72. package/dist/core/diagnostics/probes/auth.js +93 -0
  73. package/dist/core/diagnostics/probes/bare-mode.js +42 -0
  74. package/dist/core/diagnostics/probes/cli-version.js +127 -0
  75. package/dist/core/diagnostics/probes/config.js +72 -0
  76. package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
  77. package/dist/core/diagnostics/probes/disk.js +81 -0
  78. package/dist/core/diagnostics/probes/engine-live.js +46 -0
  79. package/dist/core/diagnostics/probes/git.js +65 -0
  80. package/dist/core/diagnostics/probes/hooks.js +118 -0
  81. package/dist/core/diagnostics/probes/mcp.js +75 -0
  82. package/dist/core/diagnostics/probes/node.js +59 -0
  83. package/dist/core/diagnostics/probes/pnpm.js +36 -0
  84. package/dist/core/diagnostics/probes/pugi-md.js +89 -0
  85. package/dist/core/diagnostics/probes/sandbox.js +40 -0
  86. package/dist/core/diagnostics/probes/session.js +74 -0
  87. package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
  88. package/dist/core/diagnostics/probes/workspace.js +63 -0
  89. package/dist/core/diagnostics/types.js +70 -0
  90. package/dist/core/dispatch/cache-cleanup.js +197 -0
  91. package/dist/core/dispatch/cache-handoff.js +295 -0
  92. package/dist/core/edits/apply-patch-layer-e.js +189 -0
  93. package/dist/core/edits/dispatch.js +333 -7
  94. package/dist/core/edits/format-detector.js +260 -0
  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 +5 -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 +29 -29
  108. package/dist/core/engine/anvil-client.js +214 -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 +129 -19
  117. package/dist/core/engine/strip-internal-fields.js +124 -0
  118. package/dist/core/engine/tool-bridge.js +1792 -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 +46 -0
  129. package/dist/core/hooks/index.js +15 -0
  130. package/dist/core/hooks/registry.js +216 -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/hooks/worktree-events.js +158 -0
  141. package/dist/core/image/renderer.js +71 -0
  142. package/dist/core/init/detector.js +582 -0
  143. package/dist/core/init/template-renderer.js +242 -0
  144. package/dist/core/jobs/registry.js +18 -18
  145. package/dist/core/ledger/results-tsv.js +142 -0
  146. package/dist/core/log-discipline/stdout-redirect.js +51 -0
  147. package/dist/core/lsp/cache.js +105 -0
  148. package/dist/core/lsp/client.js +551 -41
  149. package/dist/core/lsp/language-detect.js +66 -0
  150. package/dist/core/lsp/post-edit-diagnostics.js +171 -0
  151. package/dist/core/lsp/server-detect.js +173 -0
  152. package/dist/core/lsp/symbol-cache.js +162 -0
  153. package/dist/core/lsp/symbol-tools.js +664 -0
  154. package/dist/core/mcp/client.js +97 -28
  155. package/dist/core/mcp/http-server.js +553 -0
  156. package/dist/core/mcp/orchestrator-tools.js +662 -0
  157. package/dist/core/mcp/permission.js +190 -0
  158. package/dist/core/mcp/registry.js +39 -17
  159. package/dist/core/mcp/server-tools.js +219 -0
  160. package/dist/core/mcp/server.js +397 -0
  161. package/dist/core/mcp/trust.js +10 -10
  162. package/dist/core/memory/dual-write.js +416 -0
  163. package/dist/core/memory/passive-extract.js +130 -0
  164. package/dist/core/memory/phase1-kinds.js +20 -0
  165. package/dist/core/memory/secret-scanner.js +304 -0
  166. package/dist/core/memory-sync/queue.js +170 -0
  167. package/dist/core/metrics/extract.js +113 -0
  168. package/dist/core/modes/roo-modes.js +68 -0
  169. package/dist/core/onboarding/ensure-initialized.js +133 -0
  170. package/dist/core/onboarding/marker.js +111 -0
  171. package/dist/core/onboarding/telemetry-state.js +108 -0
  172. package/dist/core/output-style/presets.js +176 -0
  173. package/dist/core/output-style/state.js +185 -0
  174. package/dist/core/path-security.js +287 -5
  175. package/dist/core/permission.js +82 -22
  176. package/dist/core/permissions/auto-classifier.js +124 -0
  177. package/dist/core/permissions/bash-parser.js +371 -0
  178. package/dist/core/permissions/circuit-breaker.js +83 -0
  179. package/dist/core/permissions/constrained-edit.js +91 -0
  180. package/dist/core/permissions/gate.js +278 -0
  181. package/dist/core/permissions/index.js +20 -0
  182. package/dist/core/permissions/mode.js +174 -0
  183. package/dist/core/permissions/network-egress.js +137 -0
  184. package/dist/core/permissions/state.js +241 -0
  185. package/dist/core/permissions/tool-class.js +93 -0
  186. package/dist/core/plan-mode/ui-state.js +51 -0
  187. package/dist/core/plans/plan-artifact.js +721 -0
  188. package/dist/core/policy-limits/etag-store.js +122 -0
  189. package/dist/core/prd-check/parser.js +215 -0
  190. package/dist/core/prd-check/reporter.js +127 -0
  191. package/dist/core/prd-check/session-review.js +557 -0
  192. package/dist/core/prd-check/verifiers.js +223 -0
  193. package/dist/core/prompt-cache/client-cache.js +99 -0
  194. package/dist/core/prompts/assembly.js +29 -0
  195. package/dist/core/prompts/registry.js +364 -0
  196. package/dist/core/pugi-md/cc-compat-rules.js +735 -0
  197. package/dist/core/pugi-md/context-injector.js +76 -0
  198. package/dist/core/pugi-md/walk-up.js +207 -0
  199. package/dist/core/python/uv-installer.js +270 -0
  200. package/dist/core/python/uv-resolver.js +83 -0
  201. package/dist/core/rate-limit/narrator.js +146 -0
  202. package/dist/core/recipes/cli-types.js +20 -0
  203. package/dist/core/recipes/loader.js +103 -0
  204. package/dist/core/recipes/runner.js +345 -0
  205. package/dist/core/recipes/schema.js +587 -0
  206. package/dist/core/release-notes/parser.js +241 -0
  207. package/dist/core/release-notes/state.js +116 -0
  208. package/dist/core/repl/ask.js +37 -37
  209. package/dist/core/repl/cancellation.js +26 -26
  210. package/dist/core/repl/cap-warning.js +4 -4
  211. package/dist/core/repl/clipboard-read.js +11 -11
  212. package/dist/core/repl/dispatch-fsm.js +12 -12
  213. package/dist/core/repl/history-search.js +15 -15
  214. package/dist/core/repl/history.js +28 -18
  215. package/dist/core/repl/kill-ring.js +5 -5
  216. package/dist/core/repl/model-pricing.js +135 -0
  217. package/dist/core/repl/privacy-banner.js +22 -22
  218. package/dist/core/repl/session.js +2148 -217
  219. package/dist/core/repl/slash-commands.js +501 -41
  220. package/dist/core/repl/store/index.js +1 -1
  221. package/dist/core/repl/store/jsonl-log.js +22 -22
  222. package/dist/core/repl/store/lockfile.js +10 -10
  223. package/dist/core/repl/store/session-store.js +136 -107
  224. package/dist/core/repl/store/types.js +15 -15
  225. package/dist/core/repl/store/uuid-v7.js +12 -12
  226. package/dist/core/repl/workspace-context.js +43 -21
  227. package/dist/core/repo-map/build.js +125 -0
  228. package/dist/core/repo-map/cache.js +185 -0
  229. package/dist/core/repo-map/extractor.js +254 -0
  230. package/dist/core/repo-map/formatter.js +145 -0
  231. package/dist/core/repo-map/page-rank.js +105 -0
  232. package/dist/core/repo-map/scanner.js +211 -0
  233. package/dist/core/retry-budget/budget.js +284 -0
  234. package/dist/core/retry-budget/index.js +5 -0
  235. package/dist/core/retry-budget/retry-cap.js +74 -0
  236. package/dist/core/routing/lead-worker.js +43 -0
  237. package/dist/core/routing/pre-flight-estimator.js +108 -0
  238. package/dist/core/runs/run-tree.js +103 -0
  239. package/dist/core/security/injection-scanner.js +367 -0
  240. package/dist/core/security/output-filter.js +418 -0
  241. package/dist/core/session/env-file.js +105 -0
  242. package/dist/core/session/section-budgets.js +140 -0
  243. package/dist/core/session.js +92 -0
  244. package/dist/core/settings.js +324 -5
  245. package/dist/core/share/formatter.js +271 -0
  246. package/dist/core/share/redactor.js +221 -0
  247. package/dist/core/share/uploader.js +267 -0
  248. package/dist/core/skills/defaults.js +30 -30
  249. package/dist/core/skills/loader.js +22 -22
  250. package/dist/core/skills/sources.js +27 -27
  251. package/dist/core/smoke/headless-driver.js +174 -0
  252. package/dist/core/smoke/orchestrator.js +194 -0
  253. package/dist/core/smoke/runner.js +238 -0
  254. package/dist/core/smoke/scenario-parser.js +316 -0
  255. package/dist/core/statusline.js +99 -0
  256. package/dist/core/subagents/dispatcher-real.js +600 -0
  257. package/dist/core/subagents/dispatcher.js +132 -43
  258. package/dist/core/subagents/index.js +19 -6
  259. package/dist/core/subagents/isolation-matrix.js +213 -0
  260. package/dist/core/subagents/spawn.js +19 -4
  261. package/dist/core/telemetry/emitter.js +229 -0
  262. package/dist/core/telemetry/queue.js +251 -0
  263. package/dist/core/theme/context.js +91 -0
  264. package/dist/core/theme/presets.js +228 -0
  265. package/dist/core/theme/state.js +181 -0
  266. package/dist/core/todos/invariant.js +10 -0
  267. package/dist/core/todos/state.js +177 -0
  268. package/dist/core/tool-schema/compressor.js +89 -0
  269. package/dist/core/transport/version-interceptor.js +166 -0
  270. package/dist/core/trust.js +2 -2
  271. package/dist/core/tui/thinking-block.js +64 -0
  272. package/dist/core/vim/keymap.js +288 -0
  273. package/dist/core/vim/state.js +92 -0
  274. package/dist/core/watch-markers/marker-watcher.js +133 -0
  275. package/dist/core/worktree/include-parser.js +249 -0
  276. package/dist/core/worktree-manager/cleanup.js +123 -0
  277. package/dist/core/worktree-manager/manager.js +303 -0
  278. package/dist/index.js +36 -0
  279. package/dist/runtime/bootstrap.js +190 -0
  280. package/dist/runtime/cli.js +4185 -549
  281. package/dist/runtime/commands/agents.js +31 -31
  282. package/dist/runtime/commands/budget.js +5 -5
  283. package/dist/runtime/commands/cancel.js +231 -0
  284. package/dist/runtime/commands/chain.js +489 -0
  285. package/dist/runtime/commands/codegraph-status.js +227 -0
  286. package/dist/runtime/commands/compact.js +297 -0
  287. package/dist/runtime/commands/config.js +73 -39
  288. package/dist/runtime/commands/cost.js +199 -0
  289. package/dist/runtime/commands/delegate.js +27 -4
  290. package/dist/runtime/commands/dispatch.js +126 -0
  291. package/dist/runtime/commands/doctor.js +579 -0
  292. package/dist/runtime/commands/feedback.js +184 -0
  293. package/dist/runtime/commands/hooks.js +187 -0
  294. package/dist/runtime/commands/init.js +254 -0
  295. package/dist/runtime/commands/lsp.js +200 -38
  296. package/dist/runtime/commands/mcp.js +879 -0
  297. package/dist/runtime/commands/memory.js +582 -0
  298. package/dist/runtime/commands/model.js +237 -0
  299. package/dist/runtime/commands/onboarding.js +275 -0
  300. package/dist/runtime/commands/patch.js +12 -12
  301. package/dist/runtime/commands/permissions.js +112 -0
  302. package/dist/runtime/commands/plan.js +143 -0
  303. package/dist/runtime/commands/prd-check.js +285 -0
  304. package/dist/runtime/commands/privacy.js +17 -17
  305. package/dist/runtime/commands/recipe.js +325 -0
  306. package/dist/runtime/commands/redo-blob-store.js +92 -0
  307. package/dist/runtime/commands/redo.js +361 -0
  308. package/dist/runtime/commands/release-notes.js +229 -0
  309. package/dist/runtime/commands/repo-map.js +95 -0
  310. package/dist/runtime/commands/report.js +299 -0
  311. package/dist/runtime/commands/resume.js +118 -0
  312. package/dist/runtime/commands/review-consensus.js +68 -53
  313. package/dist/runtime/commands/rewind.js +333 -0
  314. package/dist/runtime/commands/roster.js +14 -14
  315. package/dist/runtime/commands/sessions.js +163 -0
  316. package/dist/runtime/commands/share.js +316 -0
  317. package/dist/runtime/commands/skills.js +31 -31
  318. package/dist/runtime/commands/status.js +186 -0
  319. package/dist/runtime/commands/stickers.js +82 -0
  320. package/dist/runtime/commands/style.js +194 -0
  321. package/dist/runtime/commands/theme.js +196 -0
  322. package/dist/runtime/commands/undo.js +54 -22
  323. package/dist/runtime/commands/update.js +289 -0
  324. package/dist/runtime/commands/vim.js +140 -0
  325. package/dist/runtime/commands/worktree.js +8 -8
  326. package/dist/runtime/commands/worktrees.js +155 -0
  327. package/dist/runtime/headless-repl.js +195 -0
  328. package/dist/runtime/headless.js +543 -0
  329. package/dist/runtime/load-hooks-or-exit.js +71 -0
  330. package/dist/runtime/plan-decompose.js +22 -22
  331. package/dist/runtime/sigint-guard.js +272 -0
  332. package/dist/runtime/update-check.js +28 -28
  333. package/dist/runtime/version.js +65 -0
  334. package/dist/runtime/worktree-bootstrap.js +579 -0
  335. package/dist/skills/bundled/batch.js +617 -0
  336. package/dist/skills/bundled/index.js +45 -0
  337. package/dist/skills/bundled/loop.js +358 -0
  338. package/dist/skills/bundled/remember.js +383 -0
  339. package/dist/skills/bundled/simplify.js +289 -0
  340. package/dist/skills/bundled/skillify.js +373 -0
  341. package/dist/skills/bundled/stuck.js +558 -0
  342. package/dist/skills/bundled/verify.js +439 -0
  343. package/dist/testing/vcr.js +486 -0
  344. package/dist/tools/agent-tool.js +229 -0
  345. package/dist/tools/apply-patch.js +89 -28
  346. package/dist/tools/ask-user-question.js +337 -0
  347. package/dist/tools/ask-user.js +115 -0
  348. package/dist/tools/bash.js +624 -46
  349. package/dist/tools/brief.js +224 -0
  350. package/dist/tools/cron.js +433 -0
  351. package/dist/tools/enter-worktree.js +250 -0
  352. package/dist/tools/exit-worktree.js +147 -0
  353. package/dist/tools/file-tools.js +161 -44
  354. package/dist/tools/lsp-tools.js +377 -1
  355. package/dist/tools/mcp-tool.js +260 -0
  356. package/dist/tools/multi-edit.js +361 -0
  357. package/dist/tools/powershell.js +268 -0
  358. package/dist/tools/registry.js +99 -4
  359. package/dist/tools/skill-tool.js +96 -0
  360. package/dist/tools/sleep.js +99 -0
  361. package/dist/tools/synthetic-output.js +133 -0
  362. package/dist/tools/tasks.js +208 -0
  363. package/dist/tools/todo-write.js +184 -0
  364. package/dist/tools/verify-plan-execution.js +295 -0
  365. package/dist/tools/web-fetch-injection-scanner.js +207 -0
  366. package/dist/tools/web-fetch.js +195 -10
  367. package/dist/tools/web-search.js +458 -0
  368. package/dist/tui/agent-progress-card.js +111 -0
  369. package/dist/tui/agent-tree.js +11 -1
  370. package/dist/tui/ask-modal.js +14 -14
  371. package/dist/tui/ask-user-question-chips.js +315 -0
  372. package/dist/tui/ask-user-question-prompt.js +203 -0
  373. package/dist/tui/compact-banner.js +81 -0
  374. package/dist/tui/conversation-pane.js +85 -11
  375. package/dist/tui/cost-table.js +111 -0
  376. package/dist/tui/device-flow.js +2 -2
  377. package/dist/tui/doctor-table.js +46 -0
  378. package/dist/tui/feedback-prompt.js +156 -0
  379. package/dist/tui/input-box.js +247 -32
  380. package/dist/tui/login-picker.js +3 -3
  381. package/dist/tui/markdown-render.js +6 -6
  382. package/dist/tui/multi-file-diff-approval.js +375 -0
  383. package/dist/tui/onboarding-wizard.js +240 -0
  384. package/dist/tui/permissions-picker.js +86 -0
  385. package/dist/tui/render.js +36 -1
  386. package/dist/tui/repl-render.js +176 -25
  387. package/dist/tui/repl-splash-art.js +16 -16
  388. package/dist/tui/repl-splash-mascot.js +48 -24
  389. package/dist/tui/repl-splash.js +22 -22
  390. package/dist/tui/repl.js +125 -45
  391. package/dist/tui/slash-palette.js +6 -6
  392. package/dist/tui/splash.js +2 -2
  393. package/dist/tui/status-bar.js +109 -31
  394. package/dist/tui/status-table.js +7 -0
  395. package/dist/tui/stickers-art.js +136 -0
  396. package/dist/tui/style-table.js +28 -0
  397. package/dist/tui/theme-table.js +29 -0
  398. package/dist/tui/thinking-spinner.js +123 -0
  399. package/dist/tui/tool-stream-pane.js +53 -4
  400. package/dist/tui/update-banner.js +27 -2
  401. package/dist/tui/vim-input.js +267 -0
  402. package/dist/tui/welcome-banner.js +107 -0
  403. package/dist/tui/welcome-data.js +293 -0
  404. package/dist/tui/workspace-context.js +2 -2
  405. package/package.json +31 -16
  406. package/test/scenarios/codegen-create-file.scenario.txt +13 -0
  407. package/test/scenarios/compact-force.scenario.txt +12 -0
  408. package/test/scenarios/identity.scenario.txt +12 -0
  409. package/test/scenarios/persona-handoff.scenario.txt +12 -0
  410. package/test/scenarios/walkback.scenario.txt +12 -0
  411. package/dist/core/engine/compaction-hook.js +0 -154
@@ -0,0 +1,358 @@
1
+ /**
2
+ * `pugi loop` — drives a repeating prompt against the engine until a
3
+ * stop-condition matches.
4
+ *
5
+ * Bundled skill, batch 2 (backlog). Useful for autonomous "fix
6
+ * until green" or "scaffold until verified" inner loops where the
7
+ * operator does not want to hand-paste the same prompt repeatedly.
8
+ *
9
+ * # Flow
10
+ *
11
+ * 1. Build the prompt + optional `--until <regex>` stop condition.
12
+ * 2. Iterate up to `--max-iterations` (default 10, hard cap 100).
13
+ * 3. Each iteration calls the injected `engineInvoker` once and
14
+ * captures the assistant text + tool-call summaries.
15
+ * 4. Concatenate the captured text and test the stop regex against
16
+ * it; if it matches, exit early with `status='matched'`.
17
+ * 5. Enforce a USD ceiling via `--max-cost-usd` (default 2.0); when
18
+ * crossed, exit early with `status='cost-cap'`.
19
+ * 6. Persist per-iteration progress to
20
+ * `.pugi/loops/<loop-id>.jsonl` (atomic tmp + rename per write).
21
+ *
22
+ * # Why a hard iteration cap
23
+ *
24
+ * The operator can set `--max-iterations` up to 100; beyond that the
25
+ * skill refuses at CLI parse time. The ceiling protects against a
26
+ * misconfigured stop regex that never matches — at $0.02/turn typical
27
+ * cost, 100 iterations is still under the default USD cap, so the
28
+ * tighter of the two limits always wins.
29
+ *
30
+ * # Provenance
31
+ *
32
+ * Inspired by the external bundled-skills pattern (intel from
33
+ * leak-research memos, independent implementation TS). No upstream code reused.
34
+ * Multi-provider council mode inside loop is backlog; today the
35
+ * skill is single-engine.
36
+ */
37
+ import { existsSync, mkdirSync, renameSync, rmSync, writeFileSync, } from 'node:fs';
38
+ import { dirname, join } from 'node:path';
39
+ const DEFAULT_MAX_ITERATIONS = 10;
40
+ const HARD_MAX_ITERATIONS = 100;
41
+ const DEFAULT_MAX_COST_USD = 2.0;
42
+ function parseFlags(args) {
43
+ const flags = {
44
+ json: false,
45
+ prompt: null,
46
+ until: null,
47
+ maxIterations: DEFAULT_MAX_ITERATIONS,
48
+ maxCostUsd: DEFAULT_MAX_COST_USD,
49
+ };
50
+ for (let i = 0; i < args.length; i += 1) {
51
+ const arg = args[i];
52
+ if (arg === undefined)
53
+ continue;
54
+ if (arg === '--json') {
55
+ flags.json = true;
56
+ continue;
57
+ }
58
+ if (arg === '--prompt') {
59
+ const next = args[i + 1];
60
+ if (next === undefined)
61
+ return { flags, error: '--prompt requires a value' };
62
+ flags.prompt = next;
63
+ i += 1;
64
+ continue;
65
+ }
66
+ if (arg === '--until') {
67
+ const next = args[i + 1];
68
+ if (next === undefined)
69
+ return { flags, error: '--until requires a regex' };
70
+ flags.until = next;
71
+ i += 1;
72
+ continue;
73
+ }
74
+ if (arg === '--max-iterations') {
75
+ const next = args[i + 1];
76
+ if (next === undefined) {
77
+ return { flags, error: '--max-iterations requires a value' };
78
+ }
79
+ const parsed = Number.parseInt(next, 10);
80
+ if (!Number.isFinite(parsed) || parsed <= 0) {
81
+ return { flags, error: '--max-iterations must be a positive integer' };
82
+ }
83
+ if (parsed > HARD_MAX_ITERATIONS) {
84
+ return {
85
+ flags,
86
+ error: `--max-iterations must be <= ${HARD_MAX_ITERATIONS}`,
87
+ };
88
+ }
89
+ flags.maxIterations = parsed;
90
+ i += 1;
91
+ continue;
92
+ }
93
+ if (arg === '--max-cost-usd') {
94
+ const next = args[i + 1];
95
+ if (next === undefined) {
96
+ return { flags, error: '--max-cost-usd requires a value' };
97
+ }
98
+ const parsed = Number.parseFloat(next);
99
+ if (!Number.isFinite(parsed) || parsed <= 0) {
100
+ return {
101
+ flags,
102
+ error: '--max-cost-usd must be a positive number (USD)',
103
+ };
104
+ }
105
+ flags.maxCostUsd = parsed;
106
+ i += 1;
107
+ continue;
108
+ }
109
+ if (arg === '--help' || arg === '-h') {
110
+ return { flags, error: 'help' };
111
+ }
112
+ return { flags, error: `unknown argument: ${arg}` };
113
+ }
114
+ return { flags, error: null };
115
+ }
116
+ /** Hard cap on `--until` source length — defends against ReDoS via long input. */
117
+ const MAX_STOP_REGEX_LEN = 256;
118
+ /**
119
+ * Reject patterns that contain nested unbounded quantifiers — the classic
120
+ * catastrophic-backtracking shape `(a+)+`, `(.+)*`, `(x*)*`, etc. Cheap
121
+ * heuristic: look for any `+`/`*` immediately following a `)` that itself
122
+ * closes a group whose body ends in another unbounded quantifier. Anything
123
+ * that matches is rejected outright rather than handed to the V8 regex
124
+ * engine where a malicious operator could pin a CPU core through the
125
+ * loop's iteration budget.
126
+ *
127
+ * NOT a full regex AST parser — it just blocks the two known shapes that
128
+ * matter. Operators with a legitimate need can pass an explicit
129
+ * `/pattern/flags` form after the check (the rejection still fires).
130
+ */
131
+ function hasNestedUnboundedQuantifier(source) {
132
+ // Strip character classes so `[+*]` does not trip the heuristic.
133
+ const stripped = source.replace(/\[(?:\\.|[^\]\\])*\]/g, '');
134
+ // `(...+)+` / `(...+)*` / `(...*)*` / `(...*)+` shapes after class strip.
135
+ return /\([^)]*[+*][^)]*\)\s*[+*]/.test(stripped);
136
+ }
137
+ /**
138
+ * Parse the `--until` argument into a RegExp. Accepts either a raw
139
+ * pattern (used with the `s` flag so `.` spans newlines, friendly to
140
+ * multi-line assistant output) or `/pattern/flags` for explicit control.
141
+ *
142
+ * Returns `null` on length overflow (> 256 chars), nested unbounded
143
+ * quantifier (ReDoS shield), or any RegExp construction error. The
144
+ * caller surfaces "invalid_stop_regex" so the operator can fix it
145
+ * rather than discover a hang at iteration N.
146
+ *
147
+ * Public for test coverage.
148
+ */
149
+ export function parseStopRegex(input) {
150
+ if (input.length === 0)
151
+ return null;
152
+ if (input.length > MAX_STOP_REGEX_LEN)
153
+ return null;
154
+ if (input.startsWith('/') && /\/[gimsuy]*$/.test(input.slice(1))) {
155
+ const lastSlash = input.lastIndexOf('/');
156
+ const source = input.slice(1, lastSlash);
157
+ if (hasNestedUnboundedQuantifier(source))
158
+ return null;
159
+ try {
160
+ return new RegExp(source, input.slice(lastSlash + 1));
161
+ }
162
+ catch {
163
+ return null;
164
+ }
165
+ }
166
+ if (hasNestedUnboundedQuantifier(input))
167
+ return null;
168
+ try {
169
+ return new RegExp(input, 's');
170
+ }
171
+ catch {
172
+ return null;
173
+ }
174
+ }
175
+ function makeLoopId(now) {
176
+ const iso = now.toISOString().replace(/[:.]/g, '-');
177
+ const suffix = Math.floor(Math.random() * 0xfffff)
178
+ .toString(16)
179
+ .padStart(5, '0');
180
+ return `loop-${iso}-${suffix}`;
181
+ }
182
+ /**
183
+ * Atomic JSONL append — keeps the file consistent for chokidar / tail
184
+ * watchers by rewriting the whole document via tmp + rename on every
185
+ * iteration. The watcher never sees a partial line.
186
+ *
187
+ * Public so the test suite can drive the helper directly.
188
+ */
189
+ export function atomicWriteFile(targetPath, body) {
190
+ const parent = dirname(targetPath);
191
+ if (!existsSync(parent)) {
192
+ mkdirSync(parent, { recursive: true });
193
+ }
194
+ const tmpPath = `${targetPath}.tmp-${process.pid}-${Date.now()}-${Math.floor(Math.random() * 1_000_000)}`;
195
+ try {
196
+ writeFileSync(tmpPath, body, 'utf8');
197
+ renameSync(tmpPath, targetPath);
198
+ }
199
+ catch (err) {
200
+ try {
201
+ rmSync(tmpPath, { force: true });
202
+ }
203
+ catch {
204
+ // ignore cleanup
205
+ }
206
+ throw err;
207
+ }
208
+ }
209
+ function renderHumanReport(result) {
210
+ const lines = [];
211
+ lines.push(`pugi loop — id=${result.loopId} status=${result.status}`);
212
+ lines.push(`iterations: ${result.iterations.length} totalCostUsd: ${result.totalCostUsd.toFixed(4)}`);
213
+ lines.push(`progress: ${result.progressPath}`);
214
+ lines.push('');
215
+ for (const iter of result.iterations) {
216
+ lines.push(` [${String(iter.iteration).padStart(3, '0')}] cost=$${iter.costUsd.toFixed(4)} (cum=$${iter.cumulativeCostUsd.toFixed(4)})${iter.stopMatched ? ' <- stop matched' : ''}`);
217
+ }
218
+ return lines.join('\n');
219
+ }
220
+ export async function runLoopCommand(args, ctx) {
221
+ const { flags, error } = parseFlags(args);
222
+ if (error === 'help') {
223
+ ctx.writeOutput({ ok: true, command: 'loop', usage: LOOP_USAGE }, LOOP_USAGE);
224
+ return emptyResult('help', '', 'aborted', 0);
225
+ }
226
+ if (error !== null) {
227
+ ctx.writeOutput({ ok: false, command: 'loop', error }, `pugi loop: ${error}`);
228
+ return emptyResult('args-error', '', 'aborted', 2);
229
+ }
230
+ if (flags.prompt === null || flags.prompt.trim() === '') {
231
+ const msg = '--prompt is required';
232
+ ctx.writeOutput({ ok: false, command: 'loop', error: msg }, `pugi loop: ${msg}\n\n${LOOP_USAGE}`);
233
+ return emptyResult('args-error', '', 'no-prompt', 2);
234
+ }
235
+ const stopRegex = flags.until !== null ? parseStopRegex(flags.until) : null;
236
+ if (flags.until !== null && stopRegex === null) {
237
+ const msg = `--until is not a valid regex: ${flags.until}`;
238
+ ctx.writeOutput({ ok: false, command: 'loop', error: msg }, `pugi loop: ${msg}`);
239
+ return emptyResult('args-error', '', 'aborted', 2);
240
+ }
241
+ const loopId = ctx.newLoopId ? ctx.newLoopId() : makeLoopId(ctx.now());
242
+ const progressPath = join(ctx.cwd, '.pugi', 'loops', `${loopId}.jsonl`);
243
+ const iterations = [];
244
+ let cumulative = 0;
245
+ let status = 'max-iterations';
246
+ for (let i = 1; i <= flags.maxIterations; i += 1) {
247
+ const startedAt = ctx.now().toISOString();
248
+ let engineOut;
249
+ try {
250
+ engineOut = await ctx.engineInvoker({
251
+ iteration: i,
252
+ prompt: flags.prompt,
253
+ transcript: iterations,
254
+ });
255
+ }
256
+ catch (err) {
257
+ const message = err instanceof Error ? err.message : String(err);
258
+ status = 'aborted';
259
+ const completedAt = ctx.now().toISOString();
260
+ iterations.push({
261
+ iteration: i,
262
+ startedAt,
263
+ completedAt,
264
+ assistantText: `engine error: ${message}`,
265
+ toolCallSummary: [],
266
+ costUsd: 0,
267
+ cumulativeCostUsd: cumulative,
268
+ stopMatched: false,
269
+ });
270
+ persistProgress(progressPath, iterations);
271
+ break;
272
+ }
273
+ const completedAt = ctx.now().toISOString();
274
+ const stopMatched = stopRegex !== null
275
+ ? stopRegex.test([engineOut.assistantText, ...engineOut.toolCallSummary].join('\n'))
276
+ : false;
277
+ cumulative += engineOut.costUsd;
278
+ iterations.push({
279
+ iteration: i,
280
+ startedAt,
281
+ completedAt,
282
+ assistantText: engineOut.assistantText,
283
+ toolCallSummary: engineOut.toolCallSummary,
284
+ costUsd: engineOut.costUsd,
285
+ cumulativeCostUsd: cumulative,
286
+ stopMatched,
287
+ });
288
+ persistProgress(progressPath, iterations);
289
+ if (stopMatched) {
290
+ status = 'matched';
291
+ break;
292
+ }
293
+ if (cumulative >= flags.maxCostUsd) {
294
+ status = 'cost-cap';
295
+ break;
296
+ }
297
+ }
298
+ const exitCode = status === 'matched' || status === 'max-iterations'
299
+ ? 0
300
+ : 1;
301
+ const result = {
302
+ loopId,
303
+ status,
304
+ iterations,
305
+ totalCostUsd: cumulative,
306
+ progressPath,
307
+ exitCode,
308
+ };
309
+ ctx.writeOutput({ ok: true, command: 'loop', result }, renderHumanReport(result));
310
+ return result;
311
+ }
312
+ function persistProgress(progressPath, iterations) {
313
+ const body = iterations
314
+ .map((iter) => JSON.stringify(iter))
315
+ .join('\n');
316
+ try {
317
+ atomicWriteFile(progressPath, body === '' ? '' : `${body}\n`);
318
+ }
319
+ catch {
320
+ // The persistence path is informational; a fs failure must not
321
+ // bring the loop down. The operator still sees the in-memory
322
+ // summary on stdout / via the returned result.
323
+ }
324
+ }
325
+ function emptyResult(loopId, progressPath, status, exitCode) {
326
+ return {
327
+ loopId,
328
+ status,
329
+ iterations: [],
330
+ totalCostUsd: 0,
331
+ progressPath,
332
+ exitCode,
333
+ };
334
+ }
335
+ const LOOP_USAGE = [
336
+ 'pugi loop — repeat a prompt against the engine until a stop condition.',
337
+ '',
338
+ 'Usage:',
339
+ ' pugi loop --prompt "<text>" [--until "<regex>"]',
340
+ ' [--max-iterations <N>] [--max-cost-usd <USD>] [--json]',
341
+ '',
342
+ 'Flags:',
343
+ ' --prompt <text> The prompt sent to the engine each iteration.',
344
+ ' --until <regex> Stop regex; matched against assistant + tool',
345
+ ' output. Bare patterns get the `s` flag (`.`',
346
+ ' spans newlines); `/pattern/flags` is explicit.',
347
+ ' --max-iterations <N> Iteration ceiling (default 10, hard cap 100).',
348
+ ' --max-cost-usd <USD> USD ceiling (default 2.0). EXPERIMENTAL — only',
349
+ ' enforced when the engine invoker emits a',
350
+ ' non-zero costUsd. The shipped stub returns 0,',
351
+ ' so this cap is a no-op until the real engine',
352
+ ' variant lands (backlog follow-up).',
353
+ ' --json JSON envelope instead of human text.',
354
+ '',
355
+ 'Progress lands at .pugi/loops/<loop-id>.jsonl (one line per iteration,',
356
+ 'rewritten atomically every iteration).',
357
+ ].join('\n');
358
+ //# sourceMappingURL=loop.js.map