@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,86 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Box, Text, useInput } from 'ink';
|
|
4
|
+
import { PERMISSION_MODES, PERMISSION_MODE_GLOSS, } from '../core/permissions/index.js';
|
|
5
|
+
/**
|
|
6
|
+
* Build the rendered rows from the canonical mode list. We map the
|
|
7
|
+
* 1-line gloss → row hint so `/permissions` and the picker stay in
|
|
8
|
+
* sync — a change to `PERMISSION_MODE_GLOSS` shows up here too.
|
|
9
|
+
*/
|
|
10
|
+
const ITEMS = PERMISSION_MODES.map((mode) => ({
|
|
11
|
+
mode,
|
|
12
|
+
title: titleCase(mode),
|
|
13
|
+
hint: PERMISSION_MODE_GLOSS[mode],
|
|
14
|
+
}));
|
|
15
|
+
function titleCase(mode) {
|
|
16
|
+
return mode.charAt(0).toUpperCase() + mode.slice(1);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Resolve the initial cursor — prefer the explicit `initialIndex`
|
|
20
|
+
* (spec / test) when provided, otherwise highlight the row matching
|
|
21
|
+
* the active mode so the operator opens the picker with their
|
|
22
|
+
* current selection focused.
|
|
23
|
+
*/
|
|
24
|
+
function resolveInitialIndex(currentMode, override) {
|
|
25
|
+
if (typeof override === 'number') {
|
|
26
|
+
return Math.min(Math.max(override, 0), ITEMS.length - 1);
|
|
27
|
+
}
|
|
28
|
+
const idx = ITEMS.findIndex((item) => item.mode === currentMode);
|
|
29
|
+
return idx >= 0 ? idx : 0;
|
|
30
|
+
}
|
|
31
|
+
export function PermissionsPicker(props) {
|
|
32
|
+
const [index, setIndex] = useState(resolveInitialIndex(props.currentMode, props.initialIndex));
|
|
33
|
+
useInput((input, key) => {
|
|
34
|
+
if (key.upArrow || input === 'k') {
|
|
35
|
+
setIndex((current) => (current === 0 ? ITEMS.length - 1 : current - 1));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (key.downArrow || input === 'j') {
|
|
39
|
+
setIndex((current) => (current === ITEMS.length - 1 ? 0 : current + 1));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (key.return) {
|
|
43
|
+
const selected = ITEMS[index];
|
|
44
|
+
if (selected)
|
|
45
|
+
props.onSelect(selected.mode);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (key.escape || input === 'q') {
|
|
49
|
+
props.onCancel();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// : number shortcuts mirror the canonical 6-mode order.
|
|
53
|
+
// Operators coming from the upstream tool reach the same mode with the
|
|
54
|
+
// same digit (1=default, 2=acceptEdits, …, 6=bypassPermissions).
|
|
55
|
+
if (input === '1')
|
|
56
|
+
props.onSelect('default');
|
|
57
|
+
if (input === '2')
|
|
58
|
+
props.onSelect('acceptEdits');
|
|
59
|
+
if (input === '3')
|
|
60
|
+
props.onSelect('plan');
|
|
61
|
+
if (input === '4')
|
|
62
|
+
props.onSelect('auto');
|
|
63
|
+
if (input === '5')
|
|
64
|
+
props.onSelect('dontAsk');
|
|
65
|
+
if (input === '6')
|
|
66
|
+
props.onSelect('bypassPermissions');
|
|
67
|
+
});
|
|
68
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Permission mode" }), _jsx(Text, { dimColor: true, children: ` (current: ${props.currentMode} — ${props.sourceLabel})` })] }), props.firstRun ? (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "First time? Mode = Ask \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E. Use /permissions \u043A change later." }) })) : null, _jsx(Box, { marginTop: 1, flexDirection: "column", children: ITEMS.map((item, itemIndex) => {
|
|
69
|
+
const isSelected = itemIndex === index;
|
|
70
|
+
const isCurrent = item.mode === props.currentMode;
|
|
71
|
+
return (_jsx(PickerRow, { isSelected: isSelected, isCurrent: isCurrent, title: item.title, hint: item.hint }, item.mode));
|
|
72
|
+
}) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: '↑/↓ select Enter confirm Esc cancel' }) })] }));
|
|
73
|
+
}
|
|
74
|
+
function PickerRow({ isSelected, isCurrent, title, hint, }) {
|
|
75
|
+
// Arrow glyph + padded title so highlighted and dim rows share
|
|
76
|
+
// column alignment. A trailing ` ●` marks the currently-effective
|
|
77
|
+
// mode (separate from cursor focus) so an operator instantly sees
|
|
78
|
+
// which row is "what I have now" vs "what I'm hovering".
|
|
79
|
+
const indicator = isSelected ? '▸ ' : ' ';
|
|
80
|
+
// : longest title is `BypassPermissions` (17 chars). Bump the
|
|
81
|
+
// pad column так the gloss column stays aligned across all 6 rows.
|
|
82
|
+
const padded = title.padEnd(18, ' ');
|
|
83
|
+
const currentMarker = isCurrent ? ' ●' : ' ';
|
|
84
|
+
return (_jsxs(Text, { children: [_jsxs(Text, { color: isSelected ? 'cyan' : undefined, bold: isSelected, children: [indicator, padded] }), _jsx(Text, { color: isCurrent ? 'green' : undefined, children: currentMarker }), _jsx(Text, { dimColor: true, children: ` ${hint}` })] }));
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=permissions-picker.js.map
|
package/dist/tui/render.js
CHANGED
|
@@ -2,6 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { render } from 'ink';
|
|
3
3
|
import { DeviceFlow } from './device-flow.js';
|
|
4
4
|
import { LoginPicker } from './login-picker.js';
|
|
5
|
+
import { PermissionsPicker } from './permissions-picker.js';
|
|
5
6
|
import { Splash } from './splash.js';
|
|
6
7
|
import { collectSplashData } from './splash-data.js';
|
|
7
8
|
/**
|
|
@@ -25,7 +26,7 @@ export async function renderSplash(cliVersion) {
|
|
|
25
26
|
* Sentinel thrown when the user dismisses the login picker via Esc
|
|
26
27
|
* or `q`. The CLI dispatcher catches it, prints a one-line abort
|
|
27
28
|
* message, and exits 130 (the standard exit code for SIGINT-style
|
|
28
|
-
* user cancellations — matches gh CLI
|
|
29
|
+
* user cancellations — matches gh CLI and peer CLIs).
|
|
29
30
|
*/
|
|
30
31
|
export class LoginCancelledError extends Error {
|
|
31
32
|
constructor() {
|
|
@@ -66,6 +67,40 @@ export function renderLoginPicker(apiUrl) {
|
|
|
66
67
|
}));
|
|
67
68
|
});
|
|
68
69
|
}
|
|
70
|
+
/**
|
|
71
|
+
* Sentinel thrown when the operator dismisses the permissions picker
|
|
72
|
+
* via Esc / q. Mirrors `LoginCancelledError` — the host catches and
|
|
73
|
+
* prints a one-line abort message; no mode flip lands.
|
|
74
|
+
*/
|
|
75
|
+
export class PermissionsPickerCancelledError extends Error {
|
|
76
|
+
constructor() {
|
|
77
|
+
super('Permissions picker cancelled');
|
|
78
|
+
this.name = 'PermissionsPickerCancelledError';
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export function renderPermissionsPicker(options) {
|
|
82
|
+
return new Promise((resolveMode, rejectMode) => {
|
|
83
|
+
let settled = false;
|
|
84
|
+
const finish = (cb) => {
|
|
85
|
+
if (settled)
|
|
86
|
+
return;
|
|
87
|
+
settled = true;
|
|
88
|
+
instance.unmount();
|
|
89
|
+
setImmediate(cb);
|
|
90
|
+
};
|
|
91
|
+
const instance = render(React.createElement(PermissionsPicker, {
|
|
92
|
+
currentMode: options.currentMode,
|
|
93
|
+
sourceLabel: options.sourceLabel,
|
|
94
|
+
firstRun: options.firstRun ?? false,
|
|
95
|
+
onSelect: (mode) => {
|
|
96
|
+
finish(() => resolveMode(mode));
|
|
97
|
+
},
|
|
98
|
+
onCancel: () => {
|
|
99
|
+
finish(() => rejectMode(new PermissionsPickerCancelledError()));
|
|
100
|
+
},
|
|
101
|
+
}));
|
|
102
|
+
});
|
|
103
|
+
}
|
|
69
104
|
/**
|
|
70
105
|
* Mount `<DeviceFlow />` on a TTY and return a handle the host uses to
|
|
71
106
|
* drive the frame. Mirrors `renderLoginPicker`'s lifecycle: we
|
package/dist/tui/repl-render.js
CHANGED
|
@@ -1,29 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Production REPL mount + transport - Sprint
|
|
2
|
+
* Production REPL mount + transport - Sprint .
|
|
3
3
|
*
|
|
4
4
|
* Owns the Ink mount lifecycle for `<Repl />` and wires the real
|
|
5
5
|
* fetch + SSE transport. The CLI dispatcher in `runtime/cli.ts` calls
|
|
6
6
|
* `renderRepl` on the bare-`pugi` path when stdin / stdout are TTYs.
|
|
7
7
|
*
|
|
8
8
|
* The transport speaks to admin-api:
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* POST /api/pugi/sessions → { sessionId }
|
|
10
|
+
* POST /api/pugi/sessions/:id/brief → { dispatchId }
|
|
11
|
+
* POST /api/pugi/sessions/:id/stop → { stopped }
|
|
12
|
+
* GET /api/pugi/sessions/:id/stream → text/event-stream
|
|
13
13
|
*
|
|
14
14
|
* SSE is parsed client-side from a streaming fetch response - Node 22
|
|
15
15
|
* native fetch returns a WHATWG `ReadableStream` which we feed through
|
|
16
16
|
* a tiny `event:`/`data:`/`id:` parser. This keeps the dependency
|
|
17
17
|
* graph at zero new packages.
|
|
18
18
|
*/
|
|
19
|
+
import { existsSync } from 'node:fs';
|
|
20
|
+
import { resolve } from 'node:path';
|
|
19
21
|
import React from 'react';
|
|
20
22
|
import { render } from 'ink';
|
|
21
23
|
import { Repl } from './repl.js';
|
|
22
24
|
import { printPugMascotPreInk } from './repl-splash-mascot.js';
|
|
25
|
+
import { collectWelcomeData } from './welcome-data.js';
|
|
26
|
+
import { ThemeProvider } from '../core/theme/context.js';
|
|
27
|
+
import { resolveTheme } from '../core/theme/state.js';
|
|
23
28
|
import { ReplSession, } from '../core/repl/session.js';
|
|
24
29
|
import { resolveWorkspaceContext } from '../core/repl/workspace-context.js';
|
|
30
|
+
import { createEngineBridge } from '../core/repl/engine-bridge.js';
|
|
31
|
+
import { profileFor, resolveIntensity } from '../core/engine/intensity.js';
|
|
25
32
|
import { SqliteSessionStore } from '../core/repl/store/index.js';
|
|
26
33
|
import { slugForCwd } from '../core/repl/history.js';
|
|
34
|
+
import { loadSettings } from '../core/settings.js';
|
|
35
|
+
import { buildRuntimeConfig } from '@pugi/sdk';
|
|
27
36
|
import { WorkingSet, buildRepoSkeleton, loadPugiIgnore, PugiWatcher, } from '../core/context/index.js';
|
|
28
37
|
/**
|
|
29
38
|
* Mount the REPL and resolve when the user exits via Ctrl+C × 2 or
|
|
@@ -31,7 +40,7 @@ import { WorkingSet, buildRepoSkeleton, loadPugiIgnore, PugiWatcher, } from '../
|
|
|
31
40
|
* `pugi resume <sessionId>` once that command exists).
|
|
32
41
|
*/
|
|
33
42
|
export async function renderRepl(options) {
|
|
34
|
-
// beta.9 CEO dogfood
|
|
43
|
+
// beta.9 CEO dogfood: claim stdin raw mode + alt-screen
|
|
35
44
|
// BEFORE any async bootstrap step so keystrokes typed during the
|
|
36
45
|
// [launch -> Ink mount] window cannot echo into the terminal in
|
|
37
46
|
// cooked mode. Previously openLocalStore (SQLite open) +
|
|
@@ -41,7 +50,7 @@ export async function renderRepl(options) {
|
|
|
41
50
|
// every typed character literally onto the screen below the
|
|
42
51
|
// pre-printed mascot/header. The visible result was the operator's
|
|
43
52
|
// "ssssss" landing on the rendered status-bar bottom row (CEO
|
|
44
|
-
// screenshot
|
|
53
|
+
// screenshot: beta.8 REPL bug 2).
|
|
45
54
|
//
|
|
46
55
|
// The claim is idempotent with Ink's own raw-mode enable: Ink
|
|
47
56
|
// ref-counts setRawMode calls, and Node's stdin.setRawMode is
|
|
@@ -50,13 +59,67 @@ export async function renderRepl(options) {
|
|
|
50
59
|
// top, and our finally{} restore drops the floor only after Ink
|
|
51
60
|
// has cleanly torn down (or never mounted on a bootstrap crash).
|
|
52
61
|
const bootstrap = claimTerminalForRepl();
|
|
62
|
+
// beta.13 auto-init wire (CEO dogfood): scaffold the
|
|
63
|
+
// `.pugi/` workspace silently on REPL boot so launching `pugi` in a
|
|
64
|
+
// fresh cwd no longer demands an explicit `pugi init` round-trip.
|
|
65
|
+
// Idempotent — every helper inside scaffoldPugiWorkspace is a
|
|
66
|
+
// `*_IfMissing` write, so re-running over an existing workspace is
|
|
67
|
+
// a no-op. Fail-safe: any FS / perms error never blocks REPL launch.
|
|
68
|
+
// Operator escape hatch: PUGI_NO_AUTO_INIT=1.
|
|
69
|
+
//
|
|
70
|
+
// Beta.13 P2 fix: gate the scaffold on project-root markers
|
|
71
|
+
// so launching `pugi` from `$HOME` / `/tmp` / arbitrary dirs does NOT
|
|
72
|
+
// sprinkle `.pugi/` directories all over the filesystem. The gate
|
|
73
|
+
// mirrors `isBoundWorkspace` from workspace-context.ts but also
|
|
74
|
+
// accepts non-JS roots (Cargo / pyproject / go.mod) because the CLI
|
|
75
|
+
// is language-agnostic and an operator working in a Rust repo deserves
|
|
76
|
+
// the same auto-init UX as a Node operator. Already-bound `.pugi/`
|
|
77
|
+
// dirs also opt back in so the scaffold can fill any missing
|
|
78
|
+
// sub-artifacts the operator deleted.
|
|
79
|
+
// `--bare` (PUGI_BARE=1) ALSO suppresses the
|
|
80
|
+
// auto-init scaffold. Bare mode is the deterministic "fresh install
|
|
81
|
+
// anywhere" path — no `.pugi/` writes, no PUGI.md scaffold, no
|
|
82
|
+
// settings.json seed. The pre-existing PUGI_NO_AUTO_INIT escape
|
|
83
|
+
// hatch stays — bare mode just unions with it.
|
|
84
|
+
const { isBareMode } = await import('../core/bare-mode/index.js');
|
|
85
|
+
if (process.env.PUGI_NO_AUTO_INIT !== '1' &&
|
|
86
|
+
!isBareMode() &&
|
|
87
|
+
isProjectRoot(process.cwd())) {
|
|
88
|
+
try {
|
|
89
|
+
const { scaffoldPugiWorkspace } = await import('../runtime/cli.js');
|
|
90
|
+
await scaffoldPugiWorkspace({
|
|
91
|
+
cwd: process.cwd(),
|
|
92
|
+
noDefaults: true,
|
|
93
|
+
log: () => {
|
|
94
|
+
/* silent — never leak scaffold progress into the REPL alt-screen */
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
// Fail-safe: read-only FS or perms error never blocks REPL launch.
|
|
100
|
+
// Beta.13 P2 fix: bare-catch swallowed the diagnostic;
|
|
101
|
+
// surface it on stderr under PUGI_DEBUG=1 so operator-triage on
|
|
102
|
+
// "why isn't .pugi/ being created?" has a starting point without
|
|
103
|
+
// having to re-instrument the bootstrap.
|
|
104
|
+
if (process.env.PUGI_DEBUG === '1') {
|
|
105
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
106
|
+
process.stderr.write(`[pugi-debug] auto-init failed: ${msg}\n`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
53
110
|
const transport = createProductionTransport();
|
|
54
|
-
// Auto-bind the workspace context from process.cwd() so
|
|
111
|
+
// Auto-bind the workspace context from process.cwd() so Pugi knows
|
|
55
112
|
// which repo the operator launched the CLI in. The resolver is
|
|
56
113
|
// best-effort — any FS error falls back to a basename-only summary,
|
|
57
|
-
// never blocks REPL launch.
|
|
114
|
+
// never blocks REPL launch. fix.
|
|
58
115
|
const workspace = options.workspace ?? resolveWorkspaceContext(process.cwd());
|
|
59
|
-
//
|
|
116
|
+
// Beta.13 P1 fix: read `ui.cyberZoo` from
|
|
117
|
+
// `.pugi/settings.json` so the operator's splash posture flows to
|
|
118
|
+
// admin-api on session open. Without this, the renderer's `cyberZoo`
|
|
119
|
+
// parameter (added beta.13) was always defaulted to 'on' regardless
|
|
120
|
+
// of the operator's actual setting.
|
|
121
|
+
const cyberZoo = readCyberZooSetting(process.cwd());
|
|
122
|
+
// : open the local SessionStore for `/resume` persistence. The
|
|
60
123
|
// store lives under `~/.pugi/projects/<slug>/`; failure is fail-safe
|
|
61
124
|
// — we log a one-line warning to stderr and continue with the REPL
|
|
62
125
|
// in memory-only mode. Lock-busy errors get the friendliest message
|
|
@@ -68,7 +131,7 @@ export async function renderRepl(options) {
|
|
|
68
131
|
workspaceRoot: process.cwd(),
|
|
69
132
|
resumeLocalSessionId: options.resumeLocalSessionId,
|
|
70
133
|
});
|
|
71
|
-
//
|
|
134
|
+
// three-tier context bootstrap. The skeleton + working set
|
|
72
135
|
// + watcher are local-first and best-effort: every step is wrapped
|
|
73
136
|
// in try/catch so an unreadable workspace never blocks REPL launch.
|
|
74
137
|
// Opt-out via PUGI_DISABLE_CONTEXT=1 for hermetic test runs.
|
|
@@ -76,13 +139,63 @@ export async function renderRepl(options) {
|
|
|
76
139
|
cwd: process.cwd(),
|
|
77
140
|
env: process.env,
|
|
78
141
|
});
|
|
142
|
+
// PUGI-538c () -- wire the production engine bridge so
|
|
143
|
+
// `<pugi-tool-route>` envelopes emitted by Pugi's coordinator
|
|
144
|
+
// actually drive a local `NativePugiEngineAdapter` run instead of
|
|
145
|
+
// surfacing "Engine bridge not configured" on the system line. The
|
|
146
|
+
// factory closure resolves `cwd` per invocation so an operator who
|
|
147
|
+
// `cd`-ed mid-session writes files into the new directory (matches
|
|
148
|
+
// `pugi code` direct-path behaviour).
|
|
149
|
+
//
|
|
150
|
+
// The bridge runtime config reuses the REPL transport credentials so
|
|
151
|
+
// a single token authenticates both the coordinator brief (via
|
|
152
|
+
// admin-api /api/pugi/sessions) AND the bridged engine call (via
|
|
153
|
+
// /api/pugi/engine). No new credential surface, no double login.
|
|
154
|
+
//
|
|
155
|
+
// Fail-safe construction: `buildRuntimeConfig` validates apiUrl via
|
|
156
|
+
// `z.string().url()` and throws on a malformed value. We must not
|
|
157
|
+
// crash REPL launch on that path -- every other bootstrap step in
|
|
158
|
+
// this file (auto-init, openLocalStore, bootstrapContext, watcher)
|
|
159
|
+
// is fail-safe. On construction failure we surface a one-line stderr
|
|
160
|
+
// diagnostic under PUGI_DEBUG=1 and pass `engineBridge: undefined`
|
|
161
|
+
// so the REPL launches; the operator sees the legacy "Engine bridge
|
|
162
|
+
// not configured" system line on the first routed brief, which is
|
|
163
|
+
// the same UX as a pre-PUGI-538c CLI build.
|
|
164
|
+
let engineBridge;
|
|
165
|
+
try {
|
|
166
|
+
// PR A (2026-06-05): resolve intensity profile once at bridge
|
|
167
|
+
// construction time. The bridge stays pure and re-uses the resolved
|
|
168
|
+
// profile across every routed brief. `resolveIntensity` reads env
|
|
169
|
+
// (`PUGI_INTENSITY`) и settings.json; the REPL launch lifecycle is
|
|
170
|
+
// the natural binding point. A future `/intensity` REPL command
|
|
171
|
+
// will rebuild the bridge to swap the profile mid-session.
|
|
172
|
+
const intensityLevel = resolveIntensity({});
|
|
173
|
+
const intensityProfile = profileFor(intensityLevel);
|
|
174
|
+
engineBridge = createEngineBridge({
|
|
175
|
+
config: buildRuntimeConfig({
|
|
176
|
+
apiUrl: options.apiUrl,
|
|
177
|
+
apiKey: options.apiKey,
|
|
178
|
+
}),
|
|
179
|
+
cwd: () => process.cwd(),
|
|
180
|
+
intensityProfile,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
if (process.env.PUGI_DEBUG === '1') {
|
|
185
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
186
|
+
process.stderr.write(`[pugi-debug] engine bridge bootstrap failed: ${msg}\n`);
|
|
187
|
+
}
|
|
188
|
+
engineBridge = undefined;
|
|
189
|
+
}
|
|
79
190
|
const session = new ReplSession({
|
|
80
191
|
apiUrl: options.apiUrl,
|
|
81
192
|
apiKey: options.apiKey,
|
|
82
193
|
workspaceLabel: options.workspaceLabel,
|
|
83
194
|
cliVersion: options.cliVersion,
|
|
84
195
|
transport,
|
|
196
|
+
...(engineBridge !== undefined ? { engineBridge } : {}),
|
|
85
197
|
workspace,
|
|
198
|
+
cyberZoo,
|
|
86
199
|
store,
|
|
87
200
|
localSessionId: openedSessionId,
|
|
88
201
|
repoSkeleton: skeleton,
|
|
@@ -113,7 +226,7 @@ export async function renderRepl(options) {
|
|
|
113
226
|
// typed it after the REPL became interactive. Idempotent: no-op
|
|
114
227
|
// when stdin is not a TTY or no bytes were buffered.
|
|
115
228
|
drainBufferedStdin(process.stdin);
|
|
116
|
-
//
|
|
229
|
+
// wave 5: paint the chafa-baked brand-pug ANSI render to
|
|
117
230
|
// stdout BEFORE Ink mounts (but AFTER alt-screen enter). Ink's
|
|
118
231
|
// layout engine would mis-measure the truecolor escape sequences,
|
|
119
232
|
// so the pug must land verbatim. The flag is passed into <Repl />
|
|
@@ -123,13 +236,56 @@ export async function renderRepl(options) {
|
|
|
123
236
|
// (operator opted out via --no-splash), we suppress the pre-print
|
|
124
237
|
// too so the boot stays silent.
|
|
125
238
|
const mascotPrePrinted = options.skipSplash === true ? false : printPugMascotPreInk(process.stdout);
|
|
126
|
-
|
|
239
|
+
// resolve the active theme ONCE at mount
|
|
240
|
+
// and wrap `<Repl />` in `<ThemeProvider>` so every Ink consumer
|
|
241
|
+
// (`<Header>`, `<DoctorTable>`, `<StyleTable>`, `<ThemeTable>`,
|
|
242
|
+
// …) picks up the same color tokens. The provider is stable for
|
|
243
|
+
// the lifetime of the REPL — operator `/theme <name>` writes to
|
|
244
|
+
// disk + appends a system line, and the next `pugi` launch re-
|
|
245
|
+
// mounts with the new slug. Re-mounting mid-session would race
|
|
246
|
+
// against Ink's raw-mode handler so we deliberately keep the
|
|
247
|
+
// session-lifetime contract instead of polling the config file.
|
|
248
|
+
const resolvedTheme = resolveTheme({
|
|
249
|
+
workspaceRoot: process.cwd(),
|
|
250
|
+
env: process.env,
|
|
251
|
+
});
|
|
252
|
+
// CEO P0 #2 : collect welcome banner data BEFORE Ink
|
|
253
|
+
// mounts so the banner paints on the first frame instead of swapping
|
|
254
|
+
// in mid-render. The collector swallows every IO error so а missing
|
|
255
|
+
// CHANGELOG / unreadable credential / malformed settings never
|
|
256
|
+
// blocks the boot.
|
|
257
|
+
let welcomeData;
|
|
258
|
+
if (options.skipSplash !== true) {
|
|
259
|
+
try {
|
|
260
|
+
welcomeData = collectWelcomeData({
|
|
261
|
+
cliVersion: options.cliVersion,
|
|
262
|
+
cwd: process.cwd(),
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
welcomeData = undefined;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
const instance = render(React.createElement(ThemeProvider, { slug: resolvedTheme.slug }, React.createElement(Repl, {
|
|
127
270
|
session,
|
|
128
271
|
updateBanner: options.updateBanner ?? null,
|
|
129
272
|
skipSplash: options.skipSplash === true,
|
|
130
273
|
hideToolStream: options.hideToolStream === true,
|
|
131
274
|
mascotPrePrinted,
|
|
132
|
-
|
|
275
|
+
welcomeData,
|
|
276
|
+
autoInitStatus: options.autoInitStatus ?? null,
|
|
277
|
+
})), {
|
|
278
|
+
// PUGI-534 — Ink kills the process on the first raw Ctrl+C by
|
|
279
|
+
// default, which beat the InputBox useInput double-tap timer to
|
|
280
|
+
// the punch (operator reported single ^C exits the REPL). Disable
|
|
281
|
+
// Ink's built-in handler so the InputBox `lastCtrlCAt` window owns
|
|
282
|
+
// the exit gesture: first press → cancel + toast, second press
|
|
283
|
+
// within 1s → `handleExit()` → `useApp().exit()`. SIGINT handlers
|
|
284
|
+
// on the process object (sigint-guard + per-engine-task in
|
|
285
|
+
// runtime/cli.ts) still fire as defence-in-depth on the rare
|
|
286
|
+
// non-raw fallback path.
|
|
287
|
+
exitOnCtrlC: false,
|
|
288
|
+
});
|
|
133
289
|
// Make sure we leave the alt screen on abrupt exits too. Without
|
|
134
290
|
// this the operator's shell stays "frozen" on the Pugi splash.
|
|
135
291
|
process.once('exit', bootstrap.restore);
|
|
@@ -242,6 +398,55 @@ export function drainBufferedStdin(stdin = process.stdin) {
|
|
|
242
398
|
return 0;
|
|
243
399
|
}
|
|
244
400
|
}
|
|
401
|
+
/**
|
|
402
|
+
* Project-root probe — beta.13 P2 fix.
|
|
403
|
+
*
|
|
404
|
+
* Beta.13 auto-init was unconditional and silently created `.pugi/` in
|
|
405
|
+
* every cwd the REPL was launched from, including `$HOME` and `/tmp`.
|
|
406
|
+
* Operators who ran `pugi` to ask a quick question outside of any
|
|
407
|
+
* project ended up with stray `.pugi/` directories polluting their
|
|
408
|
+
* filesystem. The gate looks for any of six project-root markers
|
|
409
|
+
* before scaffolding:
|
|
410
|
+
*
|
|
411
|
+
* - `package.json` — JS / TS workspaces
|
|
412
|
+
* - `.git` — any cloned repo regardless of language
|
|
413
|
+
* - `.pugi` — already-bound Pugi workspace (re-scaffold
|
|
414
|
+
* fills any missing artifacts the operator
|
|
415
|
+
* deleted, idempotent over existing files)
|
|
416
|
+
* - `Cargo.toml` — Rust crates
|
|
417
|
+
* - `pyproject.toml` — Python projects (PEP 518)
|
|
418
|
+
* - `go.mod` — Go modules
|
|
419
|
+
*
|
|
420
|
+
* The probe is six cheap `existsSync` calls; the cost is negligible
|
|
421
|
+
* compared with the alt-screen + Ink mount that follows. Exported so a
|
|
422
|
+
* future unit spec can lock the contract.
|
|
423
|
+
*/
|
|
424
|
+
export function isProjectRoot(cwd) {
|
|
425
|
+
// ESM static imports — `require()` is not defined in a `"type": "module"`
|
|
426
|
+
// bundle and would throw `ReferenceError: require is not defined` the
|
|
427
|
+
// moment the REPL bootstrap calls this gate. Beta.16 P0 fix.
|
|
428
|
+
return (existsSync(resolve(cwd, 'package.json')) ||
|
|
429
|
+
existsSync(resolve(cwd, '.git')) ||
|
|
430
|
+
existsSync(resolve(cwd, '.pugi')) ||
|
|
431
|
+
existsSync(resolve(cwd, 'Cargo.toml')) ||
|
|
432
|
+
existsSync(resolve(cwd, 'pyproject.toml')) ||
|
|
433
|
+
existsSync(resolve(cwd, 'go.mod')));
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Read the operator's cyber-zoo posture from `.pugi/settings.json`.
|
|
437
|
+
* Best-effort: when the file is missing / malformed, fall through to
|
|
438
|
+
* the historical 'on' default so the REPL never refuses to launch on
|
|
439
|
+
* a settings error. Beta.13 P1 fix.
|
|
440
|
+
*/
|
|
441
|
+
function readCyberZooSetting(cwd) {
|
|
442
|
+
try {
|
|
443
|
+
const settings = loadSettings(cwd);
|
|
444
|
+
return settings.ui?.cyberZoo ?? 'on';
|
|
445
|
+
}
|
|
446
|
+
catch {
|
|
447
|
+
return 'on';
|
|
448
|
+
}
|
|
449
|
+
}
|
|
245
450
|
/**
|
|
246
451
|
* Open the local SessionStore for the REPL bootstrap. Returns
|
|
247
452
|
* `{ store: null, openedSessionId: undefined }` on any error so the
|
|
@@ -279,11 +484,11 @@ async function openLocalStore(input) {
|
|
|
279
484
|
}
|
|
280
485
|
}
|
|
281
486
|
/**
|
|
282
|
-
* Bootstrap the
|
|
487
|
+
* Bootstrap the three-tier context primitives:
|
|
283
488
|
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
489
|
+
* - Tier 0: `RepoSkeleton` (~5KB ASCII tree + meta) for prompt injection.
|
|
490
|
+
* - Tier 1: `WorkingSet` LRU bounded at 50 entries.
|
|
491
|
+
* - Filewatch: chokidar started against cwd, ignore-filtered.
|
|
287
492
|
*
|
|
288
493
|
* The bootstrap is fail-safe: every primitive is wrapped so the REPL
|
|
289
494
|
* still launches when (e.g.) chokidar refuses to start on a
|
|
@@ -331,15 +536,22 @@ async function bootstrapContext(input) {
|
|
|
331
536
|
return { skeleton, workingSet, watcher };
|
|
332
537
|
}
|
|
333
538
|
/* ------------------------------------------------------------------ */
|
|
334
|
-
/* Production transport
|
|
539
|
+
/* Production transport */
|
|
335
540
|
/* ------------------------------------------------------------------ */
|
|
336
541
|
export function createProductionTransport() {
|
|
337
542
|
return {
|
|
338
|
-
async createSession({ apiUrl, apiKey, workspace }) {
|
|
543
|
+
async createSession({ apiUrl, apiKey, workspace, cyberZoo }) {
|
|
339
544
|
// Forward the workspace bundle in the POST body so admin-api can
|
|
340
|
-
// surface `<workspace-context>` in
|
|
545
|
+
// surface `<workspace-context>` in Pugi's prompt. Older admin-api
|
|
341
546
|
// builds ignore unknown fields, so this stays forward-compatible.
|
|
342
|
-
//
|
|
547
|
+
// fix.
|
|
548
|
+
//
|
|
549
|
+
// Beta.13 P1 fix: also forward `cyberZoo` so admin-api
|
|
550
|
+
// can render Pugi's `<cyber-zoo>` marker matching the operator's
|
|
551
|
+
// `.pugi/settings.json::ui.cyberZoo` toggle instead of the
|
|
552
|
+
// historical 'on' default. Only included on the wire when set
|
|
553
|
+
// explicitly so a missing setting still survives older admin-api
|
|
554
|
+
// builds that do not declare the DTO field.
|
|
343
555
|
const body = {};
|
|
344
556
|
if (workspace?.workspaceCwd)
|
|
345
557
|
body.workspaceCwd = workspace.workspaceCwd;
|
|
@@ -347,6 +559,8 @@ export function createProductionTransport() {
|
|
|
347
559
|
body.workspaceSlug = workspace.workspaceSlug;
|
|
348
560
|
if (workspace?.workspaceSummary)
|
|
349
561
|
body.workspaceSummary = workspace.workspaceSummary;
|
|
562
|
+
if (cyberZoo === 'on' || cyberZoo === 'off')
|
|
563
|
+
body.cyberZoo = cyberZoo;
|
|
350
564
|
const response = await fetch(joinUrl(apiUrl, '/api/pugi/sessions'), {
|
|
351
565
|
method: 'POST',
|
|
352
566
|
headers: jsonHeaders(apiKey),
|
|
@@ -392,7 +606,7 @@ export function createProductionTransport() {
|
|
|
392
606
|
if (lastEventId) {
|
|
393
607
|
headers['Last-Event-ID'] = lastEventId;
|
|
394
608
|
}
|
|
395
|
-
// beta.9 CEO dogfood
|
|
609
|
+
// beta.9 CEO dogfood: hard timeout on the SSE
|
|
396
610
|
// handshake so a CDN/proxy that buffers the response (or an
|
|
397
611
|
// admin-api that accepted the route but never flushed headers)
|
|
398
612
|
// cannot freeze the REPL in `connecting` forever. The 5s budget
|
|
@@ -468,7 +682,7 @@ export function createProductionTransport() {
|
|
|
468
682
|
};
|
|
469
683
|
}
|
|
470
684
|
/* ------------------------------------------------------------------ */
|
|
471
|
-
/* SSE parser
|
|
685
|
+
/* SSE parser */
|
|
472
686
|
/* ------------------------------------------------------------------ */
|
|
473
687
|
/**
|
|
474
688
|
* Minimal SSE parser. Reads a UTF-8 stream of `id:` / `event:` / `data:`
|
|
@@ -532,7 +746,7 @@ async function consumeSseStream(body, onEvent) {
|
|
|
532
746
|
}
|
|
533
747
|
}
|
|
534
748
|
/* ------------------------------------------------------------------ */
|
|
535
|
-
/* Small helpers
|
|
749
|
+
/* Small helpers */
|
|
536
750
|
/* ------------------------------------------------------------------ */
|
|
537
751
|
function jsonHeaders(apiKey) {
|
|
538
752
|
return {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* ASCII pug mascot for the REPL boot splash
|
|
2
|
+
* ASCII pug mascot for the REPL boot splash .
|
|
3
3
|
*
|
|
4
4
|
* Hand-crafted at 9 rows × 20 columns to read as a pug at a single
|
|
5
5
|
* glance — references the cyber-zoo hero glyph in
|
|
6
|
-
* `apps/
|
|
6
|
+
* `apps/console-web/public/brand/hero-pug.png`: blocky pug face with
|
|
7
7
|
* angular ear flaps on either side of the head, forehead crease,
|
|
8
8
|
* angular cyan eyes (`◉`), smushed snout, undershot jaw, and a small
|
|
9
9
|
* cyan circuit chip (`▐■▌`) on the lower-right cheek.
|
|
@@ -15,30 +15,30 @@
|
|
|
15
15
|
* columns cyan (#3DA9FC, brandbook §05).
|
|
16
16
|
*
|
|
17
17
|
* Convention:
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* - PUG_MASCOT[i] = one row of the silhouette
|
|
19
|
+
* - PUG_MASCOT_CYAN_MASK[i] = parallel boolean array, true => that
|
|
20
|
+
* column renders cyan instead of gray
|
|
21
21
|
*
|
|
22
22
|
* Both arrays MUST stay the same length and each mask row MUST be the
|
|
23
23
|
* same length as the corresponding art row. A unit test enforces this.
|
|
24
24
|
*/
|
|
25
25
|
/* eslint-disable no-irregular-whitespace */
|
|
26
26
|
export const PUG_MASCOT = [
|
|
27
|
-
'
|
|
28
|
-
'
|
|
29
|
-
'
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'
|
|
27
|
+
' ▄▀▀▀▄▄▄▀▀▀▄ ',
|
|
28
|
+
' █▄▄ ▄▄█ ',
|
|
29
|
+
' █ ▀▄▄▄▄▄▀ █ ',
|
|
30
|
+
' █ ◉ ◉ █ ',
|
|
31
|
+
' ▀▄ ▀█▀ ▄▀ ',
|
|
32
|
+
' █▀▀▀▀▀█ ',
|
|
33
|
+
' █▒▒▒▒▒█ ▐■▌ ',
|
|
34
|
+
' ▀▄▄▄▀ ',
|
|
35
|
+
' ▀ ',
|
|
36
36
|
];
|
|
37
37
|
/**
|
|
38
38
|
* Cyan accents are derived from the source characters so the art file
|
|
39
39
|
* stays the single source of truth. Two glyph classes get colored:
|
|
40
|
-
*
|
|
41
|
-
*
|
|
40
|
+
* - `◉` -> the two cyan eyes on row 3
|
|
41
|
+
* - `▐■▌` -> the cyan chip cluster on row 6 (right cheek)
|
|
42
42
|
*
|
|
43
43
|
* Everything else renders gray. The derivation runs at module load,
|
|
44
44
|
* which keeps the mask trivially auditable from the source array.
|