@pugi/cli 0.1.0-beta.10 → 0.1.0-beta.101

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 (464) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/LICENSE +1 -1
  3. package/README.md +55 -11
  4. package/assets/pugi-prozr2-mascot.ansi +9 -0
  5. package/bin/run.js +33 -1
  6. package/dist/commands/deploy.js +40 -40
  7. package/dist/commands/flatten.js +191 -0
  8. package/dist/commands/jobs-watch.js +201 -0
  9. package/dist/commands/jobs.js +42 -27
  10. package/dist/commands/retro.js +210 -0
  11. package/dist/commands/smoke.js +133 -0
  12. package/dist/core/agent-progress/cleanup.js +134 -0
  13. package/dist/core/agent-progress/schema.js +144 -0
  14. package/dist/core/agent-progress/writer.js +101 -0
  15. package/dist/core/agents/adaptive-router.js +330 -0
  16. package/dist/core/agents/query-decomposer.js +297 -0
  17. package/dist/core/agents/registry.js +3 -3
  18. package/dist/core/approvals/shortcut-resolver.js +98 -0
  19. package/dist/core/artifact-chain/dispatcher.js +148 -0
  20. package/dist/core/artifact-chain/exporter.js +164 -0
  21. package/dist/core/artifact-chain/state.js +243 -0
  22. package/dist/core/artifact-chain/steps.js +169 -0
  23. package/dist/core/ask-user/question.js +92 -0
  24. package/dist/core/audit/audit-trail.js +275 -0
  25. package/dist/core/auth/ensure-authenticated.js +129 -0
  26. package/dist/core/auth/env-provider.js +238 -0
  27. package/dist/core/auto-open-browser.js +4 -4
  28. package/dist/core/auto-update/channels.js +122 -0
  29. package/dist/core/auto-update/checker.js +241 -0
  30. package/dist/core/auto-update/state.js +235 -0
  31. package/dist/core/bare-mode/index.js +107 -0
  32. package/dist/core/bash/redirect.js +281 -0
  33. package/dist/core/bash-classifier.js +436 -40
  34. package/dist/core/checkpoint/resumer.js +149 -0
  35. package/dist/core/checkpoint/rewinder.js +291 -0
  36. package/dist/core/checkpoints/shadow-git.js +670 -0
  37. package/dist/core/citations/parser.js +109 -0
  38. package/dist/core/classifier/yolo-classifier.js +88 -0
  39. package/dist/core/codegraph/db.js +506 -0
  40. package/dist/core/codegraph/decision-store.js +248 -0
  41. package/dist/core/codegraph/detect-repo.js +459 -0
  42. package/dist/core/codegraph/install.js +134 -0
  43. package/dist/core/codegraph/offer-hook.js +220 -0
  44. package/dist/core/codegraph/parser.js +598 -0
  45. package/dist/core/codegraph/queries/go.scm +57 -0
  46. package/dist/core/codegraph/queries/javascript.scm +56 -0
  47. package/dist/core/codegraph/queries/python.scm +55 -0
  48. package/dist/core/codegraph/queries/rust.scm +63 -0
  49. package/dist/core/codegraph/queries/typescript.scm +91 -0
  50. package/dist/core/codegraph/reindex.js +218 -0
  51. package/dist/core/codegraph/resolve-edges.js +107 -0
  52. package/dist/core/codegraph/types.js +34 -0
  53. package/dist/core/codegraph/watcher.js +440 -0
  54. package/dist/core/compact/auto-trigger.js +96 -0
  55. package/dist/core/compact/buffer-rewriter.js +115 -0
  56. package/dist/core/compact/summarizer.js +208 -0
  57. package/dist/core/compact/token-counter.js +108 -0
  58. package/dist/core/consensus/anvil-fanout.js +25 -25
  59. package/dist/core/consensus/diff-capture.js +121 -12
  60. package/dist/core/consensus/rubric.js +21 -21
  61. package/dist/core/context/builder.js +6 -6
  62. package/dist/core/context/compaction-events.js +8 -8
  63. package/dist/core/context/compaction.js +31 -31
  64. package/dist/core/context/index.js +15 -8
  65. package/dist/core/context/invariants.js +51 -51
  66. package/dist/core/context/markdown-loader.js +28 -10
  67. package/dist/core/context/markdown-traverse.js +255 -0
  68. package/dist/core/context/pugiignore.js +41 -41
  69. package/dist/core/context/repo-skeleton.js +37 -37
  70. package/dist/core/context/tool-eviction.js +55 -0
  71. package/dist/core/context/watcher.js +32 -32
  72. package/dist/core/context/working-set.js +23 -23
  73. package/dist/core/coordinator/agent-tools.js +77 -0
  74. package/dist/core/coordinator/agent-toolset.js +65 -0
  75. package/dist/core/coordinator/fsm.js +73 -0
  76. package/dist/core/coordinator/mode-fsm.js +70 -0
  77. package/dist/core/cost/rate-card.js +129 -0
  78. package/dist/core/cost/tracker.js +221 -0
  79. package/dist/core/credentials.js +13 -13
  80. package/dist/core/cron/scheduler.js +138 -0
  81. package/dist/core/denial-tracking/index.js +8 -0
  82. package/dist/core/denial-tracking/state.js +264 -0
  83. package/dist/core/diagnostics/probe-runner.js +93 -0
  84. package/dist/core/diagnostics/probes/api.js +46 -0
  85. package/dist/core/diagnostics/probes/auth.js +93 -0
  86. package/dist/core/diagnostics/probes/bare-mode.js +42 -0
  87. package/dist/core/diagnostics/probes/cli-version.js +127 -0
  88. package/dist/core/diagnostics/probes/config.js +72 -0
  89. package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
  90. package/dist/core/diagnostics/probes/disk.js +81 -0
  91. package/dist/core/diagnostics/probes/engine-live.js +46 -0
  92. package/dist/core/diagnostics/probes/git.js +65 -0
  93. package/dist/core/diagnostics/probes/hooks.js +118 -0
  94. package/dist/core/diagnostics/probes/mcp.js +75 -0
  95. package/dist/core/diagnostics/probes/node.js +59 -0
  96. package/dist/core/diagnostics/probes/pnpm.js +36 -0
  97. package/dist/core/diagnostics/probes/pugi-md.js +89 -0
  98. package/dist/core/diagnostics/probes/sandbox.js +67 -0
  99. package/dist/core/diagnostics/probes/session.js +74 -0
  100. package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
  101. package/dist/core/diagnostics/probes/workspace.js +63 -0
  102. package/dist/core/diagnostics/types.js +70 -0
  103. package/dist/core/dispatch/cache-cleanup.js +197 -0
  104. package/dist/core/dispatch/cache-handoff.js +295 -0
  105. package/dist/core/edits/apply-patch-layer-e.js +189 -0
  106. package/dist/core/edits/dispatch.js +333 -7
  107. package/dist/core/edits/format-detector.js +260 -0
  108. package/dist/core/edits/format-matrix.js +26 -0
  109. package/dist/core/edits/fuzzy-ladder.js +650 -0
  110. package/dist/core/edits/index.js +5 -1
  111. package/dist/core/edits/journal.js +199 -0
  112. package/dist/core/edits/layer-a-apply.js +15 -15
  113. package/dist/core/edits/layer-a-fuzzy-apply.js +198 -0
  114. package/dist/core/edits/layer-b-apply.js +9 -9
  115. package/dist/core/edits/layer-c-apply.js +6 -6
  116. package/dist/core/edits/layer-d-ast.js +557 -14
  117. package/dist/core/edits/marker-parser.js +12 -12
  118. package/dist/core/edits/security-gate.js +27 -27
  119. package/dist/core/edits/verify-hook.js +273 -0
  120. package/dist/core/edits/worktree.js +29 -29
  121. package/dist/core/engine/anvil-client.js +214 -26
  122. package/dist/core/engine/auto-compact.js +247 -0
  123. package/dist/core/engine/budgets.js +220 -0
  124. package/dist/core/engine/compact-llm-summarizer.js +124 -0
  125. package/dist/core/engine/context-prefix.js +155 -0
  126. package/dist/core/engine/index.js +1 -1
  127. package/dist/core/engine/intensity.js +163 -0
  128. package/dist/core/engine/intent.js +260 -0
  129. package/dist/core/engine/native-pugi.js +1559 -227
  130. package/dist/core/engine/prompts.js +219 -19
  131. package/dist/core/engine/strip-internal-fields.js +124 -0
  132. package/dist/core/engine/tool-bridge.js +1887 -59
  133. package/dist/core/engine/verification-patterns.js +195 -0
  134. package/dist/core/eval/v1/ledger.js +83 -0
  135. package/dist/core/eval/v1/runner.js +280 -0
  136. package/dist/core/eval/v1/scoring.js +68 -0
  137. package/dist/core/eval/v1/task-loader.js +191 -0
  138. package/dist/core/eval/v1/types.js +14 -0
  139. package/dist/core/eval/v1/verifier.js +176 -0
  140. package/dist/core/eval/v1/yaml-parser.js +250 -0
  141. package/dist/core/evaluation/golden-dataset.js +293 -0
  142. package/dist/core/feedback/queue.js +177 -0
  143. package/dist/core/feedback/submitter.js +145 -0
  144. package/dist/core/file-cache.js +113 -1
  145. package/dist/core/flatten/flatten-repo.js +439 -0
  146. package/dist/core/format/osc8-link.js +28 -0
  147. package/dist/core/hook-chains.js +392 -0
  148. package/dist/core/hooks/citation-verify-hook.js +138 -0
  149. package/dist/core/hooks/citation-verify.js +112 -0
  150. package/dist/core/hooks/events.js +46 -0
  151. package/dist/core/hooks/index.js +15 -0
  152. package/dist/core/hooks/registry.js +216 -0
  153. package/dist/core/hooks/runner.js +236 -0
  154. package/dist/core/hooks/v2/event-emitter.js +115 -0
  155. package/dist/core/hooks/v2/executor.js +282 -0
  156. package/dist/core/hooks/v2/index.js +25 -0
  157. package/dist/core/hooks/v2/lifecycle.js +104 -0
  158. package/dist/core/hooks/v2/loader.js +216 -0
  159. package/dist/core/hooks/v2/matcher.js +125 -0
  160. package/dist/core/hooks/v2/trust.js +143 -0
  161. package/dist/core/hooks/v2/types.js +86 -0
  162. package/dist/core/hooks/worktree-events.js +158 -0
  163. package/dist/core/image/renderer.js +71 -0
  164. package/dist/core/init/detector.js +582 -0
  165. package/dist/core/init/template-renderer.js +242 -0
  166. package/dist/core/jobs/registry.js +18 -18
  167. package/dist/core/ledger/results-tsv.js +142 -0
  168. package/dist/core/log-discipline/stdout-redirect.js +51 -0
  169. package/dist/core/lsp/cache.js +105 -0
  170. package/dist/core/lsp/client.js +551 -41
  171. package/dist/core/lsp/language-detect.js +66 -0
  172. package/dist/core/lsp/post-edit-diagnostics.js +171 -0
  173. package/dist/core/lsp/server-detect.js +173 -0
  174. package/dist/core/lsp/symbol-cache.js +162 -0
  175. package/dist/core/lsp/symbol-tools.js +664 -0
  176. package/dist/core/mcp/client.js +97 -28
  177. package/dist/core/mcp/http-server.js +553 -0
  178. package/dist/core/mcp/orchestrator-config.js +192 -0
  179. package/dist/core/mcp/orchestrator-tools.js +806 -0
  180. package/dist/core/mcp/permission.js +190 -0
  181. package/dist/core/mcp/registry.js +39 -17
  182. package/dist/core/mcp/server-tools.js +219 -0
  183. package/dist/core/mcp/server.js +397 -0
  184. package/dist/core/mcp/trust.js +10 -10
  185. package/dist/core/memory/dual-write.js +416 -0
  186. package/dist/core/memory/passive-extract.js +130 -0
  187. package/dist/core/memory/phase1-kinds.js +20 -0
  188. package/dist/core/memory/secret-scanner.js +304 -0
  189. package/dist/core/memory-sync/queue.js +170 -0
  190. package/dist/core/metrics/extract.js +113 -0
  191. package/dist/core/modes/roo-modes.js +68 -0
  192. package/dist/core/notes/notes-paths.js +113 -0
  193. package/dist/core/notes/notes-recorder.js +140 -0
  194. package/dist/core/notes/notes-writer.js +53 -0
  195. package/dist/core/notes/renderers.js +0 -0
  196. package/dist/core/notes/slug.js +105 -0
  197. package/dist/core/onboarding/ensure-initialized.js +133 -0
  198. package/dist/core/onboarding/marker.js +111 -0
  199. package/dist/core/onboarding/telemetry-state.js +108 -0
  200. package/dist/core/output-style/presets.js +176 -0
  201. package/dist/core/output-style/state.js +185 -0
  202. package/dist/core/path-security.js +287 -5
  203. package/dist/core/permission.js +82 -22
  204. package/dist/core/permissions/auto-classifier.js +124 -0
  205. package/dist/core/permissions/bash-parser.js +371 -0
  206. package/dist/core/permissions/circuit-breaker.js +83 -0
  207. package/dist/core/permissions/constrained-edit.js +91 -0
  208. package/dist/core/permissions/gate.js +278 -0
  209. package/dist/core/permissions/index.js +20 -0
  210. package/dist/core/permissions/mode.js +174 -0
  211. package/dist/core/permissions/network-egress.js +137 -0
  212. package/dist/core/permissions/state.js +241 -0
  213. package/dist/core/permissions/tool-class.js +107 -0
  214. package/dist/core/plan-mode/ui-state.js +51 -0
  215. package/dist/core/plans/plan-artifact.js +721 -0
  216. package/dist/core/policy-limits/etag-store.js +122 -0
  217. package/dist/core/prd-check/parser.js +215 -0
  218. package/dist/core/prd-check/reporter.js +127 -0
  219. package/dist/core/prd-check/session-review.js +557 -0
  220. package/dist/core/prd-check/verifiers.js +223 -0
  221. package/dist/core/prompt-cache/client-cache.js +99 -0
  222. package/dist/core/prompts/assembly.js +29 -0
  223. package/dist/core/prompts/registry.js +364 -0
  224. package/dist/core/pugi-gitignore.js +52 -0
  225. package/dist/core/pugi-md/cc-compat-rules.js +735 -0
  226. package/dist/core/pugi-md/context-injector.js +76 -0
  227. package/dist/core/pugi-md/walk-up.js +207 -0
  228. package/dist/core/python/uv-installer.js +270 -0
  229. package/dist/core/python/uv-resolver.js +83 -0
  230. package/dist/core/rate-limit/narrator.js +146 -0
  231. package/dist/core/recipes/cli-types.js +20 -0
  232. package/dist/core/recipes/loader.js +103 -0
  233. package/dist/core/recipes/runner.js +345 -0
  234. package/dist/core/recipes/schema.js +587 -0
  235. package/dist/core/release-notes/parser.js +241 -0
  236. package/dist/core/release-notes/state.js +116 -0
  237. package/dist/core/repl/ask.js +37 -37
  238. package/dist/core/repl/cancellation.js +26 -26
  239. package/dist/core/repl/cap-warning.js +4 -4
  240. package/dist/core/repl/clipboard-read.js +11 -11
  241. package/dist/core/repl/dispatch-fsm.js +12 -12
  242. package/dist/core/repl/engine-bridge.js +303 -0
  243. package/dist/core/repl/history-search.js +15 -15
  244. package/dist/core/repl/history.js +28 -18
  245. package/dist/core/repl/kill-ring.js +5 -5
  246. package/dist/core/repl/model-pricing.js +135 -0
  247. package/dist/core/repl/privacy-banner.js +22 -22
  248. package/dist/core/repl/session.js +2690 -229
  249. package/dist/core/repl/slash-commands.js +540 -41
  250. package/dist/core/repl/store/index.js +1 -1
  251. package/dist/core/repl/store/jsonl-log.js +22 -22
  252. package/dist/core/repl/store/lockfile.js +10 -10
  253. package/dist/core/repl/store/session-store.js +136 -107
  254. package/dist/core/repl/store/types.js +15 -15
  255. package/dist/core/repl/store/uuid-v7.js +12 -12
  256. package/dist/core/repl/tool-route.js +382 -0
  257. package/dist/core/repl/workspace-context.js +43 -21
  258. package/dist/core/repo-map/build.js +125 -0
  259. package/dist/core/repo-map/cache.js +185 -0
  260. package/dist/core/repo-map/extractor.js +254 -0
  261. package/dist/core/repo-map/formatter.js +145 -0
  262. package/dist/core/repo-map/page-rank.js +105 -0
  263. package/dist/core/repo-map/scanner.js +211 -0
  264. package/dist/core/retro/git-collector.js +251 -0
  265. package/dist/core/retro/health-card.js +25 -0
  266. package/dist/core/retro/metrics.js +342 -0
  267. package/dist/core/retro/narrative.js +249 -0
  268. package/dist/core/retro/plane-collector.js +274 -0
  269. package/dist/core/retro/pr-issue-link.js +65 -0
  270. package/dist/core/retro/types.js +16 -0
  271. package/dist/core/retry-budget/budget.js +284 -0
  272. package/dist/core/retry-budget/index.js +5 -0
  273. package/dist/core/retry-budget/retry-cap.js +74 -0
  274. package/dist/core/routing/lead-worker.js +43 -0
  275. package/dist/core/routing/pre-flight-estimator.js +108 -0
  276. package/dist/core/runs/run-tree.js +103 -0
  277. package/dist/core/sandboxing/adapter.js +43 -0
  278. package/dist/core/sandboxing/bubblewrap.js +209 -0
  279. package/dist/core/sandboxing/index.js +78 -0
  280. package/dist/core/sandboxing/none.js +19 -0
  281. package/dist/core/sandboxing/policy.js +97 -0
  282. package/dist/core/sandboxing/seatbelt.js +231 -0
  283. package/dist/core/security/injection-scanner.js +367 -0
  284. package/dist/core/security/output-filter.js +418 -0
  285. package/dist/core/session/env-file.js +105 -0
  286. package/dist/core/session/section-budgets.js +140 -0
  287. package/dist/core/session.js +119 -0
  288. package/dist/core/settings.js +402 -5
  289. package/dist/core/share/formatter.js +271 -0
  290. package/dist/core/share/redactor.js +221 -0
  291. package/dist/core/share/uploader.js +267 -0
  292. package/dist/core/skills/defaults.js +30 -30
  293. package/dist/core/skills/loader.js +22 -22
  294. package/dist/core/skills/sources.js +27 -27
  295. package/dist/core/smoke/headless-driver.js +174 -0
  296. package/dist/core/smoke/orchestrator.js +194 -0
  297. package/dist/core/smoke/runner.js +238 -0
  298. package/dist/core/smoke/scenario-parser.js +316 -0
  299. package/dist/core/statusline.js +99 -0
  300. package/dist/core/subagents/dispatcher-real.js +600 -0
  301. package/dist/core/subagents/dispatcher.js +146 -52
  302. package/dist/core/subagents/index.js +19 -6
  303. package/dist/core/subagents/isolation-matrix.js +213 -0
  304. package/dist/core/subagents/spawn.js +19 -4
  305. package/dist/core/telemetry/emitter.js +229 -0
  306. package/dist/core/telemetry/queue.js +251 -0
  307. package/dist/core/theme/context.js +91 -0
  308. package/dist/core/theme/presets.js +228 -0
  309. package/dist/core/theme/state.js +181 -0
  310. package/dist/core/todos/invariant.js +10 -0
  311. package/dist/core/todos/state.js +177 -0
  312. package/dist/core/tool-schema/compressor.js +89 -0
  313. package/dist/core/transport/version-interceptor.js +166 -0
  314. package/dist/core/trust.js +2 -2
  315. package/dist/core/tui/thinking-block.js +64 -0
  316. package/dist/core/vim/keymap.js +288 -0
  317. package/dist/core/vim/state.js +92 -0
  318. package/dist/core/watch-markers/marker-watcher.js +133 -0
  319. package/dist/core/worktree/include-parser.js +249 -0
  320. package/dist/core/worktree-manager/cleanup.js +123 -0
  321. package/dist/core/worktree-manager/manager.js +303 -0
  322. package/dist/index.js +36 -0
  323. package/dist/runtime/bootstrap.js +190 -0
  324. package/dist/runtime/cli.js +4403 -561
  325. package/dist/runtime/commands/agents.js +31 -31
  326. package/dist/runtime/commands/budget.js +5 -5
  327. package/dist/runtime/commands/cancel.js +231 -0
  328. package/dist/runtime/commands/chain.js +489 -0
  329. package/dist/runtime/commands/codegraph-status.js +227 -0
  330. package/dist/runtime/commands/compact.js +297 -0
  331. package/dist/runtime/commands/config.js +74 -40
  332. package/dist/runtime/commands/cost.js +199 -0
  333. package/dist/runtime/commands/delegate.js +27 -4
  334. package/dist/runtime/commands/dispatch.js +126 -0
  335. package/dist/runtime/commands/doctor.js +579 -0
  336. package/dist/runtime/commands/eval-v1.js +266 -0
  337. package/dist/runtime/commands/feedback.js +184 -0
  338. package/dist/runtime/commands/hooks.js +187 -0
  339. package/dist/runtime/commands/index-cmd.js +459 -0
  340. package/dist/runtime/commands/init.js +254 -0
  341. package/dist/runtime/commands/lsp.js +200 -38
  342. package/dist/runtime/commands/mcp.js +935 -0
  343. package/dist/runtime/commands/memory.js +582 -0
  344. package/dist/runtime/commands/model.js +237 -0
  345. package/dist/runtime/commands/onboarding.js +275 -0
  346. package/dist/runtime/commands/patch.js +12 -12
  347. package/dist/runtime/commands/permissions.js +112 -0
  348. package/dist/runtime/commands/plan.js +143 -0
  349. package/dist/runtime/commands/prd-check.js +285 -0
  350. package/dist/runtime/commands/privacy.js +17 -17
  351. package/dist/runtime/commands/recipe.js +325 -0
  352. package/dist/runtime/commands/redo-blob-store.js +92 -0
  353. package/dist/runtime/commands/redo.js +361 -0
  354. package/dist/runtime/commands/release-notes.js +229 -0
  355. package/dist/runtime/commands/repo-map.js +95 -0
  356. package/dist/runtime/commands/report.js +299 -0
  357. package/dist/runtime/commands/resume.js +118 -0
  358. package/dist/runtime/commands/review-consensus.js +68 -53
  359. package/dist/runtime/commands/rewind.js +333 -0
  360. package/dist/runtime/commands/roster.js +14 -14
  361. package/dist/runtime/commands/servers-cli.js +182 -0
  362. package/dist/runtime/commands/servers.js +236 -0
  363. package/dist/runtime/commands/sessions.js +163 -0
  364. package/dist/runtime/commands/share.js +316 -0
  365. package/dist/runtime/commands/skills.js +31 -31
  366. package/dist/runtime/commands/status.js +186 -0
  367. package/dist/runtime/commands/stickers.js +82 -0
  368. package/dist/runtime/commands/style.js +194 -0
  369. package/dist/runtime/commands/theme.js +196 -0
  370. package/dist/runtime/commands/undo.js +54 -22
  371. package/dist/runtime/commands/update.js +289 -0
  372. package/dist/runtime/commands/vim.js +140 -0
  373. package/dist/runtime/commands/worktree.js +8 -8
  374. package/dist/runtime/commands/worktrees.js +155 -0
  375. package/dist/runtime/deprecation-warning.js +69 -0
  376. package/dist/runtime/engine-exit-code.js +50 -0
  377. package/dist/runtime/headless-repl.js +195 -0
  378. package/dist/runtime/headless.js +548 -0
  379. package/dist/runtime/load-hooks-or-exit.js +71 -0
  380. package/dist/runtime/plan-decompose.js +22 -22
  381. package/dist/runtime/sigint-guard.js +272 -0
  382. package/dist/runtime/stream-renderer.js +195 -0
  383. package/dist/runtime/update-check.js +28 -28
  384. package/dist/runtime/version.js +65 -0
  385. package/dist/runtime/worktree-bootstrap.js +579 -0
  386. package/dist/skills/bundled/batch.js +617 -0
  387. package/dist/skills/bundled/index.js +45 -0
  388. package/dist/skills/bundled/loop.js +358 -0
  389. package/dist/skills/bundled/remember.js +383 -0
  390. package/dist/skills/bundled/simplify.js +289 -0
  391. package/dist/skills/bundled/skillify.js +373 -0
  392. package/dist/skills/bundled/stuck.js +558 -0
  393. package/dist/skills/bundled/verify.js +439 -0
  394. package/dist/testing/vcr.js +486 -0
  395. package/dist/tools/agent-tool.js +229 -0
  396. package/dist/tools/apply-patch.js +89 -28
  397. package/dist/tools/ask-user-question.js +337 -0
  398. package/dist/tools/ask-user.js +115 -0
  399. package/dist/tools/bash.js +811 -49
  400. package/dist/tools/brief.js +224 -0
  401. package/dist/tools/cron.js +433 -0
  402. package/dist/tools/enter-worktree.js +250 -0
  403. package/dist/tools/exit-worktree.js +147 -0
  404. package/dist/tools/file-tools.js +161 -44
  405. package/dist/tools/http-request.js +336 -0
  406. package/dist/tools/lsp-tools.js +377 -1
  407. package/dist/tools/mcp-tool.js +260 -0
  408. package/dist/tools/multi-edit.js +361 -0
  409. package/dist/tools/powershell.js +268 -0
  410. package/dist/tools/registry.js +120 -5
  411. package/dist/tools/server-tools.js +892 -0
  412. package/dist/tools/skill-tool.js +96 -0
  413. package/dist/tools/sleep.js +99 -0
  414. package/dist/tools/synthetic-output.js +133 -0
  415. package/dist/tools/tasks.js +208 -0
  416. package/dist/tools/todo-write.js +184 -0
  417. package/dist/tools/verify-plan-execution.js +295 -0
  418. package/dist/tools/web-fetch-injection-scanner.js +207 -0
  419. package/dist/tools/web-fetch.js +195 -10
  420. package/dist/tools/web-search.js +458 -0
  421. package/dist/tui/agent-progress-card.js +111 -0
  422. package/dist/tui/agent-tree.js +22 -1
  423. package/dist/tui/ask-modal.js +14 -14
  424. package/dist/tui/ask-user-question-chips.js +315 -0
  425. package/dist/tui/ask-user-question-prompt.js +203 -0
  426. package/dist/tui/compact-banner.js +81 -0
  427. package/dist/tui/conversation-pane.js +85 -11
  428. package/dist/tui/cost-table.js +111 -0
  429. package/dist/tui/device-flow.js +2 -2
  430. package/dist/tui/doctor-table.js +46 -0
  431. package/dist/tui/feedback-prompt.js +156 -0
  432. package/dist/tui/input-box.js +247 -32
  433. package/dist/tui/login-picker.js +3 -3
  434. package/dist/tui/markdown-render.js +6 -6
  435. package/dist/tui/multi-file-diff-approval.js +375 -0
  436. package/dist/tui/onboarding-wizard.js +240 -0
  437. package/dist/tui/permissions-picker.js +86 -0
  438. package/dist/tui/render.js +36 -1
  439. package/dist/tui/repl-render.js +239 -25
  440. package/dist/tui/repl-splash-art.js +16 -16
  441. package/dist/tui/repl-splash-mascot.js +48 -24
  442. package/dist/tui/repl-splash.js +22 -22
  443. package/dist/tui/repl.js +125 -45
  444. package/dist/tui/slash-palette.js +6 -6
  445. package/dist/tui/splash.js +2 -2
  446. package/dist/tui/status-bar.js +109 -31
  447. package/dist/tui/status-table.js +7 -0
  448. package/dist/tui/stickers-art.js +136 -0
  449. package/dist/tui/style-table.js +28 -0
  450. package/dist/tui/theme-table.js +29 -0
  451. package/dist/tui/thinking-spinner.js +123 -0
  452. package/dist/tui/tool-stream-pane.js +53 -4
  453. package/dist/tui/update-banner.js +27 -2
  454. package/dist/tui/vim-input.js +267 -0
  455. package/dist/tui/welcome-banner.js +107 -0
  456. package/dist/tui/welcome-data.js +293 -0
  457. package/dist/tui/workspace-context.js +2 -2
  458. package/package.json +29 -6
  459. package/test/scenarios/codegen-create-file.scenario.txt +13 -0
  460. package/test/scenarios/compact-force.scenario.txt +12 -0
  461. package/test/scenarios/identity.scenario.txt +11 -0
  462. package/test/scenarios/persona-handoff.scenario.txt +12 -0
  463. package/test/scenarios/walkback.scenario.txt +12 -0
  464. package/dist/core/engine/compaction-hook.js +0 -154
