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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/LICENSE +1 -1
  3. package/README.md +53 -11
  4. package/THIRD_PARTY_NOTICES.md +40 -0
  5. package/assets/pugi-mascot.ansi +15 -40
  6. package/assets/pugi-prozr2-mascot.ansi +9 -0
  7. package/bin/run.js +33 -1
  8. package/dist/commands/deploy.js +40 -40
  9. package/dist/commands/flatten.js +191 -0
  10. package/dist/commands/jobs-watch.js +201 -0
  11. package/dist/commands/jobs.js +42 -27
  12. package/dist/commands/retro.js +210 -0
  13. package/dist/commands/smoke.js +133 -0
  14. package/dist/core/agent-progress/cleanup.js +134 -0
  15. package/dist/core/agent-progress/schema.js +144 -0
  16. package/dist/core/agent-progress/writer.js +101 -0
  17. package/dist/core/agents/adaptive-router.js +330 -0
  18. package/dist/core/agents/query-decomposer.js +297 -0
  19. package/dist/core/agents/registry.js +3 -3
  20. package/dist/core/approvals/shortcut-resolver.js +98 -0
  21. package/dist/core/artifact-chain/dispatcher.js +148 -0
  22. package/dist/core/artifact-chain/exporter.js +164 -0
  23. package/dist/core/artifact-chain/state.js +243 -0
  24. package/dist/core/artifact-chain/steps.js +169 -0
  25. package/dist/core/ask-user/question.js +92 -0
  26. package/dist/core/audit/audit-trail.js +275 -0
  27. package/dist/core/auth/ensure-authenticated.js +129 -0
  28. package/dist/core/auth/env-provider.js +238 -0
  29. package/dist/core/auto-open-browser.js +4 -4
  30. package/dist/core/auto-update/channels.js +122 -0
  31. package/dist/core/auto-update/checker.js +241 -0
  32. package/dist/core/auto-update/state.js +235 -0
  33. package/dist/core/bare-mode/index.js +107 -0
  34. package/dist/core/bash/redirect.js +281 -0
  35. package/dist/core/bash-classifier.js +436 -40
  36. package/dist/core/checkpoint/resumer.js +149 -0
  37. package/dist/core/checkpoint/rewinder.js +291 -0
  38. package/dist/core/checkpoints/shadow-git.js +670 -0
  39. package/dist/core/citations/parser.js +109 -0
  40. package/dist/core/classifier/yolo-classifier.js +88 -0
  41. package/dist/core/codegraph/db.js +506 -0
  42. package/dist/core/codegraph/decision-store.js +248 -0
  43. package/dist/core/codegraph/detect-repo.js +459 -0
  44. package/dist/core/codegraph/install.js +134 -0
  45. package/dist/core/codegraph/offer-hook.js +220 -0
  46. package/dist/core/codegraph/parser.js +71 -0
  47. package/dist/core/codegraph/types.js +34 -0
  48. package/dist/core/compact/auto-trigger.js +96 -0
  49. package/dist/core/compact/buffer-rewriter.js +115 -0
  50. package/dist/core/compact/summarizer.js +208 -0
  51. package/dist/core/compact/token-counter.js +108 -0
  52. package/dist/core/consensus/anvil-fanout.js +25 -25
  53. package/dist/core/consensus/diff-capture.js +121 -12
  54. package/dist/core/consensus/rubric.js +21 -21
  55. package/dist/core/context/builder.js +6 -6
  56. package/dist/core/context/compaction-events.js +8 -8
  57. package/dist/core/context/compaction.js +31 -31
  58. package/dist/core/context/index.js +15 -8
  59. package/dist/core/context/invariants.js +51 -51
  60. package/dist/core/context/markdown-loader.js +28 -10
  61. package/dist/core/context/markdown-traverse.js +255 -0
  62. package/dist/core/context/pugiignore.js +41 -41
  63. package/dist/core/context/repo-skeleton.js +37 -37
  64. package/dist/core/context/tool-eviction.js +55 -0
  65. package/dist/core/context/watcher.js +32 -32
  66. package/dist/core/context/working-set.js +23 -23
  67. package/dist/core/coordinator/agent-tools.js +77 -0
  68. package/dist/core/coordinator/agent-toolset.js +65 -0
  69. package/dist/core/coordinator/fsm.js +73 -0
  70. package/dist/core/coordinator/mode-fsm.js +70 -0
  71. package/dist/core/cost/rate-card.js +129 -0
  72. package/dist/core/cost/tracker.js +221 -0
  73. package/dist/core/credentials.js +13 -13
  74. package/dist/core/cron/scheduler.js +138 -0
  75. package/dist/core/denial-tracking/index.js +8 -0
  76. package/dist/core/denial-tracking/state.js +264 -0
  77. package/dist/core/diagnostics/probe-runner.js +93 -0
  78. package/dist/core/diagnostics/probes/api.js +46 -0
  79. package/dist/core/diagnostics/probes/auth.js +93 -0
  80. package/dist/core/diagnostics/probes/bare-mode.js +42 -0
  81. package/dist/core/diagnostics/probes/cli-version.js +127 -0
  82. package/dist/core/diagnostics/probes/config.js +72 -0
  83. package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
  84. package/dist/core/diagnostics/probes/disk.js +81 -0
  85. package/dist/core/diagnostics/probes/engine-live.js +46 -0
  86. package/dist/core/diagnostics/probes/git.js +65 -0
  87. package/dist/core/diagnostics/probes/hooks.js +118 -0
  88. package/dist/core/diagnostics/probes/mcp.js +75 -0
  89. package/dist/core/diagnostics/probes/node.js +59 -0
  90. package/dist/core/diagnostics/probes/pnpm.js +36 -0
  91. package/dist/core/diagnostics/probes/pugi-md.js +89 -0
  92. package/dist/core/diagnostics/probes/sandbox.js +72 -0
  93. package/dist/core/diagnostics/probes/session.js +74 -0
  94. package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
  95. package/dist/core/diagnostics/probes/workspace.js +63 -0
  96. package/dist/core/diagnostics/types.js +70 -0
  97. package/dist/core/dispatch/cache-cleanup.js +197 -0
  98. package/dist/core/dispatch/cache-handoff.js +295 -0
  99. package/dist/core/edits/apply-patch-layer-e.js +189 -0
  100. package/dist/core/edits/dispatch.js +333 -7
  101. package/dist/core/edits/format-detector.js +260 -0
  102. package/dist/core/edits/format-matrix.js +26 -0
  103. package/dist/core/edits/fuzzy-ladder.js +650 -0
  104. package/dist/core/edits/index.js +5 -1
  105. package/dist/core/edits/journal.js +199 -0
  106. package/dist/core/edits/layer-a-apply.js +15 -15
  107. package/dist/core/edits/layer-a-fuzzy-apply.js +198 -0
  108. package/dist/core/edits/layer-b-apply.js +9 -9
  109. package/dist/core/edits/layer-c-apply.js +6 -6
  110. package/dist/core/edits/layer-d-ast.js +557 -14
  111. package/dist/core/edits/marker-parser.js +12 -12
  112. package/dist/core/edits/security-gate.js +27 -27
  113. package/dist/core/edits/verify-hook.js +273 -0
  114. package/dist/core/edits/worktree.js +322 -0
  115. package/dist/core/engine/anvil-client.js +214 -26
  116. package/dist/core/engine/auto-compact.js +247 -0
  117. package/dist/core/engine/budgets.js +220 -0
  118. package/dist/core/engine/compact-llm-summarizer.js +124 -0
  119. package/dist/core/engine/context-prefix.js +155 -0
  120. package/dist/core/engine/index.js +1 -1
  121. package/dist/core/engine/intensity.js +163 -0
  122. package/dist/core/engine/intent.js +260 -0
  123. package/dist/core/engine/native-pugi.js +1559 -227
  124. package/dist/core/engine/prompts.js +192 -16
  125. package/dist/core/engine/strip-internal-fields.js +124 -0
  126. package/dist/core/engine/tool-bridge.js +1887 -59
  127. package/dist/core/engine/verification-patterns.js +195 -0
  128. package/dist/core/evaluation/golden-dataset.js +293 -0
  129. package/dist/core/feedback/queue.js +177 -0
  130. package/dist/core/feedback/submitter.js +145 -0
  131. package/dist/core/file-cache.js +113 -1
  132. package/dist/core/flatten/flatten-repo.js +439 -0
  133. package/dist/core/format/osc8-link.js +28 -0
  134. package/dist/core/hook-chains.js +392 -0
  135. package/dist/core/hooks/citation-verify-hook.js +138 -0
  136. package/dist/core/hooks/citation-verify.js +112 -0
  137. package/dist/core/hooks/events.js +46 -0
  138. package/dist/core/hooks/index.js +15 -0
  139. package/dist/core/hooks/registry.js +216 -0
  140. package/dist/core/hooks/runner.js +236 -0
  141. package/dist/core/hooks/v2/event-emitter.js +115 -0
  142. package/dist/core/hooks/v2/executor.js +282 -0
  143. package/dist/core/hooks/v2/index.js +25 -0
  144. package/dist/core/hooks/v2/lifecycle.js +104 -0
  145. package/dist/core/hooks/v2/loader.js +216 -0
  146. package/dist/core/hooks/v2/matcher.js +125 -0
  147. package/dist/core/hooks/v2/trust.js +143 -0
  148. package/dist/core/hooks/v2/types.js +86 -0
  149. package/dist/core/hooks/worktree-events.js +158 -0
  150. package/dist/core/image/renderer.js +71 -0
  151. package/dist/core/init/detector.js +582 -0
  152. package/dist/core/init/template-renderer.js +242 -0
  153. package/dist/core/jobs/registry.js +18 -18
  154. package/dist/core/ledger/results-tsv.js +142 -0
  155. package/dist/core/log-discipline/stdout-redirect.js +51 -0
  156. package/dist/core/lsp/cache.js +105 -0
  157. package/dist/core/lsp/client.js +1229 -0
  158. package/dist/core/lsp/language-detect.js +66 -0
  159. package/dist/core/lsp/post-edit-diagnostics.js +171 -0
  160. package/dist/core/lsp/server-detect.js +173 -0
  161. package/dist/core/lsp/symbol-cache.js +162 -0
  162. package/dist/core/lsp/symbol-tools.js +664 -0
  163. package/dist/core/mcp/client.js +97 -28
  164. package/dist/core/mcp/http-server.js +553 -0
  165. package/dist/core/mcp/orchestrator-config.js +192 -0
  166. package/dist/core/mcp/orchestrator-tools.js +806 -0
  167. package/dist/core/mcp/permission.js +190 -0
  168. package/dist/core/mcp/registry.js +39 -17
  169. package/dist/core/mcp/server-tools.js +219 -0
  170. package/dist/core/mcp/server.js +397 -0
  171. package/dist/core/mcp/trust.js +10 -10
  172. package/dist/core/memory/dual-write.js +416 -0
  173. package/dist/core/memory/passive-extract.js +130 -0
  174. package/dist/core/memory/phase1-kinds.js +20 -0
  175. package/dist/core/memory/secret-scanner.js +304 -0
  176. package/dist/core/memory-sync/queue.js +170 -0
  177. package/dist/core/metrics/extract.js +113 -0
  178. package/dist/core/modes/roo-modes.js +68 -0
  179. package/dist/core/notes/notes-paths.js +113 -0
  180. package/dist/core/notes/notes-recorder.js +140 -0
  181. package/dist/core/notes/notes-writer.js +53 -0
  182. package/dist/core/notes/renderers.js +0 -0
  183. package/dist/core/notes/slug.js +105 -0
  184. package/dist/core/onboarding/ensure-initialized.js +133 -0
  185. package/dist/core/onboarding/marker.js +111 -0
  186. package/dist/core/onboarding/telemetry-state.js +108 -0
  187. package/dist/core/output-style/presets.js +176 -0
  188. package/dist/core/output-style/state.js +185 -0
  189. package/dist/core/path-security.js +287 -5
  190. package/dist/core/permission.js +82 -22
  191. package/dist/core/permissions/auto-classifier.js +124 -0
  192. package/dist/core/permissions/bash-parser.js +371 -0
  193. package/dist/core/permissions/circuit-breaker.js +83 -0
  194. package/dist/core/permissions/constrained-edit.js +91 -0
  195. package/dist/core/permissions/gate.js +278 -0
  196. package/dist/core/permissions/index.js +20 -0
  197. package/dist/core/permissions/mode.js +174 -0
  198. package/dist/core/permissions/network-egress.js +137 -0
  199. package/dist/core/permissions/state.js +241 -0
  200. package/dist/core/permissions/tool-class.js +107 -0
  201. package/dist/core/plan-mode/ui-state.js +51 -0
  202. package/dist/core/plans/plan-artifact.js +721 -0
  203. package/dist/core/policy-limits/etag-store.js +122 -0
  204. package/dist/core/prd-check/parser.js +215 -0
  205. package/dist/core/prd-check/reporter.js +127 -0
  206. package/dist/core/prd-check/session-review.js +557 -0
  207. package/dist/core/prd-check/verifiers.js +223 -0
  208. package/dist/core/prompt-cache/client-cache.js +99 -0
  209. package/dist/core/prompts/assembly.js +29 -0
  210. package/dist/core/prompts/registry.js +364 -0
  211. package/dist/core/pugi-gitignore.js +52 -0
  212. package/dist/core/pugi-md/cc-compat-rules.js +735 -0
  213. package/dist/core/pugi-md/context-injector.js +76 -0
  214. package/dist/core/pugi-md/walk-up.js +207 -0
  215. package/dist/core/python/uv-installer.js +270 -0
  216. package/dist/core/python/uv-resolver.js +83 -0
  217. package/dist/core/rate-limit/narrator.js +146 -0
  218. package/dist/core/recipes/cli-types.js +20 -0
  219. package/dist/core/recipes/loader.js +103 -0
  220. package/dist/core/recipes/runner.js +345 -0
  221. package/dist/core/recipes/schema.js +587 -0
  222. package/dist/core/release-notes/parser.js +241 -0
  223. package/dist/core/release-notes/state.js +116 -0
  224. package/dist/core/repl/ask.js +37 -37
  225. package/dist/core/repl/cancellation.js +26 -26
  226. package/dist/core/repl/cap-warning.js +4 -4
  227. package/dist/core/repl/clipboard-read.js +11 -11
  228. package/dist/core/repl/dispatch-fsm.js +12 -12
  229. package/dist/core/repl/engine-bridge.js +303 -0
  230. package/dist/core/repl/history-search.js +15 -15
  231. package/dist/core/repl/history.js +28 -18
  232. package/dist/core/repl/kill-ring.js +5 -5
  233. package/dist/core/repl/model-pricing.js +135 -0
  234. package/dist/core/repl/privacy-banner.js +22 -22
  235. package/dist/core/repl/session.js +2714 -228
  236. package/dist/core/repl/slash-commands.js +572 -40
  237. package/dist/core/repl/store/index.js +1 -1
  238. package/dist/core/repl/store/jsonl-log.js +22 -22
  239. package/dist/core/repl/store/lockfile.js +10 -10
  240. package/dist/core/repl/store/session-store.js +136 -107
  241. package/dist/core/repl/store/types.js +15 -15
  242. package/dist/core/repl/store/uuid-v7.js +12 -12
  243. package/dist/core/repl/tool-route.js +382 -0
  244. package/dist/core/repl/workspace-context.js +43 -21
  245. package/dist/core/repo-map/build.js +125 -0
  246. package/dist/core/repo-map/cache.js +185 -0
  247. package/dist/core/repo-map/extractor.js +254 -0
  248. package/dist/core/repo-map/formatter.js +145 -0
  249. package/dist/core/repo-map/page-rank.js +105 -0
  250. package/dist/core/repo-map/scanner.js +211 -0
  251. package/dist/core/retro/git-collector.js +251 -0
  252. package/dist/core/retro/health-card.js +25 -0
  253. package/dist/core/retro/metrics.js +342 -0
  254. package/dist/core/retro/narrative.js +249 -0
  255. package/dist/core/retro/plane-collector.js +274 -0
  256. package/dist/core/retro/pr-issue-link.js +65 -0
  257. package/dist/core/retro/types.js +16 -0
  258. package/dist/core/retry-budget/budget.js +284 -0
  259. package/dist/core/retry-budget/index.js +5 -0
  260. package/dist/core/retry-budget/retry-cap.js +74 -0
  261. package/dist/core/routing/lead-worker.js +43 -0
  262. package/dist/core/routing/pre-flight-estimator.js +108 -0
  263. package/dist/core/runs/run-tree.js +103 -0
  264. package/dist/core/sandboxing/adapter.js +29 -0
  265. package/dist/core/sandboxing/index.js +49 -0
  266. package/dist/core/sandboxing/none.js +19 -0
  267. package/dist/core/sandboxing/seatbelt.js +183 -0
  268. package/dist/core/security/injection-scanner.js +367 -0
  269. package/dist/core/security/output-filter.js +418 -0
  270. package/dist/core/session/env-file.js +105 -0
  271. package/dist/core/session/section-budgets.js +140 -0
  272. package/dist/core/session.js +119 -0
  273. package/dist/core/settings.js +378 -5
  274. package/dist/core/share/formatter.js +271 -0
  275. package/dist/core/share/redactor.js +221 -0
  276. package/dist/core/share/uploader.js +267 -0
  277. package/dist/core/skills/defaults.js +457 -0
  278. package/dist/core/skills/loader.js +22 -22
  279. package/dist/core/skills/sources.js +27 -27
  280. package/dist/core/smoke/headless-driver.js +174 -0
  281. package/dist/core/smoke/orchestrator.js +194 -0
  282. package/dist/core/smoke/runner.js +238 -0
  283. package/dist/core/smoke/scenario-parser.js +316 -0
  284. package/dist/core/statusline.js +99 -0
  285. package/dist/core/subagents/dispatcher-real.js +600 -0
  286. package/dist/core/subagents/dispatcher.js +146 -52
  287. package/dist/core/subagents/index.js +19 -6
  288. package/dist/core/subagents/isolation-matrix.js +213 -0
  289. package/dist/core/subagents/spawn.js +19 -4
  290. package/dist/core/telemetry/emitter.js +229 -0
  291. package/dist/core/telemetry/queue.js +251 -0
  292. package/dist/core/theme/context.js +91 -0
  293. package/dist/core/theme/presets.js +228 -0
  294. package/dist/core/theme/state.js +181 -0
  295. package/dist/core/todos/invariant.js +10 -0
  296. package/dist/core/todos/state.js +177 -0
  297. package/dist/core/tool-schema/compressor.js +89 -0
  298. package/dist/core/transport/version-interceptor.js +166 -0
  299. package/dist/core/trust.js +2 -2
  300. package/dist/core/tui/thinking-block.js +64 -0
  301. package/dist/core/vim/keymap.js +288 -0
  302. package/dist/core/vim/state.js +92 -0
  303. package/dist/core/watch-markers/marker-watcher.js +133 -0
  304. package/dist/core/worktree/include-parser.js +249 -0
  305. package/dist/core/worktree-manager/cleanup.js +123 -0
  306. package/dist/core/worktree-manager/manager.js +303 -0
  307. package/dist/index.js +36 -0
  308. package/dist/runtime/bootstrap.js +190 -0
  309. package/dist/runtime/cli.js +4536 -477
  310. package/dist/runtime/commands/agents.js +31 -31
  311. package/dist/runtime/commands/budget.js +5 -5
  312. package/dist/runtime/commands/cancel.js +231 -0
  313. package/dist/runtime/commands/chain.js +489 -0
  314. package/dist/runtime/commands/codegraph-status.js +227 -0
  315. package/dist/runtime/commands/compact.js +297 -0
  316. package/dist/runtime/commands/config.js +74 -40
  317. package/dist/runtime/commands/cost.js +199 -0
  318. package/dist/runtime/commands/delegate.js +312 -0
  319. package/dist/runtime/commands/dispatch.js +126 -0
  320. package/dist/runtime/commands/doctor.js +579 -0
  321. package/dist/runtime/commands/feedback.js +184 -0
  322. package/dist/runtime/commands/hooks.js +187 -0
  323. package/dist/runtime/commands/index-cmd.js +353 -0
  324. package/dist/runtime/commands/init.js +254 -0
  325. package/dist/runtime/commands/lsp.js +368 -0
  326. package/dist/runtime/commands/mcp.js +935 -0
  327. package/dist/runtime/commands/memory.js +582 -0
  328. package/dist/runtime/commands/model.js +237 -0
  329. package/dist/runtime/commands/onboarding.js +275 -0
  330. package/dist/runtime/commands/patch.js +128 -0
  331. package/dist/runtime/commands/permissions.js +112 -0
  332. package/dist/runtime/commands/plan.js +143 -0
  333. package/dist/runtime/commands/prd-check.js +285 -0
  334. package/dist/runtime/commands/privacy.js +17 -17
  335. package/dist/runtime/commands/recipe.js +325 -0
  336. package/dist/runtime/commands/redo-blob-store.js +92 -0
  337. package/dist/runtime/commands/redo.js +361 -0
  338. package/dist/runtime/commands/release-notes.js +229 -0
  339. package/dist/runtime/commands/repo-map.js +95 -0
  340. package/dist/runtime/commands/report.js +299 -0
  341. package/dist/runtime/commands/resume.js +118 -0
  342. package/dist/runtime/commands/review-consensus.js +68 -53
  343. package/dist/runtime/commands/rewind.js +333 -0
  344. package/dist/runtime/commands/roster.js +117 -0
  345. package/dist/runtime/commands/servers.js +236 -0
  346. package/dist/runtime/commands/sessions.js +163 -0
  347. package/dist/runtime/commands/share.js +316 -0
  348. package/dist/runtime/commands/skills.js +31 -31
  349. package/dist/runtime/commands/status.js +186 -0
  350. package/dist/runtime/commands/stickers.js +82 -0
  351. package/dist/runtime/commands/style.js +194 -0
  352. package/dist/runtime/commands/theme.js +196 -0
  353. package/dist/runtime/commands/undo.js +54 -22
  354. package/dist/runtime/commands/update.js +289 -0
  355. package/dist/runtime/commands/vim.js +140 -0
  356. package/dist/runtime/commands/worktree.js +177 -0
  357. package/dist/runtime/commands/worktrees.js +155 -0
  358. package/dist/runtime/deprecation-warning.js +69 -0
  359. package/dist/runtime/engine-exit-code.js +50 -0
  360. package/dist/runtime/headless-repl.js +195 -0
  361. package/dist/runtime/headless.js +548 -0
  362. package/dist/runtime/load-hooks-or-exit.js +71 -0
  363. package/dist/runtime/plan-decompose.js +531 -0
  364. package/dist/runtime/sigint-guard.js +272 -0
  365. package/dist/runtime/stream-renderer.js +195 -0
  366. package/dist/runtime/update-check.js +28 -28
  367. package/dist/runtime/version.js +65 -0
  368. package/dist/runtime/worktree-bootstrap.js +579 -0
  369. package/dist/skills/bundled/batch.js +617 -0
  370. package/dist/skills/bundled/index.js +45 -0
  371. package/dist/skills/bundled/loop.js +358 -0
  372. package/dist/skills/bundled/remember.js +383 -0
  373. package/dist/skills/bundled/simplify.js +289 -0
  374. package/dist/skills/bundled/skillify.js +373 -0
  375. package/dist/skills/bundled/stuck.js +558 -0
  376. package/dist/skills/bundled/verify.js +439 -0
  377. package/dist/testing/vcr.js +486 -0
  378. package/dist/tools/agent-tool.js +229 -0
  379. package/dist/tools/apply-patch.js +556 -0
  380. package/dist/tools/ask-user-question.js +337 -0
  381. package/dist/tools/ask-user.js +115 -0
  382. package/dist/tools/bash.js +624 -46
  383. package/dist/tools/brief.js +224 -0
  384. package/dist/tools/cron.js +433 -0
  385. package/dist/tools/enter-worktree.js +250 -0
  386. package/dist/tools/exit-worktree.js +147 -0
  387. package/dist/tools/file-tools.js +161 -44
  388. package/dist/tools/http-request.js +336 -0
  389. package/dist/tools/lsp-tools.js +565 -0
  390. package/dist/tools/mcp-tool.js +260 -0
  391. package/dist/tools/multi-edit.js +361 -0
  392. package/dist/tools/powershell.js +268 -0
  393. package/dist/tools/registry.js +142 -1
  394. package/dist/tools/server-tools.js +892 -0
  395. package/dist/tools/skill-tool.js +96 -0
  396. package/dist/tools/sleep.js +99 -0
  397. package/dist/tools/synthetic-output.js +133 -0
  398. package/dist/tools/tasks.js +208 -0
  399. package/dist/tools/todo-write.js +184 -0
  400. package/dist/tools/verify-plan-execution.js +295 -0
  401. package/dist/tools/web-fetch-injection-scanner.js +207 -0
  402. package/dist/tools/web-fetch.js +195 -10
  403. package/dist/tools/web-search.js +458 -0
  404. package/dist/tui/agent-progress-card.js +111 -0
  405. package/dist/tui/agent-tree.js +22 -1
  406. package/dist/tui/ask-modal.js +14 -14
  407. package/dist/tui/ask-user-question-chips.js +315 -0
  408. package/dist/tui/ask-user-question-prompt.js +203 -0
  409. package/dist/tui/compact-banner.js +81 -0
  410. package/dist/tui/conversation-pane.js +85 -11
  411. package/dist/tui/cost-table.js +111 -0
  412. package/dist/tui/device-flow.js +2 -2
  413. package/dist/tui/doctor-table.js +46 -0
  414. package/dist/tui/feedback-prompt.js +156 -0
  415. package/dist/tui/input-box.js +247 -32
  416. package/dist/tui/login-picker.js +3 -3
  417. package/dist/tui/markdown-render.js +6 -6
  418. package/dist/tui/multi-file-diff-approval.js +375 -0
  419. package/dist/tui/onboarding-wizard.js +240 -0
  420. package/dist/tui/permissions-picker.js +86 -0
  421. package/dist/tui/render.js +36 -1
  422. package/dist/tui/repl-render.js +405 -32
  423. package/dist/tui/repl-splash-art.js +16 -16
  424. package/dist/tui/repl-splash-mascot.js +48 -24
  425. package/dist/tui/repl-splash.js +22 -22
  426. package/dist/tui/repl.js +136 -43
  427. package/dist/tui/slash-palette.js +6 -6
  428. package/dist/tui/splash.js +2 -2
  429. package/dist/tui/status-bar.js +109 -31
  430. package/dist/tui/status-table.js +7 -0
  431. package/dist/tui/stickers-art.js +136 -0
  432. package/dist/tui/style-table.js +28 -0
  433. package/dist/tui/theme-table.js +29 -0
  434. package/dist/tui/thinking-spinner.js +123 -0
  435. package/dist/tui/tool-stream-pane.js +53 -4
  436. package/dist/tui/update-banner.js +27 -2
  437. package/dist/tui/vim-input.js +267 -0
  438. package/dist/tui/welcome-banner.js +107 -0
  439. package/dist/tui/welcome-data.js +293 -0
  440. package/dist/tui/workspace-context.js +2 -2
  441. package/docs/examples/codegraph.mcp.json +10 -0
  442. package/package.json +25 -7
  443. package/test/scenarios/codegen-create-file.scenario.txt +13 -0
  444. package/test/scenarios/compact-force.scenario.txt +12 -0
  445. package/test/scenarios/identity.scenario.txt +11 -0
  446. package/test/scenarios/persona-handoff.scenario.txt +12 -0
  447. package/test/scenarios/walkback.scenario.txt +12 -0
  448. package/dist/core/engine/compaction-hook.js +0 -154
