@pugi/cli 0.1.0-beta.99 → 1.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +11 -191
  3. package/bin/pugi +8 -0
  4. package/package.json +15 -71
  5. package/postinstall.mjs +31 -0
  6. package/CHANGELOG.md +0 -132
  7. package/THIRD_PARTY_NOTICES.md +0 -40
  8. package/assets/pugi-mascot.ansi +0 -16
  9. package/assets/pugi-prozr2-mascot.ansi +0 -9
  10. package/bin/run.js +0 -34
  11. package/dist/commands/deploy.js +0 -439
  12. package/dist/commands/flatten.js +0 -191
  13. package/dist/commands/jobs-watch.js +0 -201
  14. package/dist/commands/jobs.js +0 -260
  15. package/dist/commands/retro.js +0 -210
  16. package/dist/commands/smoke.js +0 -133
  17. package/dist/core/agent-progress/cleanup.js +0 -134
  18. package/dist/core/agent-progress/schema.js +0 -144
  19. package/dist/core/agent-progress/writer.js +0 -101
  20. package/dist/core/agents/adaptive-router.js +0 -330
  21. package/dist/core/agents/loader.js +0 -104
  22. package/dist/core/agents/query-decomposer.js +0 -297
  23. package/dist/core/agents/registry.js +0 -69
  24. package/dist/core/approvals/shortcut-resolver.js +0 -98
  25. package/dist/core/artifact-chain/dispatcher.js +0 -148
  26. package/dist/core/artifact-chain/exporter.js +0 -164
  27. package/dist/core/artifact-chain/state.js +0 -243
  28. package/dist/core/artifact-chain/steps.js +0 -169
  29. package/dist/core/ask-user/question.js +0 -92
  30. package/dist/core/audit/audit-trail.js +0 -275
  31. package/dist/core/auth/ensure-authenticated.js +0 -129
  32. package/dist/core/auth/env-provider.js +0 -238
  33. package/dist/core/auto-open-browser.js +0 -128
  34. package/dist/core/auto-update/channels.js +0 -122
  35. package/dist/core/auto-update/checker.js +0 -241
  36. package/dist/core/auto-update/state.js +0 -235
  37. package/dist/core/bare-mode/index.js +0 -107
  38. package/dist/core/bash/redirect.js +0 -281
  39. package/dist/core/bash-classifier.js +0 -1397
  40. package/dist/core/checkpoint/resumer.js +0 -149
  41. package/dist/core/checkpoint/rewinder.js +0 -291
  42. package/dist/core/checkpoints/shadow-git.js +0 -670
  43. package/dist/core/citations/parser.js +0 -109
  44. package/dist/core/classifier/yolo-classifier.js +0 -88
  45. package/dist/core/clipboard.js +0 -70
  46. package/dist/core/codegraph/decision-store.js +0 -248
  47. package/dist/core/codegraph/detect-repo.js +0 -459
  48. package/dist/core/codegraph/install.js +0 -134
  49. package/dist/core/codegraph/offer-hook.js +0 -220
  50. package/dist/core/compact/auto-trigger.js +0 -96
  51. package/dist/core/compact/buffer-rewriter.js +0 -115
  52. package/dist/core/compact/summarizer.js +0 -208
  53. package/dist/core/compact/token-counter.js +0 -108
  54. package/dist/core/consensus/anvil-fanout.js +0 -276
  55. package/dist/core/consensus/diff-capture.js +0 -491
  56. package/dist/core/consensus/rubric.js +0 -233
  57. package/dist/core/context/builder.js +0 -114
  58. package/dist/core/context/compaction-events.js +0 -99
  59. package/dist/core/context/compaction.js +0 -602
  60. package/dist/core/context/index.js +0 -28
  61. package/dist/core/context/invariants.js +0 -250
  62. package/dist/core/context/markdown-loader.js +0 -288
  63. package/dist/core/context/markdown-traverse.js +0 -255
  64. package/dist/core/context/pugiignore.js +0 -316
  65. package/dist/core/context/repo-skeleton.js +0 -533
  66. package/dist/core/context/tool-eviction.js +0 -55
  67. package/dist/core/context/watcher.js +0 -342
  68. package/dist/core/context/working-set.js +0 -165
  69. package/dist/core/coordinator/agent-tools.js +0 -77
  70. package/dist/core/coordinator/agent-toolset.js +0 -65
  71. package/dist/core/coordinator/fsm.js +0 -73
  72. package/dist/core/coordinator/mode-fsm.js +0 -70
  73. package/dist/core/cost/rate-card.js +0 -129
  74. package/dist/core/cost/tracker.js +0 -221
  75. package/dist/core/credentials.js +0 -355
  76. package/dist/core/cron/scheduler.js +0 -138
  77. package/dist/core/denial-tracking/index.js +0 -8
  78. package/dist/core/denial-tracking/state.js +0 -264
  79. package/dist/core/diagnostics/probe-runner.js +0 -93
  80. package/dist/core/diagnostics/probes/api.js +0 -46
  81. package/dist/core/diagnostics/probes/auth.js +0 -93
  82. package/dist/core/diagnostics/probes/bare-mode.js +0 -42
  83. package/dist/core/diagnostics/probes/cli-version.js +0 -127
  84. package/dist/core/diagnostics/probes/config.js +0 -72
  85. package/dist/core/diagnostics/probes/denial-tracking.js +0 -57
  86. package/dist/core/diagnostics/probes/disk.js +0 -81
  87. package/dist/core/diagnostics/probes/engine-live.js +0 -46
  88. package/dist/core/diagnostics/probes/git.js +0 -65
  89. package/dist/core/diagnostics/probes/hooks.js +0 -118
  90. package/dist/core/diagnostics/probes/mcp.js +0 -75
  91. package/dist/core/diagnostics/probes/node.js +0 -59
  92. package/dist/core/diagnostics/probes/pnpm.js +0 -36
  93. package/dist/core/diagnostics/probes/pugi-md.js +0 -89
  94. package/dist/core/diagnostics/probes/sandbox.js +0 -72
  95. package/dist/core/diagnostics/probes/session.js +0 -74
  96. package/dist/core/diagnostics/probes/status-snapshot.js +0 -488
  97. package/dist/core/diagnostics/probes/workspace.js +0 -63
  98. package/dist/core/diagnostics/types.js +0 -70
  99. package/dist/core/dispatch/cache-cleanup.js +0 -197
  100. package/dist/core/dispatch/cache-handoff.js +0 -295
  101. package/dist/core/edits/apply-patch-layer-e.js +0 -189
  102. package/dist/core/edits/dispatch.js +0 -511
  103. package/dist/core/edits/format-detector.js +0 -260
  104. package/dist/core/edits/format-matrix.js +0 -26
  105. package/dist/core/edits/fuzzy-ladder.js +0 -650
  106. package/dist/core/edits/index.js +0 -19
  107. package/dist/core/edits/journal.js +0 -199
  108. package/dist/core/edits/layer-a-apply.js +0 -217
  109. package/dist/core/edits/layer-a-fuzzy-apply.js +0 -198
  110. package/dist/core/edits/layer-b-apply.js +0 -211
  111. package/dist/core/edits/layer-c-apply.js +0 -160
  112. package/dist/core/edits/layer-d-ast.js +0 -572
  113. package/dist/core/edits/marker-parser.js +0 -401
  114. package/dist/core/edits/security-gate.js +0 -223
  115. package/dist/core/edits/verify-hook.js +0 -273
  116. package/dist/core/edits/worktree.js +0 -322
  117. package/dist/core/engine/adapter-runner.js +0 -8
  118. package/dist/core/engine/anvil-client.js +0 -344
  119. package/dist/core/engine/auto-compact.js +0 -179
  120. package/dist/core/engine/budgets.js +0 -195
  121. package/dist/core/engine/context-prefix.js +0 -155
  122. package/dist/core/engine/index.js +0 -12
  123. package/dist/core/engine/intensity.js +0 -163
  124. package/dist/core/engine/intent.js +0 -260
  125. package/dist/core/engine/native-pugi.js +0 -1616
  126. package/dist/core/engine/noop.js +0 -27
  127. package/dist/core/engine/prompts.js +0 -236
  128. package/dist/core/engine/strip-internal-fields.js +0 -124
  129. package/dist/core/engine/tool-bridge.js +0 -2173
  130. package/dist/core/engine/verification-patterns.js +0 -195
  131. package/dist/core/evaluation/golden-dataset.js +0 -293
  132. package/dist/core/feedback/queue.js +0 -177
  133. package/dist/core/feedback/submitter.js +0 -145
  134. package/dist/core/file-cache.js +0 -141
  135. package/dist/core/flatten/flatten-repo.js +0 -439
  136. package/dist/core/format/osc8-link.js +0 -28
  137. package/dist/core/hook-chains.js +0 -392
  138. package/dist/core/hooks/citation-verify-hook.js +0 -138
  139. package/dist/core/hooks/citation-verify.js +0 -112
  140. package/dist/core/hooks/events.js +0 -46
  141. package/dist/core/hooks/index.js +0 -15
  142. package/dist/core/hooks/registry.js +0 -216
  143. package/dist/core/hooks/runner.js +0 -236
  144. package/dist/core/hooks/v2/event-emitter.js +0 -115
  145. package/dist/core/hooks/v2/executor.js +0 -282
  146. package/dist/core/hooks/v2/index.js +0 -25
  147. package/dist/core/hooks/v2/lifecycle.js +0 -104
  148. package/dist/core/hooks/v2/loader.js +0 -216
  149. package/dist/core/hooks/v2/matcher.js +0 -125
  150. package/dist/core/hooks/v2/trust.js +0 -143
  151. package/dist/core/hooks/v2/types.js +0 -86
  152. package/dist/core/hooks/worktree-events.js +0 -158
  153. package/dist/core/hooks.js +0 -415
  154. package/dist/core/image/renderer.js +0 -71
  155. package/dist/core/index-store.js +0 -260
  156. package/dist/core/init/detector.js +0 -582
  157. package/dist/core/init/template-renderer.js +0 -242
  158. package/dist/core/jobs/registry.js +0 -462
  159. package/dist/core/ledger/results-tsv.js +0 -142
  160. package/dist/core/log-discipline/stdout-redirect.js +0 -51
  161. package/dist/core/lsp/cache.js +0 -105
  162. package/dist/core/lsp/client.js +0 -1229
  163. package/dist/core/lsp/language-detect.js +0 -66
  164. package/dist/core/lsp/post-edit-diagnostics.js +0 -171
  165. package/dist/core/lsp/server-detect.js +0 -173
  166. package/dist/core/lsp/symbol-cache.js +0 -162
  167. package/dist/core/lsp/symbol-tools.js +0 -664
  168. package/dist/core/mcp/client.js +0 -385
  169. package/dist/core/mcp/http-server.js +0 -553
  170. package/dist/core/mcp/orchestrator-config.js +0 -192
  171. package/dist/core/mcp/orchestrator-tools.js +0 -806
  172. package/dist/core/mcp/permission.js +0 -190
  173. package/dist/core/mcp/registry.js +0 -193
  174. package/dist/core/mcp/server-tools.js +0 -219
  175. package/dist/core/mcp/server.js +0 -397
  176. package/dist/core/mcp/trust.js +0 -91
  177. package/dist/core/memory/dual-write.js +0 -416
  178. package/dist/core/memory/passive-extract.js +0 -130
  179. package/dist/core/memory/phase1-kinds.js +0 -20
  180. package/dist/core/memory/secret-scanner.js +0 -304
  181. package/dist/core/memory-sync/queue.js +0 -170
  182. package/dist/core/metrics/extract.js +0 -113
  183. package/dist/core/modes/roo-modes.js +0 -68
  184. package/dist/core/onboarding/ensure-initialized.js +0 -133
  185. package/dist/core/onboarding/marker.js +0 -111
  186. package/dist/core/onboarding/telemetry-state.js +0 -108
  187. package/dist/core/output-style/presets.js +0 -176
  188. package/dist/core/output-style/state.js +0 -185
  189. package/dist/core/path-security.js +0 -345
  190. package/dist/core/permission.js +0 -369
  191. package/dist/core/permissions/auto-classifier.js +0 -124
  192. package/dist/core/permissions/bash-parser.js +0 -371
  193. package/dist/core/permissions/circuit-breaker.js +0 -83
  194. package/dist/core/permissions/constrained-edit.js +0 -91
  195. package/dist/core/permissions/gate.js +0 -278
  196. package/dist/core/permissions/index.js +0 -20
  197. package/dist/core/permissions/mode.js +0 -174
  198. package/dist/core/permissions/network-egress.js +0 -137
  199. package/dist/core/permissions/state.js +0 -241
  200. package/dist/core/permissions/tool-class.js +0 -107
  201. package/dist/core/plan-mode/ui-state.js +0 -51
  202. package/dist/core/plans/plan-artifact.js +0 -721
  203. package/dist/core/policy-limits/etag-store.js +0 -122
  204. package/dist/core/prd-check/parser.js +0 -215
  205. package/dist/core/prd-check/reporter.js +0 -127
  206. package/dist/core/prd-check/session-review.js +0 -557
  207. package/dist/core/prd-check/verifiers.js +0 -223
  208. package/dist/core/prompt-cache/client-cache.js +0 -99
  209. package/dist/core/prompts/assembly.js +0 -29
  210. package/dist/core/prompts/registry.js +0 -364
  211. package/dist/core/pugi-gitignore.js +0 -52
  212. package/dist/core/pugi-md/cc-compat-rules.js +0 -735
  213. package/dist/core/pugi-md/context-injector.js +0 -76
  214. package/dist/core/pugi-md/walk-up.js +0 -207
  215. package/dist/core/python/uv-installer.js +0 -270
  216. package/dist/core/python/uv-resolver.js +0 -83
  217. package/dist/core/rate-limit/narrator.js +0 -146
  218. package/dist/core/recipes/cli-types.js +0 -20
  219. package/dist/core/recipes/loader.js +0 -103
  220. package/dist/core/recipes/runner.js +0 -345
  221. package/dist/core/recipes/schema.js +0 -587
  222. package/dist/core/release-notes/parser.js +0 -241
  223. package/dist/core/release-notes/state.js +0 -116
  224. package/dist/core/repl/ask.js +0 -512
  225. package/dist/core/repl/cancellation.js +0 -98
  226. package/dist/core/repl/cap-warning.js +0 -91
  227. package/dist/core/repl/clipboard-read.js +0 -174
  228. package/dist/core/repl/dispatch-fsm.js +0 -220
  229. package/dist/core/repl/engine-bridge.js +0 -303
  230. package/dist/core/repl/history-search.js +0 -175
  231. package/dist/core/repl/history.js +0 -182
  232. package/dist/core/repl/kill-ring.js +0 -138
  233. package/dist/core/repl/model-pricing.js +0 -135
  234. package/dist/core/repl/privacy-banner.js +0 -71
  235. package/dist/core/repl/session.js +0 -4962
  236. package/dist/core/repl/slash-commands.js +0 -747
  237. package/dist/core/repl/store/index.js +0 -12
  238. package/dist/core/repl/store/jsonl-log.js +0 -321
  239. package/dist/core/repl/store/lockfile.js +0 -155
  240. package/dist/core/repl/store/session-store.js +0 -821
  241. package/dist/core/repl/store/types.js +0 -44
  242. package/dist/core/repl/store/uuid-v7.js +0 -68
  243. package/dist/core/repl/tool-route.js +0 -382
  244. package/dist/core/repl/workspace-context.js +0 -206
  245. package/dist/core/repo-map/build.js +0 -125
  246. package/dist/core/repo-map/cache.js +0 -185
  247. package/dist/core/repo-map/extractor.js +0 -254
  248. package/dist/core/repo-map/formatter.js +0 -145
  249. package/dist/core/repo-map/page-rank.js +0 -105
  250. package/dist/core/repo-map/scanner.js +0 -211
  251. package/dist/core/retro/git-collector.js +0 -251
  252. package/dist/core/retro/health-card.js +0 -25
  253. package/dist/core/retro/metrics.js +0 -342
  254. package/dist/core/retro/narrative.js +0 -249
  255. package/dist/core/retro/plane-collector.js +0 -274
  256. package/dist/core/retro/pr-issue-link.js +0 -65
  257. package/dist/core/retro/types.js +0 -16
  258. package/dist/core/retry-budget/budget.js +0 -284
  259. package/dist/core/retry-budget/index.js +0 -5
  260. package/dist/core/retry-budget/retry-cap.js +0 -74
  261. package/dist/core/routing/lead-worker.js +0 -43
  262. package/dist/core/routing/pre-flight-estimator.js +0 -108
  263. package/dist/core/runs/run-tree.js +0 -103
  264. package/dist/core/sandboxing/adapter.js +0 -29
  265. package/dist/core/sandboxing/index.js +0 -49
  266. package/dist/core/sandboxing/none.js +0 -19
  267. package/dist/core/sandboxing/seatbelt.js +0 -183
  268. package/dist/core/security/injection-scanner.js +0 -367
  269. package/dist/core/security/output-filter.js +0 -418
  270. package/dist/core/session/env-file.js +0 -105
  271. package/dist/core/session/section-budgets.js +0 -140
  272. package/dist/core/session.js +0 -377
  273. package/dist/core/settings.js +0 -400
  274. package/dist/core/share/formatter.js +0 -271
  275. package/dist/core/share/redactor.js +0 -221
  276. package/dist/core/share/uploader.js +0 -267
  277. package/dist/core/skills/defaults.js +0 -457
  278. package/dist/core/skills/loader.js +0 -454
  279. package/dist/core/skills/sources.js +0 -480
  280. package/dist/core/skills/trust.js +0 -172
  281. package/dist/core/smoke/headless-driver.js +0 -174
  282. package/dist/core/smoke/orchestrator.js +0 -194
  283. package/dist/core/smoke/runner.js +0 -238
  284. package/dist/core/smoke/scenario-parser.js +0 -316
  285. package/dist/core/statusline.js +0 -99
  286. package/dist/core/subagents/dispatcher-real.js +0 -600
  287. package/dist/core/subagents/dispatcher.js +0 -352
  288. package/dist/core/subagents/index.js +0 -39
  289. package/dist/core/subagents/isolation-matrix.js +0 -213
  290. package/dist/core/subagents/spawn.js +0 -101
  291. package/dist/core/telemetry/emitter.js +0 -229
  292. package/dist/core/telemetry/queue.js +0 -251
  293. package/dist/core/theme/context.js +0 -91
  294. package/dist/core/theme/presets.js +0 -228
  295. package/dist/core/theme/state.js +0 -181
  296. package/dist/core/todos/invariant.js +0 -10
  297. package/dist/core/todos/state.js +0 -177
  298. package/dist/core/tool-schema/compressor.js +0 -89
  299. package/dist/core/transport/version-interceptor.js +0 -166
  300. package/dist/core/trust.js +0 -109
  301. package/dist/core/tui/thinking-block.js +0 -64
  302. package/dist/core/vim/keymap.js +0 -288
  303. package/dist/core/vim/state.js +0 -92
  304. package/dist/core/watch-markers/marker-watcher.js +0 -133
  305. package/dist/core/worktree/include-parser.js +0 -249
  306. package/dist/core/worktree-manager/cleanup.js +0 -123
  307. package/dist/core/worktree-manager/manager.js +0 -303
  308. package/dist/index.js +0 -44
  309. package/dist/runtime/bootstrap.js +0 -190
  310. package/dist/runtime/cli.js +0 -8121
  311. package/dist/runtime/commands/agents.js +0 -385
  312. package/dist/runtime/commands/budget.js +0 -192
  313. package/dist/runtime/commands/cancel.js +0 -231
  314. package/dist/runtime/commands/chain.js +0 -489
  315. package/dist/runtime/commands/codegraph-status.js +0 -227
  316. package/dist/runtime/commands/compact.js +0 -297
  317. package/dist/runtime/commands/config.js +0 -595
  318. package/dist/runtime/commands/cost.js +0 -199
  319. package/dist/runtime/commands/delegate.js +0 -312
  320. package/dist/runtime/commands/dispatch.js +0 -126
  321. package/dist/runtime/commands/doctor.js +0 -579
  322. package/dist/runtime/commands/feedback.js +0 -184
  323. package/dist/runtime/commands/hooks.js +0 -187
  324. package/dist/runtime/commands/init.js +0 -254
  325. package/dist/runtime/commands/lsp.js +0 -368
  326. package/dist/runtime/commands/mcp.js +0 -935
  327. package/dist/runtime/commands/memory.js +0 -582
  328. package/dist/runtime/commands/model.js +0 -237
  329. package/dist/runtime/commands/onboarding.js +0 -275
  330. package/dist/runtime/commands/patch.js +0 -128
  331. package/dist/runtime/commands/permissions.js +0 -112
  332. package/dist/runtime/commands/plan.js +0 -143
  333. package/dist/runtime/commands/prd-check.js +0 -285
  334. package/dist/runtime/commands/privacy.js +0 -107
  335. package/dist/runtime/commands/recipe.js +0 -325
  336. package/dist/runtime/commands/redo-blob-store.js +0 -92
  337. package/dist/runtime/commands/redo.js +0 -361
  338. package/dist/runtime/commands/release-notes.js +0 -229
  339. package/dist/runtime/commands/repo-map.js +0 -95
  340. package/dist/runtime/commands/report.js +0 -299
  341. package/dist/runtime/commands/resume.js +0 -118
  342. package/dist/runtime/commands/review-consensus.js +0 -414
  343. package/dist/runtime/commands/rewind.js +0 -333
  344. package/dist/runtime/commands/roster.js +0 -117
  345. package/dist/runtime/commands/sessions.js +0 -163
  346. package/dist/runtime/commands/share.js +0 -316
  347. package/dist/runtime/commands/skills.js +0 -401
  348. package/dist/runtime/commands/status.js +0 -186
  349. package/dist/runtime/commands/stickers.js +0 -82
  350. package/dist/runtime/commands/style.js +0 -194
  351. package/dist/runtime/commands/theme.js +0 -196
  352. package/dist/runtime/commands/undo.js +0 -361
  353. package/dist/runtime/commands/update.js +0 -289
  354. package/dist/runtime/commands/vim.js +0 -140
  355. package/dist/runtime/commands/worktree.js +0 -177
  356. package/dist/runtime/commands/worktrees.js +0 -155
  357. package/dist/runtime/deprecation-warning.js +0 -69
  358. package/dist/runtime/engine-exit-code.js +0 -50
  359. package/dist/runtime/headless-repl.js +0 -195
  360. package/dist/runtime/headless.js +0 -548
  361. package/dist/runtime/load-hooks-or-exit.js +0 -71
  362. package/dist/runtime/plan-decompose.js +0 -531
  363. package/dist/runtime/sigint-guard.js +0 -272
  364. package/dist/runtime/stream-renderer.js +0 -195
  365. package/dist/runtime/update-check.js +0 -294
  366. package/dist/runtime/version.js +0 -65
  367. package/dist/runtime/worktree-bootstrap.js +0 -579
  368. package/dist/skills/bundled/batch.js +0 -617
  369. package/dist/skills/bundled/index.js +0 -45
  370. package/dist/skills/bundled/loop.js +0 -358
  371. package/dist/skills/bundled/remember.js +0 -383
  372. package/dist/skills/bundled/simplify.js +0 -289
  373. package/dist/skills/bundled/skillify.js +0 -373
  374. package/dist/skills/bundled/stuck.js +0 -558
  375. package/dist/skills/bundled/verify.js +0 -439
  376. package/dist/testing/vcr.js +0 -486
  377. package/dist/tools/agent-tool.js +0 -229
  378. package/dist/tools/apply-patch.js +0 -556
  379. package/dist/tools/ask-user-question.js +0 -337
  380. package/dist/tools/ask-user.js +0 -115
  381. package/dist/tools/bash.js +0 -1238
  382. package/dist/tools/brief.js +0 -224
  383. package/dist/tools/cron.js +0 -433
  384. package/dist/tools/enter-worktree.js +0 -250
  385. package/dist/tools/exit-worktree.js +0 -147
  386. package/dist/tools/file-tools.js +0 -553
  387. package/dist/tools/http-request.js +0 -336
  388. package/dist/tools/lsp-tools.js +0 -565
  389. package/dist/tools/mcp-tool.js +0 -260
  390. package/dist/tools/multi-edit.js +0 -361
  391. package/dist/tools/powershell.js +0 -268
  392. package/dist/tools/registry.js +0 -166
  393. package/dist/tools/server-tools.js +0 -892
  394. package/dist/tools/skill-tool.js +0 -96
  395. package/dist/tools/sleep.js +0 -99
  396. package/dist/tools/synthetic-output.js +0 -133
  397. package/dist/tools/tasks.js +0 -208
  398. package/dist/tools/todo-write.js +0 -184
  399. package/dist/tools/verify-plan-execution.js +0 -295
  400. package/dist/tools/web-fetch-injection-scanner.js +0 -207
  401. package/dist/tools/web-fetch.js +0 -720
  402. package/dist/tools/web-search.js +0 -458
  403. package/dist/tui/agent-progress-card.js +0 -111
  404. package/dist/tui/agent-tree-pane.js +0 -9
  405. package/dist/tui/agent-tree.js +0 -87
  406. package/dist/tui/ask-cli.js +0 -52
  407. package/dist/tui/ask-modal.js +0 -211
  408. package/dist/tui/ask-user-question-chips.js +0 -315
  409. package/dist/tui/ask-user-question-prompt.js +0 -203
  410. package/dist/tui/compact-banner.js +0 -81
  411. package/dist/tui/conversation-pane.js +0 -164
  412. package/dist/tui/cost-table.js +0 -111
  413. package/dist/tui/device-flow.js +0 -142
  414. package/dist/tui/doctor-table.js +0 -46
  415. package/dist/tui/feedback-prompt.js +0 -156
  416. package/dist/tui/input-box.js +0 -732
  417. package/dist/tui/login-picker.js +0 -69
  418. package/dist/tui/markdown-render.js +0 -266
  419. package/dist/tui/multi-file-diff-approval.js +0 -375
  420. package/dist/tui/onboarding-wizard.js +0 -240
  421. package/dist/tui/permissions-picker.js +0 -86
  422. package/dist/tui/render.js +0 -160
  423. package/dist/tui/repl-render.js +0 -770
  424. package/dist/tui/repl-splash-art.js +0 -64
  425. package/dist/tui/repl-splash-mascot.js +0 -154
  426. package/dist/tui/repl-splash.js +0 -117
  427. package/dist/tui/repl.js +0 -378
  428. package/dist/tui/slash-palette.js +0 -106
  429. package/dist/tui/splash-data.js +0 -61
  430. package/dist/tui/splash.js +0 -31
  431. package/dist/tui/status-bar.js +0 -209
  432. package/dist/tui/status-table.js +0 -7
  433. package/dist/tui/stickers-art.js +0 -136
  434. package/dist/tui/style-table.js +0 -28
  435. package/dist/tui/theme-table.js +0 -29
  436. package/dist/tui/thinking-spinner.js +0 -123
  437. package/dist/tui/tool-stream-pane.js +0 -140
  438. package/dist/tui/update-banner.js +0 -33
  439. package/dist/tui/vim-input.js +0 -267
  440. package/dist/tui/welcome-banner.js +0 -107
  441. package/dist/tui/welcome-data.js +0 -293
  442. package/dist/tui/workspace-context.js +0 -105
  443. package/docs/examples/codegraph.mcp.json +0 -10
  444. package/test/scenarios/codegen-create-file.scenario.txt +0 -13
  445. package/test/scenarios/compact-force.scenario.txt +0 -12
  446. package/test/scenarios/identity.scenario.txt +0 -11
  447. package/test/scenarios/persona-handoff.scenario.txt +0 -12
  448. package/test/scenarios/walkback.scenario.txt +0 -12
