@pugi/cli 0.1.0-beta.10 → 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 (445) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/LICENSE +1 -1
  3. package/README.md +53 -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 +71 -0
  45. package/dist/core/codegraph/types.js +34 -0
  46. package/dist/core/compact/auto-trigger.js +96 -0
  47. package/dist/core/compact/buffer-rewriter.js +115 -0
  48. package/dist/core/compact/summarizer.js +208 -0
  49. package/dist/core/compact/token-counter.js +108 -0
  50. package/dist/core/consensus/anvil-fanout.js +25 -25
  51. package/dist/core/consensus/diff-capture.js +121 -12
  52. package/dist/core/consensus/rubric.js +21 -21
  53. package/dist/core/context/builder.js +6 -6
  54. package/dist/core/context/compaction-events.js +8 -8
  55. package/dist/core/context/compaction.js +31 -31
  56. package/dist/core/context/index.js +15 -8
  57. package/dist/core/context/invariants.js +51 -51
  58. package/dist/core/context/markdown-loader.js +28 -10
  59. package/dist/core/context/markdown-traverse.js +255 -0
  60. package/dist/core/context/pugiignore.js +41 -41
  61. package/dist/core/context/repo-skeleton.js +37 -37
  62. package/dist/core/context/tool-eviction.js +55 -0
  63. package/dist/core/context/watcher.js +32 -32
  64. package/dist/core/context/working-set.js +23 -23
  65. package/dist/core/coordinator/agent-tools.js +77 -0
  66. package/dist/core/coordinator/agent-toolset.js +65 -0
  67. package/dist/core/coordinator/fsm.js +73 -0
  68. package/dist/core/coordinator/mode-fsm.js +70 -0
  69. package/dist/core/cost/rate-card.js +129 -0
  70. package/dist/core/cost/tracker.js +221 -0
  71. package/dist/core/credentials.js +13 -13
  72. package/dist/core/cron/scheduler.js +138 -0
  73. package/dist/core/denial-tracking/index.js +8 -0
  74. package/dist/core/denial-tracking/state.js +264 -0
  75. package/dist/core/diagnostics/probe-runner.js +93 -0
  76. package/dist/core/diagnostics/probes/api.js +46 -0
  77. package/dist/core/diagnostics/probes/auth.js +93 -0
  78. package/dist/core/diagnostics/probes/bare-mode.js +42 -0
  79. package/dist/core/diagnostics/probes/cli-version.js +127 -0
  80. package/dist/core/diagnostics/probes/config.js +72 -0
  81. package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
  82. package/dist/core/diagnostics/probes/disk.js +81 -0
  83. package/dist/core/diagnostics/probes/engine-live.js +46 -0
  84. package/dist/core/diagnostics/probes/git.js +65 -0
  85. package/dist/core/diagnostics/probes/hooks.js +118 -0
  86. package/dist/core/diagnostics/probes/mcp.js +75 -0
  87. package/dist/core/diagnostics/probes/node.js +59 -0
  88. package/dist/core/diagnostics/probes/pnpm.js +36 -0
  89. package/dist/core/diagnostics/probes/pugi-md.js +89 -0
  90. package/dist/core/diagnostics/probes/sandbox.js +72 -0
  91. package/dist/core/diagnostics/probes/session.js +74 -0
  92. package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
  93. package/dist/core/diagnostics/probes/workspace.js +63 -0
  94. package/dist/core/diagnostics/types.js +70 -0
  95. package/dist/core/dispatch/cache-cleanup.js +197 -0
  96. package/dist/core/dispatch/cache-handoff.js +295 -0
  97. package/dist/core/edits/apply-patch-layer-e.js +189 -0
  98. package/dist/core/edits/dispatch.js +333 -7
  99. package/dist/core/edits/format-detector.js +260 -0
  100. package/dist/core/edits/format-matrix.js +26 -0
  101. package/dist/core/edits/fuzzy-ladder.js +650 -0
  102. package/dist/core/edits/index.js +5 -1
  103. package/dist/core/edits/journal.js +199 -0
  104. package/dist/core/edits/layer-a-apply.js +15 -15
  105. package/dist/core/edits/layer-a-fuzzy-apply.js +198 -0
  106. package/dist/core/edits/layer-b-apply.js +9 -9
  107. package/dist/core/edits/layer-c-apply.js +6 -6
  108. package/dist/core/edits/layer-d-ast.js +557 -14
  109. package/dist/core/edits/marker-parser.js +12 -12
  110. package/dist/core/edits/security-gate.js +27 -27
  111. package/dist/core/edits/verify-hook.js +273 -0
  112. package/dist/core/edits/worktree.js +29 -29
  113. package/dist/core/engine/anvil-client.js +214 -26
  114. package/dist/core/engine/auto-compact.js +247 -0
  115. package/dist/core/engine/budgets.js +220 -0
  116. package/dist/core/engine/compact-llm-summarizer.js +124 -0
  117. package/dist/core/engine/context-prefix.js +155 -0
  118. package/dist/core/engine/index.js +1 -1
  119. package/dist/core/engine/intensity.js +163 -0
  120. package/dist/core/engine/intent.js +260 -0
  121. package/dist/core/engine/native-pugi.js +1559 -227
  122. package/dist/core/engine/prompts.js +187 -19
  123. package/dist/core/engine/strip-internal-fields.js +124 -0
  124. package/dist/core/engine/tool-bridge.js +1887 -59
  125. package/dist/core/engine/verification-patterns.js +195 -0
  126. package/dist/core/evaluation/golden-dataset.js +293 -0
  127. package/dist/core/feedback/queue.js +177 -0
  128. package/dist/core/feedback/submitter.js +145 -0
  129. package/dist/core/file-cache.js +113 -1
  130. package/dist/core/flatten/flatten-repo.js +439 -0
  131. package/dist/core/format/osc8-link.js +28 -0
  132. package/dist/core/hook-chains.js +392 -0
  133. package/dist/core/hooks/citation-verify-hook.js +138 -0
  134. package/dist/core/hooks/citation-verify.js +112 -0
  135. package/dist/core/hooks/events.js +46 -0
  136. package/dist/core/hooks/index.js +15 -0
  137. package/dist/core/hooks/registry.js +216 -0
  138. package/dist/core/hooks/runner.js +236 -0
  139. package/dist/core/hooks/v2/event-emitter.js +115 -0
  140. package/dist/core/hooks/v2/executor.js +282 -0
  141. package/dist/core/hooks/v2/index.js +25 -0
  142. package/dist/core/hooks/v2/lifecycle.js +104 -0
  143. package/dist/core/hooks/v2/loader.js +216 -0
  144. package/dist/core/hooks/v2/matcher.js +125 -0
  145. package/dist/core/hooks/v2/trust.js +143 -0
  146. package/dist/core/hooks/v2/types.js +86 -0
  147. package/dist/core/hooks/worktree-events.js +158 -0
  148. package/dist/core/image/renderer.js +71 -0
  149. package/dist/core/init/detector.js +582 -0
  150. package/dist/core/init/template-renderer.js +242 -0
  151. package/dist/core/jobs/registry.js +18 -18
  152. package/dist/core/ledger/results-tsv.js +142 -0
  153. package/dist/core/log-discipline/stdout-redirect.js +51 -0
  154. package/dist/core/lsp/cache.js +105 -0
  155. package/dist/core/lsp/client.js +551 -41
  156. package/dist/core/lsp/language-detect.js +66 -0
  157. package/dist/core/lsp/post-edit-diagnostics.js +171 -0
  158. package/dist/core/lsp/server-detect.js +173 -0
  159. package/dist/core/lsp/symbol-cache.js +162 -0
  160. package/dist/core/lsp/symbol-tools.js +664 -0
  161. package/dist/core/mcp/client.js +97 -28
  162. package/dist/core/mcp/http-server.js +553 -0
  163. package/dist/core/mcp/orchestrator-config.js +192 -0
  164. package/dist/core/mcp/orchestrator-tools.js +806 -0
  165. package/dist/core/mcp/permission.js +190 -0
  166. package/dist/core/mcp/registry.js +39 -17
  167. package/dist/core/mcp/server-tools.js +219 -0
  168. package/dist/core/mcp/server.js +397 -0
  169. package/dist/core/mcp/trust.js +10 -10
  170. package/dist/core/memory/dual-write.js +416 -0
  171. package/dist/core/memory/passive-extract.js +130 -0
  172. package/dist/core/memory/phase1-kinds.js +20 -0
  173. package/dist/core/memory/secret-scanner.js +304 -0
  174. package/dist/core/memory-sync/queue.js +170 -0
  175. package/dist/core/metrics/extract.js +113 -0
  176. package/dist/core/modes/roo-modes.js +68 -0
  177. package/dist/core/notes/notes-paths.js +113 -0
  178. package/dist/core/notes/notes-recorder.js +140 -0
  179. package/dist/core/notes/notes-writer.js +53 -0
  180. package/dist/core/notes/renderers.js +0 -0
  181. package/dist/core/notes/slug.js +105 -0
  182. package/dist/core/onboarding/ensure-initialized.js +133 -0
  183. package/dist/core/onboarding/marker.js +111 -0
  184. package/dist/core/onboarding/telemetry-state.js +108 -0
  185. package/dist/core/output-style/presets.js +176 -0
  186. package/dist/core/output-style/state.js +185 -0
  187. package/dist/core/path-security.js +287 -5
  188. package/dist/core/permission.js +82 -22
  189. package/dist/core/permissions/auto-classifier.js +124 -0
  190. package/dist/core/permissions/bash-parser.js +371 -0
  191. package/dist/core/permissions/circuit-breaker.js +83 -0
  192. package/dist/core/permissions/constrained-edit.js +91 -0
  193. package/dist/core/permissions/gate.js +278 -0
  194. package/dist/core/permissions/index.js +20 -0
  195. package/dist/core/permissions/mode.js +174 -0
  196. package/dist/core/permissions/network-egress.js +137 -0
  197. package/dist/core/permissions/state.js +241 -0
  198. package/dist/core/permissions/tool-class.js +107 -0
  199. package/dist/core/plan-mode/ui-state.js +51 -0
  200. package/dist/core/plans/plan-artifact.js +721 -0
  201. package/dist/core/policy-limits/etag-store.js +122 -0
  202. package/dist/core/prd-check/parser.js +215 -0
  203. package/dist/core/prd-check/reporter.js +127 -0
  204. package/dist/core/prd-check/session-review.js +557 -0
  205. package/dist/core/prd-check/verifiers.js +223 -0
  206. package/dist/core/prompt-cache/client-cache.js +99 -0
  207. package/dist/core/prompts/assembly.js +29 -0
  208. package/dist/core/prompts/registry.js +364 -0
  209. package/dist/core/pugi-gitignore.js +52 -0
  210. package/dist/core/pugi-md/cc-compat-rules.js +735 -0
  211. package/dist/core/pugi-md/context-injector.js +76 -0
  212. package/dist/core/pugi-md/walk-up.js +207 -0
  213. package/dist/core/python/uv-installer.js +270 -0
  214. package/dist/core/python/uv-resolver.js +83 -0
  215. package/dist/core/rate-limit/narrator.js +146 -0
  216. package/dist/core/recipes/cli-types.js +20 -0
  217. package/dist/core/recipes/loader.js +103 -0
  218. package/dist/core/recipes/runner.js +345 -0
  219. package/dist/core/recipes/schema.js +587 -0
  220. package/dist/core/release-notes/parser.js +241 -0
  221. package/dist/core/release-notes/state.js +116 -0
  222. package/dist/core/repl/ask.js +37 -37
  223. package/dist/core/repl/cancellation.js +26 -26
  224. package/dist/core/repl/cap-warning.js +4 -4
  225. package/dist/core/repl/clipboard-read.js +11 -11
  226. package/dist/core/repl/dispatch-fsm.js +12 -12
  227. package/dist/core/repl/engine-bridge.js +303 -0
  228. package/dist/core/repl/history-search.js +15 -15
  229. package/dist/core/repl/history.js +28 -18
  230. package/dist/core/repl/kill-ring.js +5 -5
  231. package/dist/core/repl/model-pricing.js +135 -0
  232. package/dist/core/repl/privacy-banner.js +22 -22
  233. package/dist/core/repl/session.js +2690 -229
  234. package/dist/core/repl/slash-commands.js +540 -41
  235. package/dist/core/repl/store/index.js +1 -1
  236. package/dist/core/repl/store/jsonl-log.js +22 -22
  237. package/dist/core/repl/store/lockfile.js +10 -10
  238. package/dist/core/repl/store/session-store.js +136 -107
  239. package/dist/core/repl/store/types.js +15 -15
  240. package/dist/core/repl/store/uuid-v7.js +12 -12
  241. package/dist/core/repl/tool-route.js +382 -0
  242. package/dist/core/repl/workspace-context.js +43 -21
  243. package/dist/core/repo-map/build.js +125 -0
  244. package/dist/core/repo-map/cache.js +185 -0
  245. package/dist/core/repo-map/extractor.js +254 -0
  246. package/dist/core/repo-map/formatter.js +145 -0
  247. package/dist/core/repo-map/page-rank.js +105 -0
  248. package/dist/core/repo-map/scanner.js +211 -0
  249. package/dist/core/retro/git-collector.js +251 -0
  250. package/dist/core/retro/health-card.js +25 -0
  251. package/dist/core/retro/metrics.js +342 -0
  252. package/dist/core/retro/narrative.js +249 -0
  253. package/dist/core/retro/plane-collector.js +274 -0
  254. package/dist/core/retro/pr-issue-link.js +65 -0
  255. package/dist/core/retro/types.js +16 -0
  256. package/dist/core/retry-budget/budget.js +284 -0
  257. package/dist/core/retry-budget/index.js +5 -0
  258. package/dist/core/retry-budget/retry-cap.js +74 -0
  259. package/dist/core/routing/lead-worker.js +43 -0
  260. package/dist/core/routing/pre-flight-estimator.js +108 -0
  261. package/dist/core/runs/run-tree.js +103 -0
  262. package/dist/core/sandboxing/adapter.js +29 -0
  263. package/dist/core/sandboxing/index.js +49 -0
  264. package/dist/core/sandboxing/none.js +19 -0
  265. package/dist/core/sandboxing/seatbelt.js +183 -0
  266. package/dist/core/security/injection-scanner.js +367 -0
  267. package/dist/core/security/output-filter.js +418 -0
  268. package/dist/core/session/env-file.js +105 -0
  269. package/dist/core/session/section-budgets.js +140 -0
  270. package/dist/core/session.js +119 -0
  271. package/dist/core/settings.js +378 -5
  272. package/dist/core/share/formatter.js +271 -0
  273. package/dist/core/share/redactor.js +221 -0
  274. package/dist/core/share/uploader.js +267 -0
  275. package/dist/core/skills/defaults.js +30 -30
  276. package/dist/core/skills/loader.js +22 -22
  277. package/dist/core/skills/sources.js +27 -27
  278. package/dist/core/smoke/headless-driver.js +174 -0
  279. package/dist/core/smoke/orchestrator.js +194 -0
  280. package/dist/core/smoke/runner.js +238 -0
  281. package/dist/core/smoke/scenario-parser.js +316 -0
  282. package/dist/core/statusline.js +99 -0
  283. package/dist/core/subagents/dispatcher-real.js +600 -0
  284. package/dist/core/subagents/dispatcher.js +146 -52
  285. package/dist/core/subagents/index.js +19 -6
  286. package/dist/core/subagents/isolation-matrix.js +213 -0
  287. package/dist/core/subagents/spawn.js +19 -4
  288. package/dist/core/telemetry/emitter.js +229 -0
  289. package/dist/core/telemetry/queue.js +251 -0
  290. package/dist/core/theme/context.js +91 -0
  291. package/dist/core/theme/presets.js +228 -0
  292. package/dist/core/theme/state.js +181 -0
  293. package/dist/core/todos/invariant.js +10 -0
  294. package/dist/core/todos/state.js +177 -0
  295. package/dist/core/tool-schema/compressor.js +89 -0
  296. package/dist/core/transport/version-interceptor.js +166 -0
  297. package/dist/core/trust.js +2 -2
  298. package/dist/core/tui/thinking-block.js +64 -0
  299. package/dist/core/vim/keymap.js +288 -0
  300. package/dist/core/vim/state.js +92 -0
  301. package/dist/core/watch-markers/marker-watcher.js +133 -0
  302. package/dist/core/worktree/include-parser.js +249 -0
  303. package/dist/core/worktree-manager/cleanup.js +123 -0
  304. package/dist/core/worktree-manager/manager.js +303 -0
  305. package/dist/index.js +36 -0
  306. package/dist/runtime/bootstrap.js +190 -0
  307. package/dist/runtime/cli.js +4345 -561
  308. package/dist/runtime/commands/agents.js +31 -31
  309. package/dist/runtime/commands/budget.js +5 -5
  310. package/dist/runtime/commands/cancel.js +231 -0
  311. package/dist/runtime/commands/chain.js +489 -0
  312. package/dist/runtime/commands/codegraph-status.js +227 -0
  313. package/dist/runtime/commands/compact.js +297 -0
  314. package/dist/runtime/commands/config.js +74 -40
  315. package/dist/runtime/commands/cost.js +199 -0
  316. package/dist/runtime/commands/delegate.js +27 -4
  317. package/dist/runtime/commands/dispatch.js +126 -0
  318. package/dist/runtime/commands/doctor.js +579 -0
  319. package/dist/runtime/commands/feedback.js +184 -0
  320. package/dist/runtime/commands/hooks.js +187 -0
  321. package/dist/runtime/commands/index-cmd.js +353 -0
  322. package/dist/runtime/commands/init.js +254 -0
  323. package/dist/runtime/commands/lsp.js +200 -38
  324. package/dist/runtime/commands/mcp.js +935 -0
  325. package/dist/runtime/commands/memory.js +582 -0
  326. package/dist/runtime/commands/model.js +237 -0
  327. package/dist/runtime/commands/onboarding.js +275 -0
  328. package/dist/runtime/commands/patch.js +12 -12
  329. package/dist/runtime/commands/permissions.js +112 -0
  330. package/dist/runtime/commands/plan.js +143 -0
  331. package/dist/runtime/commands/prd-check.js +285 -0
  332. package/dist/runtime/commands/privacy.js +17 -17
  333. package/dist/runtime/commands/recipe.js +325 -0
  334. package/dist/runtime/commands/redo-blob-store.js +92 -0
  335. package/dist/runtime/commands/redo.js +361 -0
  336. package/dist/runtime/commands/release-notes.js +229 -0
  337. package/dist/runtime/commands/repo-map.js +95 -0
  338. package/dist/runtime/commands/report.js +299 -0
  339. package/dist/runtime/commands/resume.js +118 -0
  340. package/dist/runtime/commands/review-consensus.js +68 -53
  341. package/dist/runtime/commands/rewind.js +333 -0
  342. package/dist/runtime/commands/roster.js +14 -14
  343. package/dist/runtime/commands/servers.js +236 -0
  344. package/dist/runtime/commands/sessions.js +163 -0
  345. package/dist/runtime/commands/share.js +316 -0
  346. package/dist/runtime/commands/skills.js +31 -31
  347. package/dist/runtime/commands/status.js +186 -0
  348. package/dist/runtime/commands/stickers.js +82 -0
  349. package/dist/runtime/commands/style.js +194 -0
  350. package/dist/runtime/commands/theme.js +196 -0
  351. package/dist/runtime/commands/undo.js +54 -22
  352. package/dist/runtime/commands/update.js +289 -0
  353. package/dist/runtime/commands/vim.js +140 -0
  354. package/dist/runtime/commands/worktree.js +8 -8
  355. package/dist/runtime/commands/worktrees.js +155 -0
  356. package/dist/runtime/deprecation-warning.js +69 -0
  357. package/dist/runtime/engine-exit-code.js +50 -0
  358. package/dist/runtime/headless-repl.js +195 -0
  359. package/dist/runtime/headless.js +548 -0
  360. package/dist/runtime/load-hooks-or-exit.js +71 -0
  361. package/dist/runtime/plan-decompose.js +22 -22
  362. package/dist/runtime/sigint-guard.js +272 -0
  363. package/dist/runtime/stream-renderer.js +195 -0
  364. package/dist/runtime/update-check.js +28 -28
  365. package/dist/runtime/version.js +65 -0
  366. package/dist/runtime/worktree-bootstrap.js +579 -0
  367. package/dist/skills/bundled/batch.js +617 -0
  368. package/dist/skills/bundled/index.js +45 -0
  369. package/dist/skills/bundled/loop.js +358 -0
  370. package/dist/skills/bundled/remember.js +383 -0
  371. package/dist/skills/bundled/simplify.js +289 -0
  372. package/dist/skills/bundled/skillify.js +373 -0
  373. package/dist/skills/bundled/stuck.js +558 -0
  374. package/dist/skills/bundled/verify.js +439 -0
  375. package/dist/testing/vcr.js +486 -0
  376. package/dist/tools/agent-tool.js +229 -0
  377. package/dist/tools/apply-patch.js +89 -28
  378. package/dist/tools/ask-user-question.js +337 -0
  379. package/dist/tools/ask-user.js +115 -0
  380. package/dist/tools/bash.js +624 -46
  381. package/dist/tools/brief.js +224 -0
  382. package/dist/tools/cron.js +433 -0
  383. package/dist/tools/enter-worktree.js +250 -0
  384. package/dist/tools/exit-worktree.js +147 -0
  385. package/dist/tools/file-tools.js +161 -44
  386. package/dist/tools/http-request.js +336 -0
  387. package/dist/tools/lsp-tools.js +377 -1
  388. package/dist/tools/mcp-tool.js +260 -0
  389. package/dist/tools/multi-edit.js +361 -0
  390. package/dist/tools/powershell.js +268 -0
  391. package/dist/tools/registry.js +120 -5
  392. package/dist/tools/server-tools.js +892 -0
  393. package/dist/tools/skill-tool.js +96 -0
  394. package/dist/tools/sleep.js +99 -0
  395. package/dist/tools/synthetic-output.js +133 -0
  396. package/dist/tools/tasks.js +208 -0
  397. package/dist/tools/todo-write.js +184 -0
  398. package/dist/tools/verify-plan-execution.js +295 -0
  399. package/dist/tools/web-fetch-injection-scanner.js +207 -0
  400. package/dist/tools/web-fetch.js +195 -10
  401. package/dist/tools/web-search.js +458 -0
  402. package/dist/tui/agent-progress-card.js +111 -0
  403. package/dist/tui/agent-tree.js +22 -1
  404. package/dist/tui/ask-modal.js +14 -14
  405. package/dist/tui/ask-user-question-chips.js +315 -0
  406. package/dist/tui/ask-user-question-prompt.js +203 -0
  407. package/dist/tui/compact-banner.js +81 -0
  408. package/dist/tui/conversation-pane.js +85 -11
  409. package/dist/tui/cost-table.js +111 -0
  410. package/dist/tui/device-flow.js +2 -2
  411. package/dist/tui/doctor-table.js +46 -0
  412. package/dist/tui/feedback-prompt.js +156 -0
  413. package/dist/tui/input-box.js +247 -32
  414. package/dist/tui/login-picker.js +3 -3
  415. package/dist/tui/markdown-render.js +6 -6
  416. package/dist/tui/multi-file-diff-approval.js +375 -0
  417. package/dist/tui/onboarding-wizard.js +240 -0
  418. package/dist/tui/permissions-picker.js +86 -0
  419. package/dist/tui/render.js +36 -1
  420. package/dist/tui/repl-render.js +239 -25
  421. package/dist/tui/repl-splash-art.js +16 -16
  422. package/dist/tui/repl-splash-mascot.js +48 -24
  423. package/dist/tui/repl-splash.js +22 -22
  424. package/dist/tui/repl.js +125 -45
  425. package/dist/tui/slash-palette.js +6 -6
  426. package/dist/tui/splash.js +2 -2
  427. package/dist/tui/status-bar.js +109 -31
  428. package/dist/tui/status-table.js +7 -0
  429. package/dist/tui/stickers-art.js +136 -0
  430. package/dist/tui/style-table.js +28 -0
  431. package/dist/tui/theme-table.js +29 -0
  432. package/dist/tui/thinking-spinner.js +123 -0
  433. package/dist/tui/tool-stream-pane.js +53 -4
  434. package/dist/tui/update-banner.js +27 -2
  435. package/dist/tui/vim-input.js +267 -0
  436. package/dist/tui/welcome-banner.js +107 -0
  437. package/dist/tui/welcome-data.js +293 -0
  438. package/dist/tui/workspace-context.js +2 -2
  439. package/package.json +21 -5
  440. package/test/scenarios/codegen-create-file.scenario.txt +13 -0
  441. package/test/scenarios/compact-force.scenario.txt +12 -0
  442. package/test/scenarios/identity.scenario.txt +11 -0
  443. package/test/scenarios/persona-handoff.scenario.txt +12 -0
  444. package/test/scenarios/walkback.scenario.txt +12 -0
  445. package/dist/core/engine/compaction-hook.js +0 -154
