@pugi/cli 0.1.0-beta.10 → 0.1.0-beta.101
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +132 -0
- package/LICENSE +1 -1
- package/README.md +55 -11
- 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/retro.js +210 -0
- 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/db.js +506 -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/codegraph/parser.js +598 -0
- package/dist/core/codegraph/queries/go.scm +57 -0
- package/dist/core/codegraph/queries/javascript.scm +56 -0
- package/dist/core/codegraph/queries/python.scm +55 -0
- package/dist/core/codegraph/queries/rust.scm +63 -0
- package/dist/core/codegraph/queries/typescript.scm +91 -0
- package/dist/core/codegraph/reindex.js +218 -0
- package/dist/core/codegraph/resolve-edges.js +107 -0
- package/dist/core/codegraph/types.js +34 -0
- package/dist/core/codegraph/watcher.js +440 -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 +13 -13
- 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 +67 -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 +333 -7
- package/dist/core/edits/format-detector.js +260 -0
- package/dist/core/edits/format-matrix.js +26 -0
- package/dist/core/edits/fuzzy-ladder.js +650 -0
- package/dist/core/edits/index.js +5 -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 +29 -29
- package/dist/core/engine/anvil-client.js +214 -26
- package/dist/core/engine/auto-compact.js +247 -0
- package/dist/core/engine/budgets.js +220 -0
- package/dist/core/engine/compact-llm-summarizer.js +124 -0
- package/dist/core/engine/context-prefix.js +155 -0
- package/dist/core/engine/index.js +1 -1
- package/dist/core/engine/intensity.js +163 -0
- package/dist/core/engine/intent.js +260 -0
- package/dist/core/engine/native-pugi.js +1559 -227
- package/dist/core/engine/prompts.js +219 -19
- package/dist/core/engine/strip-internal-fields.js +124 -0
- package/dist/core/engine/tool-bridge.js +1887 -59
- package/dist/core/engine/verification-patterns.js +195 -0
- package/dist/core/eval/v1/ledger.js +83 -0
- package/dist/core/eval/v1/runner.js +280 -0
- package/dist/core/eval/v1/scoring.js +68 -0
- package/dist/core/eval/v1/task-loader.js +191 -0
- package/dist/core/eval/v1/types.js +14 -0
- package/dist/core/eval/v1/verifier.js +176 -0
- package/dist/core/eval/v1/yaml-parser.js +250 -0
- 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 +46 -0
- package/dist/core/hooks/index.js +15 -0
- package/dist/core/hooks/registry.js +216 -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/hooks/worktree-events.js +158 -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 +551 -41
- package/dist/core/lsp/language-detect.js +66 -0
- package/dist/core/lsp/post-edit-diagnostics.js +171 -0
- package/dist/core/lsp/server-detect.js +173 -0
- package/dist/core/lsp/symbol-cache.js +162 -0
- package/dist/core/lsp/symbol-tools.js +664 -0
- package/dist/core/mcp/client.js +97 -28
- package/dist/core/mcp/http-server.js +553 -0
- package/dist/core/mcp/orchestrator-config.js +192 -0
- package/dist/core/mcp/orchestrator-tools.js +806 -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/notes/notes-paths.js +113 -0
- package/dist/core/notes/notes-recorder.js +140 -0
- package/dist/core/notes/notes-writer.js +53 -0
- package/dist/core/notes/renderers.js +0 -0
- package/dist/core/notes/slug.js +105 -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 +107 -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-gitignore.js +52 -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/engine-bridge.js +303 -0
- 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 +2690 -229
- package/dist/core/repl/slash-commands.js +540 -41
- 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/tool-route.js +382 -0
- 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/retro/git-collector.js +251 -0
- package/dist/core/retro/health-card.js +25 -0
- package/dist/core/retro/metrics.js +342 -0
- package/dist/core/retro/narrative.js +249 -0
- package/dist/core/retro/plane-collector.js +274 -0
- package/dist/core/retro/pr-issue-link.js +65 -0
- package/dist/core/retro/types.js +16 -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/sandboxing/adapter.js +43 -0
- package/dist/core/sandboxing/bubblewrap.js +209 -0
- package/dist/core/sandboxing/index.js +78 -0
- package/dist/core/sandboxing/none.js +19 -0
- package/dist/core/sandboxing/policy.js +97 -0
- package/dist/core/sandboxing/seatbelt.js +231 -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 +119 -0
- package/dist/core/settings.js +402 -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 +30 -30
- 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 +146 -52
- 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/include-parser.js +249 -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 +4403 -561
- package/dist/runtime/commands/agents.js +31 -31
- 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 +74 -40
- package/dist/runtime/commands/cost.js +199 -0
- package/dist/runtime/commands/delegate.js +27 -4
- package/dist/runtime/commands/dispatch.js +126 -0
- package/dist/runtime/commands/doctor.js +579 -0
- package/dist/runtime/commands/eval-v1.js +266 -0
- package/dist/runtime/commands/feedback.js +184 -0
- package/dist/runtime/commands/hooks.js +187 -0
- package/dist/runtime/commands/index-cmd.js +459 -0
- package/dist/runtime/commands/init.js +254 -0
- package/dist/runtime/commands/lsp.js +200 -38
- package/dist/runtime/commands/mcp.js +935 -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 +12 -12
- 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/servers-cli.js +182 -0
- package/dist/runtime/commands/servers.js +236 -0
- 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 +8 -8
- package/dist/runtime/commands/worktrees.js +155 -0
- package/dist/runtime/deprecation-warning.js +69 -0
- package/dist/runtime/engine-exit-code.js +50 -0
- package/dist/runtime/headless-repl.js +195 -0
- package/dist/runtime/headless.js +548 -0
- package/dist/runtime/load-hooks-or-exit.js +71 -0
- package/dist/runtime/plan-decompose.js +22 -22
- package/dist/runtime/sigint-guard.js +272 -0
- package/dist/runtime/stream-renderer.js +195 -0
- package/dist/runtime/update-check.js +28 -28
- package/dist/runtime/version.js +65 -0
- package/dist/runtime/worktree-bootstrap.js +579 -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 +89 -28
- package/dist/tools/ask-user-question.js +337 -0
- package/dist/tools/ask-user.js +115 -0
- package/dist/tools/bash.js +811 -49
- package/dist/tools/brief.js +224 -0
- package/dist/tools/cron.js +433 -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/http-request.js +336 -0
- package/dist/tools/lsp-tools.js +377 -1
- 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 +120 -5
- package/dist/tools/server-tools.js +892 -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 +22 -1
- package/dist/tui/ask-modal.js +14 -14
- package/dist/tui/ask-user-question-chips.js +315 -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/multi-file-diff-approval.js +375 -0
- package/dist/tui/onboarding-wizard.js +240 -0
- package/dist/tui/permissions-picker.js +86 -0
- package/dist/tui/render.js +36 -1
- package/dist/tui/repl-render.js +239 -25
- 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 +125 -45
- 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/package.json +29 -6
- package/test/scenarios/codegen-create-file.scenario.txt +13 -0
- package/test/scenarios/compact-force.scenario.txt +12 -0
- package/test/scenarios/identity.scenario.txt +11 -0
- package/test/scenarios/persona-handoff.scenario.txt +12 -0
- package/test/scenarios/walkback.scenario.txt +12 -0
- package/dist/core/engine/compaction-hook.js +0 -154
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Probe runner — orchestrates a set of diagnostic probes in parallel
|
|
3
|
+
* with per-probe fail-isolation + a global wall-clock budget.
|
|
4
|
+
*
|
|
5
|
+
* Design contract:
|
|
6
|
+
*
|
|
7
|
+
* - Probes are independent: one probe's throw or timeout NEVER stops
|
|
8
|
+
* the others. The runner wraps each call in a try/catch + a
|
|
9
|
+
* `Promise.race` against a timeout sentinel.
|
|
10
|
+
*
|
|
11
|
+
* - Order preservation: the returned `probes[]` array preserves the
|
|
12
|
+
* input order so the table renderer always lists rows in the same
|
|
13
|
+
* sequence (operators rely on muscle memory: "auth is the first
|
|
14
|
+
* row, api is the second").
|
|
15
|
+
*
|
|
16
|
+
* - No I/O ownership: the runner owns ZERO file or network calls.
|
|
17
|
+
* Every external dependency is injected via the probe function
|
|
18
|
+
* itself. This keeps the test surface minimal and verifies the
|
|
19
|
+
* fail-isolation contract without spinning real subprocesses.
|
|
20
|
+
*
|
|
21
|
+
* - Crashes attributed to the probe: a probe that throws maps to a
|
|
22
|
+
* synthetic `error` ProbeResult with the probe name + the error
|
|
23
|
+
* message. A probe that exceeds the timeout becomes a synthetic
|
|
24
|
+
* `warn` (timing out is asymmetric — the host is reachable but
|
|
25
|
+
* slow).
|
|
26
|
+
*
|
|
27
|
+
* - The aggregate `DoctorReport` shape comes straight from
|
|
28
|
+
* `types.ts` so the doctor command + the Ink table renderer both
|
|
29
|
+
* consume the same struct without any glue layer.
|
|
30
|
+
*/
|
|
31
|
+
import { computeOverall, countProbes, } from './types.js';
|
|
32
|
+
/**
|
|
33
|
+
* Run a set of probes in parallel and produce a structured report.
|
|
34
|
+
* Never throws — every failure mode maps to a structured ProbeResult.
|
|
35
|
+
*/
|
|
36
|
+
export async function runProbes(probes, options = {}) {
|
|
37
|
+
const now = options.now ?? Date.now;
|
|
38
|
+
const defaultTimeoutMs = options.defaultTimeoutMs ?? 5_000;
|
|
39
|
+
const startedAt = now();
|
|
40
|
+
// Each probe is wrapped in a fail-isolation envelope.
|
|
41
|
+
const results = await Promise.all(probes.map(async (entry) => runOne(entry, defaultTimeoutMs)));
|
|
42
|
+
const overall = computeOverall(results);
|
|
43
|
+
const counts = countProbes(results);
|
|
44
|
+
const durationMs = now() - startedAt;
|
|
45
|
+
return {
|
|
46
|
+
probes: results,
|
|
47
|
+
overall,
|
|
48
|
+
counts,
|
|
49
|
+
durationMs,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async function runOne(entry, defaultTimeoutMs) {
|
|
53
|
+
const budget = entry.timeoutMs ?? defaultTimeoutMs;
|
|
54
|
+
try {
|
|
55
|
+
return await raceWithTimeout(entry, budget);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
59
|
+
if (error instanceof ProbeTimeoutError) {
|
|
60
|
+
return {
|
|
61
|
+
name: entry.name,
|
|
62
|
+
status: 'warn',
|
|
63
|
+
detail: `Probe timed out after ${budget}ms`,
|
|
64
|
+
remediation: 'Re-run later; the host or registry may be slow',
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
name: entry.name,
|
|
69
|
+
status: 'error',
|
|
70
|
+
detail: `Probe crashed: ${message}`,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
class ProbeTimeoutError extends Error {
|
|
75
|
+
constructor(name, budgetMs) {
|
|
76
|
+
super(`Probe ${name} exceeded ${budgetMs}ms`);
|
|
77
|
+
this.name = 'ProbeTimeoutError';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function raceWithTimeout(entry, budgetMs) {
|
|
81
|
+
let timer;
|
|
82
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
83
|
+
timer = setTimeout(() => reject(new ProbeTimeoutError(entry.name, budgetMs)), budgetMs);
|
|
84
|
+
});
|
|
85
|
+
try {
|
|
86
|
+
return await Promise.race([entry.run(), timeoutPromise]);
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
if (timer !== undefined)
|
|
90
|
+
clearTimeout(timer);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=probe-runner.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API probe — verifies `api.pugi.io` (or the active apiUrl) is
|
|
3
|
+
* reachable WITHOUT requiring a valid auth token. The auth probe
|
|
4
|
+
* covers the credentialed path; this probe answers the orthogonal
|
|
5
|
+
* "is the network broken" question so the operator can disambiguate
|
|
6
|
+
* "I'm offline" from "my token is bad" without reading two probe
|
|
7
|
+
* details together.
|
|
8
|
+
*
|
|
9
|
+
* Success criteria: any HTTP response (including 401 unauthenticated)
|
|
10
|
+
* proves the host is reachable. A thrown fetch (DNS / TCP / TLS
|
|
11
|
+
* failure) is the only true failure mode.
|
|
12
|
+
*/
|
|
13
|
+
export async function probeApi(ctx, deps) {
|
|
14
|
+
const apiUrl = deps.resolveApiUrl(ctx.env);
|
|
15
|
+
const startedAt = deps.now();
|
|
16
|
+
try {
|
|
17
|
+
const response = await deps.fetchImpl(`${stripTrailingSlash(apiUrl)}/api/pugi/health`, {
|
|
18
|
+
method: 'GET',
|
|
19
|
+
});
|
|
20
|
+
const latencyMs = deps.now() - startedAt;
|
|
21
|
+
// Any HTTP response confirms the host is reachable. The auth probe
|
|
22
|
+
// is responsible for verdicting the 401 / 200 split — here we just
|
|
23
|
+
// confirm we can talk to the server.
|
|
24
|
+
return {
|
|
25
|
+
name: 'API',
|
|
26
|
+
status: 'ok',
|
|
27
|
+
detail: `${apiUrl} reachable (${response.status})`,
|
|
28
|
+
latencyMs,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
const latencyMs = deps.now() - startedAt;
|
|
33
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
34
|
+
return {
|
|
35
|
+
name: 'API',
|
|
36
|
+
status: 'error',
|
|
37
|
+
detail: `Cannot reach ${apiUrl}`,
|
|
38
|
+
latencyMs,
|
|
39
|
+
remediation: `Check network or override with PUGI_API_URL: ${message}`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function stripTrailingSlash(url) {
|
|
44
|
+
return url.endsWith('/') ? url.slice(0, -1) : url;
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AUTH probe — verifies the active credential resolves to a working
|
|
3
|
+
* Bearer token by calling `GET /api/pugi/health` with it.
|
|
4
|
+
*
|
|
5
|
+
* Failure modes (deterministic mapping):
|
|
6
|
+
* - no credential found in env or `~/.pugi/credentials.json`
|
|
7
|
+
* → status `skipped`, detail = `unauthenticated (no credentials configured)`
|
|
8
|
+
* Distinguished from "configured but broken" so offline / pre-login
|
|
9
|
+
* doctor runs do NOT exit 2. The remediation still points operators
|
|
10
|
+
* to `pugi login` for when they are ready to authenticate.
|
|
11
|
+
* - credential exists but server returns 401/403
|
|
12
|
+
* → status `error`, remediation = `pugi login` (token expired/revoked)
|
|
13
|
+
* - credential exists but server returns 5xx OR network fails
|
|
14
|
+
* → status `warn` (server-side; don't blame the operator)
|
|
15
|
+
* - credential exists and server returns 200
|
|
16
|
+
* → status `ok` (latency captured)
|
|
17
|
+
*
|
|
18
|
+
* NOTE: the probe must NEVER log the token itself. Memory hit
|
|
19
|
+
* `feedback_no_claude_attribution_anywhere_hard_rule` plus the CSO
|
|
20
|
+
* sweep on bearer leaks (history: PR-AGENT-MERGE-GATE)
|
|
21
|
+
* frame why this is enforced at the probe layer.
|
|
22
|
+
*/
|
|
23
|
+
export async function probeAuth(ctx, deps) {
|
|
24
|
+
const credential = deps.resolveCredential(ctx.env, ctx.home);
|
|
25
|
+
if (!credential) {
|
|
26
|
+
// "Not configured" vs "configured but broken" — offline / pre-login
|
|
27
|
+
// operators must not see `pugi doctor` exit 2 because they haven't
|
|
28
|
+
// authenticated yet. Skipped is the correct status: it carries the
|
|
29
|
+
// remediation hint without counting against the overall verdict.
|
|
30
|
+
return {
|
|
31
|
+
name: 'AUTH',
|
|
32
|
+
status: 'skipped',
|
|
33
|
+
detail: 'unauthenticated (no PUGI_API_KEY env and no ~/.pugi/credentials.json)',
|
|
34
|
+
remediation: 'Run `pugi login` to authenticate',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const startedAt = deps.now();
|
|
38
|
+
let response;
|
|
39
|
+
try {
|
|
40
|
+
response = await deps.fetchImpl(`${stripTrailingSlash(credential.apiUrl)}/api/pugi/health`, {
|
|
41
|
+
method: 'GET',
|
|
42
|
+
headers: {
|
|
43
|
+
Authorization: `Bearer ${credential.apiKey}`,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
49
|
+
return {
|
|
50
|
+
name: 'AUTH',
|
|
51
|
+
status: 'warn',
|
|
52
|
+
detail: `Auth check skipped — network error contacting ${credential.apiUrl}`,
|
|
53
|
+
remediation: `Verify network: ${message}`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const latencyMs = deps.now() - startedAt;
|
|
57
|
+
if (response.status === 401 || response.status === 403) {
|
|
58
|
+
return {
|
|
59
|
+
name: 'AUTH',
|
|
60
|
+
status: 'error',
|
|
61
|
+
detail: `Token rejected (${response.status}) by ${credential.apiUrl}`,
|
|
62
|
+
latencyMs,
|
|
63
|
+
remediation: 'Token expired or revoked — run `pugi login`',
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
if (response.status >= 500) {
|
|
67
|
+
return {
|
|
68
|
+
name: 'AUTH',
|
|
69
|
+
status: 'warn',
|
|
70
|
+
detail: `Server error ${response.status} from ${credential.apiUrl}`,
|
|
71
|
+
latencyMs,
|
|
72
|
+
remediation: 'Try again in a moment; if it persists, check api.pugi.io status',
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
if (response.status !== 200) {
|
|
76
|
+
return {
|
|
77
|
+
name: 'AUTH',
|
|
78
|
+
status: 'warn',
|
|
79
|
+
detail: `Unexpected status ${response.status} from /api/pugi/health`,
|
|
80
|
+
latencyMs,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
name: 'AUTH',
|
|
85
|
+
status: 'ok',
|
|
86
|
+
detail: `Authenticated against ${credential.apiUrl}`,
|
|
87
|
+
latencyMs,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function stripTrailingSlash(url) {
|
|
91
|
+
return url.endsWith('/') ? url.slice(0, -1) : url;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BARE MODE probe — .
|
|
3
|
+
*
|
|
4
|
+
* Surfaces the `--bare` activation state inside `pugi doctor`. The row is
|
|
5
|
+
* informational: bare mode is an opt-in operator choice, never an error.
|
|
6
|
+
* Operators triaging "why is Pugi ignoring my PUGI.md / why was the
|
|
7
|
+
* `.pugi/` scaffold skipped" see the cause without grep'ing the env.
|
|
8
|
+
*
|
|
9
|
+
* Status semantics:
|
|
10
|
+
* - `skipped` when bare mode is OFF (default). The probe stays silent
|
|
11
|
+
* in the table since there is nothing to report; the row still
|
|
12
|
+
* renders so the JSON consumer can read a stable schema.
|
|
13
|
+
* - `ok` when bare mode is ON via `--bare` or `PUGI_BARE=1`. The detail
|
|
14
|
+
* enumerates the surfaces that are currently bypassed.
|
|
15
|
+
*
|
|
16
|
+
* No I/O — pure env probe. Wired into `buildDefaultProbes` in
|
|
17
|
+
* `runtime/commands/doctor.ts`.
|
|
18
|
+
*/
|
|
19
|
+
import { isBareMode, BARE_MODE_DOCTOR_LABEL } from '../../bare-mode/index.js';
|
|
20
|
+
/**
|
|
21
|
+
* One-line summary printed in the `--bare` row when bare mode is on.
|
|
22
|
+
* Exported so the spec can assert the exact wording — operators reading
|
|
23
|
+
* `pugi doctor` should see the list of surfaces that the flag disables.
|
|
24
|
+
*/
|
|
25
|
+
export const BARE_MODE_ACTIVE_DETAIL = 'bare mode active: PUGI.md walk-up + auto-init + persona auto-load disabled';
|
|
26
|
+
export const BARE_MODE_INACTIVE_DETAIL = 'bare mode off (default auto-discovery)';
|
|
27
|
+
export function probeBareMode(input = {}) {
|
|
28
|
+
const env = input.env ?? process.env;
|
|
29
|
+
if (isBareMode(env)) {
|
|
30
|
+
return {
|
|
31
|
+
name: BARE_MODE_DOCTOR_LABEL,
|
|
32
|
+
status: 'ok',
|
|
33
|
+
detail: BARE_MODE_ACTIVE_DETAIL,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
name: BARE_MODE_DOCTOR_LABEL,
|
|
38
|
+
status: 'skipped',
|
|
39
|
+
detail: BARE_MODE_INACTIVE_DETAIL,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=bare-mode.js.map
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI VERSION probe — compares the running @pugi/cli version against
|
|
3
|
+
* the npm registry's `latest` tag. Surfaces an upgrade banner when
|
|
4
|
+
* the operator is behind.
|
|
5
|
+
*
|
|
6
|
+
* Semver comparison is intentionally minimal — we only need to answer
|
|
7
|
+
* "is local strictly older than latest" for the WARN gate. Edge cases
|
|
8
|
+
* (pre-release ordering, build metadata) collapse к string equality
|
|
9
|
+
* because the publish pipeline only tags clean `X.Y.Z[-channel.N]`.
|
|
10
|
+
*
|
|
11
|
+
* Network failure is NOT an error — the operator is offline, that's
|
|
12
|
+
* a transient condition surfaced by the API probe; this probe reports
|
|
13
|
+
* `warn` so the doctor table still ships a usable verdict.
|
|
14
|
+
*/
|
|
15
|
+
const REGISTRY_URL = 'https://registry.npmjs.org/@pugi/cli/latest';
|
|
16
|
+
/**
|
|
17
|
+
* Strict-newer comparison. Returns true when `b` is strictly newer
|
|
18
|
+
* than `a`. Treats unparseable inputs as equal (no false-positive
|
|
19
|
+
* upgrade banner on a hand-edited local version).
|
|
20
|
+
*/
|
|
21
|
+
export function isNewerVersion(a, b) {
|
|
22
|
+
const left = parseSemver(a);
|
|
23
|
+
const right = parseSemver(b);
|
|
24
|
+
if (!left || !right)
|
|
25
|
+
return false;
|
|
26
|
+
if (right.major !== left.major)
|
|
27
|
+
return right.major > left.major;
|
|
28
|
+
if (right.minor !== left.minor)
|
|
29
|
+
return right.minor > left.minor;
|
|
30
|
+
if (right.patch !== left.patch)
|
|
31
|
+
return right.patch > left.patch;
|
|
32
|
+
// Same X.Y.Z — pre-release ordering: a stable release is newer
|
|
33
|
+
// than any pre-release of the same X.Y.Z; otherwise compare
|
|
34
|
+
// pre-release tokens lexicographically as a coarse heuristic
|
|
35
|
+
// sufficient for the upgrade banner.
|
|
36
|
+
if (!right.pre && left.pre)
|
|
37
|
+
return true;
|
|
38
|
+
if (right.pre && !left.pre)
|
|
39
|
+
return false;
|
|
40
|
+
if (right.pre && left.pre)
|
|
41
|
+
return right.pre > left.pre;
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
function parseSemver(version) {
|
|
45
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?/.exec(version);
|
|
46
|
+
if (!match)
|
|
47
|
+
return null;
|
|
48
|
+
const major = Number(match[1]);
|
|
49
|
+
const minor = Number(match[2]);
|
|
50
|
+
const patch = Number(match[3]);
|
|
51
|
+
if (!Number.isFinite(major) || !Number.isFinite(minor) || !Number.isFinite(patch)) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
return { major, minor, patch, pre: match[4] ?? '' };
|
|
55
|
+
}
|
|
56
|
+
export async function probeCliVersion(deps) {
|
|
57
|
+
const url = deps.registryUrl ?? REGISTRY_URL;
|
|
58
|
+
const timeoutMs = deps.timeoutMs ?? 3_000;
|
|
59
|
+
const controller = new AbortController();
|
|
60
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
61
|
+
const startedAt = deps.now();
|
|
62
|
+
let response;
|
|
63
|
+
try {
|
|
64
|
+
response = await deps.fetchImpl(url, {
|
|
65
|
+
method: 'GET',
|
|
66
|
+
headers: { Accept: 'application/json' },
|
|
67
|
+
signal: controller.signal,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
clearTimeout(timer);
|
|
72
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
73
|
+
return {
|
|
74
|
+
name: 'CLI VERSION',
|
|
75
|
+
status: 'warn',
|
|
76
|
+
detail: `local=${deps.localVersion} — registry unreachable`,
|
|
77
|
+
remediation: `Skip-able. Network error: ${message}`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
clearTimeout(timer);
|
|
81
|
+
const latencyMs = deps.now() - startedAt;
|
|
82
|
+
if (!response.ok) {
|
|
83
|
+
return {
|
|
84
|
+
name: 'CLI VERSION',
|
|
85
|
+
status: 'warn',
|
|
86
|
+
detail: `local=${deps.localVersion} — registry returned ${response.status}`,
|
|
87
|
+
latencyMs,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
let body;
|
|
91
|
+
try {
|
|
92
|
+
body = (await response.json());
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return {
|
|
96
|
+
name: 'CLI VERSION',
|
|
97
|
+
status: 'warn',
|
|
98
|
+
detail: `local=${deps.localVersion} — registry JSON unparseable`,
|
|
99
|
+
latencyMs,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const remote = body.version;
|
|
103
|
+
if (typeof remote !== 'string' || remote.length === 0) {
|
|
104
|
+
return {
|
|
105
|
+
name: 'CLI VERSION',
|
|
106
|
+
status: 'warn',
|
|
107
|
+
detail: `local=${deps.localVersion} — registry response missing version`,
|
|
108
|
+
latencyMs,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (isNewerVersion(deps.localVersion, remote)) {
|
|
112
|
+
return {
|
|
113
|
+
name: 'CLI VERSION',
|
|
114
|
+
status: 'warn',
|
|
115
|
+
detail: `local=${deps.localVersion}, latest=${remote}`,
|
|
116
|
+
latencyMs,
|
|
117
|
+
remediation: 'Run `npm i -g @pugi/cli@latest` to upgrade',
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
name: 'CLI VERSION',
|
|
122
|
+
status: 'ok',
|
|
123
|
+
detail: `${deps.localVersion} (latest)`,
|
|
124
|
+
latencyMs,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=cli-version.js.map
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CONFIG probe — verifies `~/.pugi/credentials.json` exists, parses,
|
|
3
|
+
* and carries the canonical shape (a `tokens` array). Lighter-weight
|
|
4
|
+
* than the auth probe (no network); catches `corrupted JSON` /
|
|
5
|
+
* `accidentally overwrote with empty file` / `bad permissions` cases
|
|
6
|
+
* that would otherwise surface as confusing errors deeper in the
|
|
7
|
+
* auth path.
|
|
8
|
+
*
|
|
9
|
+
* Absence of the file is NOT an error here — the operator may not
|
|
10
|
+
* have run `pugi login` yet. That case is caught by the AUTH probe
|
|
11
|
+
* with a clean "run pugi login" remediation. CONFIG's job is to
|
|
12
|
+
* verify the file is sane WHEN it exists.
|
|
13
|
+
*/
|
|
14
|
+
export function probeConfig(ctx, fs) {
|
|
15
|
+
const credPath = `${ctx.home}/.pugi/credentials.json`;
|
|
16
|
+
if (!fs.existsSync(credPath)) {
|
|
17
|
+
return {
|
|
18
|
+
name: 'CONFIG',
|
|
19
|
+
status: 'skipped',
|
|
20
|
+
detail: '~/.pugi/credentials.json absent (operator has not logged in)',
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
let raw;
|
|
24
|
+
try {
|
|
25
|
+
raw = fs.readFileSync(credPath, 'utf8');
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
29
|
+
return {
|
|
30
|
+
name: 'CONFIG',
|
|
31
|
+
status: 'error',
|
|
32
|
+
detail: `Cannot read ~/.pugi/credentials.json`,
|
|
33
|
+
remediation: `Fix permissions or delete and re-login: ${message}`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
let parsed;
|
|
37
|
+
try {
|
|
38
|
+
parsed = JSON.parse(raw);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
42
|
+
return {
|
|
43
|
+
name: 'CONFIG',
|
|
44
|
+
status: 'error',
|
|
45
|
+
detail: `~/.pugi/credentials.json is not valid JSON`,
|
|
46
|
+
remediation: `Delete and re-login: ${message}`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
50
|
+
return {
|
|
51
|
+
name: 'CONFIG',
|
|
52
|
+
status: 'error',
|
|
53
|
+
detail: `credentials.json root is not an object`,
|
|
54
|
+
remediation: 'Delete and re-login',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
const tokens = parsed.tokens;
|
|
58
|
+
if (!Array.isArray(tokens)) {
|
|
59
|
+
return {
|
|
60
|
+
name: 'CONFIG',
|
|
61
|
+
status: 'error',
|
|
62
|
+
detail: `credentials.json missing required \`tokens\` array`,
|
|
63
|
+
remediation: 'Delete and re-login',
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
name: 'CONFIG',
|
|
68
|
+
status: 'ok',
|
|
69
|
+
detail: `~/.pugi/credentials.json valid (${tokens.length} token(s) stored)`,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L11 — DENIAL TRACKING probe for `pugi doctor`.
|
|
3
|
+
*
|
|
4
|
+
* Reports the current session's denial pressure: total denial count,
|
|
5
|
+
* unique (tool, args) patterns, and how many patterns have repeated
|
|
6
|
+
* past the reminder threshold. Operators read this to spot:
|
|
7
|
+
*
|
|
8
|
+
* - A hook script refusing more dispatches than expected (mis-
|
|
9
|
+
* configured `.pugi/hooks.json`).
|
|
10
|
+
* - Plan-mode runs where the model keeps trying mutating tools
|
|
11
|
+
* (a sign the prompt is not anchoring it correctly).
|
|
12
|
+
* - Stale-read loops indicating concurrent multi-agent writes.
|
|
13
|
+
*
|
|
14
|
+
* Status semantics:
|
|
15
|
+
*
|
|
16
|
+
* - `ok` when the tracker is empty OR carries denials but none have
|
|
17
|
+
* repeated past the threshold. Single denials are normal session
|
|
18
|
+
* hygiene; repeats are the signal.
|
|
19
|
+
* - `warn` when one or more patterns repeated >= the reminder
|
|
20
|
+
* threshold. The probe surfaces the count so the operator can act.
|
|
21
|
+
* - `skipped` when no tracker is wired (e.g. doctor invoked outside
|
|
22
|
+
* a live REPL session, top-level `pugi doctor`).
|
|
23
|
+
*
|
|
24
|
+
* Pure: takes a tracker snapshot — no I/O, no module-level state.
|
|
25
|
+
*/
|
|
26
|
+
import { DENIAL_REMINDER_THRESHOLD, } from '../../denial-tracking/state.js';
|
|
27
|
+
export function probeDenialTracking(deps) {
|
|
28
|
+
if (!deps.tracker) {
|
|
29
|
+
return {
|
|
30
|
+
name: 'DENIAL TRACKING',
|
|
31
|
+
status: 'skipped',
|
|
32
|
+
detail: 'No live session — run `pugi doctor` from inside the REPL to see denials.',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const summary = deps.tracker.summary();
|
|
36
|
+
if (summary.totalDenials === 0) {
|
|
37
|
+
return {
|
|
38
|
+
name: 'DENIAL TRACKING',
|
|
39
|
+
status: 'ok',
|
|
40
|
+
detail: 'No tool denials this session.',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (summary.repeatedPatterns === 0) {
|
|
44
|
+
return {
|
|
45
|
+
name: 'DENIAL TRACKING',
|
|
46
|
+
status: 'ok',
|
|
47
|
+
detail: `${summary.totalDenials} denial(s), ${summary.uniquePatterns} unique pattern(s), none repeated.`,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
name: 'DENIAL TRACKING',
|
|
52
|
+
status: 'warn',
|
|
53
|
+
detail: `${summary.totalDenials} denial(s), ${summary.repeatedPatterns} pattern(s) repeated >= ${DENIAL_REMINDER_THRESHOLD}.`,
|
|
54
|
+
remediation: 'Inspect via `/permissions denials` (when L6 lands) or check `.pugi/events.jsonl` for the latest refusals.',
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=denial-tracking.js.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DISK probe — warn the operator when the home partition is dangerously
|
|
3
|
+
* full. The session log, file cache, MCP working dirs, and the engine
|
|
4
|
+
* artifact bundle all land under `~/.pugi/`, so a full disk produces
|
|
5
|
+
* cryptic ENOSPC errors mid-dispatch. We catch that early.
|
|
6
|
+
*
|
|
7
|
+
* Implementation strategy: call `df -k` (POSIX-portable BSD tool with a
|
|
8
|
+
* stable column ordering) on the home dir and parse the available
|
|
9
|
+
* column. Bytes math + 1k blocks = simple integer arithmetic. We
|
|
10
|
+
* deliberately avoid `statvfs` because Node's stable surface for it
|
|
11
|
+
* (`fs.statfs` introduced in Node 18.15) returns BigInts that callers
|
|
12
|
+
* routinely mishandle on cross-platform builds.
|
|
13
|
+
*
|
|
14
|
+
* Thresholds:
|
|
15
|
+
* - `< 256 MiB` available → error (Pugi cannot do meaningful work)
|
|
16
|
+
* - `< 1 GiB` available → warn (operator should clear space soon)
|
|
17
|
+
* - otherwise → ok
|
|
18
|
+
*/
|
|
19
|
+
const MIB = 1024 * 1024;
|
|
20
|
+
const GIB = MIB * 1024;
|
|
21
|
+
const ERROR_THRESHOLD_BYTES = 256 * MIB;
|
|
22
|
+
const WARN_THRESHOLD_BYTES = 1 * GIB;
|
|
23
|
+
export function probeDisk(ctx, deps) {
|
|
24
|
+
let freeBytes;
|
|
25
|
+
try {
|
|
26
|
+
freeBytes = deps.getFreeBytes(ctx.home);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
30
|
+
return {
|
|
31
|
+
name: 'DISK',
|
|
32
|
+
status: 'warn',
|
|
33
|
+
detail: `Cannot determine free space on ${ctx.home}`,
|
|
34
|
+
remediation: `Inspection failed: ${message}`,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
if (!Number.isFinite(freeBytes) || freeBytes < 0) {
|
|
38
|
+
return {
|
|
39
|
+
name: 'DISK',
|
|
40
|
+
status: 'warn',
|
|
41
|
+
detail: `df returned implausible value (${freeBytes}) for ${ctx.home}`,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const human = formatBytes(freeBytes);
|
|
45
|
+
if (freeBytes < ERROR_THRESHOLD_BYTES) {
|
|
46
|
+
return {
|
|
47
|
+
name: 'DISK',
|
|
48
|
+
status: 'error',
|
|
49
|
+
detail: `${human} free on home partition`,
|
|
50
|
+
remediation: 'Free disk space — Pugi writes ~/.pugi/sessions and cache files',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
if (freeBytes < WARN_THRESHOLD_BYTES) {
|
|
54
|
+
return {
|
|
55
|
+
name: 'DISK',
|
|
56
|
+
status: 'warn',
|
|
57
|
+
detail: `${human} free on home partition`,
|
|
58
|
+
remediation: 'Consider clearing ~/.pugi/sessions older entries',
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
name: 'DISK',
|
|
63
|
+
status: 'ok',
|
|
64
|
+
detail: `${human} free on home partition`,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Format bytes as `1.2GB` / `512MB` / `42KB`. Stays in IEC base-1024
|
|
69
|
+
* because that's what `df -k` returns and what operators reading the
|
|
70
|
+
* doctor table expect to see on their `df` follow-up.
|
|
71
|
+
*/
|
|
72
|
+
export function formatBytes(bytes) {
|
|
73
|
+
if (bytes >= GIB)
|
|
74
|
+
return `${(bytes / GIB).toFixed(1)}GB`;
|
|
75
|
+
if (bytes >= MIB)
|
|
76
|
+
return `${Math.round(bytes / MIB)}MB`;
|
|
77
|
+
if (bytes >= 1024)
|
|
78
|
+
return `${Math.round(bytes / 1024)}KB`;
|
|
79
|
+
return `${bytes}B`;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=disk.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const LIVE_PROMPT = 'Reply with the single word OK.';
|
|
2
|
+
const TIMEOUT_MS = 15_000;
|
|
3
|
+
export async function probeEngineLive(ctx, deps) {
|
|
4
|
+
const apiKey = deps.resolveApiKey(ctx.env);
|
|
5
|
+
if (!apiKey) {
|
|
6
|
+
return { name: 'ENGINE LIVE', status: 'skipped', detail: 'no API key (run `pugi login` or set PUGI_API_KEY)' };
|
|
7
|
+
}
|
|
8
|
+
const apiUrl = deps.resolveApiUrl(ctx.env);
|
|
9
|
+
const startedAt = deps.now();
|
|
10
|
+
const url = (apiUrl.endsWith('/') ? apiUrl.slice(0, -1) : apiUrl) + '/api/pugi/engine';
|
|
11
|
+
try {
|
|
12
|
+
const res = await deps.fetchImpl(url, {
|
|
13
|
+
method: 'POST',
|
|
14
|
+
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
15
|
+
headers: { 'content-type': 'application/json', authorization: `Bearer ${apiKey}` },
|
|
16
|
+
body: JSON.stringify({
|
|
17
|
+
personaSlug: 'main',
|
|
18
|
+
command: 'explain',
|
|
19
|
+
messages: [{ role: 'user', content: LIVE_PROMPT }],
|
|
20
|
+
tools: [],
|
|
21
|
+
temperature: 0,
|
|
22
|
+
maxTokens: 32,
|
|
23
|
+
}),
|
|
24
|
+
});
|
|
25
|
+
const latencyMs = deps.now() - startedAt;
|
|
26
|
+
if (!res.ok) {
|
|
27
|
+
const body = await res.text().catch(() => '');
|
|
28
|
+
return { name: 'ENGINE LIVE', status: 'error', detail: `engine returned HTTP ${res.status}${body ? `: ${body.slice(0, 200)}` : ''}`, latencyMs };
|
|
29
|
+
}
|
|
30
|
+
const json = (await res.json().catch(() => null));
|
|
31
|
+
if (!json)
|
|
32
|
+
return { name: 'ENGINE LIVE', status: 'error', detail: 'engine returned 2xx but body is not JSON', latencyMs };
|
|
33
|
+
const model = typeof json['model'] === 'string' ? json['model'] : 'unknown';
|
|
34
|
+
const content = typeof json['content'] === 'string' ? json['content'] : '';
|
|
35
|
+
if (!content.toLowerCase().includes('ok')) {
|
|
36
|
+
return { name: 'ENGINE LIVE', status: 'warn', detail: `round-trip OK via ${model} (${latencyMs}ms) but reply did not contain expected token; got "${content.slice(0, 80)}"`, latencyMs };
|
|
37
|
+
}
|
|
38
|
+
return { name: 'ENGINE LIVE', status: 'ok', detail: `round-trip OK via ${model} (${latencyMs}ms)`, latencyMs };
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
const latencyMs = deps.now() - startedAt;
|
|
42
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
43
|
+
return { name: 'ENGINE LIVE', status: 'error', detail: `engine round-trip failed: ${message}`, latencyMs };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=engine-live.js.map
|