@@ -1,595 +0,0 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
- import { homedir } from 'node:os';
3
- import { dirname, resolve } from 'node:path';
4
- import { z } from 'zod';
5
- import { loadMcpRegistry } from '../../core/mcp/registry.js';
6
- import { listMcpTrust, setMcpTrust, } from '../../core/mcp/trust.js';
7
- import { request } from 'undici';
8
- import { trustWorkspace } from '../../core/trust.js';
9
- import { resolveActiveCredential } from '../../core/credentials.js';
10
- /**
11
- * `pugi config` — operator-level configuration surface.
12
- *
13
- * Subcommands:
14
- * - `pugi config get <key>` read a value from `~/.pugi/config.json`
15
- * - `pugi config set <key> <value>` write a value
16
- * - `pugi config list` dump all values
17
- * - `pugi config trust .` trust the current workspace (delegates to core/trust.ts)
18
- * - `pugi config mcp trust <name>` flip MCP server to trusted
19
- * - `pugi config mcp deny <name>` flip MCP server to denied
20
- * - `pugi config mcp list` show declared servers + their trust state
21
- *
22
- * Schema (pugi-config-v1):
23
- * {
24
- * "permissionMode": "ask" | "acceptEdits" | "auto" | "plan" | "dontAsk" | "bypassPermissions",
25
- * "privacy": "local-only" | "metadata" | "full",
26
- * "model": "<id>" | null,
27
- * "preferredEndpoint": "https://api.pugi.io"
28
- * }
29
- *
30
- * The config file lives at `~/.pugi/config.json` (PUGI_HOME-aware) and uses
31
- * mode 0o600. Unknown keys are rejected by `set` so a typo never silently
32
- * persists.
33
- */
34
- const configSchema = z
35
- .object({
36
- permissionMode: z
37
- .enum(['plan', 'ask', 'acceptEdits', 'auto', 'dontAsk', 'bypassPermissions'])
38
- .optional(),
39
- privacy: z.enum(['local-only', 'metadata', 'full']).optional(),
40
- model: z.string().nullable().optional(),
41
- preferredEndpoint: z.string().url().optional(),
42
- // PUGI-260 — persistent default for the 1M context tier opt-in.
43
- // `pugi config set contextTier 1m` (or the dotted form
44
- // `context.tier 1m`) writes this; per-invocation `--context-tier=...`
45
- // flags override it at request time. Closed enum mirrors the CLI
46
- // flag и the admin-api DTO so a typo here surfaces as a Zod parse
47
- // error при load, not a silent fallback. Stored on the flat user-
48
- // level config (~/.pugi/config.json) so all workspaces inherit the
49
- // same default — operators с consistent long-context workloads
50
- // (large monorepos, audits) set it once instead of remembering к
51
- // pass --context-tier=1m on every dispatch.
52
- contextTier: z.enum(['1m', 'standard']).optional(),
53
- })
54
- .strict();
55
- const CONFIG_KEYS = [
56
- 'permissionMode',
57
- 'privacy',
58
- 'model',
59
- 'preferredEndpoint',
60
- // PUGI-260 — exposed на `pugi config list` so operators see the
61
- // current default. Hidden synonym `context.tier` accepted by
62
- // runConfigSet / runConfigGet for a dotted-key familiar UX.
63
- 'contextTier',
64
- ];
65
- /**
66
- * PUGI-260: legacy / nested key aliasing. `pugi config set context.tier 1m`
67
- * is the documented form в the feat doc; we normalise it onto the flat
68
- * `contextTier` key before the strict-schema validation так future
69
- * settings.json migrations keep one canonical key. Mirrors the
70
- * legacy privacy-mode aliasing that already lives in the file.
71
- */
72
- function normaliseConfigKey(raw) {
73
- if (raw === 'context.tier')
74
- return 'contextTier';
75
- return raw;
76
- }
77
- export async function runConfigCommand(args, ctx) {
78
- const sub = args[0];
79
- if (!sub || sub === '--help' || sub === '-h') {
80
- ctx.writeOutput({
81
- command: 'config',
82
- usage: [
83
- 'pugi config get <key>',
84
- 'pugi config set <key> <value>',
85
- 'pugi config list',
86
- 'pugi config trust .',
87
- 'pugi config mcp trust <name>',
88
- 'pugi config mcp deny <name>',
89
- 'pugi config mcp list',
90
- 'pugi config get routing',
91
- 'pugi config set routing.<tag>.<budget>=<model>',
92
- 'pugi config unset routing.<tag>.<budget>',
93
- 'pugi config get privacy',
94
- 'pugi config set privacy=strict|balanced|permissive',
95
- ],
96
- }, [
97
- 'Usage:',
98
- ' pugi config get <key> Read a config value.',
99
- ' pugi config set <key> <value> Write a config value.',
100
- ' pugi config list Show all config values.',
101
- ' pugi config trust . Trust the current workspace for hooks + MCP.',
102
- ' pugi config mcp trust <name> Mark an MCP server as trusted.',
103
- ' pugi config mcp deny <name> Block an MCP server.',
104
- ' pugi config mcp list Show declared MCP servers + trust state.',
105
- ' pugi config get routing Show effective routing table (defaults + tenant overrides).',
106
- ' pugi config set routing.<tag>.<budget>=<model> Override the model for one (tag, budget) lane.',
107
- ' pugi config unset routing.<tag>.<budget> Remove a routing override (revert to default).',
108
- ' pugi config get privacy Show current tenant privacy mode + last-flip metadata.',
109
- ' pugi config set privacy=<mode> Flip privacy mode (strict | balanced | permissive).',
110
- ].join('\n'));
111
- return;
112
- }
113
- switch (sub) {
114
- case 'get':
115
- // Special form: `pugi config get routing` hits the admin-api surface,
116
- // not the local config file. Anything else is a local-config read.
117
- if (args[1] === 'routing') {
118
- return runRoutingGet(ctx);
119
- }
120
- // alpha 6.13: `pugi config get privacy` hits the admin-api
121
- // /api/admin/privacy/mode surface. The privacy mode is a tenant-
122
- // scoped server-side setting (so the Anvil filter can enforce it),
123
- // not a local-only preference.
124
- if (args[1] === 'privacy') {
125
- return runPrivacyGet(ctx);
126
- }
127
- return runConfigGet(args.slice(1), ctx);
128
- case 'set':
129
- // Special form: `pugi config set routing.<tag>.<budget>=<model>` hits
130
- // the admin-api routing override surface.
131
- if (args[1] && args[1].startsWith('routing.')) {
132
- return runRoutingSet(args.slice(1), ctx);
133
- }
134
- // alpha 6.13: `pugi config set privacy=<mode>` (or `privacy <mode>`)
135
- // flips the tenant-scoped server-side mode IFF <mode> is one of
136
- // the new closed set (strict | balanced | permissive). Legacy
137
- // values (local-only | metadata | full) still hit the local
138
- // config schema via runConfigSet so existing operators do not
139
- // get a surprise 4xx when their playbook still uses the old
140
- // names. The unit spec for config.ts has a regression test for
141
- // both code paths.
142
- //
143
- // Triple-review P2 fix : the prior disambiguation
144
- // only excluded the bare form (`privacy local-only`) - the `=`
145
- // form (`privacy=local-only`) still routed to runPrivacySet and
146
- // 4xx'd. We now check the value AFTER `=` and route legacy local
147
- // values to runConfigSet; new-style values + unknown values
148
- // continue to runPrivacySet so its client-side validator surfaces
149
- // a structured "Unknown privacy mode" error (preserves the
150
- // existing UX for typos like `privacy=paranoid`).
151
- if (args[1]) {
152
- const equalsForm = args[1].startsWith('privacy=');
153
- const bareForm = args[1] === 'privacy';
154
- if (equalsForm) {
155
- const valueAfterEquals = args[1].slice('privacy='.length);
156
- if (isLegacyLocalPrivacyValue(valueAfterEquals)) {
157
- // Legacy local form (`privacy=local-only|metadata|full`) -
158
- // split into `['privacy', '<value>']` so runConfigSet sees
159
- // the same shape it would for the bare form.
160
- return runConfigSet(['privacy', valueAfterEquals], ctx);
161
- }
162
- return runPrivacySet(args.slice(1), ctx);
163
- }
164
- if (bareForm && isNewPrivacyModeValue(args[2])) {
165
- return runPrivacySet(args.slice(1), ctx);
166
- }
167
- }
168
- return runConfigSet(args.slice(1), ctx);
169
- case 'unset':
170
- if (args[1] && args[1].startsWith('routing.')) {
171
- return runRoutingUnset(args.slice(1), ctx);
172
- }
173
- throw new Error(`Unknown sub-command "pugi config unset ${args[1] ?? ''}". Only routing.<tag>.<budget> is supported today.`);
174
- case 'list':
175
- return runConfigList(ctx);
176
- case 'trust':
177
- return runConfigTrust(args.slice(1), ctx);
178
- case 'mcp':
179
- return runConfigMcp(args.slice(1), ctx);
180
- default:
181
- throw new Error(`Unknown sub-command "pugi config ${sub}". Expected get, set, unset, list, trust, or mcp.`);
182
- }
183
- }
184
- function configPath() {
185
- const home = process.env.PUGI_HOME ?? resolve(homedir(), '.pugi');
186
- return resolve(home, 'config.json');
187
- }
188
- export function readConfig() {
189
- const path = configPath();
190
- if (!existsSync(path))
191
- return {};
192
- const raw = readFileSync(path, 'utf8');
193
- if (raw.trim() === '')
194
- return {};
195
- const parsed = JSON.parse(raw);
196
- return configSchema.parse(parsed);
197
- }
198
- function writeConfig(config) {
199
- const path = configPath();
200
- mkdirSync(dirname(path), { recursive: true });
201
- // 0o600 — `preferredEndpoint` could be a private self-hosted URL; the
202
- // config does not contain secrets, but file mode parity with the trust
203
- // ledger keeps the audit surface uniform.
204
- writeFileSync(path, `${JSON.stringify(config, null, 2)}\n`, {
205
- encoding: 'utf8',
206
- mode: 0o600,
207
- });
208
- }
209
- function isConfigKey(value) {
210
- return CONFIG_KEYS.includes(value);
211
- }
212
- function runConfigGet(args, ctx) {
213
- const rawKey = args[0];
214
- if (!rawKey)
215
- throw new Error('pugi config get requires a key.');
216
- const key = normaliseConfigKey(rawKey);
217
- if (!isConfigKey(key)) {
218
- throw new Error(`Unknown config key "${rawKey}". Allowed: ${CONFIG_KEYS.join(', ')}.`);
219
- }
220
- const config = readConfig();
221
- const value = config[key] ?? null;
222
- ctx.writeOutput({ command: 'config.get', key, value }, value === null || value === undefined ? `${key} = (unset)` : `${key} = ${String(value)}`);
223
- }
224
- function runConfigSet(args, ctx) {
225
- const rawKey = args[0];
226
- const value = args.slice(1).join(' ');
227
- if (!rawKey)
228
- throw new Error('pugi config set requires a key.');
229
- if (value.length === 0)
230
- throw new Error('pugi config set requires a value.');
231
- const key = normaliseConfigKey(rawKey);
232
- if (!isConfigKey(key)) {
233
- throw new Error(`Unknown config key "${rawKey}". Allowed: ${CONFIG_KEYS.join(', ')}.`);
234
- }
235
- const current = readConfig();
236
- // Build the candidate and validate via the schema so an invalid value
237
- // (e.g. `permissionMode = nonsense`) is rejected before persistence.
238
- const candidate = { ...current };
239
- candidate[key] = coerceValue(key, value);
240
- const validated = configSchema.parse(candidate);
241
- writeConfig(validated);
242
- ctx.writeOutput({
243
- command: 'config.set',
244
- key,
245
- value: validated[key] ?? null,
246
- }, `${key} = ${String(validated[key] ?? '')}`);
247
- }
248
- function coerceValue(key, raw) {
249
- if (key === 'model') {
250
- return raw === 'null' || raw === '' ? null : raw;
251
- }
252
- return raw;
253
- }
254
- function runConfigList(ctx) {
255
- const config = readConfig();
256
- const entries = CONFIG_KEYS.map((key) => ({
257
- key,
258
- value: config[key] ?? null,
259
- }));
260
- ctx.writeOutput({ command: 'config.list', config, entries }, entries
261
- .map((entry) => entry.value === null || entry.value === undefined
262
- ? `${entry.key} = (unset)`
263
- : `${entry.key} = ${String(entry.value)}`)
264
- .join('\n'));
265
- }
266
- async function runConfigTrust(args, ctx) {
267
- const target = args[0];
268
- if (!target)
269
- throw new Error('pugi config trust requires a path (use "." for cwd).');
270
- const root = target === '.' ? ctx.workspaceRoot : resolve(ctx.workspaceRoot, target);
271
- // Identity for the audit entry: prefer the explicit env override
272
- // (`PUGI_TRUSTED_BY`), then `USER` from the shell, then literal
273
- // 'cli'. The trust ledger requires a non-empty string and we want
274
- // it to mean something for a future audit replay.
275
- const by = process.env.PUGI_TRUSTED_BY?.trim() ||
276
- process.env.USER?.trim() ||
277
- process.env.USERNAME?.trim() ||
278
- 'cli';
279
- await trustWorkspace(root, by);
280
- ctx.writeOutput({ command: 'config.trust', workspaceRoot: root, trustedBy: by }, `Trusted workspace: ${root}`);
281
- }
282
- async function runConfigMcp(args, ctx) {
283
- const sub = args[0];
284
- if (!sub) {
285
- throw new Error('pugi config mcp requires a sub-command: trust, deny, or list.');
286
- }
287
- switch (sub) {
288
- case 'list':
289
- return runConfigMcpList(ctx);
290
- case 'trust':
291
- return runConfigMcpFlip(args.slice(1), ctx, 'trusted');
292
- case 'deny':
293
- return runConfigMcpFlip(args.slice(1), ctx, 'denied');
294
- default:
295
- throw new Error(`Unknown sub-command "pugi config mcp ${sub}". Expected trust, deny, or list.`);
296
- }
297
- }
298
- async function runConfigMcpList(ctx) {
299
- const registry = await loadMcpRegistry(ctx.workspaceRoot, { connect: false });
300
- const declared = Array.from(registry.servers.values()).map((state) => ({
301
- name: state.name,
302
- command: state.config.command,
303
- args: state.config.args,
304
- trust: state.trust,
305
- surfacedTools: state.surfacedTools.length,
306
- lastError: state.lastError ?? null,
307
- }));
308
- const ledger = await listMcpTrust();
309
- await registry.shutdown();
310
- if (declared.length === 0) {
311
- ctx.writeOutput({ command: 'config.mcp.list', servers: [], ledger }, 'No MCP servers declared. Add one to .pugi/mcp.json or ~/.pugi/mcp.json.');
312
- return;
313
- }
314
- ctx.writeOutput({ command: 'config.mcp.list', servers: declared, ledger }, [
315
- 'MCP servers:',
316
- ...declared.map((server) => ` ${server.name.padEnd(20)} ${server.trust.padEnd(8)} ${server.command} ${server.args.join(' ')}`),
317
- ].join('\n'));
318
- }
319
- async function runConfigMcpFlip(args, ctx, state) {
320
- const name = args[0];
321
- if (!name) {
322
- throw new Error(`pugi config mcp ${state === 'trusted' ? 'trust' : 'deny'} requires a server name.`);
323
- }
324
- const by = process.env.PUGI_TRUSTED_BY?.trim() ||
325
- process.env.USER?.trim() ||
326
- process.env.USERNAME?.trim() ||
327
- 'cli';
328
- await setMcpTrust(name, state, by);
329
- ctx.writeOutput({ command: `config.mcp.${state === 'trusted' ? 'trust' : 'deny'}`, name, state, decidedBy: by }, state === 'trusted'
330
- ? `MCP server "${name}" is now trusted.`
331
- : `MCP server "${name}" is now denied.`);
332
- }
333
- /* ------------------------------------------------------------------ */
334
- /* multi-model routing — config.routing.* subcommands */
335
- /* ------------------------------------------------------------------ */
336
- /**
337
- * Closed sets — match
338
- * `apps/admin-api/src/pugi/routing/dispatch-tag.ts` verbatim. Pinning
339
- * them in the CLI lets us reject typos client-side before round-tripping
340
- * to the admin-api (better UX, smaller blast radius for a wrong typo on
341
- * a flaky network).
342
- */
343
- const ROUTING_TAGS = [
344
- 'classify',
345
- 'reason',
346
- 'codegen',
347
- 'summarize',
348
- 'vision',
349
- 'embed',
350
- ];
351
- const ROUTING_BUDGETS = ['min', 'std', 'max'];
352
- function isRoutingTag(value) {
353
- return ROUTING_TAGS.includes(value);
354
- }
355
- function isRoutingBudget(value) {
356
- return ROUTING_BUDGETS.includes(value);
357
- }
358
- /**
359
- * Resolve the admin-api host + bearer token from the CLI credential
360
- * store. Throws a structured "anonymous" error when the operator has
361
- * not logged in — same shape as `pugi whoami` so the harness exit
362
- * codes stay aligned.
363
- */
364
- function resolveAdminApi() {
365
- const credential = resolveActiveCredential();
366
- if (!credential) {
367
- throw new Error('pugi config routing requires authentication. Run `pugi login` first.');
368
- }
369
- return { apiUrl: credential.apiUrl, apiKey: credential.apiKey };
370
- }
371
- /**
372
- * `pugi config get routing` — fetch the static default table + the
373
- * tenant's override table, merge, and render as `routing.<tag>.<budget> = <model>`.
374
- * Shows which lanes are overridden vs default.
375
- */
376
- async function runRoutingGet(ctx) {
377
- const { apiUrl, apiKey } = resolveAdminApi();
378
- const [defaults, overrides] = await Promise.all([
379
- fetchJson(`${apiUrl}/api/admin/model-routing/defaults`, apiKey),
380
- fetchJson(`${apiUrl}/api/admin/model-routing/overrides`, apiKey),
381
- ]);
382
- const overrideMap = new Map();
383
- for (const row of overrides.overrides) {
384
- overrideMap.set(`${row.tag}.${row.budgetHint}`, row.model);
385
- }
386
- const cells = defaults.defaults.map((cell) => {
387
- const overridden = overrideMap.get(`${cell.tag}.${cell.budgetHint}`);
388
- return {
389
- tag: cell.tag,
390
- budgetHint: cell.budgetHint,
391
- model: overridden ?? cell.model,
392
- source: overridden ? 'override' : 'default',
393
- };
394
- });
395
- const text = [
396
- 'Routing table (effective = override | default):',
397
- ...cells.map((cell) => ` routing.${cell.tag.padEnd(10)}.${cell.budgetHint.padEnd(3)} = ${cell.model.padEnd(28)} (${cell.source})`),
398
- ].join('\n');
399
- ctx.writeOutput({
400
- command: 'config.routing.get',
401
- apiUrl,
402
- cells,
403
- }, text);
404
- }
405
- /**
406
- * `pugi config set routing.<tag>.<budget>=<model>` — PUT to the admin-api
407
- * override surface. Validates tag + budget client-side before round-tripping
408
- * so a typo fails fast.
409
- */
410
- async function runRoutingSet(args, ctx) {
411
- // The original arg is `routing.<tag>.<budget>=<model>` — args[0] holds
412
- // everything up to the first whitespace, but the value may have been
413
- // split. Re-join and re-split on `=` to be robust against a
414
- // model slug containing `/` or `-`.
415
- const raw = args.join(' ').trim();
416
- const eqIdx = raw.indexOf('=');
417
- if (eqIdx === -1) {
418
- throw new Error('pugi config set routing.<tag>.<budget>=<model> requires an =<model> suffix.');
419
- }
420
- const lhs = raw.slice(0, eqIdx).trim();
421
- const value = raw.slice(eqIdx + 1).trim();
422
- const lhsParts = lhs.split('.');
423
- if (lhsParts.length !== 3 || lhsParts[0] !== 'routing') {
424
- throw new Error(`Expected routing.<tag>.<budget>, got "${lhs}".`);
425
- }
426
- const tag = lhsParts[1] ?? '';
427
- const budget = lhsParts[2] ?? '';
428
- if (!isRoutingTag(tag)) {
429
- throw new Error(`Unknown routing tag "${tag}". Allowed: ${ROUTING_TAGS.join(', ')}.`);
430
- }
431
- if (!isRoutingBudget(budget)) {
432
- throw new Error(`Unknown routing budget "${budget}". Allowed: ${ROUTING_BUDGETS.join(', ')}.`);
433
- }
434
- if (value.length === 0) {
435
- throw new Error('Model slug must be non-empty.');
436
- }
437
- const { apiUrl, apiKey } = resolveAdminApi();
438
- await fetchJson(`${apiUrl}/api/admin/model-routing/overrides/${tag}/${budget}`, apiKey, { method: 'PUT', body: { model: value } });
439
- ctx.writeOutput({
440
- command: 'config.routing.set',
441
- tag,
442
- budget,
443
- model: value,
444
- }, `routing.${tag}.${budget} = ${value}`);
445
- }
446
- /**
447
- * `pugi config unset routing.<tag>.<budget>` — DELETE the override and
448
- * revert the lane to its static default. Idempotent.
449
- */
450
- async function runRoutingUnset(args, ctx) {
451
- const lhs = (args[0] ?? '').trim();
452
- const lhsParts = lhs.split('.');
453
- if (lhsParts.length !== 3 || lhsParts[0] !== 'routing') {
454
- throw new Error(`Expected routing.<tag>.<budget>, got "${lhs}".`);
455
- }
456
- const tag = lhsParts[1] ?? '';
457
- const budget = lhsParts[2] ?? '';
458
- if (!isRoutingTag(tag)) {
459
- throw new Error(`Unknown routing tag "${tag}". Allowed: ${ROUTING_TAGS.join(', ')}.`);
460
- }
461
- if (!isRoutingBudget(budget)) {
462
- throw new Error(`Unknown routing budget "${budget}". Allowed: ${ROUTING_BUDGETS.join(', ')}.`);
463
- }
464
- const { apiUrl, apiKey } = resolveAdminApi();
465
- const result = await fetchJson(`${apiUrl}/api/admin/model-routing/overrides/${tag}/${budget}`, apiKey, { method: 'DELETE' });
466
- ctx.writeOutput({
467
- command: 'config.routing.unset',
468
- tag,
469
- budget,
470
- removed: result.removed,
471
- }, result.removed
472
- ? `routing.${tag}.${budget} reverted to default.`
473
- : `routing.${tag}.${budget} had no override (nothing to remove).`);
474
- }
475
- /* ------------------------------------------------------------------ */
476
- /* alpha 6.13 privacy 3-mode - config.privacy.* subcommands */
477
- /* ------------------------------------------------------------------ */
478
- /**
479
- * Closed mirror of the server-side PRIVACY_MODES enum
480
- * (apps/admin-api/src/privacy/privacy-mode.ts). Pinning the literal
481
- * set here lets the CLI reject typos client-side before the round-
482
- * trip to admin-api (better UX, smaller blast radius on a flaky
483
- * network).
484
- */
485
- const PRIVACY_MODES = ['strict', 'balanced', 'permissive'];
486
- function isNewPrivacyModeValue(value) {
487
- return typeof value === 'string' && PRIVACY_MODES.includes(value);
488
- }
489
- function isPrivacyMode(value) {
490
- return PRIVACY_MODES.includes(value);
491
- }
492
- /**
493
- * Legacy local-config privacy values from before alpha 6.13. Kept so
494
- * `pugi config set privacy=local-only` continues to write to the local
495
- * config file (matching the bare-form behaviour). Triple-review P2 fix
496
- * : the prior disambiguation only excluded the bare form;
497
- * the `=` form routed to runPrivacySet and 4xx'd on the unknown mode.
498
- */
499
- const LEGACY_LOCAL_PRIVACY_VALUES = [
500
- 'local-only',
501
- 'metadata',
502
- 'full',
503
- ];
504
- function isLegacyLocalPrivacyValue(value) {
505
- return (typeof value === 'string' &&
506
- LEGACY_LOCAL_PRIVACY_VALUES.includes(value));
507
- }
508
- /**
509
- * `pugi config get privacy` - fetch the current privacy mode snapshot
510
- * from /api/admin/privacy/mode + render it in human-readable form.
511
- */
512
- async function runPrivacyGet(ctx) {
513
- const { apiUrl, apiKey } = resolveAdminApi();
514
- const snapshot = await fetchJson(`${apiUrl}/api/admin/privacy/mode`, apiKey);
515
- const lastUpdatedLine = snapshot.lastUpdated
516
- ? `(last set by ${snapshot.lastUpdatedBy ?? 'unknown'} on ${snapshot.lastUpdated})`
517
- : '(no flips recorded; on implicit default)';
518
- const text = [
519
- `privacy.mode = ${snapshot.mode}`,
520
- `privacy.defaultMode = ${snapshot.defaultMode}`,
521
- lastUpdatedLine,
522
- ].join('\n');
523
- ctx.writeOutput({
524
- command: 'config.privacy.get',
525
- apiUrl,
526
- snapshot,
527
- }, text);
528
- }
529
- /**
530
- * `pugi config set privacy=<mode>` - PUT to /api/admin/privacy/mode.
531
- * Validates the mode client-side against the closed set before
532
- * round-tripping.
533
- *
534
- * Accepts both `privacy <mode>` and `privacy=<mode>` argument forms so
535
- * the operator can type it either way.
536
- */
537
- async function runPrivacySet(args, ctx) {
538
- const raw = args.join(' ').trim();
539
- let mode;
540
- if (raw.startsWith('privacy=')) {
541
- mode = raw.slice('privacy='.length).trim();
542
- }
543
- else if (raw === 'privacy') {
544
- throw new Error('pugi config set privacy requires a mode. Try: pugi config set privacy=balanced');
545
- }
546
- else if (raw.startsWith('privacy ')) {
547
- mode = raw.slice('privacy '.length).trim();
548
- }
549
- else {
550
- throw new Error(`pugi config set privacy: unrecognised argument "${raw}". Try: pugi config set privacy=balanced`);
551
- }
552
- if (mode.length === 0) {
553
- throw new Error('pugi config set privacy requires a mode. Try: pugi config set privacy=balanced');
554
- }
555
- if (!isPrivacyMode(mode)) {
556
- throw new Error(`Unknown privacy mode "${mode}". Allowed: ${PRIVACY_MODES.join(', ')}.`);
557
- }
558
- const { apiUrl, apiKey } = resolveAdminApi();
559
- const snapshot = await fetchJson(`${apiUrl}/api/admin/privacy/mode`, apiKey, { method: 'PUT', body: { mode } });
560
- ctx.writeOutput({
561
- command: 'config.privacy.set',
562
- mode: snapshot.mode,
563
- snapshot,
564
- }, `privacy.mode = ${snapshot.mode}`);
565
- }
566
- /**
567
- * Thin authenticated fetch helper. Adds the bearer token + accepts JSON +
568
- * surfaces structured errors. Uses undici `request` (not native `fetch`)
569
- * because the test suite intercepts via `MockAgent` + `setGlobalDispatcher`
570
- * — undici's `request` honours the global dispatcher reliably across the
571
- * pinned undici version. Kept local (not shared with `pugi whoami`) so
572
- * the routing surface is self-contained — extracting a common helper is
573
- * cleanup once we see two callers.
574
- */
575
- async function fetchJson(url, apiKey, options = {}) {
576
- const method = options.method ?? 'GET';
577
- const headers = {
578
- authorization: `Bearer ${apiKey}`,
579
- accept: 'application/json',
580
- };
581
- let body;
582
- if (options.body !== undefined) {
583
- body = JSON.stringify(options.body);
584
- headers['content-type'] = 'application/json';
585
- }
586
- const res = await request(url, { method, headers, body });
587
- if (res.statusCode < 200 || res.statusCode >= 300) {
588
- const detail = await res.body.text().catch(() => '');
589
- throw new Error(`pugi config routing: HTTP ${res.statusCode} on ${method} ${url}${detail ? ` -- ${detail.slice(0, 200)}` : ''}`);
590
- }
591
- // undici's `request` already returns `body` as a stream wrapped with
592
- // helpers — `.json()` parses + closes for us.
593
- return (await res.body.json());
594
- }
595
- //# sourceMappingURL=config.js.map