@@ -0,0 +1,86 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { Box, Text, useInput } from 'ink';
4
+ import { PERMISSION_MODES, PERMISSION_MODE_GLOSS, } from '../core/permissions/index.js';
5
+ /**
6
+ * Build the rendered rows from the canonical mode list. We map the
7
+ * 1-line gloss → row hint so `/permissions` and the picker stay in
8
+ * sync — a change to `PERMISSION_MODE_GLOSS` shows up here too.
9
+ */
10
+ const ITEMS = PERMISSION_MODES.map((mode) => ({
11
+ mode,
12
+ title: titleCase(mode),
13
+ hint: PERMISSION_MODE_GLOSS[mode],
14
+ }));
15
+ function titleCase(mode) {
16
+ return mode.charAt(0).toUpperCase() + mode.slice(1);
17
+ }
18
+ /**
19
+ * Resolve the initial cursor — prefer the explicit `initialIndex`
20
+ * (spec / test) when provided, otherwise highlight the row matching
21
+ * the active mode so the operator opens the picker with their
22
+ * current selection focused.
23
+ */
24
+ function resolveInitialIndex(currentMode, override) {
25
+ if (typeof override === 'number') {
26
+ return Math.min(Math.max(override, 0), ITEMS.length - 1);
27
+ }
28
+ const idx = ITEMS.findIndex((item) => item.mode === currentMode);
29
+ return idx >= 0 ? idx : 0;
30
+ }
31
+ export function PermissionsPicker(props) {
32
+ const [index, setIndex] = useState(resolveInitialIndex(props.currentMode, props.initialIndex));
33
+ useInput((input, key) => {
34
+ if (key.upArrow || input === 'k') {
35
+ setIndex((current) => (current === 0 ? ITEMS.length - 1 : current - 1));
36
+ return;
37
+ }
38
+ if (key.downArrow || input === 'j') {
39
+ setIndex((current) => (current === ITEMS.length - 1 ? 0 : current + 1));
40
+ return;
41
+ }
42
+ if (key.return) {
43
+ const selected = ITEMS[index];
44
+ if (selected)
45
+ props.onSelect(selected.mode);
46
+ return;
47
+ }
48
+ if (key.escape || input === 'q') {
49
+ props.onCancel();
50
+ return;
51
+ }
52
+ // : number shortcuts mirror the canonical 6-mode order.
53
+ // Operators coming from the upstream tool reach the same mode with the
54
+ // same digit (1=default, 2=acceptEdits, …, 6=bypassPermissions).
55
+ if (input === '1')
56
+ props.onSelect('default');
57
+ if (input === '2')
58
+ props.onSelect('acceptEdits');
59
+ if (input === '3')
60
+ props.onSelect('plan');
61
+ if (input === '4')
62
+ props.onSelect('auto');
63
+ if (input === '5')
64
+ props.onSelect('dontAsk');
65
+ if (input === '6')
66
+ props.onSelect('bypassPermissions');
67
+ });
68
+ return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Permission mode" }), _jsx(Text, { dimColor: true, children: ` (current: ${props.currentMode} — ${props.sourceLabel})` })] }), props.firstRun ? (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "First time? Mode = Ask \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E. Use /permissions \u043A change later." }) })) : null, _jsx(Box, { marginTop: 1, flexDirection: "column", children: ITEMS.map((item, itemIndex) => {
69
+ const isSelected = itemIndex === index;
70
+ const isCurrent = item.mode === props.currentMode;
71
+ return (_jsx(PickerRow, { isSelected: isSelected, isCurrent: isCurrent, title: item.title, hint: item.hint }, item.mode));
72
+ }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: '↑/↓ select Enter confirm Esc cancel' }) })] }));
73
+ }
74
+ function PickerRow({ isSelected, isCurrent, title, hint, }) {
75
+ // Arrow glyph + padded title so highlighted and dim rows share
76
+ // column alignment. A trailing ` ●` marks the currently-effective
77
+ // mode (separate from cursor focus) so an operator instantly sees
78
+ // which row is "what I have now" vs "what I'm hovering".
79
+ const indicator = isSelected ? '▸ ' : ' ';
80
+ // : longest title is `BypassPermissions` (17 chars). Bump the
81
+ // pad column так the gloss column stays aligned across all 6 rows.
82
+ const padded = title.padEnd(18, ' ');
83
+ const currentMarker = isCurrent ? ' ●' : ' ';
84
+ return (_jsxs(Text, { children: [_jsxs(Text, { color: isSelected ? 'cyan' : undefined, bold: isSelected, children: [indicator, padded] }), _jsx(Text, { color: isCurrent ? 'green' : undefined, children: currentMarker }), _jsx(Text, { dimColor: true, children: ` ${hint}` })] }));
85
+ }
86
+ //# sourceMappingURL=permissions-picker.js.map
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import { render } from 'ink';
3
3
  import { DeviceFlow } from './device-flow.js';