@@ -3,34 +3,35 @@ import { existsSync, readFileSync, renameSync, unlinkSync, writeFileSync } from
3
3
  import { resolve } from 'node:path';
4
4
  import { hashContent } from '../../core/file-cache.js';
5
5
  import { recordFileMutation, recordToolCall, recordToolResult, } from '../../core/session.js';
6
+ import { writeBlob } from './redo-blob-store.js';
6
7
  /**
7
8
  * `pugi undo` — revert the file mutations from the most recent successful
8
9
  * `write` / `edit` / `multi_edit` tool result.
9
10
  *
10
11
  * Walk strategy:
11
- * 1. Read `.pugi/events.jsonl` line by line into an array.
12
- * 2. Walk backwards. Find the most recent `tool_result` whose
13
- * `status === 'success'` and whose linked `tool_call` names a
14
- * mutating tool (write / edit / multi_edit).
15
- * 3. From that point, gather every `file_mutation` event that shares
16
- * the same `toolCallId`. M1 records one `file_mutation` per
17
- * mutating tool call, but the loop is shaped for the multi_edit
18
- * future case where a single tool call mutates many files.
12
+ * 1. Read `.pugi/events.jsonl` line by line into an array.
13
+ * 2. Walk backwards. Find the most recent `tool_result` whose
14
+ * `status === 'success'` and whose linked `tool_call` names a
15
+ * mutating tool (write / edit / multi_edit).
16
+ * 3. From that point, gather every `file_mutation` event that shares
17
+ * the same `toolCallId`. M1 records one `file_mutation` per
18
+ * mutating tool call, but the loop is shaped for the multi_edit
19
+ * future case where a single tool call mutates many files.
19
20
  *
20
21
  * Restore strategy (M1 — no blob store yet):
21
- * For each mutation we restore from the workspace's git history when
22
- * possible, with a strict safety gate to avoid silently overwriting
23
- * the user's WORK-IN-PROGRESS:
22
+ * For each mutation we restore from the workspace's git history when
23
+ * possible, with a strict safety gate to avoid silently overwriting
24
+ * the user's WORK-IN-PROGRESS:
24
25
  *
25
- * - `operation: create` → unlink the created file iff its current
26
- * sha256 matches the recorded `afterHash`. Skip otherwise (the user
27
- * has edited it since; refuse to delete their work).
28
- * - `operation: update` → restore from `HEAD:<path>` iff (a) the file
29
- * was tracked at HEAD AND (b) the HEAD content's sha256 matches the
30
- * recorded `beforeHash`. Otherwise abort the turn (no partial
31
- * reverts — the spec is atomic).
32
- * - `operation: delete` → restore the deleted file from `HEAD:<path>`
33
- * if tracked there; skip otherwise.
26
+ * - `operation: create` → unlink the created file iff its current
27
+ * sha256 matches the recorded `afterHash`. Skip otherwise (the user
28
+ * has edited it since; refuse to delete their work).
29
+ * - `operation: update` → restore from `HEAD:<path>` iff (a) the file
30
+ * was tracked at HEAD AND (b) the HEAD content's sha256 matches the
31
+ * recorded `beforeHash`. Otherwise abort the turn (no partial
32
+ * reverts — the spec is atomic).
33
+ * - `operation: delete` → restore the deleted file from `HEAD:<path>`
34
+ * if tracked there; skip otherwise.
34
35
  *
35
36
  * If any single restore is unsafe the whole turn aborts with exit code
36
37
  * 1 and no files are touched.
@@ -39,7 +40,7 @@ import { recordFileMutation, recordToolCall, recordToolResult, } from '../../cor
39
40
  * but NOT raw content (see `core/file-cache.ts`). M1 ships without a
40
41
  * dedicated blob CAS; `git show HEAD:<path>` is the cheapest authoritative
41
42
  * source for pre-mutation content as long as the workspace is a git
42
- * repository. The α6.4 SQLite session store will replace this with a
43
+ * repository. The SQLite session store will replace this with a
43
44
  * proper before-blob ledger.
44
45
  */
