ashlr-plugin 1.36.4
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/.agents/plugins/marketplace.json +20 -0
- package/.claude-plugin/marketplace.json +39 -0
- package/.claude-plugin/plugin.json +36 -0
- package/.codex/agents/README.md +9 -0
- package/.codex/agents/ashlr-explorer.md +36 -0
- package/.codex/agents/ashlr-worker.md +38 -0
- package/.codex-plugin/plugin.json +45 -0
- package/.mcp.json +14 -0
- package/LICENSE +21 -0
- package/README.md +311 -0
- package/agents/ashlr-code.md +69 -0
- package/agents/ashlr-explore.md +44 -0
- package/agents/ashlr-plan.md +54 -0
- package/bench/fixtures/notebook-large.ipynb +660 -0
- package/bench/fixtures/notebook-small.ipynb +39 -0
- package/bench/fixtures/tasklist-closed.json +62 -0
- package/bench/fixtures/tasklist-large-mixed.json +27 -0
- package/bench/fixtures/tasklist-sprint-open.json +79 -0
- package/bench/fixtures/websearch-bun-runtime.json +32 -0
- package/bench/fixtures/websearch-react-hooks-patterns.json +32 -0
- package/bench/fixtures/websearch-typescript-generics.json +38 -0
- package/bench/refs/node-sdk/.refrev +1 -0
- package/bench/refs/node-sdk/README.md +17 -0
- package/bench/refs/node-sdk/src/agent/agent.ts +163 -0
- package/bench/refs/node-sdk/src/agent/create-agent-ui-stream.ts +83 -0
- package/bench/refs/node-sdk/src/agent/tool-loop-agent.ts +238 -0
- package/bench/refs/node-sdk/src/embed/embed-many.ts +409 -0
- package/bench/refs/node-sdk/src/embed/embed-result.ts +50 -0
- package/bench/refs/node-sdk/src/embed/embed.ts +257 -0
- package/bench/refs/node-sdk/src/error/invalid-argument-error.ts +34 -0
- package/bench/refs/node-sdk/src/error/invalid-tool-input-error.ts +33 -0
- package/bench/refs/node-sdk/src/error/no-object-generated-error.ts +70 -0
- package/bench/refs/node-sdk/src/generate-image/generate-image-result.ts +42 -0
- package/bench/refs/node-sdk/src/generate-image/generate-image.ts +362 -0
- package/bench/refs/node-sdk/src/generate-object/generate-object-result.ts +67 -0
- package/bench/refs/node-sdk/src/generate-object/generate-object.ts +501 -0
- package/bench/refs/node-sdk/src/generate-object/inject-json-instruction.ts +30 -0
- package/bench/refs/node-sdk/src/generate-object/output-strategy.ts +415 -0
- package/bench/refs/node-sdk/src/generate-object/repair-text.ts +12 -0
- package/bench/refs/node-sdk/src/generate-object/stream-object.ts +960 -0
- package/bench/refs/node-sdk/src/generate-speech/generate-speech.ts +191 -0
- package/bench/refs/node-sdk/src/generate-text/generate-text.ts +1484 -0
- package/bench/refs/node-sdk/src/generate-text/stream-text.ts +2708 -0
- package/bench/refs/node-sdk/src/generate-text/tool-call.ts +59 -0
- package/bench/refs/node-sdk/src/generate-text/tool-result.ts +36 -0
- package/bench/refs/node-sdk/src/telemetry/create-telemetry-dispatcher.ts +146 -0
- package/bench/refs/node-sdk/src/telemetry/telemetry-registry.ts +15 -0
- package/bench/refs/node-sdk/src/telemetry/telemetry.ts +223 -0
- package/bench/refs/node-sdk/src/util/async-iterable-stream.ts +94 -0
- package/bench/refs/node-sdk/src/util/consume-stream.ts +31 -0
- package/bench/refs/node-sdk/src/util/create-stitchable-stream.ts +112 -0
- package/bench/refs/node-sdk/src/util/download/download.ts +74 -0
- package/bench/refs/node-sdk/src/util/error-handler.ts +1 -0
- package/bench/refs/node-sdk/src/util/fix-json.ts +401 -0
- package/bench/refs/node-sdk/src/util/merge-objects.ts +79 -0
- package/bench/refs/python-lib/.refrev +1 -0
- package/bench/refs/python-lib/README.md +18 -0
- package/bench/refs/python-lib/pandas/core/_numba/executor.py +249 -0
- package/bench/refs/python-lib/pandas/core/_numba/extensions.py +586 -0
- package/bench/refs/python-lib/pandas/core/_numba/kernels/mean_.py +198 -0
- package/bench/refs/python-lib/pandas/core/_numba/kernels/min_max_.py +178 -0
- package/bench/refs/python-lib/pandas/core/_numba/kernels/sum_.py +255 -0
- package/bench/refs/python-lib/pandas/core/_numba/kernels/var_.py +251 -0
- package/bench/refs/python-lib/pandas/core/accessor.py +520 -0
- package/bench/refs/python-lib/pandas/core/api.py +138 -0
- package/bench/refs/python-lib/pandas/core/array_algos/masked_accumulations.py +97 -0
- package/bench/refs/python-lib/pandas/core/array_algos/masked_reductions.py +252 -0
- package/bench/refs/python-lib/pandas/core/array_algos/putmask.py +150 -0
- package/bench/refs/python-lib/pandas/core/array_algos/quantile.py +232 -0
- package/bench/refs/python-lib/pandas/core/array_algos/replace.py +159 -0
- package/bench/refs/python-lib/pandas/core/array_algos/take.py +609 -0
- package/bench/refs/python-lib/pandas/core/arraylike.py +534 -0
- package/bench/refs/python-lib/pandas/core/arrays/_arrow_string_mixins.py +434 -0
- package/bench/refs/python-lib/pandas/core/arrays/_mixins.py +630 -0
- package/bench/refs/python-lib/pandas/core/arrays/_ranges.py +276 -0
- package/bench/refs/python-lib/pandas/core/arrays/_utils.py +77 -0
- package/bench/refs/python-lib/pandas/core/arrays/arrow/accessors.py +521 -0
- package/bench/refs/python-lib/pandas/core/arrays/arrow/extension_types.py +174 -0
- package/bench/refs/python-lib/pandas/core/arrays/boolean.py +454 -0
- package/bench/refs/python-lib/pandas/core/arrays/floating.py +192 -0
- package/bench/refs/python-lib/pandas/core/arrays/integer.py +296 -0
- package/bench/refs/python-lib/pandas/core/arrays/masked.py +2140 -0
- package/bench/refs/python-lib/pandas/core/arrays/numeric.py +305 -0
- package/bench/refs/python-lib/pandas/core/arrays/numpy_.py +701 -0
- package/bench/refs/python-lib/pandas/core/arrays/period.py +1586 -0
- package/bench/refs/python-lib/pandas/core/arrays/sparse/accessor.py +505 -0
- package/bench/refs/python-lib/pandas/core/arrays/sparse/scipy_sparse.py +208 -0
- package/bench/refs/rust-project/.refrev +1 -0
- package/bench/refs/rust-project/README.md +17 -0
- package/bench/refs/rust-project/tokio/src/doc/os.rs +68 -0
- package/bench/refs/rust-project/tokio/src/fs/dir_builder.rs +129 -0
- package/bench/refs/rust-project/tokio/src/fs/file.rs +1113 -0
- package/bench/refs/rust-project/tokio/src/fs/mocks.rs +176 -0
- package/bench/refs/rust-project/tokio/src/fs/mod.rs +324 -0
- package/bench/refs/rust-project/tokio/src/fs/open_options.rs +856 -0
- package/bench/refs/rust-project/tokio/src/fs/read.rs +80 -0
- package/bench/refs/rust-project/tokio/src/fs/read_dir.rs +357 -0
- package/bench/refs/rust-project/tokio/src/fs/write.rs +99 -0
- package/bench/refs/rust-project/tokio/src/future/maybe_done.rs +123 -0
- package/bench/refs/rust-project/tokio/src/future/try_join.rs +82 -0
- package/bench/refs/rust-project/tokio/src/io/async_buf_read.rs +117 -0
- package/bench/refs/rust-project/tokio/src/io/async_read.rs +133 -0
- package/bench/refs/rust-project/tokio/src/io/async_seek.rs +96 -0
- package/bench/refs/rust-project/tokio/src/io/async_write.rs +402 -0
- package/bench/refs/rust-project/tokio/src/io/blocking.rs +339 -0
- package/bench/refs/rust-project/tokio/src/io/interest.rs +345 -0
- package/bench/refs/rust-project/tokio/src/io/join.rs +130 -0
- package/bench/refs/rust-project/tokio/src/io/mod.rs +308 -0
- package/bench/refs/rust-project/tokio/src/io/poll_evented.rs +319 -0
- package/bench/refs/rust-project/tokio/src/io/read_buf.rs +344 -0
- package/bench/refs/rust-project/tokio/src/io/ready.rs +322 -0
- package/bench/refs/rust-project/tokio/src/io/split.rs +166 -0
- package/bench/refs/rust-project/tokio/src/io/stderr.rs +148 -0
- package/bench/refs/rust-project/tokio/src/io/stdin.rs +98 -0
- package/bench/refs/rust-project/tokio/src/io/stdio_common.rs +222 -0
- package/bench/refs/rust-project/tokio/src/io/stdout.rs +197 -0
- package/bench/refs/rust-project/tokio/src/io/util/buf_reader.rs +311 -0
- package/bench/refs/rust-project/tokio/src/io/util/buf_stream.rs +207 -0
- package/bench/refs/rust-project/tokio/src/io/util/buf_writer.rs +310 -0
- package/bench/refs/rust-project/tokio/src/io/util/chain.rs +144 -0
- package/commands/_spawn-patterns.json +32 -0
- package/commands/ashlr-allow.md +21 -0
- package/commands/ashlr-benchmark.md +53 -0
- package/commands/ashlr-brief.md +97 -0
- package/commands/ashlr-budget.md +76 -0
- package/commands/ashlr-compact.md +54 -0
- package/commands/ashlr-dashboard.md +37 -0
- package/commands/ashlr-doctor.md +56 -0
- package/commands/ashlr-eco-mode.md +92 -0
- package/commands/ashlr-genome-init.md +24 -0
- package/commands/ashlr-genome-keygen.md +36 -0
- package/commands/ashlr-genome-loop.md +118 -0
- package/commands/ashlr-genome-push.md +36 -0
- package/commands/ashlr-genome-rewrap.md +48 -0
- package/commands/ashlr-genome-team-init.md +67 -0
- package/commands/ashlr-handoff.md +23 -0
- package/commands/ashlr-help.md +86 -0
- package/commands/ashlr-hook-timings.md +30 -0
- package/commands/ashlr-leaderboard.md +50 -0
- package/commands/ashlr-ollama-setup.md +39 -0
- package/commands/ashlr-orchestrate-status.md +72 -0
- package/commands/ashlr-orchestrate.md +83 -0
- package/commands/ashlr-parallelize.md +63 -0
- package/commands/ashlr-report-crash.md +33 -0
- package/commands/ashlr-resume.md +72 -0
- package/commands/ashlr-savings.md +24 -0
- package/commands/ashlr-settings.md +50 -0
- package/commands/ashlr-spawn.md +61 -0
- package/commands/ashlr-start.md +60 -0
- package/commands/ashlr-status.md +64 -0
- package/commands/ashlr-team-invite.md +47 -0
- package/commands/ashlr-tier.md +122 -0
- package/commands/ashlr-tour.md +60 -0
- package/commands/ashlr-update.md +155 -0
- package/commands/ashlr-upgrade.md +96 -0
- package/commands/goal.md +58 -0
- package/commands/loop.md +40 -0
- package/docs/CNAME +1 -0
- package/docs/PRO_TIER.md +104 -0
- package/docs/README.md +21 -0
- package/docs/architecture.md +415 -0
- package/docs/ashlr-pipe.md +161 -0
- package/docs/assets/logo.svg +19 -0
- package/docs/assets/og.png +0 -0
- package/docs/assets/og.svg +41 -0
- package/docs/benchmarks-v2.json +355 -0
- package/docs/benchmarks.json +102 -0
- package/docs/benchmarks.md +211 -0
- package/docs/billing.md +185 -0
- package/docs/cloud-genome.md +155 -0
- package/docs/competitive-wozcode.md +92 -0
- package/docs/deploy.md +325 -0
- package/docs/email-templates.md +113 -0
- package/docs/embed-tuning.md +103 -0
- package/docs/genome.md +120 -0
- package/docs/github-oauth-onboarding.md +127 -0
- package/docs/hero-video-script.md +129 -0
- package/docs/index.html +2262 -0
- package/docs/install-prompt.md +78 -0
- package/docs/install-windows.md +132 -0
- package/docs/install.ps1 +171 -0
- package/docs/install.sh +146 -0
- package/docs/launch/README.md +114 -0
- package/docs/launch/hn.md +49 -0
- package/docs/launch/reddit.md +45 -0
- package/docs/launch/x.md +65 -0
- package/docs/launch-post.md +112 -0
- package/docs/legal.md +78 -0
- package/docs/llm-providers.md +99 -0
- package/docs/multi-host-mcp.md +217 -0
- package/docs/multi-turn-architecture.md +108 -0
- package/docs/operations/deployment.md +108 -0
- package/docs/operations/error-monitoring.md +70 -0
- package/docs/operations/weekly-digest.md +70 -0
- package/docs/operations.md +494 -0
- package/docs/platform-support.md +133 -0
- package/docs/policy-packs.md +188 -0
- package/docs/press-kit/fact-sheet.md +78 -0
- package/docs/press-kit/founder-bio.md +3 -0
- package/docs/press-kit/logo.svg +33 -0
- package/docs/press-kit/screenshots.md +146 -0
- package/docs/pricing.md +251 -0
- package/docs/pro-backend-architecture.md +523 -0
- package/docs/producthunt.md +52 -0
- package/docs/router-migration.md +110 -0
- package/docs/session-log-schema.md +68 -0
- package/docs/social.md +95 -0
- package/docs/team-genome.md +528 -0
- package/docs/telemetry.md +194 -0
- package/docs/test-isolation.md +100 -0
- package/docs/upgrade.md +159 -0
- package/hooks/_hook-errors.ts +87 -0
- package/hooks/_hook-perf-emit.ts +113 -0
- package/hooks/_hook-timing-ledger.ts +1133 -0
- package/hooks/_nudge-throttle.ts +127 -0
- package/hooks/_recent-blocks.ts +127 -0
- package/hooks/audit-upload.ts +86 -0
- package/hooks/codex-hooks.json +171 -0
- package/hooks/commit-attribution.ts +179 -0
- package/hooks/edit-batching-nudge.ts +154 -0
- package/hooks/genome-scribe-hook.ts +219 -0
- package/hooks/hooks.json +294 -0
- package/hooks/orient-nudge-hook.ts +242 -0
- package/hooks/policy-enforce.ts +214 -0
- package/hooks/post-tool-use-embedding.ts +93 -0
- package/hooks/post-tool-use-genome.sh +37 -0
- package/hooks/post-tool-use-genome.ts +69 -0
- package/hooks/posttooluse-correlate.ts +122 -0
- package/hooks/posttooluse-dedupe-output.ts +241 -0
- package/hooks/posttooluse-genome-refresh.ts +223 -0
- package/hooks/posttooluse-native-nudge.ts +205 -0
- package/hooks/posttooluse-stale-result.ts +277 -0
- package/hooks/pretooluse-bash.ts +63 -0
- package/hooks/pretooluse-budget-guard.ts +318 -0
- package/hooks/pretooluse-common.ts +985 -0
- package/hooks/pretooluse-eco-router.ts +196 -0
- package/hooks/pretooluse-edit.sh +93 -0
- package/hooks/pretooluse-edit.ts +197 -0
- package/hooks/pretooluse-glob.ts +70 -0
- package/hooks/pretooluse-grep.sh +85 -0
- package/hooks/pretooluse-grep.ts +96 -0
- package/hooks/pretooluse-notebookedit.ts +121 -0
- package/hooks/pretooluse-read.sh +118 -0
- package/hooks/pretooluse-read.ts +118 -0
- package/hooks/pretooluse-task.ts +130 -0
- package/hooks/pretooluse-webfetch.ts +66 -0
- package/hooks/pretooluse-websearch.ts +85 -0
- package/hooks/pretooluse-write.ts +128 -0
- package/hooks/pulse-emit.ts +197 -0
- package/hooks/session-end-consolidate.sh +35 -0
- package/hooks/session-end-consolidate.ts +188 -0
- package/hooks/session-end-stats-gc.ts +80 -0
- package/hooks/session-log-append.sh +94 -0
- package/hooks/session-log-append.ts +116 -0
- package/hooks/session-start.ts +993 -0
- package/hooks/sessionend-hook-health-nudge.ts +451 -0
- package/hooks/sessionend-savings-nudge.ts +318 -0
- package/hooks/sessionend-status-line-nudge.ts +296 -0
- package/hooks/sessionstart-brief.ts +140 -0
- package/hooks/sessionstart-cost-refactor.ts +95 -0
- package/hooks/sessionstart-efficient.ts +110 -0
- package/hooks/sessionstart-genome-author.ts +93 -0
- package/hooks/sessionstart-lean-tools.ts +98 -0
- package/hooks/sessionstart-search.ts +97 -0
- package/hooks/stop-accounting.ts +152 -0
- package/hooks/subagent-stop-rollup.ts +162 -0
- package/hooks/userpromptsubmit-brief-trigger.ts +156 -0
- package/package.json +56 -0
- package/ports/README.md +108 -0
- package/ports/cursor/mcp.json +11 -0
- package/ports/goose/recipe.yaml +26 -0
- package/scripts/ashlr-mcp.ts +40 -0
- package/scripts/auto-update.ts +177 -0
- package/scripts/baseline-scan.ts +831 -0
- package/scripts/bench-orchestrate.ts +377 -0
- package/scripts/benchmark-refs.ts +292 -0
- package/scripts/bootstrap.mjs +100 -0
- package/scripts/brief-eval.ts +234 -0
- package/scripts/bump-version.ts +82 -0
- package/scripts/bun-resolve.d.mts +11 -0
- package/scripts/bun-resolve.mjs +59 -0
- package/scripts/calibrate-grep.ts +467 -0
- package/scripts/capture-grep-workload.ts +260 -0
- package/scripts/check-tier.ts +61 -0
- package/scripts/check-version-sync.ts +97 -0
- package/scripts/cli-orchestrate-status.ts +386 -0
- package/scripts/cli-orchestrate.ts +303 -0
- package/scripts/cli.ts +478 -0
- package/scripts/cloud-smoke-test.ts +313 -0
- package/scripts/coach-report.ts +373 -0
- package/scripts/context-db-migrate.ts +137 -0
- package/scripts/context-status.ts +43 -0
- package/scripts/demo-run.ts +255 -0
- package/scripts/deploy-smoke.sh +140 -0
- package/scripts/doctor.ts +992 -0
- package/scripts/embed-file-worker.ts +104 -0
- package/scripts/embed-tune.ts +308 -0
- package/scripts/errors-report.ts +428 -0
- package/scripts/find-test-leak.ts +69 -0
- package/scripts/generate-badge.ts +357 -0
- package/scripts/genome-auto-consolidate.ts +533 -0
- package/scripts/genome-auto-propose.ts +578 -0
- package/scripts/genome-cloud-pull.ts +363 -0
- package/scripts/genome-cloud-push.ts +382 -0
- package/scripts/genome-cloud-sync.ts +587 -0
- package/scripts/genome-commit-watcher.ts +295 -0
- package/scripts/genome-init.ts +986 -0
- package/scripts/genome-key.ts +233 -0
- package/scripts/genome-keygen.ts +168 -0
- package/scripts/genome-link.ts +59 -0
- package/scripts/genome-refresh-worker.ts +364 -0
- package/scripts/genome-rewrap.ts +90 -0
- package/scripts/genome-synthesizer.ts +679 -0
- package/scripts/genome-team-init.ts +312 -0
- package/scripts/handoff-pack.ts +438 -0
- package/scripts/hook-bootstrap.mjs +75 -0
- package/scripts/hook-timing-reader.ts +371 -0
- package/scripts/hook-timings-report.ts +554 -0
- package/scripts/install-genome-hooks.ts +196 -0
- package/scripts/install-onnx-model.ts +154 -0
- package/scripts/install-permissions.ts +276 -0
- package/scripts/install-status-line.ts +150 -0
- package/scripts/mcp-entrypoint.sh +78 -0
- package/scripts/mcp-entrypoint.ts +130 -0
- package/scripts/mdx-angle-bracket-lint.ts +152 -0
- package/scripts/measure-cold-start.ts +126 -0
- package/scripts/migrate-stats-to-sqlite.ts +86 -0
- package/scripts/ollama-setup.ts +498 -0
- package/scripts/onboarding-wizard.ts +1691 -0
- package/scripts/orchestrate-emit-telemetry.ts +177 -0
- package/scripts/orchestrate-expand.ts +517 -0
- package/scripts/orchestrate-run.ts +744 -0
- package/scripts/print-legend.ts +50 -0
- package/scripts/product-metadata.ts +38 -0
- package/scripts/prune-old-memories.ts +208 -0
- package/scripts/publish.sh +88 -0
- package/scripts/read-calibration.ts +122 -0
- package/scripts/report-crash.ts +226 -0
- package/scripts/run-benchmark.ts +750 -0
- package/scripts/run-root-tests.ts +28 -0
- package/scripts/savings-dashboard.ts +1258 -0
- package/scripts/savings-report-extras.ts +447 -0
- package/scripts/savings-status-line.ts +873 -0
- package/scripts/session-event-emit.ts +266 -0
- package/scripts/session-greet.ts +686 -0
- package/scripts/session-log-report.ts +551 -0
- package/scripts/session-resume.ts +614 -0
- package/scripts/set-hook-mode.ts +83 -0
- package/scripts/smoke-cross-platform.ts +117 -0
- package/scripts/smoke-realtime.ts +257 -0
- package/scripts/smoke-tools.ts +21 -0
- package/scripts/stats-cloud-pull.ts +213 -0
- package/scripts/stats-cloud-sync.ts +261 -0
- package/scripts/telemetry-flush.ts +160 -0
- package/scripts/telemetry-status.ts +266 -0
- package/scripts/timing-budget.ts +35 -0
- package/scripts/ui-animation.ts +120 -0
- package/scripts/ui.ts +431 -0
- package/scripts/upgrade-flow.ts +775 -0
- package/scripts/weekly-digest.ts +394 -0
- package/servers/_accounting.ts +78 -0
- package/servers/_ask-router.ts +84 -0
- package/servers/_ast-chunker.ts +434 -0
- package/servers/_ast-helpers.ts +183 -0
- package/servers/_ast-languages.ts +153 -0
- package/servers/_ast-refactor/_shared.ts +221 -0
- package/servers/_ast-refactor/cross-file-rename.ts +560 -0
- package/servers/_ast-refactor/extract-function.ts +357 -0
- package/servers/_ast-refactor/file-local-rename.ts +172 -0
- package/servers/_ast-refactor.ts +41 -0
- package/servers/_ast-skeleton.ts +107 -0
- package/servers/_bash-summarizers-registry.ts +1096 -0
- package/servers/_crash-dump.ts +210 -0
- package/servers/_cwd-clamp.ts +342 -0
- package/servers/_edit-log.ts +28 -0
- package/servers/_edit-match.ts +236 -0
- package/servers/_edit-validate.ts +196 -0
- package/servers/_embed-calibration.ts +123 -0
- package/servers/_embedding-cache.ts +401 -0
- package/servers/_embedding-model.ts +329 -0
- package/servers/_events.ts +113 -0
- package/servers/_genome-cache.ts +154 -0
- package/servers/_genome-commits.ts +172 -0
- package/servers/_genome-crypto-v2.ts +242 -0
- package/servers/_genome-crypto.ts +259 -0
- package/servers/_genome-discoveries.ts +140 -0
- package/servers/_genome-embed-populator.ts +216 -0
- package/servers/_genome-freshness.ts +134 -0
- package/servers/_genome-issues.ts +171 -0
- package/servers/_genome-live.ts +263 -0
- package/servers/_genome-prs.ts +188 -0
- package/servers/_genome-search.ts +479 -0
- package/servers/_genome-sync.ts +297 -0
- package/servers/_history-tracker.ts +279 -0
- package/servers/_http-helpers.ts +151 -0
- package/servers/_identity-hash.ts +151 -0
- package/servers/_llm-providers/anthropic.ts +132 -0
- package/servers/_llm-providers/cloud.ts +195 -0
- package/servers/_llm-providers/index.ts +350 -0
- package/servers/_llm-providers/local.ts +127 -0
- package/servers/_llm-providers/onnx.ts +393 -0
- package/servers/_llm-providers/types.ts +27 -0
- package/servers/_manifest-v2.ts +447 -0
- package/servers/_mcp-host.ts +93 -0
- package/servers/_nudge-events.ts +451 -0
- package/servers/_orchestrate-executor.ts +316 -0
- package/servers/_prefetch.ts +435 -0
- package/servers/_pricing.ts +256 -0
- package/servers/_pro.ts +381 -0
- package/servers/_read-cache.ts +44 -0
- package/servers/_router-handlers.ts +46 -0
- package/servers/_router.ts +55 -0
- package/servers/_run-with-timeout.ts +173 -0
- package/servers/_savings-render.ts +214 -0
- package/servers/_stats-sqlite.ts +640 -0
- package/servers/_stats.ts +1183 -0
- package/servers/_status-line-cells.ts +469 -0
- package/servers/_streaks.ts +162 -0
- package/servers/_summarize.ts +208 -0
- package/servers/_task-graph-render.ts +217 -0
- package/servers/_task-graph.ts +545 -0
- package/servers/_telemetry.ts +719 -0
- package/servers/_test-parsers.ts +530 -0
- package/servers/_test-watch.ts +626 -0
- package/servers/_text-helpers.ts +37 -0
- package/servers/_token-measure.ts +160 -0
- package/servers/_tool-base.ts +248 -0
- package/servers/_weekly-digest.ts +391 -0
- package/servers/ask-server-handlers.ts +49 -0
- package/servers/ask-server.ts +174 -0
- package/servers/bash-server-handlers.ts +138 -0
- package/servers/bash-server.ts +1136 -0
- package/servers/bench.ts +186 -0
- package/servers/diff-semantic-server-handlers.ts +39 -0
- package/servers/diff-semantic-server.ts +566 -0
- package/servers/diff-server-handlers.ts +317 -0
- package/servers/diff-server.ts +20 -0
- package/servers/edit-server-handlers.ts +31 -0
- package/servers/edit-server.ts +209 -0
- package/servers/edit-structural-server-handlers.ts +322 -0
- package/servers/efficiency-server-handlers.ts +161 -0
- package/servers/efficiency-server.ts +1135 -0
- package/servers/flush-server-handlers.ts +21 -0
- package/servers/flush-server.ts +19 -0
- package/servers/genome-server-handlers.ts +118 -0
- package/servers/genome-server.ts +397 -0
- package/servers/github-server-handlers.ts +187 -0
- package/servers/github-server.ts +856 -0
- package/servers/glob-server-handlers.ts +233 -0
- package/servers/glob-server.ts +20 -0
- package/servers/grep-server-handlers.ts +61 -0
- package/servers/grep-server.ts +564 -0
- package/servers/http-server-handlers.ts +36 -0
- package/servers/http-server.ts +149 -0
- package/servers/logs-server-handlers.ts +42 -0
- package/servers/logs-server.ts +359 -0
- package/servers/ls-server-handlers.ts +166 -0
- package/servers/ls-server.ts +20 -0
- package/servers/multi-edit-server-handlers.ts +51 -0
- package/servers/multi-edit-server.ts +422 -0
- package/servers/notebook-edit-server-handlers.ts +34 -0
- package/servers/notebook-edit-server.ts +181 -0
- package/servers/orient-server-handlers.ts +52 -0
- package/servers/orient-server.ts +436 -0
- package/servers/pipe-server-handlers.ts +68 -0
- package/servers/pipe-server.ts +300 -0
- package/servers/read-server-handlers.ts +42 -0
- package/servers/read-server.ts +206 -0
- package/servers/rename-file-server-handlers.ts +67 -0
- package/servers/rename-file-server.ts +699 -0
- package/servers/savings-server-handlers.ts +27 -0
- package/servers/savings-server.ts +54 -0
- package/servers/search-replace-regex-server-handlers.ts +96 -0
- package/servers/search-replace-regex-server.ts +751 -0
- package/servers/sql-server-handlers.ts +58 -0
- package/servers/sql-server.ts +505 -0
- package/servers/task-server-handlers.ts +358 -0
- package/servers/task-server.ts +24 -0
- package/servers/test-server-handlers.ts +351 -0
- package/servers/test-server.ts +20 -0
- package/servers/tree-server-handlers.ts +503 -0
- package/servers/tree-server.ts +20 -0
- package/servers/webfetch-server-handlers.ts +166 -0
- package/servers/webfetch-server.ts +20 -0
- package/servers/websearch-server-handlers.ts +215 -0
- package/servers/websearch-server.ts +19 -0
- package/servers/write-server-handlers.ts +27 -0
- package/servers/write-server.ts +97 -0
- package/skills/ashlr-brief/SKILL.md +80 -0
- package/skills/ashlr-codex-doctor/SKILL.md +21 -0
- package/skills/ashlr-codex-efficient-tools/SKILL.md +17 -0
- package/skills/ashlr-codex-genome-refresh/SKILL.md +20 -0
- package/skills/ashlr-codex-parallel-explore/SKILL.md +20 -0
- package/skills/ashlr-codex-savings/SKILL.md +17 -0
- package/skills/ashlr-cost-refactor/SKILL.md +50 -0
- package/skills/ashlr-efficient/SKILL.md +64 -0
- package/skills/ashlr-genome-author/SKILL.md +43 -0
- package/skills/ashlr-lean-tools/SKILL.md +43 -0
- package/skills/ashlr-search/SKILL.md +46 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* timing-budget.ts — scale wall-clock test budgets on shared CI runners.
|
|
3
|
+
*
|
|
4
|
+
* Several tests and smoke checks assert latency bounds (e.g. router cold start
|
|
5
|
+
* < 300ms). Those bounds are calibrated on a developer machine. GitHub-hosted
|
|
6
|
+
* macOS runners are much slower and noisier: the same unchanged code has
|
|
7
|
+
* measured ~450ms median cold start there, failing required checks on PRs
|
|
8
|
+
* that touch no code.
|
|
9
|
+
*
|
|
10
|
+
* `timingBudgetMs(ms)` returns `ms` unchanged locally, so local perf checks
|
|
11
|
+
* keep their original strength, and scales it on CI:
|
|
12
|
+
* - `ASHLR_TIMING_MULTIPLIER=<n>` (n >= 1) always wins, locally or on CI;
|
|
13
|
+
* - otherwise, when `CI` is set: 3x on macOS, 2x elsewhere.
|
|
14
|
+
* Windows-specific budgets that are already loosened should stay as they are
|
|
15
|
+
* and not be passed through this helper.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export function timingMultiplier(
|
|
19
|
+
env: Record<string, string | undefined> = process.env,
|
|
20
|
+
platform: NodeJS.Platform = process.platform,
|
|
21
|
+
): number {
|
|
22
|
+
const explicit = Number(env.ASHLR_TIMING_MULTIPLIER);
|
|
23
|
+
if (Number.isFinite(explicit) && explicit >= 1) return explicit;
|
|
24
|
+
const ci = env.CI;
|
|
25
|
+
if (!ci || ci === "0" || ci.toLowerCase() === "false") return 1;
|
|
26
|
+
return platform === "darwin" ? 3 : 2;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function timingBudgetMs(
|
|
30
|
+
ms: number,
|
|
31
|
+
env: Record<string, string | undefined> = process.env,
|
|
32
|
+
platform: NodeJS.Platform = process.platform,
|
|
33
|
+
): number {
|
|
34
|
+
return Math.round(ms * timingMultiplier(env, platform));
|
|
35
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI wrapper around the pure status-line cell renderer at
|
|
3
|
+
* `servers/_status-line-cells.ts`. This module is responsible only for
|
|
4
|
+
* (a) re-exporting the pure helpers so existing callers keep working, and
|
|
5
|
+
* (b) producing ANSI-escaped strings for terminal output.
|
|
6
|
+
*
|
|
7
|
+
* The actual animation logic — gradient sweep, pulse, heartbeat, context
|
|
8
|
+
* pressure — lives in `_status-line-cells.ts` and is consumed in structured
|
|
9
|
+
* form by the Remotion hero-video renderer. Both CLI and video render from
|
|
10
|
+
* exactly the same cell decisions; see `docs/hero-video-script.md` for the
|
|
11
|
+
* video side.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
cellsToAnsi,
|
|
16
|
+
activityCell,
|
|
17
|
+
contextPressureCells,
|
|
18
|
+
heartbeatCell,
|
|
19
|
+
sparklineCells,
|
|
20
|
+
lerpColor,
|
|
21
|
+
valuesToRamp,
|
|
22
|
+
gradientTs,
|
|
23
|
+
computePulse,
|
|
24
|
+
sweepFactor,
|
|
25
|
+
detectCapability,
|
|
26
|
+
frameAt,
|
|
27
|
+
ACTIVITY_ACTIVE_MS,
|
|
28
|
+
ACTIVITY_GLYPH_ASCII,
|
|
29
|
+
ACTIVITY_GLYPH_UNICODE,
|
|
30
|
+
ASCII_RAMP,
|
|
31
|
+
BRAND_DARK,
|
|
32
|
+
BRAND_LIGHT,
|
|
33
|
+
FRAME_MS,
|
|
34
|
+
HEARTBEAT_ASCII_ACTIVE,
|
|
35
|
+
HEARTBEAT_ASCII_IDLE,
|
|
36
|
+
HEARTBEAT_FRAMES,
|
|
37
|
+
HEARTBEAT_IDLE,
|
|
38
|
+
PULSE_CELL,
|
|
39
|
+
UNICODE_RAMP,
|
|
40
|
+
type Capability,
|
|
41
|
+
type Cell,
|
|
42
|
+
type PulseState,
|
|
43
|
+
type RGB,
|
|
44
|
+
type SparklineInput,
|
|
45
|
+
} from "../servers/_status-line-cells";
|
|
46
|
+
|
|
47
|
+
// Re-export the pure API for backward compatibility with existing callers.
|
|
48
|
+
export {
|
|
49
|
+
cellsToAnsi,
|
|
50
|
+
activityCell,
|
|
51
|
+
contextPressureCells,
|
|
52
|
+
heartbeatCell,
|
|
53
|
+
sparklineCells,
|
|
54
|
+
lerpColor,
|
|
55
|
+
valuesToRamp,
|
|
56
|
+
gradientTs,
|
|
57
|
+
computePulse,
|
|
58
|
+
sweepFactor,
|
|
59
|
+
detectCapability,
|
|
60
|
+
frameAt,
|
|
61
|
+
ACTIVITY_ACTIVE_MS,
|
|
62
|
+
ACTIVITY_GLYPH_ASCII,
|
|
63
|
+
ACTIVITY_GLYPH_UNICODE,
|
|
64
|
+
ASCII_RAMP,
|
|
65
|
+
BRAND_DARK,
|
|
66
|
+
BRAND_LIGHT,
|
|
67
|
+
FRAME_MS,
|
|
68
|
+
HEARTBEAT_ASCII_ACTIVE,
|
|
69
|
+
HEARTBEAT_ASCII_IDLE,
|
|
70
|
+
HEARTBEAT_FRAMES,
|
|
71
|
+
HEARTBEAT_IDLE,
|
|
72
|
+
PULSE_CELL,
|
|
73
|
+
UNICODE_RAMP,
|
|
74
|
+
type Capability,
|
|
75
|
+
type Cell,
|
|
76
|
+
type PulseState,
|
|
77
|
+
type RGB,
|
|
78
|
+
type SparklineInput,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
// ANSI string renderers (thin wrappers around the Cell[] producers)
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
|
|
85
|
+
export interface RenderSparklineInput {
|
|
86
|
+
values: readonly number[];
|
|
87
|
+
frame: number;
|
|
88
|
+
msSinceActive: number;
|
|
89
|
+
cap: Capability;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export function renderSparkline(input: RenderSparklineInput): string {
|
|
93
|
+
return cellsToAnsi(sparklineCells(input));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function renderHeartbeat(frame: number, msSinceActive: number, cap: Capability): string {
|
|
97
|
+
return cellsToAnsi([heartbeatCell(frame, msSinceActive, cap)]);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function activityIndicator(msSinceActive: number, cap: Capability): string {
|
|
101
|
+
const cell = activityCell(msSinceActive, cap);
|
|
102
|
+
return cell ? cellsToAnsi([cell]) : "";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function renderContextPressure(pct: number, cap: Capability): string {
|
|
106
|
+
return cellsToAnsi(contextPressureCells(pct, cap));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
// Width helper (kept here — it only matters for CLI output)
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Visible character width of a rendered string — strips ANSI escapes. Used
|
|
115
|
+
* by the status line to enforce its 80-column budget regardless of color.
|
|
116
|
+
*/
|
|
117
|
+
export function visibleWidth(s: string): number {
|
|
118
|
+
const stripped = s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
119
|
+
return Array.from(stripped).length;
|
|
120
|
+
}
|
package/scripts/ui.ts
ADDED
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ashlr UI helpers — zero-dependency ANSI utilities for colored terminal
|
|
3
|
+
* output, Unicode symbols, spinners, progress bars, and bordered boxes.
|
|
4
|
+
*
|
|
5
|
+
* All helpers respect:
|
|
6
|
+
* - `NO_COLOR=1` (https://no-color.org) — disables all color/animation
|
|
7
|
+
* - `FORCE_COLOR=1` — forces color even when !isTTY
|
|
8
|
+
* - `!process.stdout.isTTY` — disables color/spinners/animation in pipes/CI
|
|
9
|
+
*
|
|
10
|
+
* Designed so that ANSI escapes never leak into scraped output, tests, or
|
|
11
|
+
* logs. When colors are disabled, every `c.*()` helper returns the input
|
|
12
|
+
* string verbatim and every symbol falls back to a plain ASCII approximation
|
|
13
|
+
* when the environment hints that UTF-8 isn't safe.
|
|
14
|
+
*/
|
|
15
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
16
|
+
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Capability detection
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
|
|
21
|
+
function detectColor(): boolean {
|
|
22
|
+
if (process.env.NO_COLOR) return false;
|
|
23
|
+
if (process.env.FORCE_COLOR) return true;
|
|
24
|
+
// stdout may not exist in some runtimes (e.g. Workers); treat as no-color.
|
|
25
|
+
const tty = typeof process.stdout?.isTTY === "boolean" ? process.stdout.isTTY : false;
|
|
26
|
+
return tty;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function detectStderrTTY(): boolean {
|
|
30
|
+
if (process.env.NO_COLOR) return false;
|
|
31
|
+
if (process.env.FORCE_COLOR) return true;
|
|
32
|
+
const tty = typeof process.stderr?.isTTY === "boolean" ? process.stderr.isTTY : false;
|
|
33
|
+
return tty;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Cached capability so repeated calls are cheap. */
|
|
37
|
+
let _colorEnabled: boolean | null = null;
|
|
38
|
+
/** Cached stderr TTY capability for spinners. */
|
|
39
|
+
let _stderrTTY: boolean | null = null;
|
|
40
|
+
|
|
41
|
+
export function isColorEnabled(): boolean {
|
|
42
|
+
if (_colorEnabled === null) _colorEnabled = detectColor();
|
|
43
|
+
return _colorEnabled;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function isStderrTTY(): boolean {
|
|
47
|
+
if (_stderrTTY === null) _stderrTTY = detectStderrTTY();
|
|
48
|
+
return _stderrTTY;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Test hook — reset cached capability detection. */
|
|
52
|
+
export function _resetCapCache(): void {
|
|
53
|
+
_colorEnabled = null;
|
|
54
|
+
_stderrTTY = null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
// ANSI primitives
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
const ESC = "\u001b[";
|
|
62
|
+
const RESET = `${ESC}0m`;
|
|
63
|
+
|
|
64
|
+
function wrap(open: string, close: string, s: string): string {
|
|
65
|
+
if (!isColorEnabled()) return s;
|
|
66
|
+
return `${ESC}${open}m${s}${ESC}${close}m`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// Colors and text styles
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
export const c = {
|
|
74
|
+
// Foreground colors
|
|
75
|
+
black: (s: string): string => wrap("30", "39", s),
|
|
76
|
+
red: (s: string): string => wrap("31", "39", s),
|
|
77
|
+
green: (s: string): string => wrap("32", "39", s),
|
|
78
|
+
yellow: (s: string): string => wrap("33", "39", s),
|
|
79
|
+
blue: (s: string): string => wrap("34", "39", s),
|
|
80
|
+
magenta: (s: string): string => wrap("35", "39", s),
|
|
81
|
+
cyan: (s: string): string => wrap("36", "39", s),
|
|
82
|
+
white: (s: string): string => wrap("37", "39", s),
|
|
83
|
+
gray: (s: string): string => wrap("90", "39", s),
|
|
84
|
+
|
|
85
|
+
// Styles
|
|
86
|
+
bold: (s: string): string => wrap("1", "22", s),
|
|
87
|
+
dim: (s: string): string => wrap("2", "22", s),
|
|
88
|
+
italic: (s: string): string => wrap("3", "23", s),
|
|
89
|
+
underline: (s: string): string => wrap("4", "24", s),
|
|
90
|
+
inverse: (s: string): string => wrap("7", "27", s),
|
|
91
|
+
|
|
92
|
+
// Bright variants — useful for emphasis without `bold` side-effects.
|
|
93
|
+
brightGreen: (s: string): string => wrap("92", "39", s),
|
|
94
|
+
brightRed: (s: string): string => wrap("91", "39", s),
|
|
95
|
+
brightYellow: (s: string): string => wrap("93", "39", s),
|
|
96
|
+
brightCyan: (s: string): string => wrap("96", "39", s),
|
|
97
|
+
brightMagenta: (s: string): string => wrap("95", "39", s),
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
// Symbols (UTF-8 glyphs with ASCII fallbacks)
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
|
|
104
|
+
/** Best-effort UTF-8 detection. Terminals that say UTF-8 in LANG or advertise
|
|
105
|
+
* a UTF-8 locale get the nice glyphs; everything else falls back to ASCII. */
|
|
106
|
+
function supportsUnicode(): boolean {
|
|
107
|
+
if (process.platform === "win32") {
|
|
108
|
+
// Modern Windows Terminal / ConEmu handle Unicode fine; naive cmd.exe may
|
|
109
|
+
// not. We favor glyphs here and let users set NO_COLOR if they need pure
|
|
110
|
+
// ASCII.
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
const l = (process.env.LC_ALL || process.env.LC_CTYPE || process.env.LANG || "").toLowerCase();
|
|
114
|
+
return l.includes("utf");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const UTF = supportsUnicode();
|
|
118
|
+
|
|
119
|
+
export const sym = {
|
|
120
|
+
check: UTF ? "\u2713" : "v", // ✓
|
|
121
|
+
cross: UTF ? "\u2717" : "x", // ✗
|
|
122
|
+
warn: UTF ? "\u26A0" : "!", // ⚠
|
|
123
|
+
info: UTF ? "\u2139" : "i", // ℹ
|
|
124
|
+
arrow: UTF ? "\u2192" : "->", // →
|
|
125
|
+
dot: UTF ? "\u00B7" : ".", // ·
|
|
126
|
+
bullet: UTF ? "\u2022" : "*",// •
|
|
127
|
+
star: UTF ? "\u2605" : "*", // ★
|
|
128
|
+
circle: UTF ? "\u25CB" : "o",// ○
|
|
129
|
+
filled: UTF ? "\u25CF" : "@",// ●
|
|
130
|
+
ellipsis: UTF ? "\u2026" : "...",
|
|
131
|
+
// Box-drawing
|
|
132
|
+
tl: UTF ? "\u256D" : "+", // ╭
|
|
133
|
+
tr: UTF ? "\u256E" : "+", // ╮
|
|
134
|
+
bl: UTF ? "\u2570" : "+", // ╰
|
|
135
|
+
br: UTF ? "\u256F" : "+", // ╯
|
|
136
|
+
h: UTF ? "\u2500" : "-", // ─
|
|
137
|
+
v: UTF ? "\u2502" : "|", // │
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
// Spinner
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
|
|
144
|
+
const SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
145
|
+
// Braille spinner — same as ora's default. Smooth on any modern terminal.
|
|
146
|
+
|
|
147
|
+
const CURSOR_HIDE = `${ESC}?25l`;
|
|
148
|
+
const CURSOR_SHOW = `${ESC}?25h`;
|
|
149
|
+
const CLEAR_LINE = `${ESC}2K\r`;
|
|
150
|
+
|
|
151
|
+
export class Spinner {
|
|
152
|
+
private frame = 0;
|
|
153
|
+
private timer: ReturnType<typeof setInterval> | null = null;
|
|
154
|
+
private message: string;
|
|
155
|
+
private stream: NodeJS.WriteStream;
|
|
156
|
+
private enabled: boolean;
|
|
157
|
+
private started = false;
|
|
158
|
+
|
|
159
|
+
constructor(message = "", opts: { stream?: NodeJS.WriteStream } = {}) {
|
|
160
|
+
this.message = message;
|
|
161
|
+
this.stream = opts.stream ?? process.stderr;
|
|
162
|
+
// Only animate when stderr is a real TTY. No-color disables the glyph
|
|
163
|
+
// color but spinners themselves only make sense on a TTY anyway.
|
|
164
|
+
this.enabled = isStderrTTY();
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** Start the spinner. If already started, updates the message instead. */
|
|
168
|
+
start(message?: string): this {
|
|
169
|
+
if (message !== undefined) this.message = message;
|
|
170
|
+
if (!this.enabled) {
|
|
171
|
+
// Non-TTY: stay silent. Callers still get to drive succeed/fail/info
|
|
172
|
+
// messages explicitly, which render as plain prefixed lines below.
|
|
173
|
+
this.started = true;
|
|
174
|
+
return this;
|
|
175
|
+
}
|
|
176
|
+
if (this.timer) return this; // already animating
|
|
177
|
+
this.stream.write(CURSOR_HIDE);
|
|
178
|
+
this.started = true;
|
|
179
|
+
this.render();
|
|
180
|
+
this.timer = setInterval(() => {
|
|
181
|
+
this.frame = (this.frame + 1) % SPINNER_FRAMES.length;
|
|
182
|
+
this.render();
|
|
183
|
+
}, 80);
|
|
184
|
+
// Best-effort cleanup on hard exits.
|
|
185
|
+
const cleanup = () => this.stop();
|
|
186
|
+
process.once("exit", cleanup);
|
|
187
|
+
process.once("SIGINT", () => { cleanup(); process.exit(130); });
|
|
188
|
+
return this;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
update(message: string): this {
|
|
192
|
+
this.message = message;
|
|
193
|
+
if (this.enabled && this.timer) this.render();
|
|
194
|
+
return this;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
succeed(message?: string): this {
|
|
198
|
+
const msg = message ?? this.message;
|
|
199
|
+
this.stop();
|
|
200
|
+
if (!this.enabled) return this; // stay quiet on non-TTY
|
|
201
|
+
const glyph = isColorEnabled() ? c.green(sym.check) : sym.check;
|
|
202
|
+
this.stream.write(`${glyph} ${msg}\n`);
|
|
203
|
+
return this;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
fail(message?: string): this {
|
|
207
|
+
const msg = message ?? this.message;
|
|
208
|
+
this.stop();
|
|
209
|
+
if (!this.enabled) {
|
|
210
|
+
// Failures are actionable — surface them even on non-TTY, but without
|
|
211
|
+
// ANSI.
|
|
212
|
+
this.stream.write(`${sym.cross} ${msg}\n`);
|
|
213
|
+
return this;
|
|
214
|
+
}
|
|
215
|
+
const glyph = isColorEnabled() ? c.red(sym.cross) : sym.cross;
|
|
216
|
+
this.stream.write(`${glyph} ${msg}\n`);
|
|
217
|
+
return this;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
warn(message?: string): this {
|
|
221
|
+
const msg = message ?? this.message;
|
|
222
|
+
this.stop();
|
|
223
|
+
if (!this.enabled) return this;
|
|
224
|
+
const glyph = isColorEnabled() ? c.yellow(sym.warn) : sym.warn;
|
|
225
|
+
this.stream.write(`${glyph} ${msg}\n`);
|
|
226
|
+
return this;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
info(message?: string): this {
|
|
230
|
+
const msg = message ?? this.message;
|
|
231
|
+
this.stop();
|
|
232
|
+
if (!this.enabled) return this;
|
|
233
|
+
const glyph = isColorEnabled() ? c.cyan(sym.info) : sym.info;
|
|
234
|
+
this.stream.write(`${glyph} ${msg}\n`);
|
|
235
|
+
return this;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** Stop the animation without printing a final line. */
|
|
239
|
+
stop(): this {
|
|
240
|
+
if (this.timer) {
|
|
241
|
+
clearInterval(this.timer);
|
|
242
|
+
this.timer = null;
|
|
243
|
+
}
|
|
244
|
+
if (this.enabled && this.started) {
|
|
245
|
+
this.stream.write(CLEAR_LINE);
|
|
246
|
+
this.stream.write(CURSOR_SHOW);
|
|
247
|
+
}
|
|
248
|
+
this.started = false;
|
|
249
|
+
return this;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private render(): void {
|
|
253
|
+
const frame = SPINNER_FRAMES[this.frame]!;
|
|
254
|
+
const colored = isColorEnabled() ? c.cyan(frame) : frame;
|
|
255
|
+
this.stream.write(`${CLEAR_LINE}${colored} ${this.message}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// ---------------------------------------------------------------------------
|
|
260
|
+
// Progress bar
|
|
261
|
+
// ---------------------------------------------------------------------------
|
|
262
|
+
|
|
263
|
+
export interface ProgressBarOpts {
|
|
264
|
+
width?: number;
|
|
265
|
+
stream?: NodeJS.WriteStream;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export class ProgressBar {
|
|
269
|
+
private total = 0;
|
|
270
|
+
private current = 0;
|
|
271
|
+
private label = "";
|
|
272
|
+
private width: number;
|
|
273
|
+
private stream: NodeJS.WriteStream;
|
|
274
|
+
private enabled: boolean;
|
|
275
|
+
private started = false;
|
|
276
|
+
private lastLen = 0;
|
|
277
|
+
|
|
278
|
+
constructor(opts: ProgressBarOpts = {}) {
|
|
279
|
+
this.width = opts.width ?? 24;
|
|
280
|
+
this.stream = opts.stream ?? process.stderr;
|
|
281
|
+
this.enabled = isStderrTTY();
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
start(total: number, label = ""): this {
|
|
285
|
+
this.total = Math.max(0, total);
|
|
286
|
+
this.current = 0;
|
|
287
|
+
this.label = label;
|
|
288
|
+
this.started = true;
|
|
289
|
+
if (this.enabled) {
|
|
290
|
+
this.stream.write(CURSOR_HIDE);
|
|
291
|
+
this.render();
|
|
292
|
+
}
|
|
293
|
+
// Non-TTY: stay silent. Progress is inherently a TTY-only UX.
|
|
294
|
+
return this;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
increment(n = 1): this {
|
|
298
|
+
this.current = Math.min(this.total, this.current + n);
|
|
299
|
+
if (this.enabled && this.started) this.render();
|
|
300
|
+
return this;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
update(current: number): this {
|
|
304
|
+
this.current = Math.min(this.total, Math.max(0, current));
|
|
305
|
+
if (this.enabled && this.started) this.render();
|
|
306
|
+
return this;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
finish(message?: string): this {
|
|
310
|
+
if (this.enabled && this.started) {
|
|
311
|
+
this.stream.write(CLEAR_LINE);
|
|
312
|
+
this.stream.write(CURSOR_SHOW);
|
|
313
|
+
}
|
|
314
|
+
this.started = false;
|
|
315
|
+
if (message && this.enabled) {
|
|
316
|
+
const glyph = isColorEnabled() ? c.green(sym.check) : sym.check;
|
|
317
|
+
this.stream.write(`${glyph} ${message}\n`);
|
|
318
|
+
}
|
|
319
|
+
return this;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
private render(): void {
|
|
323
|
+
const pct = this.total > 0 ? this.current / this.total : 0;
|
|
324
|
+
const filled = Math.round(pct * this.width);
|
|
325
|
+
const empty = this.width - filled;
|
|
326
|
+
const bar = UTF ? "\u2588".repeat(filled) + "\u2591".repeat(empty) : "#".repeat(filled) + "-".repeat(empty);
|
|
327
|
+
const coloredBar = isColorEnabled() ? c.cyan(bar) : bar;
|
|
328
|
+
const pctStr = `${Math.round(pct * 100)}%`;
|
|
329
|
+
const countStr = `${this.current}/${this.total}`;
|
|
330
|
+
const label = this.label ? ` ${this.label}` : "";
|
|
331
|
+
const line = `[${coloredBar}] ${countStr} (${isColorEnabled() ? c.dim(pctStr) : pctStr})${label}`;
|
|
332
|
+
this.stream.write(`${CLEAR_LINE}${line}`);
|
|
333
|
+
this.lastLen = line.length;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// ---------------------------------------------------------------------------
|
|
338
|
+
// Box
|
|
339
|
+
// ---------------------------------------------------------------------------
|
|
340
|
+
|
|
341
|
+
export interface BoxOpts {
|
|
342
|
+
title?: string;
|
|
343
|
+
/** Color applied to the border + title. */
|
|
344
|
+
color?: (s: string) => string;
|
|
345
|
+
/** Horizontal padding inside the box. Default 1. */
|
|
346
|
+
padding?: number;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/** Strip ANSI codes so we can measure visible width. */
|
|
350
|
+
function stripAnsi(s: string): string {
|
|
351
|
+
// eslint-disable-next-line no-control-regex
|
|
352
|
+
return s.replace(/\u001b\[[0-9;]*m/g, "");
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function visibleWidth(s: string): number {
|
|
356
|
+
// Naive: one codepoint = one column. Good enough for our ASCII+glyph usage.
|
|
357
|
+
return [...stripAnsi(s)].length;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function padRight(s: string, target: number): string {
|
|
361
|
+
const pad = target - visibleWidth(s);
|
|
362
|
+
return pad > 0 ? s + " ".repeat(pad) : s;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export function box(content: string, opts: BoxOpts = {}): string {
|
|
366
|
+
const padding = opts.padding ?? 1;
|
|
367
|
+
const color = opts.color ?? ((s: string) => s);
|
|
368
|
+
|
|
369
|
+
const rawLines = content.split("\n");
|
|
370
|
+
const titleLen = opts.title ? visibleWidth(opts.title) + 2 /* spaces */ : 0;
|
|
371
|
+
const contentW = Math.max(...rawLines.map(visibleWidth), titleLen);
|
|
372
|
+
const innerW = contentW + padding * 2;
|
|
373
|
+
|
|
374
|
+
const h = color(sym.h);
|
|
375
|
+
const v = color(sym.v);
|
|
376
|
+
const tl = color(sym.tl);
|
|
377
|
+
const tr = color(sym.tr);
|
|
378
|
+
const bl = color(sym.bl);
|
|
379
|
+
const br = color(sym.br);
|
|
380
|
+
|
|
381
|
+
// Top border with optional title
|
|
382
|
+
let top: string;
|
|
383
|
+
if (opts.title) {
|
|
384
|
+
const titleText = color(isColorEnabled() ? c.bold(opts.title) : opts.title);
|
|
385
|
+
const titleBlock = ` ${titleText} `;
|
|
386
|
+
const remaining = innerW - visibleWidth(titleBlock);
|
|
387
|
+
const left = Math.max(1, Math.floor(remaining / 2));
|
|
388
|
+
const right = Math.max(1, remaining - left);
|
|
389
|
+
top = tl + h.repeat(left) + titleBlock + h.repeat(right) + tr;
|
|
390
|
+
} else {
|
|
391
|
+
top = tl + h.repeat(innerW) + tr;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
const bottom = bl + h.repeat(innerW) + br;
|
|
395
|
+
const pad = " ".repeat(padding);
|
|
396
|
+
|
|
397
|
+
const body = rawLines.map((line) => {
|
|
398
|
+
const padded = padRight(line, contentW);
|
|
399
|
+
return `${v}${pad}${padded}${pad}${v}`;
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
return [top, ...body, bottom].join("\n");
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// ---------------------------------------------------------------------------
|
|
406
|
+
// Banner — small ASCII-art logo
|
|
407
|
+
// ---------------------------------------------------------------------------
|
|
408
|
+
|
|
409
|
+
/** Renders a small gradient-colored banner. `text` defaults to "ashlr". */
|
|
410
|
+
export function banner(text = "ashlr"): string {
|
|
411
|
+
// Simple ASCII-art: block-style lettering built from Unicode block chars.
|
|
412
|
+
// We keep this short and readable; full figlet-style ASCII art would blow
|
|
413
|
+
// up the vertical real estate.
|
|
414
|
+
const line1 = `${sym.filled} ${text}`;
|
|
415
|
+
const line2 = `${sym.h.repeat(Math.max(text.length + 3, 6))}`;
|
|
416
|
+
if (!isColorEnabled()) return `${line1}\n${line2}`;
|
|
417
|
+
return `${c.brightMagenta(c.bold(line1))}\n${c.dim(line2)}`;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// ---------------------------------------------------------------------------
|
|
421
|
+
// Convenience helpers
|
|
422
|
+
// ---------------------------------------------------------------------------
|
|
423
|
+
|
|
424
|
+
/** Colored check/cross prefix helpers for quick status lines. */
|
|
425
|
+
export const prefix = {
|
|
426
|
+
ok: (s: string): string => (isColorEnabled() ? `${c.green(sym.check)} ${s}` : `${sym.check} ${s}`),
|
|
427
|
+
fail: (s: string): string => (isColorEnabled() ? `${c.red(sym.cross)} ${s}` : `${sym.cross} ${s}`),
|
|
428
|
+
warn: (s: string): string => (isColorEnabled() ? `${c.yellow(sym.warn)} ${s}` : `${sym.warn} ${s}`),
|
|
429
|
+
info: (s: string): string => (isColorEnabled() ? `${c.cyan(sym.info)} ${s}` : `${sym.info} ${s}`),
|
|
430
|
+
arrow: (s: string): string => (isColorEnabled() ? `${c.magenta(sym.arrow)} ${s}` : `${sym.arrow} ${s}`),
|
|
431
|
+
};
|