@@ -1,14 +1,14 @@
1
1
  /**
2
- * Chafa-validated brand-pug ANSI loader (α6.14.4 wave 6, mascot regen).
2
+ * Chafa-validated brand-pug ANSI loader .
3
3
  *
4
- * CEO dogfood 2026-05-25 (first pass, α6.14.2 wave 5): the hand-crafted
4
+ * CEO dogfood (first pass, wave 5): the hand-crafted
5
5
  * 9-row ASCII pug in `repl-splash-art.ts` reads as "точно не похожа" —
6
6
  * too abstract to carry the brand at boot. This module loads a pre-baked
7
7
  * truecolor ANSI render of the canonical hero-pug PNG (cyber-zoo pug
8
8
  * face with cyan eyes + circuit + chip) so the splash matches the brand
9
9
  * glyph the operator already sees on pugi.io.
10
10
  *
11
- * CEO dogfood 2026-05-25 (α6.14.4): the first chafa bake at 32x16 still
11
+ * CEO dogfood : the first chafa bake at 32x16 still
12
12
  * read as "monitor on stand", not pug — too few rows to resolve the
13
13
  * snout / eyes / wrinkles. The vertical resolution was the bottleneck:
14
14
  * 16 char rows ≈ 16 pixel rows with the block symbol set. The fresh
@@ -21,9 +21,9 @@
21
21
  * gates at 100KB so we stay well under cap.
22
22
  *
23
23
  * Generation (operator-side, one-shot):
24
- * chafa --size 80x40 --symbols=vhalf --colors=full \
25
- * apps/clawhost-web/public/brand/hero-pug.png \
26
- * > apps/pugi-cli/assets/pugi-mascot.ansi
24
+ * chafa --size 80x40 --symbols=vhalf --colors=full \
25
+ * apps/console-web/public/brand/hero-pug.png \
26
+ * > apps/pugi-cli/assets/pugi-mascot.ansi
27
27
  *
28
28
  * The output is committed verbatim to the repo and shipped inside the
29
29
  * `@pugi/cli` npm tarball under `assets/pugi-mascot.ansi` (the
@@ -33,7 +33,7 @@
33
33
  * corruption, dev cwd drift), the splash falls back to the hand-crafted
34
34
  * `PUG_MASCOT` art so the boot never crashes.
35
35
  *
36
- * The pre-Ink write convention mirrors the Claude Code Chrome plugin
36
+ * The pre-Ink write convention mirrors the the upstream tool Chrome plugin
37
37
  * splash pattern: raw bytes go to `process.stdout` BEFORE the Ink
38
38
  * render mount, so the terminal interprets the truecolor escapes
39
39
  * directly instead of Ink trying to layout-engine over them.
@@ -48,9 +48,21 @@ import { fileURLToPath } from 'node:url';
48
48
  * — two directory hops up from this file. In a local `pnpm dev`
49
49
  * checkout the structure is the same (`src/tui/` ⇒ `../../assets/`)
50
50
  * because tsx re-resolves the same relative tree.
51
+ *
52
+ * CEO P0 #2 — banner mascot bake. The prozr2 portrait is
53
+ * the canonical brand-pug glyph from `apps/console-web/public/brand/
54
+ * Pugi-prozr2.png`, baked к а 16x8 vhalf truecolor render. We prefer
55
+ * the prozr2 bake when it ships alongside the CLI (small — ~900 bytes,
56
+ * shaped for the compact welcome-banner left column) and fall back к
57
+ * the legacy 40KB `pugi-mascot.ansi` (hero-pug 80x40) when prozr2 is
58
+ * missing — preserves the splash-mascot install surface for any
59
+ * tarball that predates the bake.
51
60
  */