4
4
  import { LoginPicker } from './login-picker.js';
5
+ import { PermissionsPicker } from './permissions-picker.js';
5
6
  import { Splash } from './splash.js';
6
7
  import { collectSplashData } from './splash-data.js';
7
8
  /**
@@ -25,7 +26,7 @@ export async function renderSplash(cliVersion) {
25
26
  * Sentinel thrown when the user dismisses the login picker via Esc
26
27
  * or `q`. The CLI dispatcher catches it, prints a one-line abort
27
28
  * message, and exits 130 (the standard exit code for SIGINT-style
28
- * user cancellations — matches gh CLI, codex, claude-code).
29
+ * user cancellations — matches gh CLI and peer CLIs).
29
30
  */
30
31
  export class LoginCancelledError extends Error {
31
32
  constructor() {
@@ -66,6 +67,40 @@ export function renderLoginPicker(apiUrl) {
66
67
  }));
67
68
  });
68
69
  }
70
+ /**
71
+ * Sentinel thrown when the operator dismisses the permissions picker
72
+ * via Esc / q. Mirrors `LoginCancelledError` — the host catches and
73
+ * prints a one-line abort message; no mode flip lands.
74
+ */
75
+ export class PermissionsPickerCancelledError extends Error {
76
+ constructor() {
77
+ super('Permissions picker cancelled');
78
+ this.name = 'PermissionsPickerCancelledError';
79
+ }
80
+ }
81
+ export function renderPermissionsPicker(options) {
82
+ return new Promise((resolveMode, rejectMode) => {
83
+ let settled = false;
84
+ const finish = (cb) => {
85
+ if (settled)
86
+ return;
87
+ settled = true;
88
+ instance.unmount();
89
+ setImmediate(cb);
90
+ };
91
+ const instance = render(React.createElement(PermissionsPicker, {
92
+ currentMode: options.currentMode,
93
+ sourceLabel: options.sourceLabel,
94
+ firstRun: options.firstRun ?? false,
95
+ onSelect: (mode) => {
96
+ finish(() => resolveMode(mode));
97
+ },
98
+ onCancel: () => {
99
+ finish(() => rejectMode(new PermissionsPickerCancelledError()));
100
+ },
101
+ }));
102
+ });
103
+ }
69
104
  /**
70
105
  * Mount `<DeviceFlow />` on a TTY and return a handle the host uses to
71
106
  * drive the frame. Mirrors `renderLoginPicker`'s lifecycle: we
@@ -1,29 +1,38 @@
1
1
  /**
2
- * Production REPL mount + transport - Sprint α5.7.
2
+ * Production REPL mount + transport - Sprint .
3
3
  *
4
4
  * Owns the Ink mount lifecycle for `<Repl />` and wires the real
5
5
  * fetch + SSE transport. The CLI dispatcher in `runtime/cli.ts` calls
6
6
  * `renderRepl` on the bare-`pugi` path when stdin / stdout are TTYs.
7
7
  *
8
8
  * The transport speaks to admin-api:
9
- * POST /api/pugi/sessions → { sessionId }
10
- * POST /api/pugi/sessions/:id/brief → { dispatchId }
11
- * POST /api/pugi/sessions/:id/stop → { stopped }
12
- * GET /api/pugi/sessions/:id/stream → text/event-stream
9
+ * POST /api/pugi/sessions → { sessionId }
10
+ * POST /api/pugi/sessions/:id/brief → { dispatchId }
11
+ * POST /api/pugi/sessions/:id/stop → { stopped }
12
+ * GET /api/pugi/sessions/:id/stream → text/event-stream
13
13
  *
14
14
  * SSE is parsed client-side from a streaming fetch response - Node 22
15
15
  * native fetch returns a WHATWG `ReadableStream` which we feed through
16
16
  * a tiny `event:`/`data:`/`id:` parser. This keeps the dependency
17
17
  * graph at zero new packages.
18
18
  */
