@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,557 @@
1
+ /**
2
+ * PRD ↔ session review — Pugi final (`/prd-check --session`,
3
+ *).
4
+ *
5
+ * The shipped `/prd-check` surface verifies a PRD's acceptance criteria
6
+ * against committed artifacts on disk (file / test / doc / command /
7
+ * route verifiers — see `core/prd-check/verifiers.ts`). That mode is
8
+ * the canonical CI gate; it inspects a snapshot of the workspace and
9
+ * decides healthy / failing / unparsed.
10
+ *
11
+ * `--session` adds a complementary mode: ask "does the work I just
12
+ * did in this REPL session actually cover the PRD?" without requiring
13
+ * the acceptance criteria to be written in the structured shape the
14
+ * verifier expects. The mode:
15
+ *
16
+ * 1. Walks up from the current working directory looking for
17
+ * `PRD.md`, then `PRODUCT.md`, then `apps/<any>/PRODUCT.md`
18
+ * under the workspace root. The first hit wins; the rest are
19
+ * ignored. We stop at the filesystem root.
20
+ *
21
+ * 2. Reads the last N (default 20) events from `.pugi/events.jsonl`
22
+ * that represent operator-visible turns: user prompts, model
23
+ * responses, and tool calls with their results. Other event
24
+ * types (`session`, `hook`, …) are filtered so the prompt the
25
+ * subagent receives is dominated by intent + work-actually-done
26
+ * rather than infrastructure noise.
27
+ *
28
+ * 3. Builds a structured prompt for a cross-review subagent. The
29
+ * subagent is dispatched via the standard `dispatch()` surface
30
+ * (see `core/subagents/dispatcher.ts`) using the `pm` persona —
31
+ * the closest match to a PRD reviewer in today's roster. The
32
+ * subagent is instructed to return two newline-separated lists:
33
+ * `Satisfied:` and `Outstanding:`.
34
+ *
35
+ * 4. Parses the subagent's response into a structured envelope so
36
+ * the slash + the top-level CLI render the same output shape
37
+ * (Markdown sections in the TUI, JSON for scripts).
38
+ *
39
+ * The module is pure with respect to dependencies — every IO surface
40
+ * (`readPrdSearch`, `readSessionEvents`, `dispatchReview`) is
41
+ * accepted as an injected dep so the spec can drive every branch
42
+ * without a real filesystem or a network call. The default
43
+ * implementations live in `defaultSessionReviewDeps`.
44
+ *
45
+ * The subagent return contract is intentionally loose: any line
46
+ * starting with `Satisfied:` (case-insensitive) opens the satisfied
47
+ * section; any line starting with `Outstanding:` opens the
48
+ * outstanding section. Bulleted lines (`-`, `*`, `•`) inside each
49
+ * section land as list items. Free prose between sections is
50
+ * captured as the `note` field on the envelope so the reviewer can
51
+ * still attach a sentence of context.
52
+ *
53
+ * Cross-review subagent: this module routes to whatever persona
54
+ * resolves the "PRD reviewer" role at dispatch time. In
55
+ * that is the `pm` persona via `dispatch({ role: 'pm', … })`. Once
56
+ * a dedicated reviewer persona lands (project tracking ID:
57
+ * cross-review subagent track), swapping it requires only changing
58
+ * `DEFAULT_REVIEW_ROLE` below.
59
+ */
60
+ import { existsSync, readFileSync, statSync } from 'node:fs';
61
+ import { dirname, join, relative, resolve } from 'node:path';
62
+ /**
63
+ * Names of PRD-style files we will try to locate. Order matters —
64
+ * `PRD.md` wins over `PRODUCT.md` so a project that has both an
65
+ * authored PRD and a legacy PRODUCT brief points at the PRD.
66
+ */
67
+ const PRD_CANDIDATE_NAMES = ['PRD.md', 'PRODUCT.md'];
68
+ /**
69
+ * Per-app product brief glob. We scan `apps/*` under the workspace
70
+ * root for a top-level `PRODUCT.md` — this matches the layout the
71
+ * Pugi monorepo uses (`apps/admin-api/PRODUCT.md`, etc.). Walk is
72
+ * shallow on purpose to keep the search bounded.
73
+ */
74
+ const APPS_DIR = 'apps';
75
+ /** Default number of NDJSON turns to surface to the reviewer. */
76
+ export const DEFAULT_TURN_COUNT = 20;
77
+ /**
78
+ * Subagent role we ask to play the PRD reviewer. `reviewer` is the
79
+ * canonical slot in the dispatcher's role enum (see
80
+ * `packages/pugi-sdk/src/subagent-contracts.ts`) — every dispatch
81
+ * resolves a role to a persona at runtime via the isolation matrix.
82
+ * The constant is exported so callers can override (e.g. route to
83
+ * `verifier` for a stricter pass).
84
+ */
85
+ export const DEFAULT_REVIEW_ROLE = 'reviewer';
86
+ /**
87
+ * Run the `--session` mode end-to-end. The function emits status
88
+ * lines through `deps.onStatus` (the slash dispatcher wires this to
89
+ * `appendSystemLine`) and returns the structured envelope.
90
+ */
91
+ export async function runSessionReview(workspaceRoot, deps, options = {}) {
92
+ const turnCount = options.turnCount ?? DEFAULT_TURN_COUNT;
93
+ const status = deps.onStatus ?? (() => undefined);
94
+ status('Locating PRD...');
95
+ const prdPath = deps.resolvePrd(workspaceRoot);
96
+ if (prdPath === null) {
97
+ return {
98
+ command: 'prd-check',
99
+ mode: 'session',
100
+ status: 'no_prd',
101
+ prdPath: null,
102
+ prdTitle: null,
103
+ turnsRead: 0,
104
+ satisfied: [],
105
+ outstanding: [],
106
+ note: '',
107
+ rawReview: null,
108
+ reason: `No PRD.md or PRODUCT.md found walking up from ${workspaceRoot}.`,
109
+ };
110
+ }
111
+ const prdSource = safeRead(prdPath);
112
+ if (prdSource === null) {
113
+ return {
114
+ command: 'prd-check',
115
+ mode: 'session',
116
+ status: 'no_prd',
117
+ prdPath: relative(workspaceRoot, prdPath) || prdPath,
118
+ prdTitle: null,
119
+ turnsRead: 0,
120
+ satisfied: [],
121
+ outstanding: [],
122
+ note: '',
123
+ rawReview: null,
124
+ reason: `PRD file at ${prdPath} is unreadable.`,
125
+ };
126
+ }
127
+ const prdTitle = extractTitle(prdSource);
128
+ status(`Reading last ${turnCount} session turns...`);
129
+ const rawEvents = deps.readEventsLog(workspaceRoot);
130
+ const turns = rawEvents === null ? [] : parseTurns(rawEvents, turnCount);
131
+ status('Reviewing against PRD...');
132
+ const prompt = buildReviewPrompt({
133
+ prdPath,
134
+ prdTitle,
135
+ prdSource,
136
+ turns,
137
+ workspaceRoot,
138
+ });
139
+ const outcome = await deps.dispatchReview({
140
+ role: DEFAULT_REVIEW_ROLE,
141
+ prompt,
142
+ workspaceRoot,
143
+ });
144
+ if (!outcome.ok) {
145
+ return {
146
+ command: 'prd-check',
147
+ mode: 'session',
148
+ status: 'dispatch_failed',
149
+ prdPath: relative(workspaceRoot, prdPath) || prdPath,
150
+ prdTitle,
151
+ turnsRead: turns.length,
152
+ satisfied: [],
153
+ outstanding: [],
154
+ note: '',
155
+ rawReview: null,
156
+ reason: outcome.reason,
157
+ };
158
+ }
159
+ const parsed = parseReviewResponse(outcome.text);
160
+ return {
161
+ command: 'prd-check',
162
+ mode: 'session',
163
+ status: 'ok',
164
+ prdPath: relative(workspaceRoot, prdPath) || prdPath,
165
+ prdTitle,
166
+ turnsRead: turns.length,
167
+ satisfied: parsed.satisfied,
168
+ outstanding: parsed.outstanding,
169
+ note: parsed.note,
170
+ rawReview: outcome.text,
171
+ };
172
+ }
173
+ /**
174
+ * Render the envelope as plain-text lines for the TUI / shell. The
175
+ * slash + the top-level CLI both use this so the surface stays
176
+ * single-sourced; the structured envelope (above) feeds `--json`.
177
+ */
178
+ export function renderSessionReview(result) {
179
+ if (result.status === 'no_prd') {
180
+ return result.reason ?? 'No PRD found.';
181
+ }
182
+ if (result.status === 'dispatch_failed') {
183
+ return `PRD review dispatch failed: ${result.reason ?? 'unknown'}`;
184
+ }
185
+ const lines = [];
186
+ lines.push(`PRD review (${result.turnsRead} turn(s) read from .pugi/events.jsonl)`);
187
+ if (result.prdPath !== null) {
188
+ const titlePart = result.prdTitle === null ? '' : ` — ${result.prdTitle}`;
189
+ lines.push(`Source: ${result.prdPath}${titlePart}`);
190
+ }
191
+ lines.push('');
192
+ if (result.satisfied.length === 0) {
193
+ lines.push('Satisfied: (none reported)');
194
+ }
195
+ else {
196
+ lines.push('Satisfied:');
197
+ for (const item of result.satisfied)
198
+ lines.push(` - ${item}`);
199
+ }
200
+ lines.push('');
201
+ if (result.outstanding.length === 0) {
202
+ lines.push('Outstanding: (none reported)');
203
+ }
204
+ else {
205
+ lines.push('Outstanding:');
206
+ for (const item of result.outstanding)
207
+ lines.push(` - ${item}`);
208
+ }
209
+ if (result.note.length > 0) {
210
+ lines.push('');
211
+ lines.push(`Note: ${result.note}`);
212
+ }
213
+ return lines.join('\n');
214
+ }
215
+ /**
216
+ * Compose the prompt handed to the reviewer subagent. The prompt is
217
+ * deterministic — input order matters for prompt cache hits so we
218
+ * keep the layout stable: PRD source first, session turns second,
219
+ * forcing-question schema last.
220
+ */
221
+ export function buildReviewPrompt(input) {
222
+ const parts = [];
223
+ parts.push('You are a PRD reviewer. Read the PRD below, then read the recent session turns, then decide which requirements are SATISFIED by the work-so-far and which remain OUTSTANDING.');
224
+ parts.push('');
225
+ parts.push('Reply in EXACTLY this shape:');
226
+ parts.push('');
227
+ parts.push('Satisfied:');
228
+ parts.push('- <requirement>');
229
+ parts.push('- <requirement>');
230
+ parts.push('');
231
+ parts.push('Outstanding:');
232
+ parts.push('- <requirement>');
233
+ parts.push('- <requirement>');
234
+ parts.push('');
235
+ parts.push('Each list item is one PRD requirement, paraphrased to fit a single line. Do not invent requirements that are not in the PRD. If the session shows no work toward a requirement, list it Outstanding.');
236
+ parts.push('');
237
+ parts.push('--- PRD start ---');
238
+ parts.push(`Path: ${relative(input.workspaceRoot, input.prdPath) || input.prdPath}`);
239
+ if (input.prdTitle !== null)
240
+ parts.push(`Title: ${input.prdTitle}`);
241
+ parts.push('');
242
+ parts.push(input.prdSource);
243
+ parts.push('--- PRD end ---');
244
+ parts.push('');
245
+ parts.push(`--- Last ${input.turns.length} session turn(s) start ---`);
246
+ for (const turn of input.turns) {
247
+ parts.push(formatTurn(turn));
248
+ }
249
+ parts.push('--- session turns end ---');
250
+ return parts.join('\n');
251
+ }
252
+ /**
253
+ * Walk up from cwd looking for the first PRD / PRODUCT file. Also
254
+ * scans `apps/*` under the workspace root once we find a directory
255
+ * that contains an `apps` folder. Returns absolute path or null.
256
+ */
257
+ export function defaultResolvePrd(cwd) {
258
+ let current = resolve(cwd);
259
+ for (let i = 0; i < 32; i += 1) {
260
+ for (const name of PRD_CANDIDATE_NAMES) {
261
+ const candidate = join(current, name);
262
+ if (existsSync(candidate) && safeIsFile(candidate)) {
263
+ return candidate;
264
+ }
265
+ }
266
+ // If this directory holds an apps/ folder, scan one level deep
267
+ // for app-scoped PRODUCT.md. We do NOT keep walking up past this
268
+ // point — the apps/ folder marks the workspace root in our
269
+ // monorepo layout.
270
+ const appsDir = join(current, APPS_DIR);
271
+ if (existsSync(appsDir) && safeIsDirectory(appsDir)) {
272
+ const appHit = scanAppsForProduct(appsDir);
273
+ if (appHit !== null)
274
+ return appHit;
275
+ return null;
276
+ }
277
+ const parent = dirname(current);
278
+ if (parent === current)
279
+ break;
280
+ current = parent;
281
+ }
282
+ return null;
283
+ }
284
+ /**
285
+ * Default events log reader. Returns the raw file contents or null
286
+ * when the log is absent — `.pugi/events.jsonl` only exists when
287
+ * the workspace has had at least one session.
288
+ */
289
+ export function defaultReadEventsLog(workspaceRoot) {
290
+ const path = join(workspaceRoot, '.pugi', 'events.jsonl');
291
+ return safeRead(path);
292
+ }
293
+ /**
294
+ * Default cross-review dispatcher. Routes through the standard
295
+ * subagents `dispatch()` surface in stub-mode (no engine client) so
296
+ * the slash + the CLI top-level have a working default that does not
297
+ * require a live admin-api connection. When an engine client is in
298
+ * scope (callers supply one via injection from the runtime cli.ts
299
+ * layer once auth is resolved), `dispatch()` will route to the real
300
+ * cross-review subagent.
301
+ *
302
+ * Imported dynamically so test paths that inject a stub never pull
303
+ * the dispatcher graph into the spec.
304
+ */
305
+ export const defaultDispatchReview = async (input) => {
306
+ try {
307
+ const { dispatch, inMemoryDispatcherContext } = await import('../subagents/dispatcher.js');
308
+ // The dispatcher's role enum is the canonical schema; `as` keeps
309
+ // the caller's role string flowing through without re-importing
310
+ // the schema here (the schema parse inside `dispatch()` will
311
+ // reject if it does not match — that is the contract gate).
312
+ const task = {
313
+ id: `prd-review-${Date.now()}`,
314
+ role: input.role,
315
+ prompt: input.prompt,
316
+ permissionMode: 'plan',
317
+ };
318
+ const ctx = inMemoryDispatcherContext({
319
+ sessionId: `prd-review-session-${Date.now()}`,
320
+ workspaceRoot: input.workspaceRoot,
321
+ sink: [],
322
+ });
323
+ const outcome = await dispatch(task, ctx);
324
+ if (!outcome || typeof outcome !== 'object') {
325
+ return { ok: false, reason: 'dispatcher returned an unexpected shape' };
326
+ }
327
+ if (typeof outcome.summary === 'string' && outcome.summary.length > 0) {
328
+ return { ok: true, text: outcome.summary };
329
+ }
330
+ return { ok: false, reason: 'dispatcher response carried no reviewable summary' };
331
+ }
332
+ catch (error) {
333
+ const message = error instanceof Error ? error.message : String(error);
334
+ return { ok: false, reason: message };
335
+ }
336
+ };
337
+ /** Convenience bundle for callers that want the real-IO defaults. */
338
+ export function defaultSessionReviewDeps(overrides = {}) {
339
+ return {
340
+ resolvePrd: overrides.resolvePrd ?? defaultResolvePrd,
341
+ readEventsLog: overrides.readEventsLog ?? defaultReadEventsLog,
342
+ dispatchReview: overrides.dispatchReview ?? defaultDispatchReview,
343
+ ...(overrides.onStatus !== undefined ? { onStatus: overrides.onStatus } : {}),
344
+ };
345
+ }
346
+ /**
347
+ * Parse NDJSON, filter to operator-visible turns, and return the
348
+ * last N in chronological order. Malformed lines are silently
349
+ * dropped — the events log is appended to from multiple processes
350
+ * and partial writes during shutdown can leave a trailing line.
351
+ */
352
+ export function parseTurns(raw, max) {
353
+ const lines = raw.split('\n').filter((line) => line.trim().length > 0);
354
+ const events = [];
355
+ for (const line of lines) {
356
+ try {
357
+ const parsed = JSON.parse(line);
358
+ if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
359
+ events.push(parsed);
360
+ }
361
+ }
362
+ catch {
363
+ // Drop malformed lines.
364
+ }
365
+ }
366
+ const visible = [];
367
+ for (const event of events) {
368
+ const role = classifyEvent(event);
369
+ if (role === null)
370
+ continue;
371
+ visible.push({
372
+ index: visible.length,
373
+ role,
374
+ summary: summariseEvent(event, role),
375
+ raw: event,
376
+ });
377
+ }
378
+ if (visible.length <= max) {
379
+ return visible.map((t, idx) => ({ ...t, index: idx }));
380
+ }
381
+ return visible.slice(visible.length - max).map((t, idx) => ({ ...t, index: idx }));
382
+ }
383
+ /**
384
+ * Pull a "Satisfied:" / "Outstanding:" pair out of the subagent text.
385
+ * Both labels are matched case-insensitively at line start. Bulleted
386
+ * items use any of `- `, `* `, or `• `. Free prose before / between
387
+ * sections lands in `note` (concatenated with a single space so the
388
+ * renderer can decide on wrapping).
389
+ */
390
+ export function parseReviewResponse(text) {
391
+ const lines = text.split('\n');
392
+ const satisfied = [];
393
+ const outstanding = [];
394
+ const noteParts = [];
395
+ let section = 'none';
396
+ for (const raw of lines) {
397
+ const line = raw.trim();
398
+ if (line.length === 0)
399
+ continue;
400
+ const header = matchSectionHeader(line);
401
+ if (header !== null) {
402
+ section = header;
403
+ // Capture any inline item after the colon, e.g. "Satisfied: foo".
404
+ const inline = stripHeaderPrefix(line);
405
+ if (inline.length > 0) {
406
+ pushItem(inline, section, satisfied, outstanding);
407
+ }
408
+ continue;
409
+ }
410
+ const bulleted = matchBulleted(line);
411
+ if (bulleted !== null) {
412
+ pushItem(bulleted, section, satisfied, outstanding);
413
+ continue;
414
+ }
415
+ if (section === 'none') {
416
+ noteParts.push(line);
417
+ }
418
+ else {
419
+ // Continuation of the previous bulleted item — append.
420
+ const target = section === 'satisfied' ? satisfied : outstanding;
421
+ if (target.length > 0) {
422
+ target[target.length - 1] = `${target[target.length - 1]} ${line}`;
423
+ }
424
+ else {
425
+ noteParts.push(line);
426
+ }
427
+ }
428
+ }
429
+ return { satisfied, outstanding, note: noteParts.join(' ') };
430
+ }
431
+ /* ------------------------------ helpers ------------------------------ */
432
+ function safeRead(path) {
433
+ try {
434
+ return readFileSync(path, 'utf8');
435
+ }
436
+ catch {
437
+ return null;
438
+ }
439
+ }
440
+ function safeIsFile(path) {
441
+ try {
442
+ return statSync(path).isFile();
443
+ }
444
+ catch {
445
+ return false;
446
+ }
447
+ }
448
+ function safeIsDirectory(path) {
449
+ try {
450
+ return statSync(path).isDirectory();
451
+ }
452
+ catch {
453
+ return false;
454
+ }
455
+ }
456
+ function scanAppsForProduct(appsDir) {
457
+ let entries;
458
+ try {
459
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
460
+ entries = require('node:fs').readdirSync(appsDir);
461
+ }
462
+ catch {
463
+ return null;
464
+ }
465
+ entries.sort();
466
+ for (const entry of entries) {
467
+ const candidate = join(appsDir, entry, 'PRODUCT.md');
468
+ if (existsSync(candidate) && safeIsFile(candidate))
469
+ return candidate;
470
+ const prdCandidate = join(appsDir, entry, 'PRD.md');
471
+ if (existsSync(prdCandidate) && safeIsFile(prdCandidate))
472
+ return prdCandidate;
473
+ }
474
+ return null;
475
+ }
476
+ function extractTitle(source) {
477
+ for (const raw of source.split('\n')) {
478
+ const line = raw.trim();
479
+ if (line.length === 0)
480
+ continue;
481
+ if (line.startsWith('# '))
482
+ return line.slice(2).trim();
483
+ if (line.startsWith('#'))
484
+ return line.replace(/^#+/, '').trim();
485
+ return null;
486
+ }
487
+ return null;
488
+ }
489
+ function classifyEvent(event) {
490
+ const type = typeof event.type === 'string' ? event.type : '';
491
+ if (type === 'user' || type === 'user_message' || type === 'prompt')
492
+ return 'user';
493
+ if (type === 'assistant' || type === 'model' || type === 'response' || type === 'completion') {
494
+ return 'model';
495
+ }
496
+ if (type === 'tool_call' || type === 'tool_result' || type === 'file_mutation')
497
+ return 'tool';
498
+ return null;
499
+ }
500
+ function summariseEvent(event, role) {
501
+ const text = typeof event.text === 'string' ? event.text : '';
502
+ const tool = typeof event.tool === 'string' ? event.tool : '';
503
+ const status = typeof event.status === 'string' ? event.status : '';
504
+ const path = typeof event.path === 'string' ? event.path : '';
505
+ const op = typeof event.operation === 'string' ? event.operation : '';
506
+ switch (role) {
507
+ case 'user':
508
+ return clip(text, 480);
509
+ case 'model':
510
+ return clip(text, 800);
511
+ case 'tool': {
512
+ if (event.type === 'tool_call')
513
+ return `tool_call ${tool || '?'}`;
514
+ if (event.type === 'tool_result')
515
+ return `tool_result ${tool || '?'} ${status}`.trim();
516
+ if (event.type === 'file_mutation')
517
+ return `file_mutation ${op} ${path}`.trim();
518
+ return `tool ${tool}`;
519
+ }
520
+ }
521
+ }
522
+ function clip(text, max) {
523
+ const oneLine = text.replace(/\s+/g, ' ').trim();
524
+ if (oneLine.length <= max)
525
+ return oneLine;
526
+ return `${oneLine.slice(0, max - 1)}…`;
527
+ }
528
+ function formatTurn(turn) {
529
+ return `[${turn.index + 1}] ${turn.role}: ${turn.summary}`;
530
+ }
531
+ function matchSectionHeader(line) {
532
+ const lower = line.toLowerCase();
533
+ if (/^satisfied\b/.test(lower))
534
+ return 'satisfied';
535
+ if (/^outstanding\b/.test(lower))
536
+ return 'outstanding';
537
+ return null;
538
+ }
539
+ function stripHeaderPrefix(line) {
540
+ const colon = line.indexOf(':');
541
+ if (colon === -1)
542
+ return '';
543
+ return line.slice(colon + 1).trim();
544
+ }
545
+ function matchBulleted(line) {
546
+ const match = /^(?:[-*•]|\d+\.)\s+(.*)$/u.exec(line);
547
+ return match === null ? null : (match[1] ?? '').trim();
548
+ }
549
+ function pushItem(item, section, satisfied, outstanding) {
550
+ if (item.length === 0)
551
+ return;
552
+ if (section === 'satisfied')
553
+ satisfied.push(item);
554
+ else if (section === 'outstanding')
555
+ outstanding.push(item);
556
+ }
557
+ //# sourceMappingURL=session-review.js.map