52
61
  export function pugMascotAssetPath() {
53
62
  const here = dirname(fileURLToPath(import.meta.url));
63
+ const prozr2 = resolvePath(here, '..', '..', 'assets', 'pugi-prozr2-mascot.ansi');
64
+ if (existsSync(prozr2))
65
+ return prozr2;
54
66
  return resolvePath(here, '..', '..', 'assets', 'pugi-mascot.ansi');
55
67
  }
56
68
  /**
@@ -83,27 +95,39 @@ export function loadPugMascotAnsi() {
83
95
  if (!raw || raw.length === 0)
84
96
  return null;
85
97
  // 1. Drop OSC sequences. Two terminator forms:
86
- // ESC ] ... BEL (0x1b 0x5d ... 0x07)
87
- // ESC ] ... ESC \ (0x1b 0x5d ... 0x1b 0x5c, the ST form)
88
- // A truecolor splash never needs OSC (those are for window title,
89
- // icon, clipboard, hyperlinks, color-palette change). Drop them
90
- // so a corrupted asset cannot rename the operator's terminal tab
91
- // or smuggle a hyperlink into the splash region.
92
- // 2. Drop CSI ? <mode> [hl] for mouse-tracking and screen-buffer
93
- // switch modes (1000, 1001, 1002, 1003, 1004, 1005, 1006, 1015,
94
- // 1049, 47, 1047, 1048). These would either start swallowing
95
- // mouse input or flip the terminal into the alternate screen.
98
+ // ESC ] ... BEL (0x1b 0x5d ... 0x07)
99
+ // ESC ] ... ESC \ (0x1b 0x5d ... 0x1b 0x5c, the ST form)
100
+ // A truecolor splash never needs OSC (those are for window title,
101
+ // icon, clipboard, hyperlinks, color-palette change). Drop them
102
+ // so a corrupted asset cannot rename the operator's terminal tab
103
+ // or smuggle a hyperlink into the splash region.
104
+ // 2. Drop ALL CSI ? <numbers and semicolons> [lh] (DEC private-mode
105
+ // set / reset). The legitimate chafa output for a splash is
106
+ // truecolor SGR (`CSI 38;2;R;G;B m`) plus cursor-positioning
107
+ // no private-mode toggle ever appears там legitimately. A
108
+ // permissive deny-all pattern covers every disruptive private
109
+ // mode in one regex:
110
+ // - cursor visibility (25)
111
+ // - alt-screen buffer (47, 1047, 1048, 1049)
112
+ // - mouse tracking (1000, 1001, 1002, 1003, 1004, 1005, 1006, 1015)
113
+ // - bracketed paste (2004)
114
+ // - focus reporting (1004)
115
+ // - multi-mode forms (e.g. `CSI ? 47 ; 1049 h` — legal per
116
+ // xterm ctlseqs but missed by the previous single-mode regex)
117
+ // - any future private mode a corrupt asset might emit
118
+ // Allowlisting the modes the splash needs is impossible because
119
+ // the splash needs ZERO of them — chafa renders glyph-by-glyph,
120
+ // not via private-mode toggles. A pure deny-all is strictly
121
+ // safer than enumerating known-bad modes one-by-one.
96
122
  // 3. Drop CSI 6 n (cursor-position report). Would inject a fake
97
- // CPR into the operator's stdin stream.
123
+ // CPR into the operator's stdin stream.
98
124
  // 4. Drop CSI [23]J / CSI [23]K (full screen / line clear). A
99
- // chafa render uses cursor-positioning per row, not bulk
100
- // erases; bulk clears would wipe whatever the operator already
101
- // had on screen above the splash.
102
- // The cursor-hide/show wrappers (CSI ? 25 [lh]) are handled by
103
- // the same CSI-?-mode pattern as the mouse / alt-screen modes.
125
+ // chafa render uses cursor-positioning per row, not bulk
126
+ // erases; bulk clears would wipe whatever the operator already
127
+ // had on screen above the splash.
104
128
  const stripped = raw
105
129
  .replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, '')
106
- .replace(/\x1b\[\?(?:25|47|1000|1001|1002|1003|1004|1005|1006|1015|1047|1048|1049)[lh]/g, '')
130
+ .replace(/\x1b\[\?[0-9;]+[lh]/g, '')
107
131
  .replace(/\x1b\[6n/g, '')
108
132
  .replace(/\x1b\[[23]?[JK]/g, '');
109
133
  if (stripped.trim().length === 0)
@@ -1,30 +1,30 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
- * REPL boot splash (α6.14 wave 3).
3
+ * REPL boot splash .
4
4
  *
5
5
  * Rendered on REPL first paint — before the conversation pane, before
6
- * any operator input lands. Mirrors the Claude Code / Codex / Gemini
6
+ * any operator input lands. Mirrors the the upstream tool / Codex / Gemini
7
7
  * CLI boot-screen aesthetic while staying Pugi-brand-pure:
8
8
  *
9
- * [PUG ASCII] Pugi.io v0.1.0-alphaN
10
- * Plan: <plan>
11
- * Model: <model>
12
- * Tenant: <customerId>
13
- * Workspace: <basename>
9
+ * [PUG ASCII] Pugi.io v0.1.0-alphaN
10
+ * Plan: <plan>
11
+ * Model: <model>
12
+ * Tenant: <customerId>
13
+ * Workspace: <basename>
14
14
  *
15
- * ─────────────────────────────────────
16
- * Tips for getting started:
17
- * 1. Type a brief, the workforce dispatches
18
- * 2. /help for slash commands, /web <url> to pull a page
19
- * 3. /skills install <name> for Anthropic / OpenClaw skills
15
+ * ─────────────────────────────────────
16
+ * Tips for getting started:
17
+ * 1. Type a brief, the workforce dispatches
18
+ * 2. /help for slash commands, /web <url> to pull a page
19
+ * 3. /skills install <name> for Anthropic / OpenClaw skills
20
20
  *
21
21
  * The splash auto-dismisses on:
22
- * - first operator keystroke (the REPL `<Repl />` host owns this and
23
- * calls the `onInteract` callback we expose),
24
- * - 10s idle timeout (built-in, configurable via `skipSplash`),
25
- * - `--no-splash` CLI flag or PUGI_SKIP_SPLASH=1 env (host gates the
26
- * mount entirely; we still respect the `skipSplash` prop as a belt
27
- * so a stray render in a test environment produces nothing).
22
+ * - first operator keystroke (the REPL `<Repl />` host owns this and
23
+ * calls the `onInteract` callback we expose),
24
+ * - 10s idle timeout (built-in, configurable via `skipSplash`),
25
+ * - `--no-splash` CLI flag or PUGI_SKIP_SPLASH=1 env (host gates the
26
+ * mount entirely; we still respect the `skipSplash` prop as a belt
27
+ * so a stray render in a test environment produces nothing).
28
28
  *
29
29
  * Brand voice gate: every visible string here is reviewed against the
30
30
  * forbidden list (`journey / explore / delight / magical / friendly /
@@ -61,13 +61,13 @@ export function ReplSplash(props) {
61
61
  if (props.skipSplash) {
62
62
  return null;
63
63
  }
64
- // α6.14.2 wave 5: when the host pre-printed the chafa-baked brand-pug
64
+ // wave 5: when the host pre-printed the chafa-baked brand-pug
65
65
  // ANSI render to stdout before Ink mounted, suppress the hand-crafted
66
66
  // PUG_MASCOT column here so the operator does not see two stacked
67
67
  // pugs. The header card still renders inline so wordmark + status
68
68
  // rows stay attached to the splash flow.
69
69
  const showHandCraftedMascot = props.mascotPrePrinted !== true;
70
- return (_jsxs(Box, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [_jsxs(Box, { flexDirection: "row", children: [showHandCraftedMascot ? _jsx(MascotColumn, {}) : null, _jsxs(Box, { flexDirection: "column", marginLeft: showHandCraftedMascot ? 2 : 0, marginTop: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Pugi" }), _jsx(Text, { bold: true, color: "cyan", children: ".io" }), _jsx(Text, { dimColor: true, children: ` v${props.cliVersion}` })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(HeaderRow, { label: "Plan", value: props.plan ?? PLACEHOLDER }), _jsx(HeaderRow, { label: "Model", value: props.model ?? PLACEHOLDER }), _jsx(HeaderRow, { label: "Tenant", value: props.tenant ?? PLACEHOLDER }), _jsx(HeaderRow, { label: "Workspace", value: props.workspaceLabel })] })] })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: '─'.repeat(40) }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "Tips for getting started:" }), _jsx(TipRow, { index: 1, text: "Type a brief, the workforce dispatches" }), _jsx(TipRow, { index: 2, text: "/help for slash commands, /web <url> to pull a page" }), _jsx(TipRow, { index: 3, text: "/skills install <name> for Anthropic / OpenClaw skills" })] })] }));
70
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [_jsxs(Box, { flexDirection: "row", children: [showHandCraftedMascot ? _jsx(MascotColumn, {}) : null, _jsxs(Box, { flexDirection: "column", marginLeft: showHandCraftedMascot ? 2 : 0, marginTop: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Pugi" }), _jsx(Text, { bold: true, color: "#3da9fc", children: ".io" }), _jsx(Text, { dimColor: true, children: ` v${props.cliVersion}` })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(HeaderRow, { label: "Plan", value: props.plan ?? PLACEHOLDER }), _jsx(HeaderRow, { label: "Model", value: props.model ?? PLACEHOLDER }), _jsx(HeaderRow, { label: "Tenant", value: props.tenant ?? PLACEHOLDER }), _jsx(HeaderRow, { label: "Workspace", value: props.workspaceLabel })] })] })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: '─'.repeat(40) }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "Tips for getting started:" }), _jsx(TipRow, { index: 1, text: "Type a brief, the workforce dispatches" }), _jsx(TipRow, { index: 2, text: "/help for slash commands, /web <url> to pull a page" }), _jsx(TipRow, { index: 3, text: "/skills install <name> for Anthropic / OpenClaw skills" })] })] }));
71
71
  }
72
72
  /**
73
73
  * Renders the multi-line ASCII pug. Each row is split into colored
@@ -105,13 +105,13 @@ function MascotRow({ row, mask, }) {
105
105
  if (buffer.length > 0) {
106
106
  runs.push({ text: buffer, cyan: bufferCyan });
107
107
  }
108
- return (_jsx(Text, { children: runs.map((run, runIndex) => run.cyan ? (_jsx(Text, { color: "cyan", children: run.text }, runIndex)) : (_jsx(Text, { color: "gray", children: run.text }, runIndex))) }));
108
+ return (_jsx(Text, { children: runs.map((run, runIndex) => run.cyan ? (_jsx(Text, { color: "#3da9fc", children: run.text }, runIndex)) : (_jsx(Text, { color: "gray", children: run.text }, runIndex))) }));
109
109
  }
110
110
  function HeaderRow({ label, value }) {
111
111
  const padded = `${label}:`.padEnd(11, ' ');
112
112
  return (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: padded }), _jsx(Text, { children: value })] }));
113
113
  }
114
114
  function TipRow({ index, text }) {
115
- return (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ` ${index}. ` }), _jsx(Text, { children: text })] }));
115
+ return (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ` ${index}. ` }), _jsx(Text, { children: text })] }));
116
116
  }
117
117
  //# sourceMappingURL=repl-splash.js.map
package/dist/tui/repl.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  /**
3
- * REPL root component - Sprint α5.7 (ADR-0056 PR-PUGI-CLI-REPL-DEFAULT).
3
+ * REPL root component - Sprint .
4
4
  *
5
5
  * Three-zone layout:
6
6
  *
7
- * header - `Pugi.io · workspace: <name> · v<X> on watch`
8
- * main - conversation pane (top half) + agent tree (bottom half)
9
- * footer - input box + status bar + key hints
7
+ * header - `Pugi.io · workspace: <name> · v<X> on watch`
8
+ * main - conversation pane (top half) + agent tree (bottom half)
9
+ * footer - input box + status bar + key hints
10
10
  *
11
11
  * The component subscribes to a ReplSession instance for state. It does
12
12
  * NOT own the SSE client or the transport - the session module does.
@@ -26,14 +26,17 @@ import { ConversationPane } from './conversation-pane.js';
26
26
  import { InputBox } from './input-box.js';
27
27
  import { ReplSplash } from './repl-splash.js';
28
28
  import { StatusBar } from './status-bar.js';
29
+ import { ThinkingSpinner } from './thinking-spinner.js';
29
30
  import { ToolStreamPane } from './tool-stream-pane.js';
30
31
  import { UpdateBanner } from './update-banner.js';
32
+ import { WelcomeBanner } from './welcome-banner.js';
31
33
  import { collectWorkspaceContext } from './workspace-context.js';
34
+ import { useTheme } from '../core/theme/context.js';
32
35
  import { slugForCwd } from '../core/repl/history.js';
33
36
  import { SLASH_COMMAND_HELP, SLASH_COMMAND_GROUPS } from '../core/repl/slash-commands.js';
34
37
  const TICK_INTERVAL_MS = 200;
35
38
  const PULSE_INTERVAL_MS = 700;
36
- // α6.12: maximum transcript rows the conversation pane renders at once.
39
+ // : maximum transcript rows the conversation pane renders at once.
37
40
  // Older rows scroll off the top; full history stays in session state.
38
41
  const CONVERSATION_WINDOW = 12;
39
42
  export function Repl(props) {
@@ -41,17 +44,28 @@ export function Repl(props) {
41
44
  const [overlay, setOverlay] = useState('none');
42
45
  const [pulsePhase, setPulsePhase] = useState(0);
43
46
  const [tickNow, setTickNow] = useState((props.now ?? Date.now)());
44
- // α6.12: operator-driven collapse for the tool stream pane. The CLI
47
+ // : operator-driven collapse for the tool stream pane. The CLI
45
48
  // host can hide the pane entirely via `--no-tool-stream`; this state
46
49
  // is the runtime toggle (Ctrl+T) for operators who want the pane on
47
50
  // screen but folded to a single row while they read a long reply.
48
51
  const [toolStreamCollapsed, setToolStreamCollapsed] = useState(false);
49
- // α6.14 wave 3: boot splash visible until first input, first
52
+ // wave 3: boot splash visible until first input, first
50
53
  // `agent.spawned` event, or 10s idle. The host gates the initial
51
54
  // visibility on `--no-splash` / PUGI_SKIP_SPLASH via `skipSplash`.
52
- const [splashVisible, setSplashVisible] = useState(props.skipSplash !== true);
55
+ // CEO dogfood: default splash to HIDDEN at boot
56
+ // (parity with the upstream tool's minimal one-line banner). Operator can
57
+ // opt back in via `/splash` slash. The chafa pug pre-print + header
58
+ // line already give the brand cue without the multi-row Plan/Model/
59
+ // Tenant block crowding the top.
60
+ const [splashVisible, setSplashVisible] = useState(false);
53
61
  const dismissSplash = useCallback(() => setSplashVisible(false), []);
54
- // α6.14 wave 3: workspace context snapshot for the status bar. We
62
+ // CEO P0 #2 : welcome banner. Visible from boot
63
+ // until the operator submits the first brief OR the session emits
64
+ // its first agent event. The host owns dismissal lifecycle (kept
65
+ // symmetric with the splash) so the welcome card never lingers
66
+ // behind а live transcript.
67
+ const [welcomeVisible, setWelcomeVisible] = useState(Boolean(props.welcomeData));
68
+ // wave 3: workspace context snapshot for the status bar. We
55
69
  // read once at mount and freeze; a brand-new PUGI.md or skill is
56
70
  // surfaced on the next REPL boot rather than via a watcher.
57
71
  const workspaceContext = useMemo(() => props.workspaceContext ?? collectWorkspaceContext(process.cwd()), [props.workspaceContext]);
@@ -83,9 +97,9 @@ export function Repl(props) {
83
97
  useEffect(() => {
84
98
  props.onOverlayChange?.(overlay);
85
99
  }, [overlay, props]);
86
- // α6.14 wave 3: dismiss the boot splash once the first agent spawns
100
+ // wave 3: dismiss the boot splash once the first agent spawns
87
101
  // (the operator has clearly engaged the system) or the transcript
88
- // gains a row. Mirrors the natural attention shift Claude Code /
102
+ // gains a row. Mirrors the natural attention shift the upstream tool /
89
103
  // Codex / Gemini CLI all do on their boot screens.
90
104
  useEffect(() => {
91
105
  if (!splashVisible)
@@ -94,6 +108,20 @@ export function Repl(props) {
94
108
  setSplashVisible(false);
95
109
  }
96
110
  }, [splashVisible, state.agents.length, state.transcript.length]);
111
+ // CEO P0 #2 v2: welcome banner stays until the operator
112
+ // actively engages the loop — first agent spawn. Boot-time auto-init
113
+ // emits system rows into `state.transcript` (skip-trust hints, dirty
114
+ // tree warnings) which used к dismiss the banner within ~2s, hiding
115
+ // the brand mascot before the operator could read it. Drop the
116
+ // `transcript.length` trigger; agent spawn (= real dispatch) remains
117
+ // the sole signal that the operator stopped reading the banner.
118
+ useEffect(() => {
119
+ if (!welcomeVisible)
120
+ return;
121
+ if (state.agents.length > 0) {
122
+ setWelcomeVisible(false);
123
+ }
124
+ }, [welcomeVisible, state.agents.length]);
97
125
  const personaNames = useMemo(() => buildPersonaNameMap(), []);
98
126
  const { exit } = useApp();
99
127
  const handleSubmit = useCallback((line) => {
@@ -101,6 +129,10 @@ export function Repl(props) {
101
129
  // `setSplashVisible(false)` is a no-op once the state already
102
130
  // settled to false (timer fired or `agent.spawned` arrived).
103
131
  setSplashVisible(false);
132
+ // CEO P0 #2 : same dismissal for the welcome banner
133
+ // — the operator engaging the input box is the cleanest signal
134
+ // they have finished reading the boot card.
135
+ setWelcomeVisible(false);
104
136
  // Run async without awaiting - the session module owns the
105
137
  // network call, errors land in the transcript automatically.
106
138
  void props.session.handleInput(line).then((verdict) => {
@@ -132,7 +164,7 @@ export function Repl(props) {
132
164
  setOverlay('none');
133
165
  }
134
166
  }, { isActive: overlay === 'help' || overlay === 'roster' });
135
- // α6.12: Ctrl+T toggles the tool stream pane between expanded and
167
+ // : Ctrl+T toggles the tool stream pane between expanded and
136
168
  // collapsed states. Active only while no overlay is open, so the
137
169
  // toggle never fights the help/roster dismiss handler. The input box
138
170
  // owns its own raw-input mode, so this listener only fires on the
@@ -142,7 +174,7 @@ export function Repl(props) {
142
174
  setToolStreamCollapsed((prev) => !prev);
143
175
  }
144
176
  }, { isActive: overlay === 'none' && props.hideToolStream !== true });
145
- // α6.3 office-hours: a pending ask or plan-review modal pauses input
177
+ // office-hours: a pending ask or plan-review modal pauses input
146
178
  // until the operator resolves it. The modal owns its own useInput
147
179
  // hook, so the InputBox unmounts while a modal is open to avoid two
148
180
  // raw-input listeners competing for the same keystroke. Resolution
@@ -156,59 +188,118 @@ export function Repl(props) {
156
188
  const handlePlanReviewResolve = useCallback((result) => {
157
189
  void props.session.resolvePlanReview(result);
158
190
  }, [props.session]);
159
- // α6.9: Ctrl+C abort handler. Forwards to ReplSession.cancel() which
191
+ // : Ctrl+C abort handler. Forwards to ReplSession.cancel() which
160
192
  // aborts the in-flight dispatch, closes the SSE stream, and surfaces
161
193
  // "Aborted." in the transcript.
162
194
  //
163
195
  // Return contract (consumed by InputBox):
164
- // - true - dispatch was cancelled (keep the buffer + DO arm
165
- // the press-again-to-exit timer; second Ctrl+C in
166
- // the window exits).
167
- // - false - idle / nothing to cancel (legacy: clear buffer +
168
- // arm the exit timer so the operator sees the hint
169
- // and can confirm exit on the next press).
170
- // - undefined - bypassed entirely (e.g. a modal owns the input).
171
- // InputBox MUST NOT arm the exit timer and MUST
172
- // NOT clear the buffer. P2 fix: previously this
173
- // returned `false` and the buffer-clear path wiped
174
- // the operator's mid-typed modal text on the first
175
- // Ctrl+C, costing a press of work.
196
+ // - true - dispatch was cancelled (keep the buffer + DO arm
197
+ // the press-again-to-exit timer; second Ctrl+C in
198
+ // the window exits).
199
+ // - false - idle / nothing to cancel (legacy: clear buffer +
200
+ // arm the exit timer so the operator sees the hint
201
+ // and can confirm exit on the next press).
202
+ // - undefined - bypassed entirely (e.g. a modal owns the input).
203
+ // InputBox MUST NOT arm the exit timer and MUST
204
+ // NOT clear the buffer. P2 fix: previously this
205
+ // returned `false` and the buffer-clear path wiped
206
+ // the operator's mid-typed modal text on the first
207
+ // Ctrl+C, costing a press of work.
176
208
  const handleCancel = useCallback(() => {
177
209
  if (modalActive)
178
210
  return undefined;
179
211
  return props.session.cancel();
180
212
  }, [props.session, modalActive]);
181
- return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [props.updateBanner ? _jsx(UpdateBanner, { result: props.updateBanner }) : null, splashVisible ? (_jsx(ReplSplash, { cliVersion: state.cliVersion, workspaceLabel: state.workspaceLabel, plan: props.splashPlan, model: props.splashModel, tenant: props.splashTenant, onDismiss: dismissSplash, mascotPrePrinted: props.mascotPrePrinted === true })) : null, _jsx(Header, { state: state }), _jsx(Box, { flexDirection: "column", marginTop: 1, children: overlay === 'help' ? (_jsx(HelpOverlay, {})) : overlay === 'roster' ? (_jsx(RosterOverlay, {})) : overlay === 'farewell' ? (_jsx(FarewellOverlay, {})) : (_jsx(MainArea, { state: state, personaNames: personaNames, nowEpochMs: tickNow, hideToolStream: props.hideToolStream === true, toolStreamCollapsed: toolStreamCollapsed })) }), state.pendingAsk ? (_jsx(Box, { marginTop: 1, children: _jsx(AskModal, { tag: state.pendingAsk, onResolve: handleAskResolve }) })) : null, state.pendingPlanReview ? (_jsx(Box, { marginTop: 1, children: _jsx(PlanReviewModal, { tag: state.pendingPlanReview, onResolve: handlePlanReviewResolve }) })) : null, _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [overlay === 'farewell' || modalActive ? null : (_jsx(InputBox, { onSubmit: handleSubmit, onExit: handleExit, onCancel: handleCancel, now: props.now,
213
+ // BT 8 (the upstream tool parity): Esc-Esc walkback. Forwards to
214
+ // ReplSession.walkbackLastTurn which trims the trailing operator
215
+ // turn + its persona response from the in-memory transcript. Returns
216
+ // `'walked-back'` so the input box knows the host did the work;
217
+ // `'nothing'` covers both the empty-transcript and dispatch-in-flight
218
+ // refusals (the session module owns the refusal copy in both cases).
219
+ const handleWalkback = useCallback(() => {
220
+ if (modalActive)
221
+ return 'nothing';
222
+ const verdict = props.session.walkbackLastTurn();
223
+ return verdict === 'walked-back' ? 'walked-back' : 'nothing';
224
+ }, [props.session, modalActive]);
225
+ // — Shift+Tab cycles the 6 canonical permission modes (CC
226
+ // parity). Refuses while a modal is active so the operator does not
227
+ // accidentally flip mode mid-prompt; otherwise resolves the current
228
+ // mode through the workspace > global > default merge, advances via
229
+ // `nextPermissionMode`, и persists к .pugi/session.json. Returns the
230
+ // new mode string so the InputBox can flash a one-line toast.
231
+ const handleCyclePermissionMode = useCallback(() => {
232
+ if (modalActive)
233
+ return null;
234
+ try {
235
+ // Lazy-require так this code path doesn't drag the permissions
236
+ // module into the splash + boot stages where it isn't needed.
237
+ // The require is sync but the inner work is pure JSON IO.
238
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
239
+ const perm = require('../core/permissions/index.js');
240
+ const workspaceRoot = process.cwd();
241
+ const current = perm.resolveMode({ workspaceRoot });
242
+ const next = perm.nextPermissionMode(current);
243
+ perm.setCurrentMode(workspaceRoot, next);
244
+ return next;
245
+ }
246
+ catch {
247
+ // Persistence is best-effort — if .pugi/session.json is read-only
248
+ // или ENOENT-on-parent the toast is suppressed so we don't lie
249
+ // about the flip к the operator.
250
+ return null;
251
+ }
252
+ }, [modalActive]);
253
+ // CEO dogfood (parity with the upstream tool): input
254
+ // box pinned to alt-screen BOTTOM, conversation grows above it.
255
+ // Beta.3's height={rows} fix broke keystroke focus - raw echo at
256
+ // viewport bottom. The right pattern is minHeight on the root +
257
+ // flexGrow=1 on the MainArea Box: empty alt-screen lives ABOVE the
258
+ // input, and the input stays the sole focusable surface adjacent
259
+ // to the cursor row, so all keystrokes route through it.
260
+ const altScreenRows = process.stdout.rows ?? 24;
261
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 1, minHeight: altScreenRows, children: [welcomeVisible && props.welcomeData ? (_jsx(WelcomeBanner, { data: props.welcomeData, mascotPrePrinted: props.mascotPrePrinted === true, autoInitStatus: props.autoInitStatus ?? null })) : null, splashVisible ? (_jsx(ReplSplash, { cliVersion: state.cliVersion, workspaceLabel: state.workspaceLabel, plan: props.splashPlan, model: props.splashModel, tenant: props.splashTenant, onDismiss: dismissSplash, mascotPrePrinted: props.mascotPrePrinted === true })) : null, _jsx(Header, { state: state }), _jsx(Box, { flexDirection: "column", marginTop: 1, flexGrow: 1, justifyContent: "flex-end", children: overlay === 'help' ? (_jsx(HelpOverlay, {})) : overlay === 'roster' ? (_jsx(RosterOverlay, {})) : overlay === 'farewell' ? (_jsx(FarewellOverlay, {})) : (_jsx(MainArea, { state: state, personaNames: personaNames, nowEpochMs: tickNow, hideToolStream: props.hideToolStream === true, toolStreamCollapsed: toolStreamCollapsed })) }), state.pendingAsk ? (_jsx(Box, { marginTop: 1, children: _jsx(AskModal, { tag: state.pendingAsk, onResolve: handleAskResolve }) })) : null, state.pendingPlanReview ? (_jsx(Box, { marginTop: 1, children: _jsx(PlanReviewModal, { tag: state.pendingPlanReview, onResolve: handlePlanReviewResolve }) })) : null, _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [overlay === 'farewell' || modalActive ? null : (_jsx(InputBox, { onSubmit: handleSubmit, onExit: handleExit, onCancel: handleCancel, onWalkback: handleWalkback, onCyclePermissionMode: handleCyclePermissionMode, now: props.now,
182
262
  // Slug from process.cwd() (full path) so two workspaces with
183
263
  // the same basename do not share history. state.workspaceLabel
184
264
  // is the basename only. Codex review P2.
185
- workspaceSlug: slugForCwd(process.cwd()) })), _jsx(StatusBar, { connection: state.connection, activeAgentCount: countActive(state), tokensDownstreamTotal: state.tokensDownstreamTotal, briefStartedAtEpochMs: state.briefStartedAtEpochMs, nowEpochMs: tickNow, pulsePhase: pulsePhase, pugiMdCount: workspaceContext.pugiMdCount, mcpServerCount: workspaceContext.mcpServerCount, skillCount: workspaceContext.skillCount, quotaPct: props.quotaPct, dispatchState: state.dispatchState, dispatchToolLabel: state.dispatchToolLabel })] })] }));
265
+ workspaceSlug: slugForCwd(process.cwd()) })), _jsx(ThinkingSpinner, { dispatchState: state.dispatchState, dispatchToolLabel: state.dispatchToolLabel }), _jsx(StatusBar, { connection: state.connection, activeAgentCount: countActive(state), tokensDownstreamTotal: state.tokensDownstreamTotal, briefStartedAtEpochMs: state.briefStartedAtEpochMs, nowEpochMs: tickNow, pulsePhase: pulsePhase, pugiMdCount: workspaceContext.pugiMdCount, mcpServerCount: workspaceContext.mcpServerCount, skillCount: workspaceContext.skillCount, quotaPct: props.quotaPct, dispatchState: state.dispatchState, dispatchToolLabel: state.dispatchToolLabel, lastCompletedOutcome: state.lastCompletedOutcome,
266
+ // cost-meter sprint — surface accumulated session totals
267
+ // + per-turn delta flash on the status bar's top row. The
268
+ // session module owns accumulation; the bar is a pure render.
269
+ sessionTokensIn: state.sessionTokensIn, sessionTokensOut: state.sessionTokensOut, sessionCostUsd: state.sessionCostUsd, sessionStartedAtEpochMs: state.sessionStartedAtEpochMs, lastTurnDelta: state.lastTurnDelta }), props.updateBanner ? _jsx(UpdateBanner, { result: props.updateBanner }) : null] })] }));
186
270
  }
187
271
  function Header({ state }) {
188
- return (_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Pugi" }), _jsx(Text, { bold: true, color: "cyan", children: ".io" }), _jsx(Text, { dimColor: true, children: ` · workspace: ${state.workspaceLabel} · v${state.cliVersion} · ` }), _jsx(Text, { color: "cyan", children: state.connection === 'on_watch' ? 'on watch' : state.connection.replace('_', ' ') })] }));
272
+ // the header `.io` brand accent + connection
273
+ // pill route through `useTheme()` so the operator's `/theme` flip
274
+ // (default / dark / light / colorblind) re-tints the chrome on
275
+ // re-mount. The `useTheme` hook returns the `default` preset's
276
+ // colors when no provider is mounted, preserving the previous
277
+ // `#3da9fc` constants for tests that import `<Repl />` standalone.
278
+ const theme = useTheme();
279
+ return (_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Pugi" }), _jsx(Text, { bold: true, color: theme.accent, children: ".io" }), _jsx(Text, { dimColor: true, children: ` · workspace: ${state.workspaceLabel} · v${state.cliVersion} · ` }), _jsx(Text, { color: theme.accent, children: state.connection === 'on_watch' ? 'on watch' : state.connection.replace('_', ' ') })] }));
189
280
  }
190
281
  function MainArea({ state, personaNames, nowEpochMs, hideToolStream, toolStreamCollapsed, }) {
191
- // α6.12: three vertical panes stacked above the input box.
282
+ // : three vertical panes stacked above the input box.
192
283
  //
193
- // 1. Conversation pane (top) - transcript with Markdown render.
194
- // 2. Tool stream pane (mid) - live Read/Edit/Bash/Grep lines.
195
- // Hidden when `--no-tool-stream` is
196
- // set; collapsed via Ctrl+T while
197
- // the pane is visible.
198
- // 3. Agent tree pane (bottom) - Cyber-Zoo roster with persona /
199
- // status / duration / token counts.
284
+ // 1. Conversation pane (top) - transcript with Markdown render.
285
+ // 2. Tool stream pane (mid) - live Read/Edit/Bash/Grep lines.
286
+ // Hidden when `--no-tool-stream` is
287
+ // set; collapsed via Ctrl+T while
288
+ // the pane is visible.
289
+ // 3. Agent tree pane (bottom) - Cyber-Zoo roster with persona /
290
+ // status / duration / token counts.
200
291
  //
201
292
  // The window over the transcript is small (last 12 rows) so the
202
293
  // bottom of the frame stays anchored to the input box. New agents
203
- // push the operator line up the screen, mirroring Claude Code /
204
- // Codex CLI / Gemini CLI rendering.
294
+ // push the operator line up the screen, mirroring the upstream tool /
295
+ // peer CLI / Gemini CLI rendering.
205
296
  const conversationSlice = state.transcript.slice(-CONVERSATION_WINDOW);
206
297
  return (_jsxs(Box, { flexDirection: "column", children: [_jsx(ConversationPane, { rows: conversationSlice, personaNames: personaNames }), hideToolStream ? null : (_jsx(Box, { marginTop: 1, children: _jsx(ToolStreamPane, { calls: state.toolCalls, collapsed: toolStreamCollapsed }) })), _jsx(Box, { marginTop: 1, children: _jsx(AgentTreePane, { agents: state.agents, nowEpochMs: nowEpochMs }) })] }));
207
298
  }
208
299
  function HelpOverlay() {
209
300
  // Group commands by their `group` field so the operator scans the
210
301
  // palette by intent (dispatch → session → tools → settings → meta).
211
- // The α6.14 wave-2 expansion grew the surface from 6 to 20 commands;
302
+ // The wave-2 expansion grew the surface from 6 to 20 commands;
212
303
  // a flat list would force the operator to read 20 rows top-to-bottom
213
304
  // every time. Grouping cuts perceived complexity dramatically.
214
305
  const grouped = new Map();
@@ -225,14 +316,14 @@ function HelpOverlay() {
225
316
  const rows = grouped.get(group);
226
317
  if (!rows || rows.length === 0)
227
318
  return null;
228
- return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { dimColor: true, children: ` -- ${group} --` }), rows.map((row) => (_jsxs(Box, { children: [_jsx(Text, { bold: true, color: "cyan", children: ` /${row.name} ${row.args}`.padEnd(22, ' ') }), _jsx(Text, { dimColor: true, children: row.gloss })] }, row.name)))] }, group));
319
+ return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { dimColor: true, children: ` -- ${group} --` }), rows.map((row) => (_jsxs(Box, { children: [_jsx(Text, { bold: true, color: "#3da9fc", children: ` /${row.name} ${row.args}`.padEnd(22, ' ') }), _jsx(Text, { dimColor: true, children: row.gloss })] }, row.name)))] }, group));
229
320
  }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: `${PUGI_TAGLINE}` }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: 'Press any key to dismiss.' }) })] }));
230
321
  }
231
322
  function RosterOverlay() {
232
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "On-watch roster" }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: THE_TEN.map((persona) => (_jsxs(Box, { children: [_jsx(Text, { bold: true, children: ` ${persona.name.padEnd(10, ' ')}` }), _jsx(Text, { dimColor: true, children: `${persona.role.padEnd(20, ' ')}` }), _jsx(Text, { children: persona.oneLiner })] }, persona.slug))) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: 'Press any key to dismiss.' }) })] }));
323
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "On-watch roster" }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: THE_TEN.map((persona) => (_jsxs(Box, { children: [_jsx(Text, { bold: true, children: ` ${persona.name.padEnd(10, ' ')}` }), _jsx(Text, { dimColor: true, children: `${persona.role.padEnd(20, ' ')}` }), _jsx(Text, { children: persona.oneLiner })] }, persona.slug))) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: 'Press any key to dismiss.' }) })] }));
233
324
  }
234
325
  function FarewellOverlay() {
235
- return (_jsx(Box, { flexDirection: "column", alignItems: "center", paddingY: 2, children: _jsx(Text, { bold: true, color: "cyan", children: PUGI_TAGLINE }) }));
326
+ return (_jsx(Box, { flexDirection: "column", alignItems: "center", paddingY: 2, children: _jsx(Text, { bold: true, color: "#3da9fc", children: PUGI_TAGLINE }) }));
236
327
  }
237
328
  function applyVerdictSideEffects(verdict, handlers) {
238
329
  switch (verdict.kind) {
@@ -257,8 +348,10 @@ function applyVerdictSideEffects(verdict, handlers) {
257
348
  case 'consensus':
258
349
  case 'diff':
259
350
  case 'cost':
351
+ case 'quota':
260
352
  case 'status':
261
353
  case 'resume':
354
+ case 'mcp':
262
355
  case 'stub':
263
356
  // All non-overlay verdicts: the session module already appended
264
357
  // any operator-visible system lines (and, for `ask`, set
@@ -7,7 +7,7 @@ export const PALETTE_ROW_LIMIT = 8;
7
7
  * Centralises the "starts-with-slash → filter SLASH_COMMAND_HELP"
8
8
  * logic so the input box and the unit test agree on the shape.
9
9
  *
10
- * Wave 4 fix 2026-05-25: returns the FULL filtered set, not just the
10
+ * fix: returns the FULL filtered set, not just the
11
11
  * first PALETTE_ROW_LIMIT rows. The palette renderer now windows the
12
12
  * visible slice internally based on `focusedIndex`, so the operator
13
13
  * can scroll past row 7 via ↑/↓ on a long list (e.g. 20 commands when
@@ -15,9 +15,9 @@ export const PALETTE_ROW_LIMIT = 8;
15
15
  * shape for backward compatibility but always equals `rows.length`.
16
16
  *
17
17
  * Behaviour:
18
- * - Empty / non-slash buffer → empty result; palette stays hidden.
19
- * - `/` alone → all registry rows (the operator wants to browse).
20
- * - `/he` → rows whose name starts with `he` (case-insensitive).
18
+ * - Empty / non-slash buffer → empty result; palette stays hidden.
19
+ * - `/` alone → all registry rows (the operator wants to browse).
20
+ * - `/he` → rows whose name starts with `he` (case-insensitive).
21
21
  */