45
46
  const MUTATING_TOOLS = new Set(['write', 'edit', 'multi_edit']);
@@ -81,6 +82,37 @@ export async function runUndoCommand(_args, ctx) {
81
82
  const restored = [];
82
83
  for (const step of plan.steps) {
83
84
  try {
85
+ // : snapshot the AFTER state into the redo
86
+ // blob store BEFORE we revert the file on disk. /redo reads this
87
+ // blob keyed by `step.beforeHash` (= original afterHash) to
88
+ // reapply the change. We only snapshot for operations that have
89
+ // on-disk AFTER content: `create` (file exists, about to be
90
+ // deleted) and `update` (file exists, about to be overwritten).
91
+ // For `delete` reverts (file was deleted by Pugi, the "after" is
92
+ // nothing) redo replays the delete itself — no content needed.
93
+ // Best-effort: a blob-store failure must not abort the undo, so
94
+ // the writeBlob call is wrapped и any error swallowed.
95
+ if (step.operation === 'create' || step.operation === 'update') {
96
+ try {
97
+ const abs = resolve(ctx.workspaceRoot, step.path);
98
+ if (existsSync(abs) && step.beforeHash) {
99
+ const current = readFileSync(abs, 'utf8');
100
+ // Defensive: only snapshot if the current sha matches the
101
+ // pre-revert hash the planner verified. The planner already
102
+ // gated this, but a TOCTOU between plan + execute would
103
+ // produce a wrong blob — silently dropping it is safer than
104
+ // shipping content under the wrong sha.
105
+ if (hashContent(current) === step.beforeHash) {
106
+ writeBlob(ctx.workspaceRoot, current);
107
+ }
108
+ }
109
+ }
110
+ catch {
111
+ // Best-effort. Failure to snapshot means /redo will report
112
+ // "no captured content" — operator can re-run the mutation
113
+ // manually. Better than aborting the undo.
114
+ }
115
+ }
84
116
  executeRevert(ctx.workspaceRoot, step);
85
117
  restored.push({ path: step.path, operation: step.operation });
86
118
  }
@@ -119,7 +151,7 @@ export async function runUndoCommand(_args, ctx) {
119
151
  restored,
120
152
  }, [
121
153
  `Undid ${restored.length} mutation(s) from ${target.toolCallId}:`,
122
- ...restored.map((entry) => ` ${entry.operation.padEnd(7)} ${entry.path}`),
154
+ ...restored.map((entry) => ` ${entry.operation.padEnd(7)} ${entry.path}`),
123
155
  ].join('\n'));
124
156
  }
