@pugi/cli 0.1.0-beta.8 → 0.1.0-beta.88
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.
- package/CHANGELOG.md +132 -0
- package/LICENSE +1 -1
- package/THIRD_PARTY_NOTICES.md +40 -0
- package/assets/pugi-prozr2-mascot.ansi +9 -0
- package/bin/run.js +33 -1
- package/dist/commands/deploy.js +40 -40
- package/dist/commands/flatten.js +191 -0
- package/dist/commands/jobs-watch.js +201 -0
- package/dist/commands/jobs.js +42 -27
- package/dist/commands/smoke.js +133 -0
- package/dist/core/agent-progress/cleanup.js +134 -0
- package/dist/core/agent-progress/schema.js +144 -0
- package/dist/core/agent-progress/writer.js +101 -0
- package/dist/core/agents/adaptive-router.js +330 -0
- package/dist/core/agents/query-decomposer.js +297 -0
- package/dist/core/agents/registry.js +3 -3
- package/dist/core/approvals/shortcut-resolver.js +98 -0
- package/dist/core/artifact-chain/dispatcher.js +148 -0
- package/dist/core/artifact-chain/exporter.js +164 -0
- package/dist/core/artifact-chain/state.js +243 -0
- package/dist/core/artifact-chain/steps.js +169 -0
- package/dist/core/ask-user/question.js +92 -0
- package/dist/core/audit/audit-trail.js +275 -0
- package/dist/core/auth/ensure-authenticated.js +129 -0
- package/dist/core/auth/env-provider.js +238 -0
- package/dist/core/auto-open-browser.js +4 -4
- package/dist/core/auto-update/channels.js +122 -0
- package/dist/core/auto-update/checker.js +241 -0
- package/dist/core/auto-update/state.js +235 -0
- package/dist/core/bare-mode/index.js +107 -0
- package/dist/core/bash/redirect.js +281 -0
- package/dist/core/bash-classifier.js +436 -40
- package/dist/core/checkpoint/resumer.js +149 -0
- package/dist/core/checkpoint/rewinder.js +291 -0
- package/dist/core/checkpoints/shadow-git.js +670 -0
- package/dist/core/citations/parser.js +109 -0
- package/dist/core/classifier/yolo-classifier.js +88 -0
- package/dist/core/codegraph/decision-store.js +248 -0
- package/dist/core/codegraph/detect-repo.js +459 -0
- package/dist/core/codegraph/install.js +134 -0
- package/dist/core/codegraph/offer-hook.js +220 -0
- package/dist/core/compact/auto-trigger.js +96 -0
- package/dist/core/compact/buffer-rewriter.js +115 -0
- package/dist/core/compact/summarizer.js +208 -0
- package/dist/core/compact/token-counter.js +108 -0
- package/dist/core/consensus/anvil-fanout.js +25 -25
- package/dist/core/consensus/diff-capture.js +121 -12
- package/dist/core/consensus/rubric.js +21 -21
- package/dist/core/context/builder.js +6 -6
- package/dist/core/context/compaction-events.js +8 -8
- package/dist/core/context/compaction.js +31 -31
- package/dist/core/context/index.js +15 -8
- package/dist/core/context/invariants.js +51 -51
- package/dist/core/context/markdown-loader.js +28 -10
- package/dist/core/context/markdown-traverse.js +255 -0
- package/dist/core/context/pugiignore.js +41 -41
- package/dist/core/context/repo-skeleton.js +37 -37
- package/dist/core/context/tool-eviction.js +55 -0
- package/dist/core/context/watcher.js +32 -32
- package/dist/core/context/working-set.js +23 -23
- package/dist/core/coordinator/agent-tools.js +77 -0
- package/dist/core/coordinator/agent-toolset.js +65 -0
- package/dist/core/coordinator/fsm.js +73 -0
- package/dist/core/coordinator/mode-fsm.js +70 -0
- package/dist/core/cost/rate-card.js +129 -0
- package/dist/core/cost/tracker.js +221 -0
- package/dist/core/credentials.js +12 -12
- package/dist/core/cron/scheduler.js +138 -0
- package/dist/core/denial-tracking/index.js +8 -0
- package/dist/core/denial-tracking/state.js +264 -0
- package/dist/core/diagnostics/probe-runner.js +93 -0
- package/dist/core/diagnostics/probes/api.js +46 -0
- package/dist/core/diagnostics/probes/auth.js +93 -0
- package/dist/core/diagnostics/probes/bare-mode.js +42 -0
- package/dist/core/diagnostics/probes/cli-version.js +127 -0
- package/dist/core/diagnostics/probes/config.js +72 -0
- package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
- package/dist/core/diagnostics/probes/disk.js +81 -0
- package/dist/core/diagnostics/probes/engine-live.js +46 -0
- package/dist/core/diagnostics/probes/git.js +65 -0
- package/dist/core/diagnostics/probes/hooks.js +118 -0
- package/dist/core/diagnostics/probes/mcp.js +75 -0
- package/dist/core/diagnostics/probes/node.js +59 -0
- package/dist/core/diagnostics/probes/pnpm.js +36 -0
- package/dist/core/diagnostics/probes/pugi-md.js +89 -0
- package/dist/core/diagnostics/probes/sandbox.js +40 -0
- package/dist/core/diagnostics/probes/session.js +74 -0
- package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
- package/dist/core/diagnostics/probes/workspace.js +63 -0
- package/dist/core/diagnostics/types.js +70 -0
- package/dist/core/dispatch/cache-cleanup.js +197 -0
- package/dist/core/dispatch/cache-handoff.js +295 -0
- package/dist/core/edits/apply-patch-layer-e.js +189 -0
- package/dist/core/edits/dispatch.js +293 -7
- package/dist/core/edits/format-matrix.js +26 -0
- package/dist/core/edits/fuzzy-ladder.js +650 -0
- package/dist/core/edits/index.js +3 -1
- package/dist/core/edits/journal.js +199 -0
- package/dist/core/edits/layer-a-apply.js +15 -15
- package/dist/core/edits/layer-a-fuzzy-apply.js +198 -0
- package/dist/core/edits/layer-b-apply.js +9 -9
- package/dist/core/edits/layer-c-apply.js +6 -6
- package/dist/core/edits/layer-d-ast.js +557 -14
- package/dist/core/edits/marker-parser.js +12 -12
- package/dist/core/edits/security-gate.js +27 -27
- package/dist/core/edits/verify-hook.js +273 -0
- package/dist/core/edits/worktree.js +322 -0
- package/dist/core/engine/anvil-client.js +151 -26
- package/dist/core/engine/auto-compact.js +179 -0
- package/dist/core/engine/budgets.js +186 -0
- package/dist/core/engine/context-prefix.js +155 -0
- package/dist/core/engine/index.js +1 -1
- package/dist/core/engine/intensity.js +158 -0
- package/dist/core/engine/intent.js +260 -0
- package/dist/core/engine/native-pugi.js +1295 -227
- package/dist/core/engine/prompts.js +134 -16
- package/dist/core/engine/strip-internal-fields.js +124 -0
- package/dist/core/engine/tool-bridge.js +1295 -59
- package/dist/core/evaluation/golden-dataset.js +293 -0
- package/dist/core/feedback/queue.js +177 -0
- package/dist/core/feedback/submitter.js +145 -0
- package/dist/core/file-cache.js +113 -1
- package/dist/core/flatten/flatten-repo.js +439 -0
- package/dist/core/format/osc8-link.js +28 -0
- package/dist/core/hook-chains.js +392 -0
- package/dist/core/hooks/citation-verify-hook.js +138 -0
- package/dist/core/hooks/citation-verify.js +112 -0
- package/dist/core/hooks/events.js +44 -0
- package/dist/core/hooks/index.js +15 -0
- package/dist/core/hooks/registry.js +213 -0
- package/dist/core/hooks/runner.js +236 -0
- package/dist/core/hooks/v2/event-emitter.js +115 -0
- package/dist/core/hooks/v2/executor.js +282 -0
- package/dist/core/hooks/v2/index.js +25 -0
- package/dist/core/hooks/v2/lifecycle.js +104 -0
- package/dist/core/hooks/v2/loader.js +216 -0
- package/dist/core/hooks/v2/matcher.js +125 -0
- package/dist/core/hooks/v2/trust.js +143 -0
- package/dist/core/hooks/v2/types.js +86 -0
- package/dist/core/image/renderer.js +71 -0
- package/dist/core/init/detector.js +582 -0
- package/dist/core/init/template-renderer.js +242 -0
- package/dist/core/jobs/registry.js +18 -18
- package/dist/core/ledger/results-tsv.js +142 -0
- package/dist/core/log-discipline/stdout-redirect.js +51 -0
- package/dist/core/lsp/cache.js +105 -0
- package/dist/core/lsp/client.js +776 -0
- package/dist/core/lsp/language-detect.js +66 -0
- package/dist/core/lsp/post-edit-diagnostics.js +171 -0
- package/dist/core/lsp/symbol-tools.js +372 -0
- package/dist/core/mcp/client.js +97 -28
- package/dist/core/mcp/http-server.js +553 -0
- package/dist/core/mcp/orchestrator-tools.js +662 -0
- package/dist/core/mcp/permission.js +190 -0
- package/dist/core/mcp/registry.js +39 -17
- package/dist/core/mcp/server-tools.js +219 -0
- package/dist/core/mcp/server.js +397 -0
- package/dist/core/mcp/trust.js +10 -10
- package/dist/core/memory/dual-write.js +416 -0
- package/dist/core/memory/passive-extract.js +130 -0
- package/dist/core/memory/phase1-kinds.js +20 -0
- package/dist/core/memory/secret-scanner.js +304 -0
- package/dist/core/memory-sync/queue.js +170 -0
- package/dist/core/metrics/extract.js +113 -0
- package/dist/core/modes/roo-modes.js +68 -0
- package/dist/core/onboarding/ensure-initialized.js +133 -0
- package/dist/core/onboarding/marker.js +111 -0
- package/dist/core/onboarding/telemetry-state.js +108 -0
- package/dist/core/output-style/presets.js +176 -0
- package/dist/core/output-style/state.js +185 -0
- package/dist/core/path-security.js +287 -5
- package/dist/core/permission.js +82 -22
- package/dist/core/permissions/auto-classifier.js +124 -0
- package/dist/core/permissions/bash-parser.js +371 -0
- package/dist/core/permissions/circuit-breaker.js +83 -0
- package/dist/core/permissions/constrained-edit.js +91 -0
- package/dist/core/permissions/gate.js +278 -0
- package/dist/core/permissions/index.js +20 -0
- package/dist/core/permissions/mode.js +174 -0
- package/dist/core/permissions/network-egress.js +137 -0
- package/dist/core/permissions/state.js +241 -0
- package/dist/core/permissions/tool-class.js +93 -0
- package/dist/core/plan-mode/ui-state.js +51 -0
- package/dist/core/plans/plan-artifact.js +721 -0
- package/dist/core/policy-limits/etag-store.js +122 -0
- package/dist/core/prd-check/parser.js +215 -0
- package/dist/core/prd-check/reporter.js +127 -0
- package/dist/core/prd-check/session-review.js +557 -0
- package/dist/core/prd-check/verifiers.js +223 -0
- package/dist/core/prompt-cache/client-cache.js +99 -0
- package/dist/core/prompts/assembly.js +29 -0
- package/dist/core/prompts/registry.js +364 -0
- package/dist/core/pugi-md/cc-compat-rules.js +735 -0
- package/dist/core/pugi-md/context-injector.js +76 -0
- package/dist/core/pugi-md/walk-up.js +207 -0
- package/dist/core/python/uv-installer.js +270 -0
- package/dist/core/python/uv-resolver.js +83 -0
- package/dist/core/rate-limit/narrator.js +146 -0
- package/dist/core/recipes/cli-types.js +20 -0
- package/dist/core/recipes/loader.js +103 -0
- package/dist/core/recipes/runner.js +345 -0
- package/dist/core/recipes/schema.js +587 -0
- package/dist/core/release-notes/parser.js +241 -0
- package/dist/core/release-notes/state.js +116 -0
- package/dist/core/repl/ask.js +37 -37
- package/dist/core/repl/cancellation.js +26 -26
- package/dist/core/repl/cap-warning.js +4 -4
- package/dist/core/repl/clipboard-read.js +11 -11
- package/dist/core/repl/dispatch-fsm.js +12 -12
- package/dist/core/repl/history-search.js +15 -15
- package/dist/core/repl/history.js +28 -18
- package/dist/core/repl/kill-ring.js +5 -5
- package/dist/core/repl/model-pricing.js +135 -0
- package/dist/core/repl/privacy-banner.js +22 -22
- package/dist/core/repl/session.js +2157 -214
- package/dist/core/repl/slash-commands.js +533 -40
- package/dist/core/repl/store/index.js +1 -1
- package/dist/core/repl/store/jsonl-log.js +22 -22
- package/dist/core/repl/store/lockfile.js +10 -10
- package/dist/core/repl/store/session-store.js +136 -107
- package/dist/core/repl/store/types.js +15 -15
- package/dist/core/repl/store/uuid-v7.js +12 -12
- package/dist/core/repl/workspace-context.js +43 -21
- package/dist/core/repo-map/build.js +125 -0
- package/dist/core/repo-map/cache.js +185 -0
- package/dist/core/repo-map/extractor.js +254 -0
- package/dist/core/repo-map/formatter.js +145 -0
- package/dist/core/repo-map/page-rank.js +105 -0
- package/dist/core/repo-map/scanner.js +211 -0
- package/dist/core/retry-budget/budget.js +284 -0
- package/dist/core/retry-budget/index.js +5 -0
- package/dist/core/retry-budget/retry-cap.js +74 -0
- package/dist/core/routing/lead-worker.js +43 -0
- package/dist/core/routing/pre-flight-estimator.js +108 -0
- package/dist/core/runs/run-tree.js +103 -0
- package/dist/core/security/injection-scanner.js +367 -0
- package/dist/core/security/output-filter.js +418 -0
- package/dist/core/session/env-file.js +105 -0
- package/dist/core/session/section-budgets.js +140 -0
- package/dist/core/session.js +92 -0
- package/dist/core/settings.js +298 -5
- package/dist/core/share/formatter.js +271 -0
- package/dist/core/share/redactor.js +221 -0
- package/dist/core/share/uploader.js +267 -0
- package/dist/core/skills/defaults.js +457 -0
- package/dist/core/skills/loader.js +22 -22
- package/dist/core/skills/sources.js +27 -27
- package/dist/core/smoke/headless-driver.js +174 -0
- package/dist/core/smoke/orchestrator.js +194 -0
- package/dist/core/smoke/runner.js +238 -0
- package/dist/core/smoke/scenario-parser.js +316 -0
- package/dist/core/statusline.js +99 -0
- package/dist/core/subagents/dispatcher-real.js +600 -0
- package/dist/core/subagents/dispatcher.js +132 -43
- package/dist/core/subagents/index.js +19 -6
- package/dist/core/subagents/isolation-matrix.js +213 -0
- package/dist/core/subagents/spawn.js +19 -4
- package/dist/core/telemetry/emitter.js +229 -0
- package/dist/core/telemetry/queue.js +251 -0
- package/dist/core/theme/context.js +91 -0
- package/dist/core/theme/presets.js +228 -0
- package/dist/core/theme/state.js +181 -0
- package/dist/core/todos/invariant.js +10 -0
- package/dist/core/todos/state.js +177 -0
- package/dist/core/tool-schema/compressor.js +89 -0
- package/dist/core/transport/version-interceptor.js +166 -0
- package/dist/core/trust.js +2 -2
- package/dist/core/tui/thinking-block.js +64 -0
- package/dist/core/vim/keymap.js +288 -0
- package/dist/core/vim/state.js +92 -0
- package/dist/core/watch-markers/marker-watcher.js +133 -0
- package/dist/core/worktree-manager/cleanup.js +123 -0
- package/dist/core/worktree-manager/manager.js +303 -0
- package/dist/index.js +36 -0
- package/dist/runtime/bootstrap.js +190 -0
- package/dist/runtime/cli.js +4203 -493
- package/dist/runtime/commands/agents.js +30 -30
- package/dist/runtime/commands/budget.js +5 -5
- package/dist/runtime/commands/cancel.js +231 -0
- package/dist/runtime/commands/chain.js +489 -0
- package/dist/runtime/commands/codegraph-status.js +227 -0
- package/dist/runtime/commands/compact.js +297 -0
- package/dist/runtime/commands/config.js +73 -39
- package/dist/runtime/commands/cost.js +199 -0
- package/dist/runtime/commands/delegate.js +244 -13
- package/dist/runtime/commands/dispatch.js +126 -0
- package/dist/runtime/commands/doctor.js +579 -0
- package/dist/runtime/commands/feedback.js +184 -0
- package/dist/runtime/commands/hooks.js +184 -0
- package/dist/runtime/commands/init.js +254 -0
- package/dist/runtime/commands/lsp.js +368 -0
- package/dist/runtime/commands/mcp.js +879 -0
- package/dist/runtime/commands/memory.js +582 -0
- package/dist/runtime/commands/model.js +237 -0
- package/dist/runtime/commands/onboarding.js +275 -0
- package/dist/runtime/commands/patch.js +128 -0
- package/dist/runtime/commands/permissions.js +112 -0
- package/dist/runtime/commands/plan.js +143 -0
- package/dist/runtime/commands/prd-check.js +285 -0
- package/dist/runtime/commands/privacy.js +17 -17
- package/dist/runtime/commands/recipe.js +325 -0
- package/dist/runtime/commands/redo-blob-store.js +92 -0
- package/dist/runtime/commands/redo.js +361 -0
- package/dist/runtime/commands/release-notes.js +229 -0
- package/dist/runtime/commands/repo-map.js +95 -0
- package/dist/runtime/commands/report.js +299 -0
- package/dist/runtime/commands/resume.js +118 -0
- package/dist/runtime/commands/review-consensus.js +68 -53
- package/dist/runtime/commands/rewind.js +333 -0
- package/dist/runtime/commands/roster.js +14 -14
- package/dist/runtime/commands/sessions.js +163 -0
- package/dist/runtime/commands/share.js +316 -0
- package/dist/runtime/commands/skills.js +31 -31
- package/dist/runtime/commands/status.js +186 -0
- package/dist/runtime/commands/stickers.js +82 -0
- package/dist/runtime/commands/style.js +194 -0
- package/dist/runtime/commands/theme.js +196 -0
- package/dist/runtime/commands/undo.js +54 -22
- package/dist/runtime/commands/update.js +289 -0
- package/dist/runtime/commands/vim.js +140 -0
- package/dist/runtime/commands/worktree.js +177 -0
- package/dist/runtime/commands/worktrees.js +155 -0
- package/dist/runtime/headless-repl.js +195 -0
- package/dist/runtime/headless.js +543 -0
- package/dist/runtime/load-hooks-or-exit.js +71 -0
- package/dist/runtime/plan-decompose.js +531 -0
- package/dist/runtime/sigint-guard.js +272 -0
- package/dist/runtime/update-check.js +28 -28
- package/dist/runtime/version.js +65 -0
- package/dist/skills/bundled/batch.js +617 -0
- package/dist/skills/bundled/index.js +45 -0
- package/dist/skills/bundled/loop.js +358 -0
- package/dist/skills/bundled/remember.js +383 -0
- package/dist/skills/bundled/simplify.js +289 -0
- package/dist/skills/bundled/skillify.js +373 -0
- package/dist/skills/bundled/stuck.js +558 -0
- package/dist/skills/bundled/verify.js +439 -0
- package/dist/testing/vcr.js +486 -0
- package/dist/tools/agent-tool.js +229 -0
- package/dist/tools/apply-patch.js +556 -0
- package/dist/tools/ask-user-question.js +288 -0
- package/dist/tools/ask-user.js +115 -0
- package/dist/tools/bash.js +624 -46
- package/dist/tools/brief.js +224 -0
- package/dist/tools/enter-worktree.js +250 -0
- package/dist/tools/exit-worktree.js +147 -0
- package/dist/tools/file-tools.js +161 -44
- package/dist/tools/lsp-tools.js +189 -0
- package/dist/tools/mcp-tool.js +260 -0
- package/dist/tools/multi-edit.js +361 -0
- package/dist/tools/powershell.js +268 -0
- package/dist/tools/registry.js +85 -0
- package/dist/tools/skill-tool.js +96 -0
- package/dist/tools/sleep.js +99 -0
- package/dist/tools/synthetic-output.js +133 -0
- package/dist/tools/tasks.js +208 -0
- package/dist/tools/todo-write.js +184 -0
- package/dist/tools/verify-plan-execution.js +295 -0
- package/dist/tools/web-fetch-injection-scanner.js +207 -0
- package/dist/tools/web-fetch.js +195 -10
- package/dist/tools/web-search.js +458 -0
- package/dist/tui/agent-progress-card.js +111 -0
- package/dist/tui/agent-tree.js +11 -1
- package/dist/tui/ask-modal.js +14 -14
- package/dist/tui/ask-user-question-chips.js +257 -0
- package/dist/tui/ask-user-question-prompt.js +203 -0
- package/dist/tui/compact-banner.js +81 -0
- package/dist/tui/conversation-pane.js +85 -11
- package/dist/tui/cost-table.js +111 -0
- package/dist/tui/device-flow.js +2 -2
- package/dist/tui/doctor-table.js +46 -0
- package/dist/tui/feedback-prompt.js +156 -0
- package/dist/tui/input-box.js +247 -32
- package/dist/tui/login-picker.js +3 -3
- package/dist/tui/markdown-render.js +6 -6
- package/dist/tui/onboarding-wizard.js +240 -0
- package/dist/tui/permissions-picker.js +86 -0
- package/dist/tui/render.js +35 -0
- package/dist/tui/repl-render.js +332 -54
- package/dist/tui/repl-splash-art.js +16 -16
- package/dist/tui/repl-splash-mascot.js +48 -24
- package/dist/tui/repl-splash.js +22 -22
- package/dist/tui/repl.js +124 -44
- package/dist/tui/slash-palette.js +6 -6
- package/dist/tui/splash.js +2 -2
- package/dist/tui/status-bar.js +109 -31
- package/dist/tui/status-table.js +7 -0
- package/dist/tui/stickers-art.js +136 -0
- package/dist/tui/style-table.js +28 -0
- package/dist/tui/theme-table.js +29 -0
- package/dist/tui/thinking-spinner.js +123 -0
- package/dist/tui/tool-stream-pane.js +53 -4
- package/dist/tui/update-banner.js +27 -2
- package/dist/tui/vim-input.js +267 -0
- package/dist/tui/welcome-banner.js +107 -0
- package/dist/tui/welcome-data.js +293 -0
- package/dist/tui/workspace-context.js +2 -2
- package/docs/examples/codegraph.mcp.json +10 -0
- package/package.json +25 -7
- package/test/scenarios/codegen-create-file.scenario.txt +13 -0
- package/test/scenarios/compact-force.scenario.txt +11 -0
- package/test/scenarios/identity.scenario.txt +11 -0
- package/test/scenarios/persona-handoff.scenario.txt +11 -0
- package/test/scenarios/walkback.scenario.txt +12 -0
- package/dist/core/engine/compaction-hook.js +0 -154
|
@@ -11,21 +11,21 @@ import { resolveActiveCredential } from '../../core/credentials.js';
|
|
|
11
11
|
* `pugi config` — operator-level configuration surface.
|
|
12
12
|
*
|
|
13
13
|
* Subcommands:
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
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
21
|
*
|
|
22
22
|
* Schema (pugi-config-v1):
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
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
29
|
*
|
|
30
30
|
* The config file lives at `~/.pugi/config.json` (PUGI_HOME-aware) and uses
|
|
31
31
|
* mode 0o600. Unknown keys are rejected by `set` so a typo never silently
|
|
@@ -39,9 +39,41 @@ const configSchema = z
|
|
|
39
39
|
privacy: z.enum(['local-only', 'metadata', 'full']).optional(),
|
|
40
40
|
model: z.string().nullable().optional(),
|
|
41
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(),
|
|
42
53
|
})
|
|
43
54
|
.strict();
|
|
44
|
-
const CONFIG_KEYS = [
|
|
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
|
+
}
|
|
45
77
|
export async function runConfigCommand(args, ctx) {
|
|
46
78
|
const sub = args[0];
|
|
47
79
|
if (!sub || sub === '--help' || sub === '-h') {
|
|
@@ -63,18 +95,18 @@ export async function runConfigCommand(args, ctx) {
|
|
|
63
95
|
],
|
|
64
96
|
}, [
|
|
65
97
|
'Usage:',
|
|
66
|
-
'
|
|
67
|
-
'
|
|
68
|
-
'
|
|
69
|
-
'
|
|
70
|
-
'
|
|
71
|
-
'
|
|
72
|
-
'
|
|
73
|
-
'
|
|
74
|
-
'
|
|
75
|
-
'
|
|
76
|
-
'
|
|
77
|
-
'
|
|
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).',
|
|
78
110
|
].join('\n'));
|
|
79
111
|
return;
|
|
80
112
|
}
|
|
@@ -108,7 +140,7 @@ export async function runConfigCommand(args, ctx) {
|
|
|
108
140
|
// names. The unit spec for config.ts has a regression test for
|
|
109
141
|
// both code paths.
|
|
110
142
|
//
|
|
111
|
-
// Triple-review P2 fix
|
|
143
|
+
// Triple-review P2 fix : the prior disambiguation
|
|
112
144
|
// only excluded the bare form (`privacy local-only`) - the `=`
|
|
113
145
|
// form (`privacy=local-only`) still routed to runPrivacySet and
|
|
114
146
|
// 4xx'd. We now check the value AFTER `=` and route legacy local
|
|
@@ -178,25 +210,27 @@ function isConfigKey(value) {
|
|
|
178
210
|
return CONFIG_KEYS.includes(value);
|
|
179
211
|
}
|
|
180
212
|
function runConfigGet(args, ctx) {
|
|
181
|
-
const
|
|
182
|
-
if (!
|
|
213
|
+
const rawKey = args[0];
|
|
214
|
+
if (!rawKey)
|
|
183
215
|
throw new Error('pugi config get requires a key.');
|
|
216
|
+
const key = normaliseConfigKey(rawKey);
|
|
184
217
|
if (!isConfigKey(key)) {
|
|
185
|
-
throw new Error(`Unknown config key "${
|
|
218
|
+
throw new Error(`Unknown config key "${rawKey}". Allowed: ${CONFIG_KEYS.join(', ')}.`);
|
|
186
219
|
}
|
|
187
220
|
const config = readConfig();
|
|
188
221
|
const value = config[key] ?? null;
|
|
189
222
|
ctx.writeOutput({ command: 'config.get', key, value }, value === null || value === undefined ? `${key} = (unset)` : `${key} = ${String(value)}`);
|
|
190
223
|
}
|
|
191
224
|
function runConfigSet(args, ctx) {
|
|
192
|
-
const
|
|
225
|
+
const rawKey = args[0];
|
|
193
226
|
const value = args.slice(1).join(' ');
|
|
194
|
-
if (!
|
|
227
|
+
if (!rawKey)
|
|
195
228
|
throw new Error('pugi config set requires a key.');
|
|
196
229
|
if (value.length === 0)
|
|
197
230
|
throw new Error('pugi config set requires a value.');
|
|
231
|
+
const key = normaliseConfigKey(rawKey);
|
|
198
232
|
if (!isConfigKey(key)) {
|
|
199
|
-
throw new Error(`Unknown config key "${
|
|
233
|
+
throw new Error(`Unknown config key "${rawKey}". Allowed: ${CONFIG_KEYS.join(', ')}.`);
|
|
200
234
|
}
|
|
201
235
|
const current = readConfig();
|
|
202
236
|
// Build the candidate and validate via the schema so an invalid value
|
|
@@ -279,7 +313,7 @@ async function runConfigMcpList(ctx) {
|
|
|
279
313
|
}
|
|
280
314
|
ctx.writeOutput({ command: 'config.mcp.list', servers: declared, ledger }, [
|
|
281
315
|
'MCP servers:',
|
|
282
|
-
...declared.map((server) => `
|
|
316
|
+
...declared.map((server) => ` ${server.name.padEnd(20)} ${server.trust.padEnd(8)} ${server.command} ${server.args.join(' ')}`),
|
|
283
317
|
].join('\n'));
|
|
284
318
|
}
|
|
285
319
|
async function runConfigMcpFlip(args, ctx, state) {
|
|
@@ -297,7 +331,7 @@ async function runConfigMcpFlip(args, ctx, state) {
|
|
|
297
331
|
: `MCP server "${name}" is now denied.`);
|
|
298
332
|
}
|
|
299
333
|
/* ------------------------------------------------------------------ */
|
|
300
|
-
/*
|
|
334
|
+
/* multi-model routing — config.routing.* subcommands */
|
|
301
335
|
/* ------------------------------------------------------------------ */
|
|
302
336
|
/**
|
|
303
337
|
* Closed sets — match
|
|
@@ -360,7 +394,7 @@ async function runRoutingGet(ctx) {
|
|
|
360
394
|
});
|
|
361
395
|
const text = [
|
|
362
396
|
'Routing table (effective = override | default):',
|
|
363
|
-
...cells.map((cell) => `
|
|
397
|
+
...cells.map((cell) => ` routing.${cell.tag.padEnd(10)}.${cell.budgetHint.padEnd(3)} = ${cell.model.padEnd(28)} (${cell.source})`),
|
|
364
398
|
].join('\n');
|
|
365
399
|
ctx.writeOutput({
|
|
366
400
|
command: 'config.routing.get',
|
|
@@ -439,7 +473,7 @@ async function runRoutingUnset(args, ctx) {
|
|
|
439
473
|
: `routing.${tag}.${budget} had no override (nothing to remove).`);
|
|
440
474
|
}
|
|
441
475
|
/* ------------------------------------------------------------------ */
|
|
442
|
-
/* alpha 6.13 privacy 3-mode - config.privacy.* subcommands
|
|
476
|
+
/* alpha 6.13 privacy 3-mode - config.privacy.* subcommands */
|
|
443
477
|
/* ------------------------------------------------------------------ */
|
|
444
478
|
/**
|
|
445
479
|
* Closed mirror of the server-side PRIVACY_MODES enum
|
|
@@ -459,7 +493,7 @@ function isPrivacyMode(value) {
|
|
|
459
493
|
* Legacy local-config privacy values from before alpha 6.13. Kept so
|
|
460
494
|
* `pugi config set privacy=local-only` continues to write to the local
|
|
461
495
|
* config file (matching the bare-form behaviour). Triple-review P2 fix
|
|
462
|
-
*
|
|
496
|
+
* : the prior disambiguation only excluded the bare form;
|
|
463
497
|
* the `=` form routed to runPrivacySet and 4xx'd on the unknown mode.
|
|
464
498
|
*/
|
|
465
499
|
const LEGACY_LOCAL_PRIVACY_VALUES = [
|
|
@@ -536,7 +570,7 @@ async function runPrivacySet(args, ctx) {
|
|
|
536
570
|
* — undici's `request` honours the global dispatcher reliably across the
|
|
537
571
|
* pinned undici version. Kept local (not shared with `pugi whoami`) so
|
|
538
572
|
* the routing surface is self-contained — extracting a common helper is
|
|
539
|
-
*
|
|
573
|
+
* cleanup once we see two callers.
|
|
540
574
|
*/
|
|
541
575
|
async function fetchJson(url, apiKey, options = {}) {
|
|
542
576
|
const method = options.method ?? 'GET';
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `pugi cost` / `pugi usage` command handler — L19 sprint .
|
|
3
|
+
*
|
|
4
|
+
* Shared backend for three operator surfaces:
|
|
5
|
+
*
|
|
6
|
+
* - `pugi cost` current session (default)
|
|
7
|
+
* - `pugi cost --all-sessions` 30-day rolling aggregate
|
|
8
|
+
* - `pugi cost --reset --yes` wipe current session counter (operator-only)
|
|
9
|
+
* - `pugi usage` alias of `pugi cost`
|
|
10
|
+
* - `/cost` REPL slash same handler, in-REPL output
|
|
11
|
+
* - `/usage` REPL slash same handler, alias of /cost
|
|
12
|
+
*
|
|
13
|
+
* Why a separate command from the existing `pugi budget`:
|
|
14
|
+
*
|
|
15
|
+
* - `pugi budget` walks `.pugi/events.jsonl` and bills against the
|
|
16
|
+
* event-log heuristic (per-command / per-persona attribution). It
|
|
17
|
+
* is the right surface for "what did this brief / this persona
|
|
18
|
+
* spend?". It does not break down by model and it does not persist
|
|
19
|
+
* a cross-session aggregate.
|
|
20
|
+
*
|
|
21
|
+
* - `pugi cost` (this command) reads the persisted `.pugi/cost.json`
|
|
22
|
+
* written by the `CostTracker`. It is the right surface for "what
|
|
23
|
+
* did this model spend?" and "what did I spend across the last 30
|
|
24
|
+
* days?". Token + USD figures are sourced from the rate card, which
|
|
25
|
+
* distinguishes hosted Claude (per-token billed) from open-weight
|
|
26
|
+
* Qwen / Kimi / DeepSeek (infra cost only).
|
|
27
|
+
*
|
|
28
|
+
* Both commands intentionally coexist — they answer adjacent but distinct
|
|
29
|
+
* operator questions. The L19 spec calls out `/cost` and `/usage` by
|
|
30
|
+
* name; the budget surface is unaffected.
|
|
31
|
+
*/
|
|
32
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
33
|
+
import { resolve } from 'node:path';
|
|
34
|
+
import { createCostTracker, totalTokens, totalUsd, } from '../../core/cost/tracker.js';
|
|
35
|
+
import { buildCostView, renderCostTableText } from '../../tui/cost-table.js';
|
|
36
|
+
/**
|
|
37
|
+
* Parsed flag bundle. Exported for the test surface; production callers
|
|
38
|
+
* never touch it directly — `runCostCommand` owns parsing.
|
|
39
|
+
*/
|
|
40
|
+
export function parseCostFlags(args) {
|
|
41
|
+
const flags = {
|
|
42
|
+
allSessions: false,
|
|
43
|
+
reset: false,
|
|
44
|
+
yes: false,
|
|
45
|
+
json: false,
|
|
46
|
+
windowDays: 30,
|
|
47
|
+
};
|
|
48
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
49
|
+
const arg = args[i] ?? '';
|
|
50
|
+
if (arg === '--all-sessions')
|
|
51
|
+
flags.allSessions = true;
|
|
52
|
+
else if (arg === '--reset')
|
|
53
|
+
flags.reset = true;
|
|
54
|
+
else if (arg === '--yes' || arg === '-y')
|
|
55
|
+
flags.yes = true;
|
|
56
|
+
else if (arg === '--json')
|
|
57
|
+
flags.json = true;
|
|
58
|
+
else if (arg.startsWith('--window=')) {
|
|
59
|
+
const raw = Number.parseInt(arg.slice('--window='.length), 10);
|
|
60
|
+
if (Number.isFinite(raw) && raw > 0 && raw <= 365)
|
|
61
|
+
flags.windowDays = raw;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return flags;
|
|
65
|
+
}
|
|
66
|
+
export async function runCostCommand(args, ctx) {
|
|
67
|
+
const flags = parseCostFlags(args);
|
|
68
|
+
const sessionId = ctx.sessionId ?? deriveSessionIdFromEvents(ctx.workspaceRoot) ?? 'no-session';
|
|
69
|
+
const tracker = createCostTracker({
|
|
70
|
+
workspaceRoot: ctx.workspaceRoot,
|
|
71
|
+
sessionIdProvider: () => sessionId,
|
|
72
|
+
now: ctx.now,
|
|
73
|
+
});
|
|
74
|
+
// --reset: clear the current session counter. Operator-only — refuses
|
|
75
|
+
// without `--yes` so a typo / shell completion never wipes the meter.
|
|
76
|
+
if (flags.reset) {
|
|
77
|
+
if (!flags.yes) {
|
|
78
|
+
ctx.writeOutput({ command: 'cost', status: 'reset_pending_confirmation' }, 'pugi cost --reset clears the current session counter. Re-run with --yes to confirm.');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const wiped = tracker.resetCurrent();
|
|
82
|
+
const payload = {
|
|
83
|
+
command: 'cost',
|
|
84
|
+
status: 'reset_ok',
|
|
85
|
+
wiped: wiped ?? null,
|
|
86
|
+
};
|
|
87
|
+
ctx.writeOutput(payload, wiped
|
|
88
|
+
? `Cleared session ${wiped.sessionId} (${Object.keys(wiped.models).length} model(s) wiped).`
|
|
89
|
+
: 'No current session counter to clear.');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const aggregate = flags.allSessions ? tracker.aggregateWithin(flags.windowDays) : (tracker.current() ?? emptyAggregate(sessionId, ctx.now ?? Date.now));
|
|
93
|
+
const tier = ctx.resolveTier ? await safeResolveTier(ctx.resolveTier) : null;
|
|
94
|
+
const heading = flags.allSessions
|
|
95
|
+
? `Pugi cost / usage — aggregate (last ${flags.windowDays} days)`
|
|
96
|
+
: buildSessionHeading(aggregate, ctx.now ?? Date.now);
|
|
97
|
+
const view = buildCostView({ aggregate, heading, tier: tier ?? undefined });
|
|
98
|
+
const text = renderCostTableText(view);
|
|
99
|
+
ctx.writeOutput({
|
|
100
|
+
command: flags.allSessions ? 'cost.aggregate' : 'cost.session',
|
|
101
|
+
status: 'ok',
|
|
102
|
+
window: flags.allSessions ? `${flags.windowDays}d` : 'current',
|
|
103
|
+
tokens: {
|
|
104
|
+
input: view.totalInputTokens,
|
|
105
|
+
output: view.totalOutputTokens,
|
|
106
|
+
},
|
|
107
|
+
dollars: view.totalUsd,
|
|
108
|
+
perModel: view.rows.map((row) => ({
|
|
109
|
+
model: row.model,
|
|
110
|
+
input: row.inputTokens,
|
|
111
|
+
output: row.outputTokens,
|
|
112
|
+
usd: row.usd,
|
|
113
|
+
note: row.note ?? null,
|
|
114
|
+
})),
|
|
115
|
+
tier: tier ?? null,
|
|
116
|
+
}, text);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Render-only helper for the REPL slash. The slash dispatcher inside
|
|
120
|
+
* `session.ts` owns the side-effect of pushing system lines; this
|
|
121
|
+
* function builds the view and the text rendition so the slash handler
|
|
122
|
+
* can fan the lines into the existing `appendSystemLine` queue.
|
|
123
|
+
*
|
|
124
|
+
* Exposed here (not in the Ink module) so the slash path never imports
|
|
125
|
+
* Ink/React — keeps the REPL bundle slim and the slash handler async-free.
|
|
126
|
+
*/
|
|
127
|
+
export function renderCostForSlash(input) {
|
|
128
|
+
const aggregate = input.allSessions
|
|
129
|
+
? input.tracker.aggregateWithin(input.windowDays)
|
|
130
|
+
: (input.tracker.current() ?? emptyAggregate('no-session', input.now));
|
|
131
|
+
const heading = input.allSessions
|
|
132
|
+
? `Pugi cost / usage — aggregate (last ${input.windowDays} days)`
|
|
133
|
+
: buildSessionHeading(aggregate, input.now);
|
|
134
|
+
const view = buildCostView({ aggregate, heading, tier: input.tier ?? undefined });
|
|
135
|
+
return { view, lines: renderCostTableText(view).split('\n') };
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Derive a session id from `.pugi/events.jsonl` when the caller does not
|
|
139
|
+
* pass one. Walks the file once and picks the most recent `session.start`
|
|
140
|
+
* event's id. Falls back to `null` when the file is missing / corrupted
|
|
141
|
+
* — the caller substitutes a `'no-session'` placeholder so the table
|
|
142
|
+
* still renders an empty state instead of crashing.
|
|
143
|
+
*/
|
|
144
|
+
function deriveSessionIdFromEvents(workspaceRoot) {
|
|
145
|
+
const path = resolve(workspaceRoot, '.pugi/events.jsonl');
|
|
146
|
+
if (!existsSync(path))
|
|
147
|
+
return null;
|
|
148
|
+
try {
|
|
149
|
+
const raw = readFileSync(path, 'utf8');
|
|
150
|
+
const lines = raw.split('\n').filter((line) => line.trim().length > 0);
|
|
151
|
+
// Walk from newest to oldest — `session.start` is rare, no reason to
|
|
152
|
+
// scan the whole file when the answer is at the tail.
|
|
153
|
+
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
154
|
+
try {
|
|
155
|
+
const parsed = JSON.parse(lines[i]);
|
|
156
|
+
if (parsed.type === 'session' && parsed.name === 'start' && typeof parsed.sessionId === 'string') {
|
|
157
|
+
return parsed.sessionId;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
// partial-write lines are ignored
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
// best-effort; absent events.jsonl is a normal first-boot state
|
|
167
|
+
}
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
function buildSessionHeading(aggregate, now) {
|
|
171
|
+
if (!aggregate || aggregate.sessionId === 'no-session' || aggregate.sessionId === 'aggregate') {
|
|
172
|
+
return 'Pugi cost / usage — no active session';
|
|
173
|
+
}
|
|
174
|
+
const start = Date.parse(aggregate.startedAt);
|
|
175
|
+
if (!Number.isFinite(start)) {
|
|
176
|
+
return `Pugi cost / usage — session ${aggregate.sessionId}`;
|
|
177
|
+
}
|
|
178
|
+
const elapsedMin = Math.max(0, Math.floor((now() - start) / 60_000));
|
|
179
|
+
return `Pugi cost / usage — session ${aggregate.sessionId} (${elapsedMin} min)`;
|
|
180
|
+
}
|
|
181
|
+
function emptyAggregate(sessionId, now) {
|
|
182
|
+
return {
|
|
183
|
+
sessionId,
|
|
184
|
+
startedAt: new Date(now()).toISOString(),
|
|
185
|
+
models: {},
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
async function safeResolveTier(resolver) {
|
|
189
|
+
try {
|
|
190
|
+
return await resolver();
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// Re-export aggregate helpers so the cli.ts wire-up can read totals
|
|
197
|
+
// without reaching into the tracker module directly.
|
|
198
|
+
export { totalUsd, totalTokens };
|
|
199
|
+
//# sourceMappingURL=cost.js.map
|