@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,364 @@
1
+ /**
2
+ * Prompt registry primitive — versioned storage + hot-swap + rollback.
3
+ *
4
+ * Gap-analysis primitive #5 (final) from
5
+ * docs/research/2026-05-31-9-layer-rag-architecture-.md.
6
+ *
7
+ * Layout on disk (per slug):
8
+ *
9
+ * <baseDir>/
10
+ * <slug>/
11
+ * 0.1.0.md // semver-named version files
12
+ * 0.2.0.md
13
+ * 1.0.0.md
14
+ * current.md // POSIX symlink (or copy on win32) -> active version
15
+ * .history.jsonl // append-only audit log: { ts, action, version, prev? }
16
+ *
17
+ * Operations:
18
+ *
19
+ * loadPrompt — load a specific version or the active one
20
+ * listVersions — enumerate version files, sorted semver desc
21
+ * getCurrentVersion — read the active version (null when uninitialised)
22
+ * activateVersion — atomic hot-swap of `current.md` to a new version,
23
+ * append a history entry, never leave a gap
24
+ * rollbackPrompt — restore the previous active version from .history.jsonl
25
+ *
26
+ * Atomic-write contract: every `current.md` mutation lands via tmp + rename
27
+ * on the same filesystem so a concurrent reader never observes a torn state.
28
+ * Mirrors the agent-progress writer pattern (see
29
+ * apps/pugi-cli/src/core/agent-progress/writer.ts).
30
+ *
31
+ * Out of scope (separate PRs):
32
+ * - admin-api consumer wire-up
33
+ * - A/B tenant-subset pinning
34
+ * - cache invalidation hook on activate
35
+ * - migration of existing PUGI.md to versioned format
36
+ */
37
+ import { appendFile, copyFile, lstat, mkdir, readFile, readdir, readlink, rename, rm, stat, symlink, writeFile, } from 'node:fs/promises';
38
+ import { tmpdir } from 'node:os';
39
+ import { dirname, join } from 'node:path';
40
+ import semver from 'semver';
41
+ /* ---------------------------------------------------------------------- */
42
+ /* Helpers */
43
+ /* ---------------------------------------------------------------------- */
44
+ const CURRENT_FILENAME = 'current.md';
45
+ const HISTORY_FILENAME = '.history.jsonl';
46
+ const IS_WINDOWS = process.platform === 'win32';
47
+ let writeSeq = 0;
48
+ function slugDir(baseDir, slug) {
49
+ if (!slug || typeof slug !== 'string') {
50
+ throw new TypeError(`prompt-registry: slug must be a non-empty string`);
51
+ }
52
+ return join(baseDir, slug);
53
+ }
54
+ function versionFile(baseDir, slug, version) {
55
+ return join(slugDir(baseDir, slug), `${version}.md`);
56
+ }
57
+ function currentFile(baseDir, slug) {
58
+ return join(slugDir(baseDir, slug), CURRENT_FILENAME);
59
+ }
60
+ function historyFile(baseDir, slug) {
61
+ return join(slugDir(baseDir, slug), HISTORY_FILENAME);
62
+ }
63
+ async function pathExists(p) {
64
+ try {
65
+ await lstat(p);
66
+ return true;
67
+ }
68
+ catch (err) {
69
+ if (err.code === 'ENOENT')
70
+ return false;
71
+ throw err;
72
+ }
73
+ }
74
+ function nextTmpName(target) {
75
+ writeSeq += 1;
76
+ return `${target}.tmp-${process.pid}-${writeSeq}-${Date.now()}`;
77
+ }
78
+ /**
79
+ * Atomically write/replace `current.md` to point at `<version>.md`.
80
+ *
81
+ * POSIX path: write a symlink to a tmp name, then rename(tmp, current) so the
82
+ * swap is atomic — no reader ever observes the file missing.
83
+ *
84
+ * Windows path: symlinks require elevated privileges, so we copy the version
85
+ * bytes to a tmp file and rename. Still atomic on the same volume; the only
86
+ * cost is duplicated bytes.
87
+ */
88
+ async function writeCurrentAtomically(dir, version) {
89
+ const finalPath = join(dir, CURRENT_FILENAME);
90
+ const tmp = nextTmpName(finalPath);
91
+ const targetVersionFile = `${version}.md`;
92
+ try {
93
+ if (IS_WINDOWS) {
94
+ await copyFile(join(dir, targetVersionFile), tmp);
95
+ }
96
+ else {
97
+ // Relative symlink — survives moving the slug directory as long as
98
+ // the version siblings come along.
99
+ await symlink(targetVersionFile, tmp);
100
+ }
101
+ // Replace any existing current.md. rename() is atomic on the same fs.
102
+ await rename(tmp, finalPath);
103
+ }
104
+ catch (err) {
105
+ try {
106
+ await rm(tmp, { force: true });
107
+ }
108
+ catch {
109
+ // best-effort
110
+ }
111
+ throw err;
112
+ }
113
+ }
114
+ async function appendHistory(baseDir, slug, entry) {
115
+ const line = `${JSON.stringify(entry)}\n`;
116
+ await appendFile(historyFile(baseDir, slug), line, 'utf8');
117
+ }
118
+ async function readHistory(baseDir, slug) {
119
+ const path = historyFile(baseDir, slug);
120
+ try {
121
+ const raw = await readFile(path, 'utf8');
122
+ const out = [];
123
+ for (const line of raw.split('\n')) {
124
+ const trimmed = line.trim();
125
+ if (!trimmed)
126
+ continue;
127
+ try {
128
+ out.push(JSON.parse(trimmed));
129
+ }
130
+ catch {
131
+ // Skip malformed lines — append-only log should never have them, but
132
+ // tolerate corruption rather than poisoning the whole registry.
133
+ }
134
+ }
135
+ return out;
136
+ }
137
+ catch (err) {
138
+ if (err.code === 'ENOENT')
139
+ return [];
140
+ throw err;
141
+ }
142
+ }
143
+ /**
144
+ * Resolve the active version slug by inspecting `current.md`.
145
+ *
146
+ * On POSIX we read the symlink target (e.g. `1.2.0.md` -> `1.2.0`).
147
+ * On Windows we have to fall back to the most recent activate entry in
148
+ * .history.jsonl because the file is a content copy, not a link.
149
+ */
150
+ async function resolveActiveVersion(baseDir, slug) {
151
+ const path = currentFile(baseDir, slug);
152
+ if (!(await pathExists(path)))
153
+ return null;
154
+ if (!IS_WINDOWS) {
155
+ try {
156
+ const target = await readlink(path);
157
+ // Strip directory (defensive — we always write relative names) + `.md`.
158
+ const base = target.split(/[\\/]/).pop() ?? target;
159
+ return base.endsWith('.md') ? base.slice(0, -3) : base;
160
+ }
161
+ catch {
162
+ // Fall through to history lookup if current.md is a regular file
163
+ // (e.g. a manual operator override on POSIX).
164
+ }
165
+ }
166
+ const history = await readHistory(baseDir, slug);
167
+ for (let i = history.length - 1; i >= 0; i -= 1) {
168
+ const entry = history[i];
169
+ if (entry && (entry.action === 'activate' || entry.action === 'rollback')) {
170
+ return entry.version;
171
+ }
172
+ }
173
+ return null;
174
+ }
175
+ /* ---------------------------------------------------------------------- */
176
+ /* Public API */
177
+ /* ---------------------------------------------------------------------- */
178
+ /**
179
+ * Load a prompt body + metadata.
180
+ *
181
+ * Resolution rules:
182
+ * - `version` set → read `<slug>/<version>.md` directly
183
+ * - `version` omitted → read `<slug>/current.md` (follows symlink on POSIX,
184
+ * or reads the copied content on Windows)
185
+ *
186
+ * Throws:
187
+ * - TypeError when the slug directory does not exist
188
+ * - RangeError when the requested version file or `current.md` is missing
189
+ */
190
+ export async function loadPrompt(opts) {
191
+ const dir = slugDir(opts.baseDir, opts.slug);
192
+ if (!(await pathExists(dir))) {
193
+ throw new TypeError(`prompt-registry: slug directory not found: ${opts.slug} (looked in ${opts.baseDir})`);
194
+ }
195
+ let resolvedVersion = opts.version;
196
+ let path;
197
+ if (resolvedVersion) {
198
+ path = versionFile(opts.baseDir, opts.slug, resolvedVersion);
199
+ if (!(await pathExists(path))) {
200
+ throw new RangeError(`prompt-registry: version not found: ${opts.slug}@${resolvedVersion}`);
201
+ }
202
+ }
203
+ else {
204
+ path = currentFile(opts.baseDir, opts.slug);
205
+ if (!(await pathExists(path))) {
206
+ throw new RangeError(`prompt-registry: no current version set for slug: ${opts.slug}`);
207
+ }
208
+ const active = await resolveActiveVersion(opts.baseDir, opts.slug);
209
+ if (!active) {
210
+ throw new RangeError(`prompt-registry: current.md exists but version cannot be resolved for slug: ${opts.slug}`);
211
+ }
212
+ resolvedVersion = active;
213
+ }
214
+ const body = await readFile(path, 'utf8');
215
+ return {
216
+ slug: opts.slug,
217
+ version: resolvedVersion,
218
+ body,
219
+ };
220
+ }
221
+ /**
222
+ * List all version files for a slug, sorted semver descending.
223
+ * Excludes `current.md` and `.history.jsonl`. Returns `[]` for slugs
224
+ * that have no version files yet (and for slugs that do not exist).
225
+ */
226
+ export async function listVersions(opts) {
227
+ const dir = slugDir(opts.baseDir, opts.slug);
228
+ let entries;
229
+ try {
230
+ entries = await readdir(dir);
231
+ }
232
+ catch (err) {
233
+ if (err.code === 'ENOENT')
234
+ return [];
235
+ throw err;
236
+ }
237
+ const versions = [];
238
+ for (const name of entries) {
239
+ if (name === CURRENT_FILENAME || name === HISTORY_FILENAME)
240
+ continue;
241
+ if (!name.endsWith('.md'))
242
+ continue;
243
+ const v = name.slice(0, -3);
244
+ if (semver.valid(v))
245
+ versions.push(v);
246
+ }
247
+ versions.sort((a, b) => semver.rcompare(a, b));
248
+ const out = [];
249
+ for (const v of versions) {
250
+ const body = await readFile(versionFile(opts.baseDir, opts.slug, v), 'utf8');
251
+ out.push({ slug: opts.slug, version: v, body });
252
+ }
253
+ return out;
254
+ }
255
+ /**
256
+ * Return the active version slug, or `null` when no `current.md` is set
257
+ * (or when the slug/baseDir does not exist).
258
+ */
259
+ export async function getCurrentVersion(opts) {
260
+ if (!(await pathExists(opts.baseDir)))
261
+ return null;
262
+ if (!(await pathExists(slugDir(opts.baseDir, opts.slug))))
263
+ return null;
264
+ return resolveActiveVersion(opts.baseDir, opts.slug);
265
+ }
266
+ /**
267
+ * Promote `version` to be the active version. Writes `current.md` atomically
268
+ * (symlink+rename on POSIX, copy+rename on Windows) and appends an audit
269
+ * entry to `.history.jsonl`.
270
+ *
271
+ * Throws:
272
+ * - RangeError when `version` is not valid semver
273
+ * - RangeError when `<version>.md` does not exist on disk
274
+ */
275
+ export async function activateVersion(opts) {
276
+ if (!semver.valid(opts.version)) {
277
+ throw new RangeError(`prompt-registry: version must be valid semver, got: ${opts.version}`);
278
+ }
279
+ const dir = slugDir(opts.baseDir, opts.slug);
280
+ const target = versionFile(opts.baseDir, opts.slug, opts.version);
281
+ if (!(await pathExists(target))) {
282
+ throw new RangeError(`prompt-registry: version file does not exist: ${opts.slug}@${opts.version}`);
283
+ }
284
+ // Capture prior active version BEFORE swapping so the history entry is
285
+ // complete even if a concurrent activate races us.
286
+ const prev = (await resolveActiveVersion(opts.baseDir, opts.slug)) ?? undefined;
287
+ if (!(await pathExists(dir))) {
288
+ await mkdir(dir, { recursive: true });
289
+ }
290
+ await writeCurrentAtomically(dir, opts.version);
291
+ const entry = {
292
+ ts: new Date().toISOString(),
293
+ action: 'activate',
294
+ version: opts.version,
295
+ ...(prev !== undefined ? { prev } : {}),
296
+ };
297
+ await appendHistory(opts.baseDir, opts.slug, entry);
298
+ }
299
+ /**
300
+ * Restore the previous active version from `.history.jsonl`. Idempotent
301
+ * across repeated calls: each call walks one step further back through the
302
+ * history to find a non-current target.
303
+ *
304
+ * Throws RangeError when there is no prior version to restore.
305
+ */
306
+ export async function rollbackPrompt(opts) {
307
+ const history = await readHistory(opts.baseDir, opts.slug);
308
+ if (history.length === 0) {
309
+ throw new RangeError(`prompt-registry: no history to roll back for slug: ${opts.slug}`);
310
+ }
311
+ // Find the most recent entry that has a `prev` field — that's the version
312
+ // we want to restore. Entries without `prev` were the first activate, so
313
+ // there's nothing prior to fall back to from them.
314
+ let target;
315
+ for (let i = history.length - 1; i >= 0; i -= 1) {
316
+ const entry = history[i];
317
+ if (entry && entry.prev) {
318
+ target = entry.prev;
319
+ break;
320
+ }
321
+ }
322
+ if (!target) {
323
+ throw new RangeError(`prompt-registry: no prior version recorded in history for slug: ${opts.slug}`);
324
+ }
325
+ const dir = slugDir(opts.baseDir, opts.slug);
326
+ const file = versionFile(opts.baseDir, opts.slug, target);
327
+ if (!(await pathExists(file))) {
328
+ throw new RangeError(`prompt-registry: prior version file missing on disk: ${opts.slug}@${target}`);
329
+ }
330
+ const prev = (await resolveActiveVersion(opts.baseDir, opts.slug)) ?? undefined;
331
+ await writeCurrentAtomically(dir, target);
332
+ const entry = {
333
+ ts: new Date().toISOString(),
334
+ action: 'rollback',
335
+ version: target,
336
+ ...(prev !== undefined ? { prev } : {}),
337
+ };
338
+ await appendHistory(opts.baseDir, opts.slug, entry);
339
+ const body = await readFile(file, 'utf8');
340
+ return { slug: opts.slug, version: target, body };
341
+ }
342
+ /**
343
+ * Convenience helper for callers that need an OS-level temp dir for tests
344
+ * or scratch operations. Exported so the spec file can share the same
345
+ * idiom as the implementation without duplicating logic.
346
+ */
347
+ export function defaultTmpRoot(prefix = 'pugi-prompts-') {
348
+ return join(tmpdir(), prefix);
349
+ }
350
+ // Re-export the path helpers under a namespace for tests + downstream
351
+ // consumers that want to introspect the layout without re-deriving paths.
352
+ export const paths = {
353
+ slugDir,
354
+ versionFile,
355
+ currentFile,
356
+ historyFile,
357
+ };
358
+ // Silence "stat is unused" — kept in the import list because future
359
+ // consumers (cache-invalidation hook, follow-up PR) will need it and the
360
+ // import block is the single canonical place for fs/promises pulls.
361
+ void stat;
362
+ void dirname;
363
+ void writeFile;
364
+ //# sourceMappingURL=registry.js.map