19
+ import { existsSync } from 'node:fs';
20
+ import { resolve } from 'node:path';
19
21
  import React from 'react';
20
22
  import { render } from 'ink';
21
23
  import { Repl } from './repl.js';
22
24
  import { printPugMascotPreInk } from './repl-splash-mascot.js';
25
+ import { collectWelcomeData } from './welcome-data.js';
26
+ import { ThemeProvider } from '../core/theme/context.js';
27
+ import { resolveTheme } from '../core/theme/state.js';
23
28
  import { ReplSession, } from '../core/repl/session.js';
24
29
  import { resolveWorkspaceContext } from '../core/repl/workspace-context.js';
30
+ import { createEngineBridge } from '../core/repl/engine-bridge.js';
31
+ import { profileFor, resolveIntensity } from '../core/engine/intensity.js';
25
32
  import { SqliteSessionStore } from '../core/repl/store/index.js';
26
33
  import { slugForCwd } from '../core/repl/history.js';
34
+ import { loadSettings } from '../core/settings.js';
35
+ import { buildRuntimeConfig } from '@pugi/sdk';
27
36
  import { WorkingSet, buildRepoSkeleton, loadPugiIgnore, PugiWatcher, } from '../core/context/index.js';
28
37
  /**
29
38
  * Mount the REPL and resolve when the user exits via Ctrl+C × 2 or
@@ -31,7 +40,7 @@ import { WorkingSet, buildRepoSkeleton, loadPugiIgnore, PugiWatcher, } from '../
31
40
  * `pugi resume <sessionId>` once that command exists).
32
41
  */