22
22
  export function filterPalette(buffer) {
23
23
  if (!buffer.startsWith('/')) {
@@ -86,7 +86,7 @@ export function completePalette(buffer, rows, focusedIndex) {
86
86
  export function SlashPalette(props) {
87
87
  if (props.rows.length === 0)
88
88
  return null;
89
- // Wave 4 fix 2026-05-25: compute the visible window so the operator
89
+ // fix: compute the visible window so the operator
90
90
  // can scroll past row 7 on long lists. Focus indexes the full rows
91
91
  // array; the window slides to keep the focused row visible.
92
92
  const window = computePaletteWindow(props.rows, props.focusedIndex);
@@ -101,6 +101,6 @@ export function SlashPalette(props) {
101
101
  const glyph = focused ? '▸' : '·';
102
102
  const cmd = `/${row.name}${row.args ? ` ${row.args}` : ''}`.padEnd(22, ' ');
103
103
  return (_jsxs(Box, { children: [_jsx(Text, { color: focused ? 'cyan' : 'gray', children: `${glyph} ` }), _jsx(Text, { bold: focused, color: focused ? 'cyan' : undefined, dimColor: !focused, children: cmd }), _jsx(Text, { dimColor: true, children: row.gloss })] }, row.name));
104
- }), overflow ? (_jsx(Box, { children: _jsx(Text, { dimColor: true, children: ` → ${focusedDisplayIndex}/${window.total}` }) })) : null, _jsx(Box, { children: _jsx(Text, { dimColor: true, children: ' ↑/↓ select · Tab complete · Enter run · Esc close' }) })] }));
104
+ }), overflow ? (_jsx(Box, { children: _jsx(Text, { dimColor: true, children: ` → ${focusedDisplayIndex}/${window.total}` }) })) : null, _jsx(Box, { children: _jsx(Text, { dimColor: true, children: ' ↑/↓ select · Tab complete · Enter run · Esc close' }) })] }));
105
105
  }
