@pugi/cli 0.1.0-beta.9 → 0.1.0-beta.90
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/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 +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 +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 +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 +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 +129 -19
- package/dist/core/engine/strip-internal-fields.js +124 -0
- package/dist/core/engine/tool-bridge.js +1731 -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 +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-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 +2148 -217
- package/dist/core/repl/slash-commands.js +501 -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/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 +324 -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 +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/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 +4185 -549
- 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 +73 -39
- 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/feedback.js +184 -0
- package/dist/runtime/commands/hooks.js +187 -0
- package/dist/runtime/commands/init.js +254 -0
- package/dist/runtime/commands/lsp.js +200 -38
- 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 +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/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/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 +22 -22
- 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/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 +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 +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 +86 -4
- 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 +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/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 +176 -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 +31 -16
- 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 +12 -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
package/dist/tui/repl-render.js
CHANGED
|
@@ -1,29 +1,35 @@
|
|
|
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';
|
|
25
30
|
import { SqliteSessionStore } from '../core/repl/store/index.js';
|
|
26
31
|
import { slugForCwd } from '../core/repl/history.js';
|
|
32
|
+
import { loadSettings } from '../core/settings.js';
|
|
27
33
|
import { WorkingSet, buildRepoSkeleton, loadPugiIgnore, PugiWatcher, } from '../core/context/index.js';
|
|
28
34
|
/**
|
|
29
35
|
* Mount the REPL and resolve when the user exits via Ctrl+C × 2 or
|
|
@@ -31,7 +37,7 @@ import { WorkingSet, buildRepoSkeleton, loadPugiIgnore, PugiWatcher, } from '../
|
|
|
31
37
|
* `pugi resume <sessionId>` once that command exists).
|
|
32
38
|
*/
|
|
33
39
|
export async function renderRepl(options) {
|
|
34
|
-
// beta.9 CEO dogfood
|
|
40
|
+
// beta.9 CEO dogfood: claim stdin raw mode + alt-screen
|
|
35
41
|
// BEFORE any async bootstrap step so keystrokes typed during the
|
|
36
42
|
// [launch -> Ink mount] window cannot echo into the terminal in
|
|
37
43
|
// cooked mode. Previously openLocalStore (SQLite open) +
|
|
@@ -41,7 +47,7 @@ export async function renderRepl(options) {
|
|
|
41
47
|
// every typed character literally onto the screen below the
|
|
42
48
|
// pre-printed mascot/header. The visible result was the operator's
|
|
43
49
|
// "ssssss" landing on the rendered status-bar bottom row (CEO
|
|
44
|
-
// screenshot
|
|
50
|
+
// screenshot: beta.8 REPL bug 2).
|
|
45
51
|
//
|
|
46
52
|
// The claim is idempotent with Ink's own raw-mode enable: Ink
|
|
47
53
|
// ref-counts setRawMode calls, and Node's stdin.setRawMode is
|
|
@@ -50,13 +56,67 @@ export async function renderRepl(options) {
|
|
|
50
56
|
// top, and our finally{} restore drops the floor only after Ink
|
|
51
57
|
// has cleanly torn down (or never mounted on a bootstrap crash).
|
|
52
58
|
const bootstrap = claimTerminalForRepl();
|
|
59
|
+
// beta.13 auto-init wire (CEO dogfood): scaffold the
|
|
60
|
+
// `.pugi/` workspace silently on REPL boot so launching `pugi` in a
|
|
61
|
+
// fresh cwd no longer demands an explicit `pugi init` round-trip.
|
|
62
|
+
// Idempotent — every helper inside scaffoldPugiWorkspace is a
|
|
63
|
+
// `*_IfMissing` write, so re-running over an existing workspace is
|
|
64
|
+
// a no-op. Fail-safe: any FS / perms error never blocks REPL launch.
|
|
65
|
+
// Operator escape hatch: PUGI_NO_AUTO_INIT=1.
|
|
66
|
+
//
|
|
67
|
+
// Beta.13 P2 fix: gate the scaffold on project-root markers
|
|
68
|
+
// so launching `pugi` from `$HOME` / `/tmp` / arbitrary dirs does NOT
|
|
69
|
+
// sprinkle `.pugi/` directories all over the filesystem. The gate
|
|
70
|
+
// mirrors `isBoundWorkspace` from workspace-context.ts but also
|
|
71
|
+
// accepts non-JS roots (Cargo / pyproject / go.mod) because the CLI
|
|
72
|
+
// is language-agnostic and an operator working in a Rust repo deserves
|
|
73
|
+
// the same auto-init UX as a Node operator. Already-bound `.pugi/`
|
|
74
|
+
// dirs also opt back in so the scaffold can fill any missing
|
|
75
|
+
// sub-artifacts the operator deleted.
|
|
76
|
+
// `--bare` (PUGI_BARE=1) ALSO suppresses the
|
|
77
|
+
// auto-init scaffold. Bare mode is the deterministic "fresh install
|
|
78
|
+
// anywhere" path — no `.pugi/` writes, no PUGI.md scaffold, no
|
|
79
|
+
// settings.json seed. The pre-existing PUGI_NO_AUTO_INIT escape
|
|
80
|
+
// hatch stays — bare mode just unions with it.
|
|
81
|
+
const { isBareMode } = await import('../core/bare-mode/index.js');
|
|
82
|
+
if (process.env.PUGI_NO_AUTO_INIT !== '1' &&
|
|
83
|
+
!isBareMode() &&
|
|
84
|
+
isProjectRoot(process.cwd())) {
|
|
85
|
+
try {
|
|
86
|
+
const { scaffoldPugiWorkspace } = await import('../runtime/cli.js');
|
|
87
|
+
await scaffoldPugiWorkspace({
|
|
88
|
+
cwd: process.cwd(),
|
|
89
|
+
noDefaults: true,
|
|
90
|
+
log: () => {
|
|
91
|
+
/* silent — never leak scaffold progress into the REPL alt-screen */
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
// Fail-safe: read-only FS or perms error never blocks REPL launch.
|
|
97
|
+
// Beta.13 P2 fix: bare-catch swallowed the diagnostic;
|
|
98
|
+
// surface it on stderr under PUGI_DEBUG=1 so operator-triage on
|
|
99
|
+
// "why isn't .pugi/ being created?" has a starting point without
|
|
100
|
+
// having to re-instrument the bootstrap.
|
|
101
|
+
if (process.env.PUGI_DEBUG === '1') {
|
|
102
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
103
|
+
process.stderr.write(`[pugi-debug] auto-init failed: ${msg}\n`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
53
107
|
const transport = createProductionTransport();
|
|
54
|
-
// Auto-bind the workspace context from process.cwd() so
|
|
108
|
+
// Auto-bind the workspace context from process.cwd() so Pugi knows
|
|
55
109
|
// which repo the operator launched the CLI in. The resolver is
|
|
56
110
|
// best-effort — any FS error falls back to a basename-only summary,
|
|
57
|
-
// never blocks REPL launch.
|
|
111
|
+
// never blocks REPL launch. fix.
|
|
58
112
|
const workspace = options.workspace ?? resolveWorkspaceContext(process.cwd());
|
|
59
|
-
//
|
|
113
|
+
// Beta.13 P1 fix: read `ui.cyberZoo` from
|
|
114
|
+
// `.pugi/settings.json` so the operator's splash posture flows to
|
|
115
|
+
// admin-api on session open. Without this, the renderer's `cyberZoo`
|
|
116
|
+
// parameter (added beta.13) was always defaulted to 'on' regardless
|
|
117
|
+
// of the operator's actual setting.
|
|
118
|
+
const cyberZoo = readCyberZooSetting(process.cwd());
|
|
119
|
+
// : open the local SessionStore for `/resume` persistence. The
|
|
60
120
|
// store lives under `~/.pugi/projects/<slug>/`; failure is fail-safe
|
|
61
121
|
// — we log a one-line warning to stderr and continue with the REPL
|
|
62
122
|
// in memory-only mode. Lock-busy errors get the friendliest message
|
|
@@ -68,7 +128,7 @@ export async function renderRepl(options) {
|
|
|
68
128
|
workspaceRoot: process.cwd(),
|
|
69
129
|
resumeLocalSessionId: options.resumeLocalSessionId,
|
|
70
130
|
});
|
|
71
|
-
//
|
|
131
|
+
// three-tier context bootstrap. The skeleton + working set
|
|
72
132
|
// + watcher are local-first and best-effort: every step is wrapped
|
|
73
133
|
// in try/catch so an unreadable workspace never blocks REPL launch.
|
|
74
134
|
// Opt-out via PUGI_DISABLE_CONTEXT=1 for hermetic test runs.
|
|
@@ -83,6 +143,7 @@ export async function renderRepl(options) {
|
|
|
83
143
|
cliVersion: options.cliVersion,
|
|
84
144
|
transport,
|
|
85
145
|
workspace,
|
|
146
|
+
cyberZoo,
|
|
86
147
|
store,
|
|
87
148
|
localSessionId: openedSessionId,
|
|
88
149
|
repoSkeleton: skeleton,
|
|
@@ -113,7 +174,7 @@ export async function renderRepl(options) {
|
|
|
113
174
|
// typed it after the REPL became interactive. Idempotent: no-op
|
|
114
175
|
// when stdin is not a TTY or no bytes were buffered.
|
|
115
176
|
drainBufferedStdin(process.stdin);
|
|
116
|
-
//
|
|
177
|
+
// wave 5: paint the chafa-baked brand-pug ANSI render to
|
|
117
178
|
// stdout BEFORE Ink mounts (but AFTER alt-screen enter). Ink's
|
|
118
179
|
// layout engine would mis-measure the truecolor escape sequences,
|
|
119
180
|
// so the pug must land verbatim. The flag is passed into <Repl />
|
|
@@ -123,13 +184,45 @@ export async function renderRepl(options) {
|
|
|
123
184
|
// (operator opted out via --no-splash), we suppress the pre-print
|
|
124
185
|
// too so the boot stays silent.
|
|
125
186
|
const mascotPrePrinted = options.skipSplash === true ? false : printPugMascotPreInk(process.stdout);
|
|
126
|
-
|
|
187
|
+
// resolve the active theme ONCE at mount
|
|
188
|
+
// and wrap `<Repl />` in `<ThemeProvider>` so every Ink consumer
|
|
189
|
+
// (`<Header>`, `<DoctorTable>`, `<StyleTable>`, `<ThemeTable>`,
|
|
190
|
+
// …) picks up the same color tokens. The provider is stable for
|
|
191
|
+
// the lifetime of the REPL — operator `/theme <name>` writes to
|
|
192
|
+
// disk + appends a system line, and the next `pugi` launch re-
|
|
193
|
+
// mounts with the new slug. Re-mounting mid-session would race
|
|
194
|
+
// against Ink's raw-mode handler so we deliberately keep the
|
|
195
|
+
// session-lifetime contract instead of polling the config file.
|
|
196
|
+
const resolvedTheme = resolveTheme({
|
|
197
|
+
workspaceRoot: process.cwd(),
|
|
198
|
+
env: process.env,
|
|
199
|
+
});
|
|
200
|
+
// CEO P0 #2 : collect welcome banner data BEFORE Ink
|
|
201
|
+
// mounts so the banner paints on the first frame instead of swapping
|
|
202
|
+
// in mid-render. The collector swallows every IO error so а missing
|
|
203
|
+
// CHANGELOG / unreadable credential / malformed settings never
|
|
204
|
+
// blocks the boot.
|
|
205
|
+
let welcomeData;
|
|
206
|
+
if (options.skipSplash !== true) {
|
|
207
|
+
try {
|
|
208
|
+
welcomeData = collectWelcomeData({
|
|
209
|
+
cliVersion: options.cliVersion,
|
|
210
|
+
cwd: process.cwd(),
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
welcomeData = undefined;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
const instance = render(React.createElement(ThemeProvider, { slug: resolvedTheme.slug }, React.createElement(Repl, {
|
|
127
218
|
session,
|
|
128
219
|
updateBanner: options.updateBanner ?? null,
|
|
129
220
|
skipSplash: options.skipSplash === true,
|
|
130
221
|
hideToolStream: options.hideToolStream === true,
|
|
131
222
|
mascotPrePrinted,
|
|
132
|
-
|
|
223
|
+
welcomeData,
|
|
224
|
+
autoInitStatus: options.autoInitStatus ?? null,
|
|
225
|
+
})));
|
|
133
226
|
// Make sure we leave the alt screen on abrupt exits too. Without
|
|
134
227
|
// this the operator's shell stays "frozen" on the Pugi splash.
|
|
135
228
|
process.once('exit', bootstrap.restore);
|
|
@@ -242,6 +335,55 @@ export function drainBufferedStdin(stdin = process.stdin) {
|
|
|
242
335
|
return 0;
|
|
243
336
|
}
|
|
244
337
|
}
|
|
338
|
+
/**
|
|
339
|
+
* Project-root probe — beta.13 P2 fix.
|
|
340
|
+
*
|
|
341
|
+
* Beta.13 auto-init was unconditional and silently created `.pugi/` in
|
|
342
|
+
* every cwd the REPL was launched from, including `$HOME` and `/tmp`.
|
|
343
|
+
* Operators who ran `pugi` to ask a quick question outside of any
|
|
344
|
+
* project ended up with stray `.pugi/` directories polluting their
|
|
345
|
+
* filesystem. The gate looks for any of six project-root markers
|
|
346
|
+
* before scaffolding:
|
|
347
|
+
*
|
|
348
|
+
* - `package.json` — JS / TS workspaces
|
|
349
|
+
* - `.git` — any cloned repo regardless of language
|
|
350
|
+
* - `.pugi` — already-bound Pugi workspace (re-scaffold
|
|
351
|
+
* fills any missing artifacts the operator
|
|
352
|
+
* deleted, idempotent over existing files)
|
|
353
|
+
* - `Cargo.toml` — Rust crates
|
|
354
|
+
* - `pyproject.toml` — Python projects (PEP 518)
|
|
355
|
+
* - `go.mod` — Go modules
|
|
356
|
+
*
|
|
357
|
+
* The probe is six cheap `existsSync` calls; the cost is negligible
|
|
358
|
+
* compared with the alt-screen + Ink mount that follows. Exported so a
|
|
359
|
+
* future unit spec can lock the contract.
|
|
360
|
+
*/
|
|
361
|
+
export function isProjectRoot(cwd) {
|
|
362
|
+
// ESM static imports — `require()` is not defined in a `"type": "module"`
|
|
363
|
+
// bundle and would throw `ReferenceError: require is not defined` the
|
|
364
|
+
// moment the REPL bootstrap calls this gate. Beta.16 P0 fix.
|
|
365
|
+
return (existsSync(resolve(cwd, 'package.json')) ||
|
|
366
|
+
existsSync(resolve(cwd, '.git')) ||
|
|
367
|
+
existsSync(resolve(cwd, '.pugi')) ||
|
|
368
|
+
existsSync(resolve(cwd, 'Cargo.toml')) ||
|
|
369
|
+
existsSync(resolve(cwd, 'pyproject.toml')) ||
|
|
370
|
+
existsSync(resolve(cwd, 'go.mod')));
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Read the operator's cyber-zoo posture from `.pugi/settings.json`.
|
|
374
|
+
* Best-effort: when the file is missing / malformed, fall through to
|
|
375
|
+
* the historical 'on' default so the REPL never refuses to launch on
|
|
376
|
+
* a settings error. Beta.13 P1 fix.
|
|
377
|
+
*/
|
|
378
|
+
function readCyberZooSetting(cwd) {
|
|
379
|
+
try {
|
|
380
|
+
const settings = loadSettings(cwd);
|
|
381
|
+
return settings.ui?.cyberZoo ?? 'on';
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
return 'on';
|
|
385
|
+
}
|
|
386
|
+
}
|
|
245
387
|
/**
|
|
246
388
|
* Open the local SessionStore for the REPL bootstrap. Returns
|
|
247
389
|
* `{ store: null, openedSessionId: undefined }` on any error so the
|
|
@@ -279,11 +421,11 @@ async function openLocalStore(input) {
|
|
|
279
421
|
}
|
|
280
422
|
}
|
|
281
423
|
/**
|
|
282
|
-
* Bootstrap the
|
|
424
|
+
* Bootstrap the three-tier context primitives:
|
|
283
425
|
*
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
426
|
+
* - Tier 0: `RepoSkeleton` (~5KB ASCII tree + meta) for prompt injection.
|
|
427
|
+
* - Tier 1: `WorkingSet` LRU bounded at 50 entries.
|
|
428
|
+
* - Filewatch: chokidar started against cwd, ignore-filtered.
|
|
287
429
|
*
|
|
288
430
|
* The bootstrap is fail-safe: every primitive is wrapped so the REPL
|
|
289
431
|
* still launches when (e.g.) chokidar refuses to start on a
|
|
@@ -331,15 +473,22 @@ async function bootstrapContext(input) {
|
|
|
331
473
|
return { skeleton, workingSet, watcher };
|
|
332
474
|
}
|
|
333
475
|
/* ------------------------------------------------------------------ */
|
|
334
|
-
/* Production transport
|
|
476
|
+
/* Production transport */
|
|
335
477
|
/* ------------------------------------------------------------------ */
|
|
336
478
|
export function createProductionTransport() {
|
|
337
479
|
return {
|
|
338
|
-
async createSession({ apiUrl, apiKey, workspace }) {
|
|
480
|
+
async createSession({ apiUrl, apiKey, workspace, cyberZoo }) {
|
|
339
481
|
// Forward the workspace bundle in the POST body so admin-api can
|
|
340
|
-
// surface `<workspace-context>` in
|
|
482
|
+
// surface `<workspace-context>` in Pugi's prompt. Older admin-api
|
|
341
483
|
// builds ignore unknown fields, so this stays forward-compatible.
|
|
342
|
-
//
|
|
484
|
+
// fix.
|
|
485
|
+
//
|
|
486
|
+
// Beta.13 P1 fix: also forward `cyberZoo` so admin-api
|
|
487
|
+
// can render Pugi's `<cyber-zoo>` marker matching the operator's
|
|
488
|
+
// `.pugi/settings.json::ui.cyberZoo` toggle instead of the
|
|
489
|
+
// historical 'on' default. Only included on the wire when set
|
|
490
|
+
// explicitly so a missing setting still survives older admin-api
|
|
491
|
+
// builds that do not declare the DTO field.
|
|
343
492
|
const body = {};
|
|
344
493
|
if (workspace?.workspaceCwd)
|
|
345
494
|
body.workspaceCwd = workspace.workspaceCwd;
|
|
@@ -347,6 +496,8 @@ export function createProductionTransport() {
|
|
|
347
496
|
body.workspaceSlug = workspace.workspaceSlug;
|
|
348
497
|
if (workspace?.workspaceSummary)
|
|
349
498
|
body.workspaceSummary = workspace.workspaceSummary;
|
|
499
|
+
if (cyberZoo === 'on' || cyberZoo === 'off')
|
|
500
|
+
body.cyberZoo = cyberZoo;
|
|
350
501
|
const response = await fetch(joinUrl(apiUrl, '/api/pugi/sessions'), {
|
|
351
502
|
method: 'POST',
|
|
352
503
|
headers: jsonHeaders(apiKey),
|
|
@@ -392,7 +543,7 @@ export function createProductionTransport() {
|
|
|
392
543
|
if (lastEventId) {
|
|
393
544
|
headers['Last-Event-ID'] = lastEventId;
|
|
394
545
|
}
|
|
395
|
-
// beta.9 CEO dogfood
|
|
546
|
+
// beta.9 CEO dogfood: hard timeout on the SSE
|
|
396
547
|
// handshake so a CDN/proxy that buffers the response (or an
|
|
397
548
|
// admin-api that accepted the route but never flushed headers)
|
|
398
549
|
// cannot freeze the REPL in `connecting` forever. The 5s budget
|
|
@@ -468,7 +619,7 @@ export function createProductionTransport() {
|
|
|
468
619
|
};
|
|
469
620
|
}
|
|
470
621
|
/* ------------------------------------------------------------------ */
|
|
471
|
-
/* SSE parser
|
|
622
|
+
/* SSE parser */
|
|
472
623
|
/* ------------------------------------------------------------------ */
|
|
473
624
|
/**
|
|
474
625
|
* Minimal SSE parser. Reads a UTF-8 stream of `id:` / `event:` / `data:`
|
|
@@ -532,7 +683,7 @@ async function consumeSseStream(body, onEvent) {
|
|
|
532
683
|
}
|
|
533
684
|
}
|
|
534
685
|
/* ------------------------------------------------------------------ */
|
|
535
|
-
/* Small helpers
|
|
686
|
+
/* Small helpers */
|
|
536
687
|
/* ------------------------------------------------------------------ */
|
|
537
688
|
function jsonHeaders(apiKey) {
|
|
538
689
|
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.
|
|
@@ -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
|