33
42
  export async function renderRepl(options) {
34
- // beta.9 CEO dogfood 2026-05-26: claim stdin raw mode + alt-screen
43
+ // beta.9 CEO dogfood: claim stdin raw mode + alt-screen
35
44
  // BEFORE any async bootstrap step so keystrokes typed during the
36
45
  // [launch -> Ink mount] window cannot echo into the terminal in
37
46
  // cooked mode. Previously openLocalStore (SQLite open) +
@@ -41,7 +50,7 @@ export async function renderRepl(options) {
41
50
  // every typed character literally onto the screen below the
42
51
  // pre-printed mascot/header. The visible result was the operator's
43
52
  // "ssssss" landing on the rendered status-bar bottom row (CEO
44
- // screenshot 2026-05-26: beta.8 REPL bug 2).
53
+ // screenshot: beta.8 REPL bug 2).
45
54
  //
46
55
  // The claim is idempotent with Ink's own raw-mode enable: Ink
47
56
  // ref-counts setRawMode calls, and Node's stdin.setRawMode is
@@ -50,13 +59,67 @@ export async function renderRepl(options) {
50
59
  // top, and our finally{} restore drops the floor only after Ink
51
60
  // has cleanly torn down (or never mounted on a bootstrap crash).
52
61
  const bootstrap = claimTerminalForRepl();
62
+ // beta.13 auto-init wire (CEO dogfood): scaffold the
63
+ // `.pugi/` workspace silently on REPL boot so launching `pugi` in a
64
+ // fresh cwd no longer demands an explicit `pugi init` round-trip.
65
+ // Idempotent — every helper inside scaffoldPugiWorkspace is a
66
+ // `*_IfMissing` write, so re-running over an existing workspace is
67
+ // a no-op. Fail-safe: any FS / perms error never blocks REPL launch.
68
+ // Operator escape hatch: PUGI_NO_AUTO_INIT=1.
69
+ //
70
+ // Beta.13 P2 fix: gate the scaffold on project-root markers
71
+ // so launching `pugi` from `$HOME` / `/tmp` / arbitrary dirs does NOT
72
+ // sprinkle `.pugi/` directories all over the filesystem. The gate
73
+ // mirrors `isBoundWorkspace` from workspace-context.ts but also
74
+ // accepts non-JS roots (Cargo / pyproject / go.mod) because the CLI
75
+ // is language-agnostic and an operator working in a Rust repo deserves
76
+ // the same auto-init UX as a Node operator. Already-bound `.pugi/`
77
+ // dirs also opt back in so the scaffold can fill any missing
78
+ // sub-artifacts the operator deleted.
79
+ // `--bare` (PUGI_BARE=1) ALSO suppresses the
80
+ // auto-init scaffold. Bare mode is the deterministic "fresh install
81
+ // anywhere" path — no `.pugi/` writes, no PUGI.md scaffold, no
82
+ // settings.json seed. The pre-existing PUGI_NO_AUTO_INIT escape
83
+ // hatch stays — bare mode just unions with it.
84
+ const { isBareMode } = await import('../core/bare-mode/index.js');
85
+ if (process.env.PUGI_NO_AUTO_INIT !== '1' &&
86
+ !isBareMode() &&
87
+ isProjectRoot(process.cwd())) {
88
+ try {
89
+ const { scaffoldPugiWorkspace } = await import('../runtime/cli.js');
90
+ await scaffoldPugiWorkspace({
91
+ cwd: process.cwd(),
92
+ noDefaults: true,
93
+ log: () => {
94
+ /* silent — never leak scaffold progress into the REPL alt-screen */
95
+ },
96
+ });
97
+ }
98
+ catch (err) {
99
+ // Fail-safe: read-only FS or perms error never blocks REPL launch.
100
+ // Beta.13 P2 fix: bare-catch swallowed the diagnostic;
101
+ // surface it on stderr under PUGI_DEBUG=1 so operator-triage on
102
+ // "why isn't .pugi/ being created?" has a starting point without
103
+ // having to re-instrument the bootstrap.
104
+ if (process.env.PUGI_DEBUG === '1') {
105
+ const msg = err instanceof Error ? err.message : String(err);
106
+ process.stderr.write(`[pugi-debug] auto-init failed: ${msg}\n`);
107
+ }
108
+ }
109
+ }
53
110
  const transport = createProductionTransport();
54
- // Auto-bind the workspace context from process.cwd() so Mira knows
111
+ // Auto-bind the workspace context from process.cwd() so Pugi knows
55
112
  // which repo the operator launched the CLI in. The resolver is
56
113
  // best-effort — any FS error falls back to a basename-only summary,
57
- // never blocks REPL launch. Wave 4 fix 2026-05-25.
114
+ // never blocks REPL launch. fix.
58
115
  const workspace = options.workspace ?? resolveWorkspaceContext(process.cwd());
59
- // α6.4: open the local SessionStore for `/resume` persistence. The
116
+ // Beta.13 P1 fix: read `ui.cyberZoo` from
117
+ // `.pugi/settings.json` so the operator's splash posture flows to
118
+ // admin-api on session open. Without this, the renderer's `cyberZoo`
119
+ // parameter (added beta.13) was always defaulted to 'on' regardless
120
+ // of the operator's actual setting.
121
+ const cyberZoo = readCyberZooSetting(process.cwd());
122
+ // : open the local SessionStore for `/resume` persistence. The
60
123
  // store lives under `~/.pugi/projects/<slug>/`; failure is fail-safe
61
124
  // — we log a one-line warning to stderr and continue with the REPL
62
125
  // in memory-only mode. Lock-busy errors get the friendliest message
@@ -68,7 +131,7 @@ export async function renderRepl(options) {
68
131
  workspaceRoot: process.cwd(),
69
132
  resumeLocalSessionId: options.resumeLocalSessionId,
70
133
  });
71
- // α6.5 three-tier context bootstrap. The skeleton + working set
134
+ // three-tier context bootstrap. The skeleton + working set
72
135
  // + watcher are local-first and best-effort: every step is wrapped
73
136
  // in try/catch so an unreadable workspace never blocks REPL launch.
74
137
  // Opt-out via PUGI_DISABLE_CONTEXT=1 for hermetic test runs.
@@ -76,13 +139,63 @@ export async function renderRepl(options) {
76
139
  cwd: process.cwd(),
77
140
  env: process.env,
78
141
  });
142
+ // PUGI-538c () -- wire the production engine bridge so
143
+ // `<pugi-tool-route>` envelopes emitted by Pugi's coordinator
144
+ // actually drive a local `NativePugiEngineAdapter` run instead of
145
+ // surfacing "Engine bridge not configured" on the system line. The
146
+ // factory closure resolves `cwd` per invocation so an operator who
147
+ // `cd`-ed mid-session writes files into the new directory (matches
148
+ // `pugi code` direct-path behaviour).
149
+ //
150
+ // The bridge runtime config reuses the REPL transport credentials so
151
+ // a single token authenticates both the coordinator brief (via
152
+ // admin-api /api/pugi/sessions) AND the bridged engine call (via
153
+ // /api/pugi/engine). No new credential surface, no double login.
154
+ //
155
+ // Fail-safe construction: `buildRuntimeConfig` validates apiUrl via
156
+ // `z.string().url()` and throws on a malformed value. We must not
157
+ // crash REPL launch on that path -- every other bootstrap step in
158
+ // this file (auto-init, openLocalStore, bootstrapContext, watcher)
159
+ // is fail-safe. On construction failure we surface a one-line stderr
160
+ // diagnostic under PUGI_DEBUG=1 and pass `engineBridge: undefined`
161
+ // so the REPL launches; the operator sees the legacy "Engine bridge
162
+ // not configured" system line on the first routed brief, which is
163
+ // the same UX as a pre-PUGI-538c CLI build.
164
+ let engineBridge;
165
+ try {
166
+ // PR A (2026-06-05): resolve intensity profile once at bridge
167
+ // construction time. The bridge stays pure and re-uses the resolved
168
+ // profile across every routed brief. `resolveIntensity` reads env
169
+ // (`PUGI_INTENSITY`) и settings.json; the REPL launch lifecycle is
170
+ // the natural binding point. A future `/intensity` REPL command
171
+ // will rebuild the bridge to swap the profile mid-session.
172
+ const intensityLevel = resolveIntensity({});
173
+ const intensityProfile = profileFor(intensityLevel);
174
+ engineBridge = createEngineBridge({
175
+ config: buildRuntimeConfig({
176
+ apiUrl: options.apiUrl,
177
+ apiKey: options.apiKey,
178
+ }),
179
+ cwd: () => process.cwd(),
180
+ intensityProfile,
181
+ });
182
+ }
183
+ catch (err) {
184
+ if (process.env.PUGI_DEBUG === '1') {
185
+ const msg = err instanceof Error ? err.message : String(err);
186
+ process.stderr.write(`[pugi-debug] engine bridge bootstrap failed: ${msg}\n`);
187
+ }
188
+ engineBridge = undefined;
189
+ }
79
190
  const session = new ReplSession({
80
191
  apiUrl: options.apiUrl,
81
192
  apiKey: options.apiKey,
82
193
  workspaceLabel: options.workspaceLabel,
83
194
  cliVersion: options.cliVersion,
84
195
  transport,
196
+ ...(engineBridge !== undefined ? { engineBridge } : {}),
85
197
  workspace,
198
+ cyberZoo,
86
199
  store,
87
200
  localSessionId: openedSessionId,
88
201
  repoSkeleton: skeleton,
@@ -113,7 +226,7 @@ export async function renderRepl(options) {
113
226
  // typed it after the REPL became interactive. Idempotent: no-op
114
227
  // when stdin is not a TTY or no bytes were buffered.
115
228
  drainBufferedStdin(process.stdin);
116
- // α6.14.2 wave 5: paint the chafa-baked brand-pug ANSI render to
229
+ // wave 5: paint the chafa-baked brand-pug ANSI render to
117
230
  // stdout BEFORE Ink mounts (but AFTER alt-screen enter). Ink's
118
231
  // layout engine would mis-measure the truecolor escape sequences,
119
232
  // so the pug must land verbatim. The flag is passed into <Repl />
@@ -123,13 +236,56 @@ export async function renderRepl(options) {
123
236
  // (operator opted out via --no-splash), we suppress the pre-print
124
237
  // too so the boot stays silent.
125
238
  const mascotPrePrinted = options.skipSplash === true ? false : printPugMascotPreInk(process.stdout);
126
- const instance = render(React.createElement(Repl, {
239
+ // resolve the active theme ONCE at mount
240
+ // and wrap `<Repl />` in `<ThemeProvider>` so every Ink consumer
241
+ // (`<Header>`, `<DoctorTable>`, `<StyleTable>`, `<ThemeTable>`,
242
+ // …) picks up the same color tokens. The provider is stable for
243
+ // the lifetime of the REPL — operator `/theme <name>` writes to
244
+ // disk + appends a system line, and the next `pugi` launch re-
245
+ // mounts with the new slug. Re-mounting mid-session would race
246
+ // against Ink's raw-mode handler so we deliberately keep the
247
+ // session-lifetime contract instead of polling the config file.
248
+ const resolvedTheme = resolveTheme({
249
+ workspaceRoot: process.cwd(),
250
+ env: process.env,
251
+ });
252
+ // CEO P0 #2 : collect welcome banner data BEFORE Ink
253
+ // mounts so the banner paints on the first frame instead of swapping
254
+ // in mid-render. The collector swallows every IO error so а missing
255
+ // CHANGELOG / unreadable credential / malformed settings never
256
+ // blocks the boot.
257
+ let welcomeData;
258
+ if (options.skipSplash !== true) {
259
+ try {
260
+ welcomeData = collectWelcomeData({
261
+ cliVersion: options.cliVersion,
262
+ cwd: process.cwd(),
263
+ });
264
+ }
265
+ catch {
266
+ welcomeData = undefined;
267
+ }
268
+ }
269
+ const instance = render(React.createElement(ThemeProvider, { slug: resolvedTheme.slug }, React.createElement(Repl, {
127
270
  session,
128
271
  updateBanner: options.updateBanner ?? null,
129
272
  skipSplash: options.skipSplash === true,
130
273
  hideToolStream: options.hideToolStream === true,
131
274
  mascotPrePrinted,
132
- }));
275
+ welcomeData,
276
+ autoInitStatus: options.autoInitStatus ?? null,
277
+ })), {
278
+ // PUGI-534 — Ink kills the process on the first raw Ctrl+C by
279
+ // default, which beat the InputBox useInput double-tap timer to
280
+ // the punch (operator reported single ^C exits the REPL). Disable
281
+ // Ink's built-in handler so the InputBox `lastCtrlCAt` window owns
282
+ // the exit gesture: first press → cancel + toast, second press
283
+ // within 1s → `handleExit()` → `useApp().exit()`. SIGINT handlers
284
+ // on the process object (sigint-guard + per-engine-task in
285
+ // runtime/cli.ts) still fire as defence-in-depth on the rare
286
+ // non-raw fallback path.
287
+ exitOnCtrlC: false,
288
+ });
133
289
  // Make sure we leave the alt screen on abrupt exits too. Without
134
290
  // this the operator's shell stays "frozen" on the Pugi splash.
135
291
  process.once('exit', bootstrap.restore);
@@ -242,6 +398,55 @@ export function drainBufferedStdin(stdin = process.stdin) {
242
398
  return 0;
243
399
  }
244
400
  }
401
+ /**
402
+ * Project-root probe — beta.13 P2 fix.
403
+ *
404
+ * Beta.13 auto-init was unconditional and silently created `.pugi/` in
405
+ * every cwd the REPL was launched from, including `$HOME` and `/tmp`.
406
+ * Operators who ran `pugi` to ask a quick question outside of any
407
+ * project ended up with stray `.pugi/` directories polluting their
408
+ * filesystem. The gate looks for any of six project-root markers
409
+ * before scaffolding:
410
+ *
411
+ * - `package.json` — JS / TS workspaces
412
+ * - `.git` — any cloned repo regardless of language
413
+ * - `.pugi` — already-bound Pugi workspace (re-scaffold
414
+ * fills any missing artifacts the operator
415
+ * deleted, idempotent over existing files)
416
+ * - `Cargo.toml` — Rust crates
417
+ * - `pyproject.toml` — Python projects (PEP 518)
418
+ * - `go.mod` — Go modules
419
+ *
420
+ * The probe is six cheap `existsSync` calls; the cost is negligible
421
+ * compared with the alt-screen + Ink mount that follows. Exported so a
422
+ * future unit spec can lock the contract.
423
+ */
424
+ export function isProjectRoot(cwd) {
425
+ // ESM static imports — `require()` is not defined in a `"type": "module"`
426
+ // bundle and would throw `ReferenceError: require is not defined` the
427
+ // moment the REPL bootstrap calls this gate. Beta.16 P0 fix.
428
+ return (existsSync(resolve(cwd, 'package.json')) ||
429
+ existsSync(resolve(cwd, '.git')) ||
430
+ existsSync(resolve(cwd, '.pugi')) ||
431
+ existsSync(resolve(cwd, 'Cargo.toml')) ||
432
+ existsSync(resolve(cwd, 'pyproject.toml')) ||
433
+ existsSync(resolve(cwd, 'go.mod')));
434
+ }
435
+ /**
436
+ * Read the operator's cyber-zoo posture from `.pugi/settings.json`.
437
+ * Best-effort: when the file is missing / malformed, fall through to
438
+ * the historical 'on' default so the REPL never refuses to launch on
439
+ * a settings error. Beta.13 P1 fix.
440
+ */
441
+ function readCyberZooSetting(cwd) {
442
+ try {
443
+ const settings = loadSettings(cwd);
444
+ return settings.ui?.cyberZoo ?? 'on';
445
+ }
446
+ catch {
447
+ return 'on';
448
+ }
449
+ }
245
450
  /**
246
451
  * Open the local SessionStore for the REPL bootstrap. Returns
247
452
  * `{ store: null, openedSessionId: undefined }` on any error so the
@@ -279,11 +484,11 @@ async function openLocalStore(input) {
279
484
  }
280
485
  }
281
486
  /**
282
- * Bootstrap the α6.5 three-tier context primitives:
487
+ * Bootstrap the three-tier context primitives:
283
488
  *
284
- * - Tier 0: `RepoSkeleton` (~5KB ASCII tree + meta) for prompt injection.
285
- * - Tier 1: `WorkingSet` LRU bounded at 50 entries.
286
- * - Filewatch: chokidar started against cwd, ignore-filtered.
489
+ * - Tier 0: `RepoSkeleton` (~5KB ASCII tree + meta) for prompt injection.
490
+ * - Tier 1: `WorkingSet` LRU bounded at 50 entries.
491
+ * - Filewatch: chokidar started against cwd, ignore-filtered.
287
492
  *
288
493
  * The bootstrap is fail-safe: every primitive is wrapped so the REPL
289
494
  * still launches when (e.g.) chokidar refuses to start on a
@@ -331,15 +536,22 @@ async function bootstrapContext(input) {
331
536
  return { skeleton, workingSet, watcher };
332
537
  }
333
538
  /* ------------------------------------------------------------------ */
334
- /* Production transport */
539
+ /* Production transport */
335
540
  /* ------------------------------------------------------------------ */
336
541
  export function createProductionTransport() {
337
542
  return {
338
- async createSession({ apiUrl, apiKey, workspace }) {
543
+ async createSession({ apiUrl, apiKey, workspace, cyberZoo }) {
339
544
  // Forward the workspace bundle in the POST body so admin-api can
340
- // surface `<workspace-context>` in Mira's prompt. Older admin-api
545
+ // surface `<workspace-context>` in Pugi's prompt. Older admin-api
341
546
  // builds ignore unknown fields, so this stays forward-compatible.
342
- // Wave 4 fix 2026-05-25.
547
+ // fix.
548
+ //
549
+ // Beta.13 P1 fix: also forward `cyberZoo` so admin-api
550
+ // can render Pugi's `<cyber-zoo>` marker matching the operator's
551
+ // `.pugi/settings.json::ui.cyberZoo` toggle instead of the
552
+ // historical 'on' default. Only included on the wire when set
553
+ // explicitly so a missing setting still survives older admin-api
554
+ // builds that do not declare the DTO field.
343
555
  const body = {};
344
556
  if (workspace?.workspaceCwd)
345
557
  body.workspaceCwd = workspace.workspaceCwd;
@@ -347,6 +559,8 @@ export function createProductionTransport() {
347
559
  body.workspaceSlug = workspace.workspaceSlug;
348
560
  if (workspace?.workspaceSummary)
349
561
  body.workspaceSummary = workspace.workspaceSummary;
562
+ if (cyberZoo === 'on' || cyberZoo === 'off')
563
+ body.cyberZoo = cyberZoo;
350
564
  const response = await fetch(joinUrl(apiUrl, '/api/pugi/sessions'), {
351
565
  method: 'POST',
352
566
  headers: jsonHeaders(apiKey),
@@ -392,7 +606,7 @@ export function createProductionTransport() {
392
606
  if (lastEventId) {
393
607
  headers['Last-Event-ID'] = lastEventId;
394
608
  }
395
- // beta.9 CEO dogfood 2026-05-26: hard timeout on the SSE
609
+ // beta.9 CEO dogfood: hard timeout on the SSE
396
610
  // handshake so a CDN/proxy that buffers the response (or an
397
611
  // admin-api that accepted the route but never flushed headers)
398
612
  // cannot freeze the REPL in `connecting` forever. The 5s budget
@@ -468,7 +682,7 @@ export function createProductionTransport() {
468
682
  };
469
683
  }
470
684
  /* ------------------------------------------------------------------ */
471
- /* SSE parser */
685
+ /* SSE parser */
472
686
  /* ------------------------------------------------------------------ */
473
687
  /**
474
688
  * Minimal SSE parser. Reads a UTF-8 stream of `id:` / `event:` / `data:`
@@ -532,7 +746,7 @@ async function consumeSseStream(body, onEvent) {
532
746
  }
533
747
  }
534
748
  /* ------------------------------------------------------------------ */
535
- /* Small helpers */
749
+ /* Small helpers */
536
750
  /* ------------------------------------------------------------------ */
537
751
  function jsonHeaders(apiKey) {
538
752
  return {
@@ -1,9 +1,9 @@
1
1
  /**
2
- * ASCII pug mascot for the REPL boot splash (α6.14 wave 3).
2
+ * ASCII pug mascot for the REPL boot splash .
3
3
  *
4
4
  * Hand-crafted at 9 rows × 20 columns to read as a pug at a single
5
5
  * glance — references the cyber-zoo hero glyph in
6
- * `apps/clawhost-web/public/brand/hero-pug.png`: blocky pug face with
6
+ * `apps/console-web/public/brand/hero-pug.png`: blocky pug face with
7
7
  * angular ear flaps on either side of the head, forehead crease,
8
8
  * angular cyan eyes (`◉`), smushed snout, undershot jaw, and a small
9
9
  * cyan circuit chip (`▐■▌`) on the lower-right cheek.
@@ -15,30 +15,30 @@
15
15
  * columns cyan (#3DA9FC, brandbook §05).
16
16
  *
17
17
  * Convention:
18
- * - PUG_MASCOT[i] = one row of the silhouette
19
- * - PUG_MASCOT_CYAN_MASK[i] = parallel boolean array, true => that
20
- * column renders cyan instead of gray
18
+ * - PUG_MASCOT[i] = one row of the silhouette
19
+ * - PUG_MASCOT_CYAN_MASK[i] = parallel boolean array, true => that
20
+ * column renders cyan instead of gray
21
21
  *
22
22
  * Both arrays MUST stay the same length and each mask row MUST be the
23
23
  * same length as the corresponding art row. A unit test enforces this.
24
24
  */
25
25
  /* eslint-disable no-irregular-whitespace */
26
26
  export const PUG_MASCOT = [
27
- ' ▄▀▀▀▄▄▄▀▀▀▄ ',
28
- ' █▄▄ ▄▄█ ',
29
- ' ▀▄▄▄▄▄▀ ',
30
- ' ',
31
- ' ▀▄ ▀█▀ ▄▀ ',
32
- ' █▀▀▀▀▀█ ',
33
- ' █▒▒▒▒▒█ ▐■▌ ',
34
- ' ▀▄▄▄▀ ',
35
- ' ',
27
+ ' ▄▀▀▀▄▄▄▀▀▀▄ ',
28
+ ' █▄▄ ▄▄█ ',
29
+ ' ▀▄▄▄▄▄▀ ',
30
+ ' ',
31
+ ' ▀▄ ▀█▀ ▄▀ ',
32
+ ' █▀▀▀▀▀█ ',
33
+ ' █▒▒▒▒▒█ ▐■▌ ',
34
+ ' ▀▄▄▄▀ ',
35
+ ' ',
36
36
  ];
37
37
  /**
38
38
  * Cyan accents are derived from the source characters so the art file
39
39
  * stays the single source of truth. Two glyph classes get colored:
40
- * - `◉` -> the two cyan eyes on row 3
41
- * - `▐■▌` -> the cyan chip cluster on row 6 (right cheek)
40
+ * - `◉` -> the two cyan eyes on row 3
41
+ * - `▐■▌` -> the cyan chip cluster on row 6 (right cheek)
42
42
  *
43
43
  * Everything else renders gray. The derivation runs at module load,
44
44
  * which keeps the mask trivially auditable from the source array.