106
106
  //# sourceMappingURL=slash-palette.js.map
@@ -21,11 +21,11 @@ export function Splash({ data }) {
21
21
  cmd: 'pugi login',
22
22
  gloss: 'Connect this terminal to your Pugi account',
23
23
  };
24
- return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsx(Box, { children: _jsx(Text, { bold: true, color: "cyan", children: "pugi.io" }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: `v${data.cliVersion} · ${data.apiUrl}` }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Account: " }), _jsx(Text, { children: accountLine })] }), data.isAuthenticated && data.plan ? (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Plan: " }), _jsx(Text, { children: data.plan })] })) : null] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "Quick start:" }), _jsx(HintRow, { command: primaryHint.cmd, gloss: primaryHint.gloss }), data.isAuthenticated ? (_jsx(HintRow, { command: 'pugi login', gloss: 'Re-authenticate or switch accounts' })) : (_jsx(HintRow, { command: 'pugi code "fix the bug"', gloss: 'Run a one-shot coding task' })), _jsx(HintRow, { command: 'pugi review --triple', gloss: 'Run the Anvil triple-review gate' }), _jsx(HintRow, { command: 'pugi help', gloss: 'Full command reference' })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Docs: https://pugi.dev \u00B7 Status: https://pugi.io/status" }) })] }));
24
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsx(Box, { children: _jsx(Text, { bold: true, color: "#3da9fc", children: "pugi.io" }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: `v${data.cliVersion} · ${data.apiUrl}` }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Account: " }), _jsx(Text, { children: accountLine })] }), data.isAuthenticated && data.plan ? (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Plan: " }), _jsx(Text, { children: data.plan })] })) : null] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "Quick start:" }), _jsx(HintRow, { command: primaryHint.cmd, gloss: primaryHint.gloss }), data.isAuthenticated ? (_jsx(HintRow, { command: 'pugi login', gloss: 'Re-authenticate or switch accounts' })) : (_jsx(HintRow, { command: 'pugi code "fix the bug"', gloss: 'Run a one-shot coding task' })), _jsx(HintRow, { command: 'pugi review --triple', gloss: 'Run the Anvil triple-review gate' }), _jsx(HintRow, { command: 'pugi help', gloss: 'Full command reference' })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Docs: https://pugi.dev \u00B7 Status: https://pugi.io/status" }) })] }));
25
25
  }
26
26
  function HintRow({ command, gloss }) {
27
27
  // Pad command names so the gloss column lines up across rows.
28
28
  const padded = command.padEnd(28, ' ');
29
- return (_jsxs(Text, { children: [_jsx(Text, { children: ` ${padded}` }), _jsx(Text, { dimColor: true, children: gloss })] }));
29
+ return (_jsxs(Text, { children: [_jsx(Text, { children: ` ${padded}` }), _jsx(Text, { dimColor: true, children: gloss })] }));
30
30
  }
31
31
  //# sourceMappingURL=splash.js.map