@pugi/cli 0.1.0-beta.8 → 0.1.0-beta.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +132 -0
- package/LICENSE +1 -1
- package/THIRD_PARTY_NOTICES.md +40 -0
- package/assets/pugi-prozr2-mascot.ansi +9 -0
- package/bin/run.js +33 -1
- package/dist/commands/deploy.js +40 -40
- package/dist/commands/flatten.js +191 -0
- package/dist/commands/jobs-watch.js +201 -0
- package/dist/commands/jobs.js +42 -27
- package/dist/commands/smoke.js +133 -0
- package/dist/core/agent-progress/cleanup.js +134 -0
- package/dist/core/agent-progress/schema.js +144 -0
- package/dist/core/agent-progress/writer.js +101 -0
- package/dist/core/agents/adaptive-router.js +330 -0
- package/dist/core/agents/query-decomposer.js +297 -0
- package/dist/core/agents/registry.js +3 -3
- package/dist/core/approvals/shortcut-resolver.js +98 -0
- package/dist/core/artifact-chain/dispatcher.js +148 -0
- package/dist/core/artifact-chain/exporter.js +164 -0
- package/dist/core/artifact-chain/state.js +243 -0
- package/dist/core/artifact-chain/steps.js +169 -0
- package/dist/core/ask-user/question.js +92 -0
- package/dist/core/audit/audit-trail.js +275 -0
- package/dist/core/auth/ensure-authenticated.js +129 -0
- package/dist/core/auth/env-provider.js +238 -0
- package/dist/core/auto-open-browser.js +4 -4
- package/dist/core/auto-update/channels.js +122 -0
- package/dist/core/auto-update/checker.js +241 -0
- package/dist/core/auto-update/state.js +235 -0
- package/dist/core/bare-mode/index.js +107 -0
- package/dist/core/bash/redirect.js +281 -0
- package/dist/core/bash-classifier.js +436 -40
- package/dist/core/checkpoint/resumer.js +149 -0
- package/dist/core/checkpoint/rewinder.js +291 -0
- package/dist/core/checkpoints/shadow-git.js +670 -0
- package/dist/core/citations/parser.js +109 -0
- package/dist/core/classifier/yolo-classifier.js +88 -0
- package/dist/core/codegraph/decision-store.js +248 -0
- package/dist/core/codegraph/detect-repo.js +459 -0
- package/dist/core/codegraph/install.js +134 -0
- package/dist/core/codegraph/offer-hook.js +220 -0
- package/dist/core/compact/auto-trigger.js +96 -0
- package/dist/core/compact/buffer-rewriter.js +115 -0
- package/dist/core/compact/summarizer.js +208 -0
- package/dist/core/compact/token-counter.js +108 -0
- package/dist/core/consensus/anvil-fanout.js +25 -25
- package/dist/core/consensus/diff-capture.js +121 -12
- package/dist/core/consensus/rubric.js +21 -21
- package/dist/core/context/builder.js +6 -6
- package/dist/core/context/compaction-events.js +8 -8
- package/dist/core/context/compaction.js +31 -31
- package/dist/core/context/index.js +15 -8
- package/dist/core/context/invariants.js +51 -51
- package/dist/core/context/markdown-loader.js +28 -10
- package/dist/core/context/markdown-traverse.js +255 -0
- package/dist/core/context/pugiignore.js +41 -41
- package/dist/core/context/repo-skeleton.js +37 -37
- package/dist/core/context/tool-eviction.js +55 -0
- package/dist/core/context/watcher.js +32 -32
- package/dist/core/context/working-set.js +23 -23
- package/dist/core/coordinator/agent-tools.js +77 -0
- package/dist/core/coordinator/agent-toolset.js +65 -0
- package/dist/core/coordinator/fsm.js +73 -0
- package/dist/core/coordinator/mode-fsm.js +70 -0
- package/dist/core/cost/rate-card.js +129 -0
- package/dist/core/cost/tracker.js +221 -0
- package/dist/core/credentials.js +12 -12
- package/dist/core/cron/scheduler.js +138 -0
- package/dist/core/denial-tracking/index.js +8 -0
- package/dist/core/denial-tracking/state.js +264 -0
- package/dist/core/diagnostics/probe-runner.js +93 -0
- package/dist/core/diagnostics/probes/api.js +46 -0
- package/dist/core/diagnostics/probes/auth.js +93 -0
- package/dist/core/diagnostics/probes/bare-mode.js +42 -0
- package/dist/core/diagnostics/probes/cli-version.js +127 -0
- package/dist/core/diagnostics/probes/config.js +72 -0
- package/dist/core/diagnostics/probes/denial-tracking.js +57 -0
- package/dist/core/diagnostics/probes/disk.js +81 -0
- package/dist/core/diagnostics/probes/engine-live.js +46 -0
- package/dist/core/diagnostics/probes/git.js +65 -0
- package/dist/core/diagnostics/probes/hooks.js +118 -0
- package/dist/core/diagnostics/probes/mcp.js +75 -0
- package/dist/core/diagnostics/probes/node.js +59 -0
- package/dist/core/diagnostics/probes/pnpm.js +36 -0
- package/dist/core/diagnostics/probes/pugi-md.js +89 -0
- package/dist/core/diagnostics/probes/sandbox.js +40 -0
- package/dist/core/diagnostics/probes/session.js +74 -0
- package/dist/core/diagnostics/probes/status-snapshot.js +488 -0
- package/dist/core/diagnostics/probes/workspace.js +63 -0
- package/dist/core/diagnostics/types.js +70 -0
- package/dist/core/dispatch/cache-cleanup.js +197 -0
- package/dist/core/dispatch/cache-handoff.js +295 -0
- package/dist/core/edits/apply-patch-layer-e.js +189 -0
- package/dist/core/edits/dispatch.js +293 -7
- package/dist/core/edits/format-matrix.js +26 -0
- package/dist/core/edits/fuzzy-ladder.js +650 -0
- package/dist/core/edits/index.js +3 -1
- package/dist/core/edits/journal.js +199 -0
- package/dist/core/edits/layer-a-apply.js +15 -15
- package/dist/core/edits/layer-a-fuzzy-apply.js +198 -0
- package/dist/core/edits/layer-b-apply.js +9 -9
- package/dist/core/edits/layer-c-apply.js +6 -6
- package/dist/core/edits/layer-d-ast.js +557 -14
- package/dist/core/edits/marker-parser.js +12 -12
- package/dist/core/edits/security-gate.js +27 -27
- package/dist/core/edits/verify-hook.js +273 -0
- package/dist/core/edits/worktree.js +322 -0
- package/dist/core/engine/anvil-client.js +151 -26
- package/dist/core/engine/auto-compact.js +179 -0
- package/dist/core/engine/budgets.js +186 -0
- package/dist/core/engine/context-prefix.js +155 -0
- package/dist/core/engine/index.js +1 -1
- package/dist/core/engine/intensity.js +158 -0
- package/dist/core/engine/intent.js +260 -0
- package/dist/core/engine/native-pugi.js +1295 -227
- package/dist/core/engine/prompts.js +134 -16
- package/dist/core/engine/strip-internal-fields.js +124 -0
- package/dist/core/engine/tool-bridge.js +1295 -59
- package/dist/core/evaluation/golden-dataset.js +293 -0
- package/dist/core/feedback/queue.js +177 -0
- package/dist/core/feedback/submitter.js +145 -0
- package/dist/core/file-cache.js +113 -1
- package/dist/core/flatten/flatten-repo.js +439 -0
- package/dist/core/format/osc8-link.js +28 -0
- package/dist/core/hook-chains.js +392 -0
- package/dist/core/hooks/citation-verify-hook.js +138 -0
- package/dist/core/hooks/citation-verify.js +112 -0
- package/dist/core/hooks/events.js +44 -0
- package/dist/core/hooks/index.js +15 -0
- package/dist/core/hooks/registry.js +213 -0
- package/dist/core/hooks/runner.js +236 -0
- package/dist/core/hooks/v2/event-emitter.js +115 -0
- package/dist/core/hooks/v2/executor.js +282 -0
- package/dist/core/hooks/v2/index.js +25 -0
- package/dist/core/hooks/v2/lifecycle.js +104 -0
- package/dist/core/hooks/v2/loader.js +216 -0
- package/dist/core/hooks/v2/matcher.js +125 -0
- package/dist/core/hooks/v2/trust.js +143 -0
- package/dist/core/hooks/v2/types.js +86 -0
- package/dist/core/image/renderer.js +71 -0
- package/dist/core/init/detector.js +582 -0
- package/dist/core/init/template-renderer.js +242 -0
- package/dist/core/jobs/registry.js +18 -18
- package/dist/core/ledger/results-tsv.js +142 -0
- package/dist/core/log-discipline/stdout-redirect.js +51 -0
- package/dist/core/lsp/cache.js +105 -0
- package/dist/core/lsp/client.js +776 -0
- package/dist/core/lsp/language-detect.js +66 -0
- package/dist/core/lsp/post-edit-diagnostics.js +171 -0
- package/dist/core/lsp/symbol-tools.js +372 -0
- package/dist/core/mcp/client.js +97 -28
- package/dist/core/mcp/http-server.js +553 -0
- package/dist/core/mcp/orchestrator-tools.js +662 -0
- package/dist/core/mcp/permission.js +190 -0
- package/dist/core/mcp/registry.js +39 -17
- package/dist/core/mcp/server-tools.js +219 -0
- package/dist/core/mcp/server.js +397 -0
- package/dist/core/mcp/trust.js +10 -10
- package/dist/core/memory/dual-write.js +416 -0
- package/dist/core/memory/passive-extract.js +130 -0
- package/dist/core/memory/phase1-kinds.js +20 -0
- package/dist/core/memory/secret-scanner.js +304 -0
- package/dist/core/memory-sync/queue.js +170 -0
- package/dist/core/metrics/extract.js +113 -0
- package/dist/core/modes/roo-modes.js +68 -0
- package/dist/core/onboarding/ensure-initialized.js +133 -0
- package/dist/core/onboarding/marker.js +111 -0
- package/dist/core/onboarding/telemetry-state.js +108 -0
- package/dist/core/output-style/presets.js +176 -0
- package/dist/core/output-style/state.js +185 -0
- package/dist/core/path-security.js +287 -5
- package/dist/core/permission.js +82 -22
- package/dist/core/permissions/auto-classifier.js +124 -0
- package/dist/core/permissions/bash-parser.js +371 -0
- package/dist/core/permissions/circuit-breaker.js +83 -0
- package/dist/core/permissions/constrained-edit.js +91 -0
- package/dist/core/permissions/gate.js +278 -0
- package/dist/core/permissions/index.js +20 -0
- package/dist/core/permissions/mode.js +174 -0
- package/dist/core/permissions/network-egress.js +137 -0
- package/dist/core/permissions/state.js +241 -0
- package/dist/core/permissions/tool-class.js +93 -0
- package/dist/core/plan-mode/ui-state.js +51 -0
- package/dist/core/plans/plan-artifact.js +721 -0
- package/dist/core/policy-limits/etag-store.js +122 -0
- package/dist/core/prd-check/parser.js +215 -0
- package/dist/core/prd-check/reporter.js +127 -0
- package/dist/core/prd-check/session-review.js +557 -0
- package/dist/core/prd-check/verifiers.js +223 -0
- package/dist/core/prompt-cache/client-cache.js +99 -0
- package/dist/core/prompts/assembly.js +29 -0
- package/dist/core/prompts/registry.js +364 -0
- package/dist/core/pugi-md/cc-compat-rules.js +735 -0
- package/dist/core/pugi-md/context-injector.js +76 -0
- package/dist/core/pugi-md/walk-up.js +207 -0
- package/dist/core/python/uv-installer.js +270 -0
- package/dist/core/python/uv-resolver.js +83 -0
- package/dist/core/rate-limit/narrator.js +146 -0
- package/dist/core/recipes/cli-types.js +20 -0
- package/dist/core/recipes/loader.js +103 -0
- package/dist/core/recipes/runner.js +345 -0
- package/dist/core/recipes/schema.js +587 -0
- package/dist/core/release-notes/parser.js +241 -0
- package/dist/core/release-notes/state.js +116 -0
- package/dist/core/repl/ask.js +37 -37
- package/dist/core/repl/cancellation.js +26 -26
- package/dist/core/repl/cap-warning.js +4 -4
- package/dist/core/repl/clipboard-read.js +11 -11
- package/dist/core/repl/dispatch-fsm.js +12 -12
- package/dist/core/repl/history-search.js +15 -15
- package/dist/core/repl/history.js +28 -18
- package/dist/core/repl/kill-ring.js +5 -5
- package/dist/core/repl/model-pricing.js +135 -0
- package/dist/core/repl/privacy-banner.js +22 -22
- package/dist/core/repl/session.js +2157 -214
- package/dist/core/repl/slash-commands.js +533 -40
- package/dist/core/repl/store/index.js +1 -1
- package/dist/core/repl/store/jsonl-log.js +22 -22
- package/dist/core/repl/store/lockfile.js +10 -10
- package/dist/core/repl/store/session-store.js +136 -107
- package/dist/core/repl/store/types.js +15 -15
- package/dist/core/repl/store/uuid-v7.js +12 -12
- package/dist/core/repl/workspace-context.js +43 -21
- package/dist/core/repo-map/build.js +125 -0
- package/dist/core/repo-map/cache.js +185 -0
- package/dist/core/repo-map/extractor.js +254 -0
- package/dist/core/repo-map/formatter.js +145 -0
- package/dist/core/repo-map/page-rank.js +105 -0
- package/dist/core/repo-map/scanner.js +211 -0
- package/dist/core/retry-budget/budget.js +284 -0
- package/dist/core/retry-budget/index.js +5 -0
- package/dist/core/retry-budget/retry-cap.js +74 -0
- package/dist/core/routing/lead-worker.js +43 -0
- package/dist/core/routing/pre-flight-estimator.js +108 -0
- package/dist/core/runs/run-tree.js +103 -0
- package/dist/core/security/injection-scanner.js +367 -0
- package/dist/core/security/output-filter.js +418 -0
- package/dist/core/session/env-file.js +105 -0
- package/dist/core/session/section-budgets.js +140 -0
- package/dist/core/session.js +92 -0
- package/dist/core/settings.js +298 -5
- package/dist/core/share/formatter.js +271 -0
- package/dist/core/share/redactor.js +221 -0
- package/dist/core/share/uploader.js +267 -0
- package/dist/core/skills/defaults.js +457 -0
- package/dist/core/skills/loader.js +22 -22
- package/dist/core/skills/sources.js +27 -27
- package/dist/core/smoke/headless-driver.js +174 -0
- package/dist/core/smoke/orchestrator.js +194 -0
- package/dist/core/smoke/runner.js +238 -0
- package/dist/core/smoke/scenario-parser.js +316 -0
- package/dist/core/statusline.js +99 -0
- package/dist/core/subagents/dispatcher-real.js +600 -0
- package/dist/core/subagents/dispatcher.js +132 -43
- package/dist/core/subagents/index.js +19 -6
- package/dist/core/subagents/isolation-matrix.js +213 -0
- package/dist/core/subagents/spawn.js +19 -4
- package/dist/core/telemetry/emitter.js +229 -0
- package/dist/core/telemetry/queue.js +251 -0
- package/dist/core/theme/context.js +91 -0
- package/dist/core/theme/presets.js +228 -0
- package/dist/core/theme/state.js +181 -0
- package/dist/core/todos/invariant.js +10 -0
- package/dist/core/todos/state.js +177 -0
- package/dist/core/tool-schema/compressor.js +89 -0
- package/dist/core/transport/version-interceptor.js +166 -0
- package/dist/core/trust.js +2 -2
- package/dist/core/tui/thinking-block.js +64 -0
- package/dist/core/vim/keymap.js +288 -0
- package/dist/core/vim/state.js +92 -0
- package/dist/core/watch-markers/marker-watcher.js +133 -0
- package/dist/core/worktree-manager/cleanup.js +123 -0
- package/dist/core/worktree-manager/manager.js +303 -0
- package/dist/index.js +36 -0
- package/dist/runtime/bootstrap.js +190 -0
- package/dist/runtime/cli.js +4203 -493
- package/dist/runtime/commands/agents.js +30 -30
- package/dist/runtime/commands/budget.js +5 -5
- package/dist/runtime/commands/cancel.js +231 -0
- package/dist/runtime/commands/chain.js +489 -0
- package/dist/runtime/commands/codegraph-status.js +227 -0
- package/dist/runtime/commands/compact.js +297 -0
- package/dist/runtime/commands/config.js +73 -39
- package/dist/runtime/commands/cost.js +199 -0
- package/dist/runtime/commands/delegate.js +244 -13
- package/dist/runtime/commands/dispatch.js +126 -0
- package/dist/runtime/commands/doctor.js +579 -0
- package/dist/runtime/commands/feedback.js +184 -0
- package/dist/runtime/commands/hooks.js +184 -0
- package/dist/runtime/commands/init.js +254 -0
- package/dist/runtime/commands/lsp.js +368 -0
- package/dist/runtime/commands/mcp.js +879 -0
- package/dist/runtime/commands/memory.js +582 -0
- package/dist/runtime/commands/model.js +237 -0
- package/dist/runtime/commands/onboarding.js +275 -0
- package/dist/runtime/commands/patch.js +128 -0
- package/dist/runtime/commands/permissions.js +112 -0
- package/dist/runtime/commands/plan.js +143 -0
- package/dist/runtime/commands/prd-check.js +285 -0
- package/dist/runtime/commands/privacy.js +17 -17
- package/dist/runtime/commands/recipe.js +325 -0
- package/dist/runtime/commands/redo-blob-store.js +92 -0
- package/dist/runtime/commands/redo.js +361 -0
- package/dist/runtime/commands/release-notes.js +229 -0
- package/dist/runtime/commands/repo-map.js +95 -0
- package/dist/runtime/commands/report.js +299 -0
- package/dist/runtime/commands/resume.js +118 -0
- package/dist/runtime/commands/review-consensus.js +68 -53
- package/dist/runtime/commands/rewind.js +333 -0
- package/dist/runtime/commands/roster.js +14 -14
- package/dist/runtime/commands/sessions.js +163 -0
- package/dist/runtime/commands/share.js +316 -0
- package/dist/runtime/commands/skills.js +31 -31
- package/dist/runtime/commands/status.js +186 -0
- package/dist/runtime/commands/stickers.js +82 -0
- package/dist/runtime/commands/style.js +194 -0
- package/dist/runtime/commands/theme.js +196 -0
- package/dist/runtime/commands/undo.js +54 -22
- package/dist/runtime/commands/update.js +289 -0
- package/dist/runtime/commands/vim.js +140 -0
- package/dist/runtime/commands/worktree.js +177 -0
- package/dist/runtime/commands/worktrees.js +155 -0
- package/dist/runtime/headless-repl.js +195 -0
- package/dist/runtime/headless.js +543 -0
- package/dist/runtime/load-hooks-or-exit.js +71 -0
- package/dist/runtime/plan-decompose.js +531 -0
- package/dist/runtime/sigint-guard.js +272 -0
- package/dist/runtime/update-check.js +28 -28
- package/dist/runtime/version.js +65 -0
- package/dist/skills/bundled/batch.js +617 -0
- package/dist/skills/bundled/index.js +45 -0
- package/dist/skills/bundled/loop.js +358 -0
- package/dist/skills/bundled/remember.js +383 -0
- package/dist/skills/bundled/simplify.js +289 -0
- package/dist/skills/bundled/skillify.js +373 -0
- package/dist/skills/bundled/stuck.js +558 -0
- package/dist/skills/bundled/verify.js +439 -0
- package/dist/testing/vcr.js +486 -0
- package/dist/tools/agent-tool.js +229 -0
- package/dist/tools/apply-patch.js +556 -0
- package/dist/tools/ask-user-question.js +288 -0
- package/dist/tools/ask-user.js +115 -0
- package/dist/tools/bash.js +624 -46
- package/dist/tools/brief.js +224 -0
- package/dist/tools/enter-worktree.js +250 -0
- package/dist/tools/exit-worktree.js +147 -0
- package/dist/tools/file-tools.js +161 -44
- package/dist/tools/lsp-tools.js +189 -0
- package/dist/tools/mcp-tool.js +260 -0
- package/dist/tools/multi-edit.js +361 -0
- package/dist/tools/powershell.js +268 -0
- package/dist/tools/registry.js +85 -0
- package/dist/tools/skill-tool.js +96 -0
- package/dist/tools/sleep.js +99 -0
- package/dist/tools/synthetic-output.js +133 -0
- package/dist/tools/tasks.js +208 -0
- package/dist/tools/todo-write.js +184 -0
- package/dist/tools/verify-plan-execution.js +295 -0
- package/dist/tools/web-fetch-injection-scanner.js +207 -0
- package/dist/tools/web-fetch.js +195 -10
- package/dist/tools/web-search.js +458 -0
- package/dist/tui/agent-progress-card.js +111 -0
- package/dist/tui/agent-tree.js +11 -1
- package/dist/tui/ask-modal.js +14 -14
- package/dist/tui/ask-user-question-chips.js +257 -0
- package/dist/tui/ask-user-question-prompt.js +203 -0
- package/dist/tui/compact-banner.js +81 -0
- package/dist/tui/conversation-pane.js +85 -11
- package/dist/tui/cost-table.js +111 -0
- package/dist/tui/device-flow.js +2 -2
- package/dist/tui/doctor-table.js +46 -0
- package/dist/tui/feedback-prompt.js +156 -0
- package/dist/tui/input-box.js +247 -32
- package/dist/tui/login-picker.js +3 -3
- package/dist/tui/markdown-render.js +6 -6
- package/dist/tui/onboarding-wizard.js +240 -0
- package/dist/tui/permissions-picker.js +86 -0
- package/dist/tui/render.js +35 -0
- package/dist/tui/repl-render.js +332 -54
- package/dist/tui/repl-splash-art.js +16 -16
- package/dist/tui/repl-splash-mascot.js +48 -24
- package/dist/tui/repl-splash.js +22 -22
- package/dist/tui/repl.js +124 -44
- package/dist/tui/slash-palette.js +6 -6
- package/dist/tui/splash.js +2 -2
- package/dist/tui/status-bar.js +109 -31
- package/dist/tui/status-table.js +7 -0
- package/dist/tui/stickers-art.js +136 -0
- package/dist/tui/style-table.js +28 -0
- package/dist/tui/theme-table.js +29 -0
- package/dist/tui/thinking-spinner.js +123 -0
- package/dist/tui/tool-stream-pane.js +53 -4
- package/dist/tui/update-banner.js +27 -2
- package/dist/tui/vim-input.js +267 -0
- package/dist/tui/welcome-banner.js +107 -0
- package/dist/tui/welcome-data.js +293 -0
- package/dist/tui/workspace-context.js +2 -2
- package/docs/examples/codegraph.mcp.json +10 -0
- package/package.json +25 -7
- package/test/scenarios/codegen-create-file.scenario.txt +13 -0
- package/test/scenarios/compact-force.scenario.txt +11 -0
- package/test/scenarios/identity.scenario.txt +11 -0
- package/test/scenarios/persona-handoff.scenario.txt +11 -0
- package/test/scenarios/walkback.scenario.txt +12 -0
- package/dist/core/engine/compaction-hook.js +0 -154
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Chafa-validated brand-pug ANSI loader
|
|
2
|
+
* Chafa-validated brand-pug ANSI loader .
|
|
3
3
|
*
|
|
4
|
-
* CEO dogfood
|
|
4
|
+
* CEO dogfood (first pass, wave 5): the hand-crafted
|
|
5
5
|
* 9-row ASCII pug in `repl-splash-art.ts` reads as "точно не похожа" —
|
|
6
6
|
* too abstract to carry the brand at boot. This module loads a pre-baked
|
|
7
7
|
* truecolor ANSI render of the canonical hero-pug PNG (cyber-zoo pug
|
|
8
8
|
* face with cyan eyes + circuit + chip) so the splash matches the brand
|
|
9
9
|
* glyph the operator already sees on pugi.io.
|
|
10
10
|
*
|
|
11
|
-
* CEO dogfood
|
|
11
|
+
* CEO dogfood : the first chafa bake at 32x16 still
|
|
12
12
|
* read as "monitor on stand", not pug — too few rows to resolve the
|
|
13
13
|
* snout / eyes / wrinkles. The vertical resolution was the bottleneck:
|
|
14
14
|
* 16 char rows ≈ 16 pixel rows with the block symbol set. The fresh
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
* gates at 100KB so we stay well under cap.
|
|
22
22
|
*
|
|
23
23
|
* Generation (operator-side, one-shot):
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
24
|
+
* chafa --size 80x40 --symbols=vhalf --colors=full \
|
|
25
|
+
* apps/console-web/public/brand/hero-pug.png \
|
|
26
|
+
* > apps/pugi-cli/assets/pugi-mascot.ansi
|
|
27
27
|
*
|
|
28
28
|
* The output is committed verbatim to the repo and shipped inside the
|
|
29
29
|
* `@pugi/cli` npm tarball under `assets/pugi-mascot.ansi` (the
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
* corruption, dev cwd drift), the splash falls back to the hand-crafted
|
|
34
34
|
* `PUG_MASCOT` art so the boot never crashes.
|
|
35
35
|
*
|
|
36
|
-
* The pre-Ink write convention mirrors the
|
|
36
|
+
* The pre-Ink write convention mirrors the the upstream tool Chrome plugin
|
|
37
37
|
* splash pattern: raw bytes go to `process.stdout` BEFORE the Ink
|
|
38
38
|
* render mount, so the terminal interprets the truecolor escapes
|
|
39
39
|
* directly instead of Ink trying to layout-engine over them.
|
|
@@ -48,9 +48,21 @@ import { fileURLToPath } from 'node:url';
|
|
|
48
48
|
* — two directory hops up from this file. In a local `pnpm dev`
|
|
49
49
|
* checkout the structure is the same (`src/tui/` ⇒ `../../assets/`)
|
|
50
50
|
* because tsx re-resolves the same relative tree.
|
|
51
|
+
*
|
|
52
|
+
* CEO P0 #2 — banner mascot bake. The prozr2 portrait is
|
|
53
|
+
* the canonical brand-pug glyph from `apps/console-web/public/brand/
|
|
54
|
+
* Pugi-prozr2.png`, baked к а 16x8 vhalf truecolor render. We prefer
|
|
55
|
+
* the prozr2 bake when it ships alongside the CLI (small — ~900 bytes,
|
|
56
|
+
* shaped for the compact welcome-banner left column) and fall back к
|
|
57
|
+
* the legacy 40KB `pugi-mascot.ansi` (hero-pug 80x40) when prozr2 is
|
|
58
|
+
* missing — preserves the splash-mascot install surface for any
|
|
59
|
+
* tarball that predates the bake.
|
|
51
60
|
*/
|
|
52
61
|
export function pugMascotAssetPath() {
|
|
53
62
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
63
|
+
const prozr2 = resolvePath(here, '..', '..', 'assets', 'pugi-prozr2-mascot.ansi');
|
|
64
|
+
if (existsSync(prozr2))
|
|
65
|
+
return prozr2;
|
|
54
66
|
return resolvePath(here, '..', '..', 'assets', 'pugi-mascot.ansi');
|
|
55
67
|
}
|
|
56
68
|
/**
|
|
@@ -83,27 +95,39 @@ export function loadPugMascotAnsi() {
|
|
|
83
95
|
if (!raw || raw.length === 0)
|
|
84
96
|
return null;
|
|
85
97
|
// 1. Drop OSC sequences. Two terminator forms:
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
//
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
// 2. Drop CSI ? <
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
//
|
|
98
|
+
// ESC ] ... BEL (0x1b 0x5d ... 0x07)
|
|
99
|
+
// ESC ] ... ESC \ (0x1b 0x5d ... 0x1b 0x5c, the ST form)
|
|
100
|
+
// A truecolor splash never needs OSC (those are for window title,
|
|
101
|
+
// icon, clipboard, hyperlinks, color-palette change). Drop them
|
|
102
|
+
// so a corrupted asset cannot rename the operator's terminal tab
|
|
103
|
+
// or smuggle a hyperlink into the splash region.
|
|
104
|
+
// 2. Drop ALL CSI ? <numbers and semicolons> [lh] (DEC private-mode
|
|
105
|
+
// set / reset). The legitimate chafa output for a splash is
|
|
106
|
+
// truecolor SGR (`CSI 38;2;R;G;B m`) plus cursor-positioning —
|
|
107
|
+
// no private-mode toggle ever appears там legitimately. A
|
|
108
|
+
// permissive deny-all pattern covers every disruptive private
|
|
109
|
+
// mode in one regex:
|
|
110
|
+
// - cursor visibility (25)
|
|
111
|
+
// - alt-screen buffer (47, 1047, 1048, 1049)
|
|
112
|
+
// - mouse tracking (1000, 1001, 1002, 1003, 1004, 1005, 1006, 1015)
|
|
113
|
+
// - bracketed paste (2004)
|
|
114
|
+
// - focus reporting (1004)
|
|
115
|
+
// - multi-mode forms (e.g. `CSI ? 47 ; 1049 h` — legal per
|
|
116
|
+
// xterm ctlseqs but missed by the previous single-mode regex)
|
|
117
|
+
// - any future private mode a corrupt asset might emit
|
|
118
|
+
// Allowlisting the modes the splash needs is impossible because
|
|
119
|
+
// the splash needs ZERO of them — chafa renders glyph-by-glyph,
|
|
120
|
+
// not via private-mode toggles. A pure deny-all is strictly
|
|
121
|
+
// safer than enumerating known-bad modes one-by-one.
|
|
96
122
|
// 3. Drop CSI 6 n (cursor-position report). Would inject a fake
|
|
97
|
-
//
|
|
123
|
+
// CPR into the operator's stdin stream.
|
|
98
124
|
// 4. Drop CSI [23]J / CSI [23]K (full screen / line clear). A
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
// The cursor-hide/show wrappers (CSI ? 25 [lh]) are handled by
|
|
103
|
-
// the same CSI-?-mode pattern as the mouse / alt-screen modes.
|
|
125
|
+
// chafa render uses cursor-positioning per row, not bulk
|
|
126
|
+
// erases; bulk clears would wipe whatever the operator already
|
|
127
|
+
// had on screen above the splash.
|
|
104
128
|
const stripped = raw
|
|
105
129
|
.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, '')
|
|
106
|
-
.replace(/\x1b\[\?
|
|
130
|
+
.replace(/\x1b\[\?[0-9;]+[lh]/g, '')
|
|
107
131
|
.replace(/\x1b\[6n/g, '')
|
|
108
132
|
.replace(/\x1b\[[23]?[JK]/g, '');
|
|
109
133
|
if (stripped.trim().length === 0)
|
package/dist/tui/repl-splash.js
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
|
-
* REPL boot splash
|
|
3
|
+
* REPL boot splash .
|
|
4
4
|
*
|
|
5
5
|
* Rendered on REPL first paint — before the conversation pane, before
|
|
6
|
-
* any operator input lands. Mirrors the
|
|
6
|
+
* any operator input lands. Mirrors the the upstream tool / Codex / Gemini
|
|
7
7
|
* CLI boot-screen aesthetic while staying Pugi-brand-pure:
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* [PUG ASCII] Pugi.io v0.1.0-alphaN
|
|
10
|
+
* Plan: <plan>
|
|
11
|
+
* Model: <model>
|
|
12
|
+
* Tenant: <customerId>
|
|
13
|
+
* Workspace: <basename>
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
15
|
+
* ─────────────────────────────────────
|
|
16
|
+
* Tips for getting started:
|
|
17
|
+
* 1. Type a brief, the workforce dispatches
|
|
18
|
+
* 2. /help for slash commands, /web <url> to pull a page
|
|
19
|
+
* 3. /skills install <name> for Anthropic / OpenClaw skills
|
|
20
20
|
*
|
|
21
21
|
* The splash auto-dismisses on:
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
22
|
+
* - first operator keystroke (the REPL `<Repl />` host owns this and
|
|
23
|
+
* calls the `onInteract` callback we expose),
|
|
24
|
+
* - 10s idle timeout (built-in, configurable via `skipSplash`),
|
|
25
|
+
* - `--no-splash` CLI flag or PUGI_SKIP_SPLASH=1 env (host gates the
|
|
26
|
+
* mount entirely; we still respect the `skipSplash` prop as a belt
|
|
27
|
+
* so a stray render in a test environment produces nothing).
|
|
28
28
|
*
|
|
29
29
|
* Brand voice gate: every visible string here is reviewed against the
|
|
30
30
|
* forbidden list (`journey / explore / delight / magical / friendly /
|
|
@@ -61,13 +61,13 @@ export function ReplSplash(props) {
|
|
|
61
61
|
if (props.skipSplash) {
|
|
62
62
|
return null;
|
|
63
63
|
}
|
|
64
|
-
//
|
|
64
|
+
// wave 5: when the host pre-printed the chafa-baked brand-pug
|
|
65
65
|
// ANSI render to stdout before Ink mounted, suppress the hand-crafted
|
|
66
66
|
// PUG_MASCOT column here so the operator does not see two stacked
|
|
67
67
|
// pugs. The header card still renders inline so wordmark + status
|
|
68
68
|
// rows stay attached to the splash flow.
|
|
69
69
|
const showHandCraftedMascot = props.mascotPrePrinted !== true;
|
|
70
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [_jsxs(Box, { flexDirection: "row", children: [showHandCraftedMascot ? _jsx(MascotColumn, {}) : null, _jsxs(Box, { flexDirection: "column", marginLeft: showHandCraftedMascot ? 2 : 0, marginTop: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Pugi" }), _jsx(Text, { bold: true, color: "
|
|
70
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, paddingY: 1, children: [_jsxs(Box, { flexDirection: "row", children: [showHandCraftedMascot ? _jsx(MascotColumn, {}) : null, _jsxs(Box, { flexDirection: "column", marginLeft: showHandCraftedMascot ? 2 : 0, marginTop: 1, children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Pugi" }), _jsx(Text, { bold: true, color: "#3da9fc", children: ".io" }), _jsx(Text, { dimColor: true, children: ` v${props.cliVersion}` })] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(HeaderRow, { label: "Plan", value: props.plan ?? PLACEHOLDER }), _jsx(HeaderRow, { label: "Model", value: props.model ?? PLACEHOLDER }), _jsx(HeaderRow, { label: "Tenant", value: props.tenant ?? PLACEHOLDER }), _jsx(HeaderRow, { label: "Workspace", value: props.workspaceLabel })] })] })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: '─'.repeat(40) }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "Tips for getting started:" }), _jsx(TipRow, { index: 1, text: "Type a brief, the workforce dispatches" }), _jsx(TipRow, { index: 2, text: "/help for slash commands, /web <url> to pull a page" }), _jsx(TipRow, { index: 3, text: "/skills install <name> for Anthropic / OpenClaw skills" })] })] }));
|
|
71
71
|
}
|
|
72
72
|
/**
|
|
73
73
|
* Renders the multi-line ASCII pug. Each row is split into colored
|
|
@@ -105,13 +105,13 @@ function MascotRow({ row, mask, }) {
|
|
|
105
105
|
if (buffer.length > 0) {
|
|
106
106
|
runs.push({ text: buffer, cyan: bufferCyan });
|
|
107
107
|
}
|
|
108
|
-
return (_jsx(Text, { children: runs.map((run, runIndex) => run.cyan ? (_jsx(Text, { color: "
|
|
108
|
+
return (_jsx(Text, { children: runs.map((run, runIndex) => run.cyan ? (_jsx(Text, { color: "#3da9fc", children: run.text }, runIndex)) : (_jsx(Text, { color: "gray", children: run.text }, runIndex))) }));
|
|
109
109
|
}
|
|
110
110
|
function HeaderRow({ label, value }) {
|
|
111
111
|
const padded = `${label}:`.padEnd(11, ' ');
|
|
112
112
|
return (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: padded }), _jsx(Text, { children: value })] }));
|
|
113
113
|
}
|
|
114
114
|
function TipRow({ index, text }) {
|
|
115
|
-
return (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: `
|
|
115
|
+
return (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ` ${index}. ` }), _jsx(Text, { children: text })] }));
|
|
116
116
|
}
|
|
117
117
|
//# sourceMappingURL=repl-splash.js.map
|
package/dist/tui/repl.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
|
-
* REPL root component - Sprint
|
|
3
|
+
* REPL root component - Sprint .
|
|
4
4
|
*
|
|
5
5
|
* Three-zone layout:
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* header - `Pugi.io · workspace: <name> · v<X> on watch`
|
|
8
|
+
* main - conversation pane (top half) + agent tree (bottom half)
|
|
9
|
+
* footer - input box + status bar + key hints
|
|
10
10
|
*
|
|
11
11
|
* The component subscribes to a ReplSession instance for state. It does
|
|
12
12
|
* NOT own the SSE client or the transport - the session module does.
|
|
@@ -26,14 +26,17 @@ import { ConversationPane } from './conversation-pane.js';
|
|
|
26
26
|
import { InputBox } from './input-box.js';
|
|
27
27
|
import { ReplSplash } from './repl-splash.js';
|
|
28
28
|
import { StatusBar } from './status-bar.js';
|
|
29
|
+
import { ThinkingSpinner } from './thinking-spinner.js';
|
|
29
30
|
import { ToolStreamPane } from './tool-stream-pane.js';
|
|
30
31
|
import { UpdateBanner } from './update-banner.js';
|
|
32
|
+
import { WelcomeBanner } from './welcome-banner.js';
|
|
31
33
|
import { collectWorkspaceContext } from './workspace-context.js';
|
|
34
|
+
import { useTheme } from '../core/theme/context.js';
|
|
32
35
|
import { slugForCwd } from '../core/repl/history.js';
|
|
33
36
|
import { SLASH_COMMAND_HELP, SLASH_COMMAND_GROUPS } from '../core/repl/slash-commands.js';
|
|
34
37
|
const TICK_INTERVAL_MS = 200;
|
|
35
38
|
const PULSE_INTERVAL_MS = 700;
|
|
36
|
-
//
|
|
39
|
+
// : maximum transcript rows the conversation pane renders at once.
|
|
37
40
|
// Older rows scroll off the top; full history stays in session state.
|
|
38
41
|
const CONVERSATION_WINDOW = 12;
|
|
39
42
|
export function Repl(props) {
|
|
@@ -41,22 +44,28 @@ export function Repl(props) {
|
|
|
41
44
|
const [overlay, setOverlay] = useState('none');
|
|
42
45
|
const [pulsePhase, setPulsePhase] = useState(0);
|
|
43
46
|
const [tickNow, setTickNow] = useState((props.now ?? Date.now)());
|
|
44
|
-
//
|
|
47
|
+
// : operator-driven collapse for the tool stream pane. The CLI
|
|
45
48
|
// host can hide the pane entirely via `--no-tool-stream`; this state
|
|
46
49
|
// is the runtime toggle (Ctrl+T) for operators who want the pane on
|
|
47
50
|
// screen but folded to a single row while they read a long reply.
|
|
48
51
|
const [toolStreamCollapsed, setToolStreamCollapsed] = useState(false);
|
|
49
|
-
//
|
|
52
|
+
// wave 3: boot splash visible until first input, first
|
|
50
53
|
// `agent.spawned` event, or 10s idle. The host gates the initial
|
|
51
54
|
// visibility on `--no-splash` / PUGI_SKIP_SPLASH via `skipSplash`.
|
|
52
|
-
//
|
|
53
|
-
// (parity with
|
|
55
|
+
// CEO dogfood: default splash to HIDDEN at boot
|
|
56
|
+
// (parity with the upstream tool's minimal one-line banner). Operator can
|
|
54
57
|
// opt back in via `/splash` slash. The chafa pug pre-print + header
|
|
55
58
|
// line already give the brand cue without the multi-row Plan/Model/
|
|
56
59
|
// Tenant block crowding the top.
|
|
57
60
|
const [splashVisible, setSplashVisible] = useState(false);
|
|
58
61
|
const dismissSplash = useCallback(() => setSplashVisible(false), []);
|
|
59
|
-
//
|
|
62
|
+
// CEO P0 #2 : welcome banner. Visible from boot
|
|
63
|
+
// until the operator submits the first brief OR the session emits
|
|
64
|
+
// its first agent event. The host owns dismissal lifecycle (kept
|
|
65
|
+
// symmetric with the splash) so the welcome card never lingers
|
|
66
|
+
// behind а live transcript.
|
|
67
|
+
const [welcomeVisible, setWelcomeVisible] = useState(Boolean(props.welcomeData));
|
|
68
|
+
// wave 3: workspace context snapshot for the status bar. We
|
|
60
69
|
// read once at mount and freeze; a brand-new PUGI.md or skill is
|
|
61
70
|
// surfaced on the next REPL boot rather than via a watcher.
|
|
62
71
|
const workspaceContext = useMemo(() => props.workspaceContext ?? collectWorkspaceContext(process.cwd()), [props.workspaceContext]);
|
|
@@ -88,9 +97,9 @@ export function Repl(props) {
|
|
|
88
97
|
useEffect(() => {
|
|
89
98
|
props.onOverlayChange?.(overlay);
|
|
90
99
|
}, [overlay, props]);
|
|
91
|
-
//
|
|
100
|
+
// wave 3: dismiss the boot splash once the first agent spawns
|
|
92
101
|
// (the operator has clearly engaged the system) or the transcript
|
|
93
|
-
// gains a row. Mirrors the natural attention shift
|
|
102
|
+
// gains a row. Mirrors the natural attention shift the upstream tool /
|
|
94
103
|
// Codex / Gemini CLI all do on their boot screens.
|
|
95
104
|
useEffect(() => {
|
|
96
105
|
if (!splashVisible)
|
|
@@ -99,6 +108,20 @@ export function Repl(props) {
|
|
|
99
108
|
setSplashVisible(false);
|
|
100
109
|
}
|
|
101
110
|
}, [splashVisible, state.agents.length, state.transcript.length]);
|
|
111
|
+
// CEO P0 #2 v2: welcome banner stays until the operator
|
|
112
|
+
// actively engages the loop — first agent spawn. Boot-time auto-init
|
|
113
|
+
// emits system rows into `state.transcript` (skip-trust hints, dirty
|
|
114
|
+
// tree warnings) which used к dismiss the banner within ~2s, hiding
|
|
115
|
+
// the brand mascot before the operator could read it. Drop the
|
|
116
|
+
// `transcript.length` trigger; agent spawn (= real dispatch) remains
|
|
117
|
+
// the sole signal that the operator stopped reading the banner.
|
|
118
|
+
useEffect(() => {
|
|
119
|
+
if (!welcomeVisible)
|
|
120
|
+
return;
|
|
121
|
+
if (state.agents.length > 0) {
|
|
122
|
+
setWelcomeVisible(false);
|
|
123
|
+
}
|
|
124
|
+
}, [welcomeVisible, state.agents.length]);
|
|
102
125
|
const personaNames = useMemo(() => buildPersonaNameMap(), []);
|
|
103
126
|
const { exit } = useApp();
|
|
104
127
|
const handleSubmit = useCallback((line) => {
|
|
@@ -106,6 +129,10 @@ export function Repl(props) {
|
|
|
106
129
|
// `setSplashVisible(false)` is a no-op once the state already
|
|
107
130
|
// settled to false (timer fired or `agent.spawned` arrived).
|
|
108
131
|
setSplashVisible(false);
|
|
132
|
+
// CEO P0 #2 : same dismissal for the welcome banner
|
|
133
|
+
// — the operator engaging the input box is the cleanest signal
|
|
134
|
+
// they have finished reading the boot card.
|
|
135
|
+
setWelcomeVisible(false);
|
|
109
136
|
// Run async without awaiting - the session module owns the
|
|
110
137
|
// network call, errors land in the transcript automatically.
|
|
111
138
|
void props.session.handleInput(line).then((verdict) => {
|
|
@@ -137,7 +164,7 @@ export function Repl(props) {
|
|
|
137
164
|
setOverlay('none');
|
|
138
165
|
}
|
|
139
166
|
}, { isActive: overlay === 'help' || overlay === 'roster' });
|
|
140
|
-
//
|
|
167
|
+
// : Ctrl+T toggles the tool stream pane between expanded and
|
|
141
168
|
// collapsed states. Active only while no overlay is open, so the
|
|
142
169
|
// toggle never fights the help/roster dismiss handler. The input box
|
|
143
170
|
// owns its own raw-input mode, so this listener only fires on the
|
|
@@ -147,7 +174,7 @@ export function Repl(props) {
|
|
|
147
174
|
setToolStreamCollapsed((prev) => !prev);
|
|
148
175
|
}
|
|
149
176
|
}, { isActive: overlay === 'none' && props.hideToolStream !== true });
|
|
150
|
-
//
|
|
177
|
+
// office-hours: a pending ask or plan-review modal pauses input
|
|
151
178
|
// until the operator resolves it. The modal owns its own useInput
|
|
152
179
|
// hook, so the InputBox unmounts while a modal is open to avoid two
|
|
153
180
|
// raw-input listeners competing for the same keystroke. Resolution
|
|
@@ -161,29 +188,69 @@ export function Repl(props) {
|
|
|
161
188
|
const handlePlanReviewResolve = useCallback((result) => {
|
|
162
189
|
void props.session.resolvePlanReview(result);
|
|
163
190
|
}, [props.session]);
|
|
164
|
-
//
|
|
191
|
+
// : Ctrl+C abort handler. Forwards to ReplSession.cancel() which
|
|
165
192
|
// aborts the in-flight dispatch, closes the SSE stream, and surfaces
|
|
166
193
|
// "Aborted." in the transcript.
|
|
167
194
|
//
|
|
168
195
|
// Return contract (consumed by InputBox):
|
|
169
|
-
//
|
|
170
|
-
//
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
//
|
|
196
|
+
// - true - dispatch was cancelled (keep the buffer + DO arm
|
|
197
|
+
// the press-again-to-exit timer; second Ctrl+C in
|
|
198
|
+
// the window exits).
|
|
199
|
+
// - false - idle / nothing to cancel (legacy: clear buffer +
|
|
200
|
+
// arm the exit timer so the operator sees the hint
|
|
201
|
+
// and can confirm exit on the next press).
|
|
202
|
+
// - undefined - bypassed entirely (e.g. a modal owns the input).
|
|
203
|
+
// InputBox MUST NOT arm the exit timer and MUST
|
|
204
|
+
// NOT clear the buffer. P2 fix: previously this
|
|
205
|
+
// returned `false` and the buffer-clear path wiped
|
|
206
|
+
// the operator's mid-typed modal text on the first
|
|
207
|
+
// Ctrl+C, costing a press of work.
|
|
181
208
|
const handleCancel = useCallback(() => {
|
|
182
209
|
if (modalActive)
|
|
183
210
|
return undefined;
|
|
184
211
|
return props.session.cancel();
|
|
185
212
|
}, [props.session, modalActive]);
|
|
186
|
-
//
|
|
213
|
+
// BT 8 (the upstream tool parity): Esc-Esc walkback. Forwards to
|
|
214
|
+
// ReplSession.walkbackLastTurn which trims the trailing operator
|
|
215
|
+
// turn + its persona response from the in-memory transcript. Returns
|
|
216
|
+
// `'walked-back'` so the input box knows the host did the work;
|
|
217
|
+
// `'nothing'` covers both the empty-transcript and dispatch-in-flight
|
|
218
|
+
// refusals (the session module owns the refusal copy in both cases).
|
|
219
|
+
const handleWalkback = useCallback(() => {
|
|
220
|
+
if (modalActive)
|
|
221
|
+
return 'nothing';
|
|
222
|
+
const verdict = props.session.walkbackLastTurn();
|
|
223
|
+
return verdict === 'walked-back' ? 'walked-back' : 'nothing';
|
|
224
|
+
}, [props.session, modalActive]);
|
|
225
|
+
// — Shift+Tab cycles the 6 canonical permission modes (CC
|
|
226
|
+
// parity). Refuses while a modal is active so the operator does not
|
|
227
|
+
// accidentally flip mode mid-prompt; otherwise resolves the current
|
|
228
|
+
// mode through the workspace > global > default merge, advances via
|
|
229
|
+
// `nextPermissionMode`, и persists к .pugi/session.json. Returns the
|
|
230
|
+
// new mode string so the InputBox can flash a one-line toast.
|
|
231
|
+
const handleCyclePermissionMode = useCallback(() => {
|
|
232
|
+
if (modalActive)
|
|
233
|
+
return null;
|
|
234
|
+
try {
|
|
235
|
+
// Lazy-require так this code path doesn't drag the permissions
|
|
236
|
+
// module into the splash + boot stages where it isn't needed.
|
|
237
|
+
// The require is sync but the inner work is pure JSON IO.
|
|
238
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
239
|
+
const perm = require('../core/permissions/index.js');
|
|
240
|
+
const workspaceRoot = process.cwd();
|
|
241
|
+
const current = perm.resolveMode({ workspaceRoot });
|
|
242
|
+
const next = perm.nextPermissionMode(current);
|
|
243
|
+
perm.setCurrentMode(workspaceRoot, next);
|
|
244
|
+
return next;
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
// Persistence is best-effort — if .pugi/session.json is read-only
|
|
248
|
+
// или ENOENT-on-parent the toast is suppressed so we don't lie
|
|
249
|
+
// about the flip к the operator.
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
}, [modalActive]);
|
|
253
|
+
// CEO dogfood (parity with the upstream tool): input
|
|
187
254
|
// box pinned to alt-screen BOTTOM, conversation grows above it.
|
|
188
255
|
// Beta.3's height={rows} fix broke keystroke focus - raw echo at
|
|
189
256
|
// viewport bottom. The right pattern is minHeight on the root +
|
|
@@ -191,29 +258,40 @@ export function Repl(props) {
|
|
|
191
258
|
// input, and the input stays the sole focusable surface adjacent
|
|
192
259
|
// to the cursor row, so all keystrokes route through it.
|
|
193
260
|
const altScreenRows = process.stdout.rows ?? 24;
|
|
194
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, minHeight: altScreenRows, children: [props.
|
|
261
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, minHeight: altScreenRows, children: [welcomeVisible && props.welcomeData ? (_jsx(WelcomeBanner, { data: props.welcomeData, mascotPrePrinted: props.mascotPrePrinted === true, autoInitStatus: props.autoInitStatus ?? null })) : null, splashVisible ? (_jsx(ReplSplash, { cliVersion: state.cliVersion, workspaceLabel: state.workspaceLabel, plan: props.splashPlan, model: props.splashModel, tenant: props.splashTenant, onDismiss: dismissSplash, mascotPrePrinted: props.mascotPrePrinted === true })) : null, _jsx(Header, { state: state }), _jsx(Box, { flexDirection: "column", marginTop: 1, flexGrow: 1, justifyContent: "flex-end", children: overlay === 'help' ? (_jsx(HelpOverlay, {})) : overlay === 'roster' ? (_jsx(RosterOverlay, {})) : overlay === 'farewell' ? (_jsx(FarewellOverlay, {})) : (_jsx(MainArea, { state: state, personaNames: personaNames, nowEpochMs: tickNow, hideToolStream: props.hideToolStream === true, toolStreamCollapsed: toolStreamCollapsed })) }), state.pendingAsk ? (_jsx(Box, { marginTop: 1, children: _jsx(AskModal, { tag: state.pendingAsk, onResolve: handleAskResolve }) })) : null, state.pendingPlanReview ? (_jsx(Box, { marginTop: 1, children: _jsx(PlanReviewModal, { tag: state.pendingPlanReview, onResolve: handlePlanReviewResolve }) })) : null, _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [overlay === 'farewell' || modalActive ? null : (_jsx(InputBox, { onSubmit: handleSubmit, onExit: handleExit, onCancel: handleCancel, onWalkback: handleWalkback, onCyclePermissionMode: handleCyclePermissionMode, now: props.now,
|
|
195
262
|
// Slug from process.cwd() (full path) so two workspaces with
|
|
196
263
|
// the same basename do not share history. state.workspaceLabel
|
|
197
264
|
// is the basename only. Codex review P2.
|
|
198
|
-
workspaceSlug: slugForCwd(process.cwd()) })), _jsx(StatusBar, { connection: state.connection, activeAgentCount: countActive(state), tokensDownstreamTotal: state.tokensDownstreamTotal, briefStartedAtEpochMs: state.briefStartedAtEpochMs, nowEpochMs: tickNow, pulsePhase: pulsePhase, pugiMdCount: workspaceContext.pugiMdCount, mcpServerCount: workspaceContext.mcpServerCount, skillCount: workspaceContext.skillCount, quotaPct: props.quotaPct, dispatchState: state.dispatchState, dispatchToolLabel: state.dispatchToolLabel
|
|
265
|
+
workspaceSlug: slugForCwd(process.cwd()) })), _jsx(ThinkingSpinner, { dispatchState: state.dispatchState, dispatchToolLabel: state.dispatchToolLabel }), _jsx(StatusBar, { connection: state.connection, activeAgentCount: countActive(state), tokensDownstreamTotal: state.tokensDownstreamTotal, briefStartedAtEpochMs: state.briefStartedAtEpochMs, nowEpochMs: tickNow, pulsePhase: pulsePhase, pugiMdCount: workspaceContext.pugiMdCount, mcpServerCount: workspaceContext.mcpServerCount, skillCount: workspaceContext.skillCount, quotaPct: props.quotaPct, dispatchState: state.dispatchState, dispatchToolLabel: state.dispatchToolLabel, lastCompletedOutcome: state.lastCompletedOutcome,
|
|
266
|
+
// cost-meter sprint — surface accumulated session totals
|
|
267
|
+
// + per-turn delta flash on the status bar's top row. The
|
|
268
|
+
// session module owns accumulation; the bar is a pure render.
|
|
269
|
+
sessionTokensIn: state.sessionTokensIn, sessionTokensOut: state.sessionTokensOut, sessionCostUsd: state.sessionCostUsd, sessionStartedAtEpochMs: state.sessionStartedAtEpochMs, lastTurnDelta: state.lastTurnDelta }), props.updateBanner ? _jsx(UpdateBanner, { result: props.updateBanner }) : null] })] }));
|
|
199
270
|
}
|
|
200
271
|
function Header({ state }) {
|
|
201
|
-
|
|
272
|
+
// the header `.io` brand accent + connection
|
|
273
|
+
// pill route through `useTheme()` so the operator's `/theme` flip
|
|
274
|
+
// (default / dark / light / colorblind) re-tints the chrome on
|
|
275
|
+
// re-mount. The `useTheme` hook returns the `default` preset's
|
|
276
|
+
// colors when no provider is mounted, preserving the previous
|
|
277
|
+
// `#3da9fc` constants for tests that import `<Repl />` standalone.
|
|
278
|
+
const theme = useTheme();
|
|
279
|
+
return (_jsxs(Box, { children: [_jsx(Text, { bold: true, children: "Pugi" }), _jsx(Text, { bold: true, color: theme.accent, children: ".io" }), _jsx(Text, { dimColor: true, children: ` · workspace: ${state.workspaceLabel} · v${state.cliVersion} · ` }), _jsx(Text, { color: theme.accent, children: state.connection === 'on_watch' ? 'on watch' : state.connection.replace('_', ' ') })] }));
|
|
202
280
|
}
|
|
203
281
|
function MainArea({ state, personaNames, nowEpochMs, hideToolStream, toolStreamCollapsed, }) {
|
|
204
|
-
//
|
|
282
|
+
// : three vertical panes stacked above the input box.
|
|
205
283
|
//
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
//
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
//
|
|
284
|
+
// 1. Conversation pane (top) - transcript with Markdown render.
|
|
285
|
+
// 2. Tool stream pane (mid) - live Read/Edit/Bash/Grep lines.
|
|
286
|
+
// Hidden when `--no-tool-stream` is
|
|
287
|
+
// set; collapsed via Ctrl+T while
|
|
288
|
+
// the pane is visible.
|
|
289
|
+
// 3. Agent tree pane (bottom) - Cyber-Zoo roster with persona /
|
|
290
|
+
// status / duration / token counts.
|
|
213
291
|
//
|
|
214
292
|
// The window over the transcript is small (last 12 rows) so the
|
|
215
293
|
// bottom of the frame stays anchored to the input box. New agents
|
|
216
|
-
// push the operator line up the screen, mirroring
|
|
294
|
+
// push the operator line up the screen, mirroring the upstream tool /
|
|
217
295
|
// Codex CLI / Gemini CLI rendering.
|
|
218
296
|
const conversationSlice = state.transcript.slice(-CONVERSATION_WINDOW);
|
|
219
297
|
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(ConversationPane, { rows: conversationSlice, personaNames: personaNames }), hideToolStream ? null : (_jsx(Box, { marginTop: 1, children: _jsx(ToolStreamPane, { calls: state.toolCalls, collapsed: toolStreamCollapsed }) })), _jsx(Box, { marginTop: 1, children: _jsx(AgentTreePane, { agents: state.agents, nowEpochMs: nowEpochMs }) })] }));
|
|
@@ -221,7 +299,7 @@ function MainArea({ state, personaNames, nowEpochMs, hideToolStream, toolStreamC
|
|
|
221
299
|
function HelpOverlay() {
|
|
222
300
|
// Group commands by their `group` field so the operator scans the
|
|
223
301
|
// palette by intent (dispatch → session → tools → settings → meta).
|
|
224
|
-
// The
|
|
302
|
+
// The wave-2 expansion grew the surface from 6 to 20 commands;
|
|
225
303
|
// a flat list would force the operator to read 20 rows top-to-bottom
|
|
226
304
|
// every time. Grouping cuts perceived complexity dramatically.
|
|
227
305
|
const grouped = new Map();
|
|
@@ -238,14 +316,14 @@ function HelpOverlay() {
|
|
|
238
316
|
const rows = grouped.get(group);
|
|
239
317
|
if (!rows || rows.length === 0)
|
|
240
318
|
return null;
|
|
241
|
-
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { dimColor: true, children: `
|
|
319
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { dimColor: true, children: ` -- ${group} --` }), rows.map((row) => (_jsxs(Box, { children: [_jsx(Text, { bold: true, color: "#3da9fc", children: ` /${row.name} ${row.args}`.padEnd(22, ' ') }), _jsx(Text, { dimColor: true, children: row.gloss })] }, row.name)))] }, group));
|
|
242
320
|
}), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: `${PUGI_TAGLINE}` }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: 'Press any key to dismiss.' }) })] }));
|
|
243
321
|
}
|
|
244
322
|
function RosterOverlay() {
|
|
245
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "On-watch roster" }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: THE_TEN.map((persona) => (_jsxs(Box, { children: [_jsx(Text, { bold: true, children: `
|
|
323
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { bold: true, children: "On-watch roster" }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: THE_TEN.map((persona) => (_jsxs(Box, { children: [_jsx(Text, { bold: true, children: ` ${persona.name.padEnd(10, ' ')}` }), _jsx(Text, { dimColor: true, children: `${persona.role.padEnd(20, ' ')}` }), _jsx(Text, { children: persona.oneLiner })] }, persona.slug))) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: 'Press any key to dismiss.' }) })] }));
|
|
246
324
|
}
|
|
247
325
|
function FarewellOverlay() {
|
|
248
|
-
return (_jsx(Box, { flexDirection: "column", alignItems: "center", paddingY: 2, children: _jsx(Text, { bold: true, color: "
|
|
326
|
+
return (_jsx(Box, { flexDirection: "column", alignItems: "center", paddingY: 2, children: _jsx(Text, { bold: true, color: "#3da9fc", children: PUGI_TAGLINE }) }));
|
|
249
327
|
}
|
|
250
328
|
function applyVerdictSideEffects(verdict, handlers) {
|
|
251
329
|
switch (verdict.kind) {
|
|
@@ -270,8 +348,10 @@ function applyVerdictSideEffects(verdict, handlers) {
|
|
|
270
348
|
case 'consensus':
|
|
271
349
|
case 'diff':
|
|
272
350
|
case 'cost':
|
|
351
|
+
case 'quota':
|
|
273
352
|
case 'status':
|
|
274
353
|
case 'resume':
|
|
354
|
+
case 'mcp':
|
|
275
355
|
case 'stub':
|
|
276
356
|
// All non-overlay verdicts: the session module already appended
|
|
277
357
|
// any operator-visible system lines (and, for `ask`, set
|
|
@@ -7,7 +7,7 @@ export const PALETTE_ROW_LIMIT = 8;
|
|
|
7
7
|
* Centralises the "starts-with-slash → filter SLASH_COMMAND_HELP"
|
|
8
8
|
* logic so the input box and the unit test agree on the shape.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
10
|
+
* fix: returns the FULL filtered set, not just the
|
|
11
11
|
* first PALETTE_ROW_LIMIT rows. The palette renderer now windows the
|
|
12
12
|
* visible slice internally based on `focusedIndex`, so the operator
|
|
13
13
|
* can scroll past row 7 via ↑/↓ on a long list (e.g. 20 commands when
|
|
@@ -15,9 +15,9 @@ export const PALETTE_ROW_LIMIT = 8;
|
|
|
15
15
|
* shape for backward compatibility but always equals `rows.length`.
|
|
16
16
|
*
|
|
17
17
|
* Behaviour:
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* - Empty / non-slash buffer → empty result; palette stays hidden.
|
|
19
|
+
* - `/` alone → all registry rows (the operator wants to browse).
|
|
20
|
+
* - `/he` → rows whose name starts with `he` (case-insensitive).
|
|
21
21
|
*/
|
|
22
22
|
export function filterPalette(buffer) {
|
|
23
23
|
if (!buffer.startsWith('/')) {
|
|
@@ -86,7 +86,7 @@ export function completePalette(buffer, rows, focusedIndex) {
|
|
|
86
86
|
export function SlashPalette(props) {
|
|
87
87
|
if (props.rows.length === 0)
|
|
88
88
|
return null;
|
|
89
|
-
//
|
|
89
|
+
// fix: compute the visible window so the operator
|
|
90
90
|
// can scroll past row 7 on long lists. Focus indexes the full rows
|
|
91
91
|
// array; the window slides to keep the focused row visible.
|
|
92
92
|
const window = computePaletteWindow(props.rows, props.focusedIndex);
|
|
@@ -101,6 +101,6 @@ export function SlashPalette(props) {
|
|
|
101
101
|
const glyph = focused ? '▸' : '·';
|
|
102
102
|
const cmd = `/${row.name}${row.args ? ` ${row.args}` : ''}`.padEnd(22, ' ');
|
|
103
103
|
return (_jsxs(Box, { children: [_jsx(Text, { color: focused ? 'cyan' : 'gray', children: `${glyph} ` }), _jsx(Text, { bold: focused, color: focused ? 'cyan' : undefined, dimColor: !focused, children: cmd }), _jsx(Text, { dimColor: true, children: row.gloss })] }, row.name));
|
|
104
|
-
}), overflow ? (_jsx(Box, { children: _jsx(Text, { dimColor: true, children: `
|
|
104
|
+
}), overflow ? (_jsx(Box, { children: _jsx(Text, { dimColor: true, children: ` → ${focusedDisplayIndex}/${window.total}` }) })) : null, _jsx(Box, { children: _jsx(Text, { dimColor: true, children: ' ↑/↓ select · Tab complete · Enter run · Esc close' }) })] }));
|
|
105
105
|
}
|
|
106
106
|
//# sourceMappingURL=slash-palette.js.map
|
package/dist/tui/splash.js
CHANGED
|
@@ -21,11 +21,11 @@ export function Splash({ data }) {
|
|
|
21
21
|
cmd: 'pugi login',
|
|
22
22
|
gloss: 'Connect this terminal to your Pugi account',
|
|
23
23
|
};
|
|
24
|
-
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsx(Box, { children: _jsx(Text, { bold: true, color: "
|
|
24
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: [_jsx(Box, { children: _jsx(Text, { bold: true, color: "#3da9fc", children: "pugi.io" }) }), _jsx(Box, { children: _jsx(Text, { dimColor: true, children: `v${data.cliVersion} · ${data.apiUrl}` }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Account: " }), _jsx(Text, { children: accountLine })] }), data.isAuthenticated && data.plan ? (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: "Plan: " }), _jsx(Text, { children: data.plan })] })) : null] }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { dimColor: true, children: "Quick start:" }), _jsx(HintRow, { command: primaryHint.cmd, gloss: primaryHint.gloss }), data.isAuthenticated ? (_jsx(HintRow, { command: 'pugi login', gloss: 'Re-authenticate or switch accounts' })) : (_jsx(HintRow, { command: 'pugi code "fix the bug"', gloss: 'Run a one-shot coding task' })), _jsx(HintRow, { command: 'pugi review --triple', gloss: 'Run the Anvil triple-review gate' }), _jsx(HintRow, { command: 'pugi help', gloss: 'Full command reference' })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Docs: https://pugi.dev \u00B7 Status: https://pugi.io/status" }) })] }));
|
|
25
25
|
}
|
|
26
26
|
function HintRow({ command, gloss }) {
|
|
27
27
|
// Pad command names so the gloss column lines up across rows.
|
|
28
28
|
const padded = command.padEnd(28, ' ');
|
|
29
|
-
return (_jsxs(Text, { children: [_jsx(Text, { children: `
|
|
29
|
+
return (_jsxs(Text, { children: [_jsx(Text, { children: ` ${padded}` }), _jsx(Text, { dimColor: true, children: gloss })] }));
|
|
30
30
|
}
|
|
31
31
|
//# sourceMappingURL=splash.js.map
|