125
157
  function parseEvents(eventsPath) {
@@ -0,0 +1,289 @@
1
+ /**
2
+ * — `pugi update` dispatcher.
3
+ *
4
+ * Top-level command + in-REPL `/update` slash share this handler.
5
+ * Both surfaces delegate IO + persistence here so the channel
6
+ * resolution, the registry probe, and the install shell-out stay
7
+ * single-sourced.
8
+ *
9
+ * Command grammar:
10
+ *
11
+ * pugi update -> probe + interactive prompt
12
+ * pugi update --check -> probe + JSON envelope (scripted)
13
+ * pugi update --channel <name> -> switch channel + probe
14
+ * pugi update --apply -> probe + shell `npm i -g …`
15
+ * (confirms unless --yes)
16
+ * pugi update --apply --yes -> probe + shell, no confirmation
17
+ *
18
+ * Exit codes:
19
+ *
20
+ * 0 — happy path (no update OR update completed) OR `--check` JSON
21
+ * 1 — install / probe failure with structured error envelope
22
+ * 2 — argument error (bad channel, conflicting flags)
23
+ *
24
+ * R2 atomic swap deferred (sprint plan L27 mention): the upstream behavior
25
+ * also describes the upstream tool's R2-backed binary swap. Pugi ships
26
+ * exclusively via npm today; building a parallel R2 distribution
27
+ * channel + checksum verification + rollback is materially more work
28
+ * than the L27 acceptance criteria allow. Document the deferral in
29
+ * the PR body and revisit when npm's once-per-day rate-limit or
30
+ * outage cadence justifies the parallel pipeline.
31
+ */
32
+ import { spawn } from 'node:child_process';
33
+ import { homedir } from 'node:os';
34
+ import { DEFAULT_UPDATE_CHANNEL, UPDATE_CHANNELS, describeChannel, npmTagForChannel, parseUpdateChannel, } from '../../core/auto-update/channels.js';
35
+ import { checkForChannelUpdate, } from '../../core/auto-update/checker.js';
36
+ import { resolveEffectiveChannel, setUpdateChannel, writeLastCheckedAt, } from '../../core/auto-update/state.js';
37
+ import { PUGI_CLI_VERSION } from '../version.js';
38
+ /**
39
+ * Default subprocess runner. Spawns `npm install -g @pugi/cli@<tag>`
40
+ * inheriting stdio so the operator sees the live npm output.
41
+ */
42
+ export function defaultSpawnInstaller(channel) {
43
+ const tag = npmTagForChannel(channel);
44
+ const args = ['install', '-g', `@pugi/cli@${tag}`];
45
+ return new Promise((resolvePromise) => {
46
+ const child = spawn('npm', args, { stdio: 'inherit' });
47
+ child.on('exit', (code) => {
48
+ resolvePromise(typeof code === 'number' ? code : 1);
49
+ });
50
+ child.on('error', () => {
51
+ // ENOENT / EACCES — npm not on PATH or permission denied. We
52
+ // surface a non-zero code so the dispatcher's JSON envelope
53
+ // tells the operator the apply failed; the inherited stdio
54
+ // already printed the underlying error to the terminal.
55
+ resolvePromise(127);
56
+ });
57
+ });
58
+ }
59
+ /**
60
+ * Parse a CLI / slash argv into our `UpdateCommandFlags`. Returns
61
+ * `null` AND writes the usage error via `writeError` for conflicting
62
+ * combinations. Both `pugi update` and the in-REPL `/update <args>`
63
+ * surface call through this so the validation lives in one place.
64
+ */
65
+ export function parseUpdateArgs(argv, options = {}) {
66
+ let check = false;
67
+ let apply = false;
68
+ let yes = false;
69
+ let json = options.jsonDefault ?? false;
70
+ let channel = null;
71
+ let channelInvalid;
72
+ for (let i = 0; i < argv.length; i += 1) {
73
+ const token = argv[i] ?? '';
74
+ if (token === '--check') {
75
+ check = true;
76
+ }
77
+ else if (token === '--apply') {
78
+ apply = true;
79
+ }
80
+ else if (token === '--yes' || token === '-y') {
81
+ yes = true;
82
+ }
83
+ else if (token === '--json') {
84
+ json = true;
85
+ }
86
+ else if (token === '--channel') {
87
+ const value = argv[i + 1];
88
+ i += 1;
89
+ const parsed = parseUpdateChannel(value);
90
+ if (!parsed) {
91
+ channelInvalid = value ?? '';
92
+ continue;
93
+ }
94
+ channel = parsed;
95
+ }
96
+ else if (token.startsWith('--channel=')) {
97
+ const value = token.slice('--channel='.length);
98
+ const parsed = parseUpdateChannel(value);
99
+ if (!parsed) {
100
+ channelInvalid = value;
101
+ continue;
102
+ }
103
+ channel = parsed;
104
+ }
105
+ else {
106
+ return {
107
+ error: `pugi update: unknown argument '${token}'. See \`pugi update --help\`.`,
108
+ };
109
+ }
110
+ }
111
+ if (channelInvalid !== undefined) {
112
+ return {
113
+ error: `pugi update: unknown channel '${channelInvalid}'. Allowed: ${UPDATE_CHANNELS.join(' / ')}.`,
114
+ };
115
+ }
116
+ return {
117
+ check,
118
+ apply,
119
+ yes,
120
+ json,
121
+ channel,
122
+ };
123
+ }
124
+ /**
125
+ * Run the full command. Returns the structured envelope so the in-
126
+ * REPL slash can decide whether to render the human-readable text OR
127
+ * pretty-print the JSON.
128
+ */
129
+ export async function runUpdateCommand(ctx) {
130
+ const flags = ctx.flags;
131
+ const home = ctx.home;
132
+ // 1. Resolve channel. `--channel <name>` wins; otherwise read the
133
+ // persisted preference; otherwise hard default `beta`.
134
+ const cliFlagChannel = flags.channel;
135
+ const effectiveChannel = resolveEffectiveChannel({
136
+ cliFlag: cliFlagChannel,
137
+ homeDir: home,
138
+ });
139
+ // 2. Persist the channel switch BEFORE the probe so a probe failure
140
+ // still leaves the operator on the channel they asked for.
141
+ let switched = false;
142
+ if (cliFlagChannel) {
143
+ setUpdateChannel(cliFlagChannel, home);
144
+ switched = true;
145
+ }
146
+ // 3. Probe the registry.
147
+ const outcome = await checkForChannelUpdate({
148
+ channel: effectiveChannel,
149
+ currentVersion: PUGI_CLI_VERSION,
150
+ ...(ctx.fetchImpl ? { fetchImpl: ctx.fetchImpl } : {}),
151
+ ...(ctx.registryUrl ? { registryUrl: ctx.registryUrl } : {}),
152
+ });
153
+ // 4. Record the timestamp on a successful probe (regardless of
154
+ // whether an update is available). Failed probes do NOT update
155
+ // the timestamp so the cold-start banner retries on the next
156
+ // invocation.
157
+ if (!outcome.error) {
158
+ const now = ctx.now ? new Date(ctx.now()) : new Date();
159
+ try {
160
+ writeLastCheckedAt(now, home);
161
+ }
162
+ catch {
163
+ // Best-effort — a read-only home should not crash the dispatcher.
164
+ }
165
+ }
166
+ // 5. Build the envelope shape ALL action paths share.
167
+ const baseEnvelope = {
168
+ command: 'update',
169
+ ok: outcome.error === null,
170
+ available: outcome.available,
171
+ channel: outcome.channel,
172
+ npmTag: outcome.npmTag,
173
+ current: outcome.current,
174
+ latest: outcome.latest,
175
+ gap: outcome.gap,
176
+ installCommand: outcome.installCommand,
177
+ action: outcome.error ? 'error' : 'probe',
178
+ error: outcome.error,
179
+ meta: { cliVersion: PUGI_CLI_VERSION },
180
+ };
181
+ // 6. --check: emit the envelope, never prompt, never apply.
182
+ if (flags.check) {
183
+ const text = renderHumanText(baseEnvelope, { switched });
184
+ ctx.writeOutput(baseEnvelope, text);
185
+ return baseEnvelope;
186
+ }
187
+ // 7. No update available — bail with a friendly message.
188
+ if (!outcome.available || !outcome.latest) {
189
+ const envelope = {
190
+ ...baseEnvelope,
191
+ action: outcome.error ? 'error' : (switched ? 'switch' : 'no_update'),
192
+ };
193
+ const text = renderHumanText(envelope, { switched });
194
+ ctx.writeOutput(envelope, text);
195
+ return envelope;
196
+ }
197
+ // 8. Update IS available. Branch on --apply.
198
+ if (!flags.apply) {
199
+ // Default: print the offer, suggest the install command, leave
200
+ // the install to the operator. Mirrors the upstream behavior note:
201
+ // operators install side-effects must remain explicit on the CLI
202
+ // happy path — `pugi update` showing the gap is informational,
203
+ // `pugi update --apply` is the destructive verb.
204
+ const envelope = {
205
+ ...baseEnvelope,
206
+ action: switched ? 'switch' : 'probe',
207
+ };
208
+ const text = renderHumanText(envelope, { switched });
209
+ ctx.writeOutput(envelope, text);
210
+ return envelope;
211
+ }
212
+ // 9. --apply path. Confirm unless --yes, then spawn npm.
213
+ const installer = ctx.spawnInstaller ?? defaultSpawnInstaller;
214
+ let confirmed = flags.yes;
215
+ if (!confirmed) {
216
+ confirmed = await ctx.promptConfirm(`Run \`${outcome.installCommand}\` to update ${outcome.current} -> ${outcome.latest}? [y/N]`);
217
+ }
218
+ if (!confirmed) {
219
+ const envelope = {
220
+ ...baseEnvelope,
221
+ action: 'probe',
222
+ ok: false,
223
+ error: 'apply_cancelled_by_operator',
224
+ };
225
+ const text = `Cancelled. Run \`${outcome.installCommand}\` manually when you are ready.`;
226
+ ctx.writeOutput(envelope, text);
227
+ return envelope;
228
+ }
229
+ const exitCode = await installer(outcome.channel);
230
+ const applyEnvelope = {
231
+ ...baseEnvelope,
232
+ action: 'apply',
233
+ installExitCode: exitCode,
234
+ ok: exitCode === 0,
235
+ error: exitCode === 0 ? null : `npm_install_exit_${exitCode}`,
236
+ };
237
+ const applyText = exitCode === 0
238
+ ? `Updated to @pugi/cli@${outcome.latest}. Restart your shell so the new binary takes effect.`
239
+ : `Update failed (npm exit ${exitCode}). Try \`${outcome.installCommand}\` manually.`;
240
+ ctx.writeOutput(applyEnvelope, applyText);
241
+ return applyEnvelope;
242
+ }
243
+ /**
244
+ * Build the operator-readable hint that lives next to the JSON
245
+ * envelope. The text + the JSON are both passed to `writeOutput`; the
246
+ * caller (`writeOutput` in cli.ts) picks based on `--json`. Exported
247
+ * so the spec can assert the literal strings the operator sees.
248
+ */
249
+ export function renderHumanText(envelope, options = {}) {
250
+ const { current, latest, channel, installCommand, available, error } = envelope;
251
+ const lines = [];
252
+ lines.push(`Channel: ${channel} — ${describeChannel(channel)}`);
253
+ if (options.switched) {
254
+ lines.push(`Persisted channel selection -> ${channel}.`);
255
+ }
256
+ if (error) {
257
+ lines.push(`Update check failed: ${error}`);
258
+ lines.push(`Manual: \`${installCommand}\` (no probe necessary).`);
259
+ return lines.join('\n');
260
+ }
261
+ if (available && latest) {
262
+ lines.push(`Update available: ${current} -> ${latest}.`);
263
+ lines.push(`Run \`${installCommand}\` to upgrade.`);
264
+ lines.push(`Or \`pugi update --apply\` to upgrade with confirmation.`);
265
+ return lines.join('\n');
266
+ }
267
+ lines.push(`Up to date (${current} is the latest on ${channel}).`);
268
+ return lines.join('\n');
269
+ }
270
+ /**
271
+ * Render a one-line cold-start hint that callers (REPL boot, doctor
272
+ * banner) splice above their own UI. Returns `null` when there is
273
+ * nothing to nudge the operator about. Pure — no IO.
274
+ */
275
+ export function renderUpdateHint(outcome) {
276
+ if (!outcome.available || !outcome.latest)
277
+ return null;
278
+ return `Update available: ${outcome.current} -> ${outcome.latest}. Run \`pugi update\`.`;
279
+ }
280
+ /**
281
+ * Convenience entry point — resolve the effective channel from
282
+ * `~/.pugi/config.json` + DEFAULT_UPDATE_CHANNEL without forcing the
283
+ * caller to import multiple modules. Used by the cold-start banner +
284
+ * the doctor probe.
285
+ */
286
+ export function effectiveChannel(home = homedir()) {
287
+ return resolveEffectiveChannel({ homeDir: home }) ?? DEFAULT_UPDATE_CHANNEL;
288
+ }
289
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1,140 @@
1
+ /**
2
+ * — `pugi vim` top-level command + REPL slash
3
+ * companion.
4
+ *
5
+ * Operator surface:
6
+ *
7
+ * pugi vim Show current vim-mode state.
8
+ * pugi vim on Enable + persist (~/.pugi/config.json).
9
+ * pugi vim off Disable + persist (default).
10
+ * /vim Toggle from inside the REPL.
11
+ * /vim on Enable from inside the REPL.
12
+ * /vim off Disable from inside the REPL.
13
+ *
14
+ * The same runner backs both surfaces so the slash + the shell verb
15
+ * stay single-sourced — operators trained on one read the same
16
+ * payload + banner on the other.
17
+ *
18
+ * Exit codes:
19
+ * 0 — show / enable / disable / toggle happy path
20
+ * 2 — unknown subcommand (e.g. `pugi vim chaos`)
21
+ *
22
+ * NOTE: there are NO `--persist` flag and no workspace tier. Vim mode
23
+ * is a single user-level preference, matching the upstream behavior note
24
+ * that operators expect modal editing to be a body-memory trait, not
25
+ * a per-repo concern (see `core/vim/state.ts` header).
26
+ */
27
+ import { resolveVimMode, setVimMode } from '../../core/vim/state.js';
28
+ /**
29
+ * Banner shown on enable so the operator can see the binding cheat
30
+ * sheet without reaching for `/help`. Echoed by both surfaces.
31
+ */
32
+ export const VIM_ENABLED_BANNER = 'Vim mode on. Esc=normal, i=insert, :w=submit, :q=cancel.';
33
+ /**
34
+ * Entry point. Parses `args`, flips persistence as needed, emits the
35
+ * payload + text via `ctx.writeOutput`, and returns the exit code.
36
+ */
37
+ export async function runVimCommand(args, ctx) {
38
+ // Validate args before reading state so a bad call never has a
39
+ // side-effect.
40
+ if (args.length > 1) {
41
+ const payload = {
42
+ command: 'vim',
43
+ status: 'invalid_args',
44
+ active: resolveVimMode({ env: ctx.env }),
45
+ message: `pugi vim takes at most one argument (on / off / toggle). Got: ${args.join(' ')}`,
46
+ attemptedArg: args.join(' '),
47
+ };
48
+ ctx.writeOutput(payload, payload.message);
49
+ return 2;
50
+ }
51
+ const current = resolveVimMode({ env: ctx.env });
52
+ const verb = args[0]?.toLowerCase() ?? '';
53
+ // No args → toggle (slash convention from the upstream behavior ). The
54
+ // CLI shell surface ALSO toggles on bare invocation so the two
55
+ // surfaces converge; if the operator wants the read-only show they
56
+ // can pipe through `pugi vim --json` or query the config directly.
57
+ // We surface the change as a `show` status when nothing flipped so
58
+ // scripts can distinguish read from write.
59
+ if (verb === '') {
60
+ const next = !current;
61
+ setVimMode(next, { env: ctx.env });
62
+ const status = next ? 'enabled' : 'disabled';
63
+ const message = next ? VIM_ENABLED_BANNER : 'Vim mode off.';
64
+ const payload = {
65
+ command: 'vim',
66
+ status,
67
+ active: next,
68
+ previous: current,
69
+ message,
70
+ };
71
+ ctx.writeOutput(payload, payload.message);
72
+ return 0;
73
+ }
74
+ if (verb === 'on' || verb === 'enable' || verb === 'true') {
75
+ if (current) {
76
+ const payload = {
77
+ command: 'vim',
78
+ status: 'unchanged',
79
+ active: true,
80
+ previous: true,
81
+ message: 'Vim mode already on.',
82
+ };
83
+ ctx.writeOutput(payload, payload.message);
84
+ return 0;
85
+ }
86
+ setVimMode(true, { env: ctx.env });
87
+ const payload = {
88
+ command: 'vim',
89
+ status: 'enabled',
90
+ active: true,
91
+ previous: current,
92
+ message: VIM_ENABLED_BANNER,
93
+ };
94
+ ctx.writeOutput(payload, payload.message);
95
+ return 0;
96
+ }
97
+ if (verb === 'off' || verb === 'disable' || verb === 'false') {
98
+ if (!current) {
99
+ const payload = {
100
+ command: 'vim',
101
+ status: 'unchanged',
102
+ active: false,
103
+ previous: false,
104
+ message: 'Vim mode already off.',
105
+ };
106
+ ctx.writeOutput(payload, payload.message);
107
+ return 0;
108
+ }
109
+ setVimMode(false, { env: ctx.env });
110
+ const payload = {
111
+ command: 'vim',
112
+ status: 'disabled',
113
+ active: false,
114
+ previous: current,
115
+ message: 'Vim mode off.',
116
+ };
117
+ ctx.writeOutput(payload, payload.message);
118
+ return 0;
119
+ }
120
+ if (verb === 'status' || verb === 'show') {
121
+ const payload = {
122
+ command: 'vim',
123
+ status: 'show',
124
+ active: current,
125
+ message: current ? 'Vim mode is on.' : 'Vim mode is off.',
126
+ };
127
+ ctx.writeOutput(payload, payload.message);
128
+ return 0;
129
+ }
130
+ const payload = {
131
+ command: 'vim',
132
+ status: 'invalid_args',
133
+ active: current,
134
+ message: `Unknown vim subcommand "${verb}". Try one of: on, off, status.`,
135
+ attemptedArg: verb,
136
+ };
137
+ ctx.writeOutput(payload, payload.message);
138
+ return 2;
139
+ }
140
+ //# sourceMappingURL=vim.js.map
@@ -1,11 +1,11 @@
1
1
  /**
2
- * `pugi worktree <op>` — α7.7 Phase 1.
2
+ * `pugi worktree <op>` — Phase 1.
3
3
  *
4
4
  * Manual control over the scratch worktree primitive. Three subcommands:
5
5
  *
6
- * pugi worktree create [branch] # spawns `.pugi/worktrees/<uuid>`
7
- * pugi worktree promote <path> # applies the worktree's diff back to cwd
8
- * pugi worktree drop <path> # removes the worktree (idempotent)
6
+ * pugi worktree create [branch] # spawns `.pugi/worktrees/<uuid>`
7
+ * pugi worktree promote <path> # applies the worktree's diff back to cwd
8
+ * pugi worktree drop <path> # removes the worktree (idempotent)
9
9
  *
10
10
  * Output: human-readable by default, structured JSON under --json so
11
11
  * scripted callers can chain (`pugi worktree create --json | jq .path`).
@@ -20,7 +20,7 @@ import { spawnSync } from 'node:child_process';
20
20
  import { resolve, sep } from 'node:path';
21
21
  import { createWorktree, dropWorktree, promoteWorktree } from '../../core/edits/worktree.js';
22
22
  /**
23
- * R1 fix (2026-05-26, PR #413 r1, P2 #10): operator-facing path
23
+ * R1 fix (2026-05-26, PR r1, P2 #10): operator-facing path
24
24
  * validation. The core `promoteWorktree` / `dropWorktree` primitives
25
25
  * already gate their inputs, but mirroring the check at the CLI surface
26
26
  * gives the operator a clean error message before we even attempt the
@@ -168,9 +168,9 @@ function usage() {
168
168
  return {
169
169
  ok: false,
170
170
  text: 'Usage: pugi worktree <op>\n' +
171
- ' pugi worktree create [branch]\n' +
172
- ' pugi worktree promote <path>\n' +
173
- ' pugi worktree drop <path>',
171
+ ' pugi worktree create [branch]\n' +
172
+ ' pugi worktree promote <path>\n' +
173
+ ' pugi worktree drop <path>',
174
174
  exitCode: 2,
175
175
  };
176
176
  }