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,150 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* One-shot installer that wires the ashlr status-line script into the user's
|
|
4
|
+
* Claude Code settings.
|
|
5
|
+
*
|
|
6
|
+
* Strategy for safe merging:
|
|
7
|
+
* 1. Read ~/.claude/settings.json if it exists; parse it as JSON. If the file
|
|
8
|
+
* is corrupt, abort loudly — we will not overwrite a file we can't parse.
|
|
9
|
+
* 2. Take a timestamped backup (settings.json.bak-<epoch>) before writing.
|
|
10
|
+
* 3. Shallow-merge: set settings.statusLine = { type: "command", command: "..." }
|
|
11
|
+
* only if statusLine is missing OR already points at our script. We never
|
|
12
|
+
* clobber a custom statusLine the user has configured for something else.
|
|
13
|
+
* 4. Ensure settings.ashlr defaults exist (statusLine + sub-toggles), again
|
|
14
|
+
* only filling in keys that aren't already set.
|
|
15
|
+
* 5. Write back with 2-space indent, preserving every other top-level key.
|
|
16
|
+
*
|
|
17
|
+
* Idempotent: re-running is a no-op aside from refreshing the absolute path
|
|
18
|
+
* to the script (in case the plugin moved).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { existsSync, readFileSync, writeFileSync, copyFileSync, mkdirSync } from "fs";
|
|
22
|
+
import { homedir } from "os";
|
|
23
|
+
import { dirname, join, resolve } from "path";
|
|
24
|
+
import { c, sym, box, isColorEnabled, prefix } from "./ui.ts";
|
|
25
|
+
|
|
26
|
+
interface StatusLineCmd {
|
|
27
|
+
type: "command";
|
|
28
|
+
command: string;
|
|
29
|
+
padding?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface ClaudeSettings {
|
|
33
|
+
statusLine?: StatusLineCmd | unknown;
|
|
34
|
+
ashlr?: Record<string, unknown>;
|
|
35
|
+
[k: string]: unknown;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const SCRIPT_PATH = resolve(import.meta.dir, "savings-status-line.ts");
|
|
39
|
+
const SETTINGS_PATH = join(homedir(), ".claude", "settings.json");
|
|
40
|
+
const COMMAND = `bun run ${SCRIPT_PATH}`;
|
|
41
|
+
|
|
42
|
+
function isOurStatusLine(sl: unknown): sl is StatusLineCmd {
|
|
43
|
+
if (!sl || typeof sl !== "object") return false;
|
|
44
|
+
const cmd = (sl as { command?: unknown }).command;
|
|
45
|
+
return typeof cmd === "string" && cmd.includes("savings-status-line");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function main(): void {
|
|
49
|
+
let settings: ClaudeSettings = {};
|
|
50
|
+
let existed = false;
|
|
51
|
+
|
|
52
|
+
if (existsSync(SETTINGS_PATH)) {
|
|
53
|
+
existed = true;
|
|
54
|
+
const raw = readFileSync(SETTINGS_PATH, "utf-8");
|
|
55
|
+
try {
|
|
56
|
+
settings = JSON.parse(raw) as ClaudeSettings;
|
|
57
|
+
} catch (err) {
|
|
58
|
+
const msg = (err as Error).message;
|
|
59
|
+
const head = isColorEnabled()
|
|
60
|
+
? `${c.red(sym.cross)} ${c.bold("refusing to touch")} ${c.cyan(SETTINGS_PATH)}`
|
|
61
|
+
: `refusing to touch ${SETTINGS_PATH}`;
|
|
62
|
+
console.error(`${head}: not valid JSON (${msg})`);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
// Backup before any write.
|
|
66
|
+
const backup = `${SETTINGS_PATH}.bak-${Date.now()}`;
|
|
67
|
+
copyFileSync(SETTINGS_PATH, backup);
|
|
68
|
+
} else {
|
|
69
|
+
mkdirSync(dirname(SETTINGS_PATH), { recursive: true });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const actions: string[] = [];
|
|
73
|
+
|
|
74
|
+
// 1. statusLine command
|
|
75
|
+
const currentSl = settings.statusLine;
|
|
76
|
+
if (!currentSl) {
|
|
77
|
+
settings.statusLine = { type: "command", command: COMMAND, padding: 0 };
|
|
78
|
+
actions.push("added statusLine command");
|
|
79
|
+
} else if (isOurStatusLine(currentSl)) {
|
|
80
|
+
if ((currentSl as StatusLineCmd).command !== COMMAND) {
|
|
81
|
+
(settings.statusLine as StatusLineCmd).command = COMMAND;
|
|
82
|
+
actions.push("refreshed statusLine command path");
|
|
83
|
+
} else {
|
|
84
|
+
actions.push("statusLine already installed (no change)");
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
const warnHead = isColorEnabled()
|
|
88
|
+
? `${c.yellow(sym.warn)} ${c.bold("warning:")}`
|
|
89
|
+
: "warning:";
|
|
90
|
+
console.warn(
|
|
91
|
+
`${warnHead} an existing statusLine is configured and points elsewhere; leaving it alone.`,
|
|
92
|
+
);
|
|
93
|
+
const cmd = isColorEnabled() ? c.cyan(COMMAND) : COMMAND;
|
|
94
|
+
console.warn(` to use ashlr instead, set statusLine.command to: ${cmd}`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 2. ashlr defaults
|
|
98
|
+
const ashlr = (settings.ashlr ??= {}) as Record<string, unknown>;
|
|
99
|
+
const defaults: Record<string, boolean> = {
|
|
100
|
+
statusLine: true,
|
|
101
|
+
statusLineSession: true,
|
|
102
|
+
statusLineLifetime: true,
|
|
103
|
+
statusLineTips: true,
|
|
104
|
+
};
|
|
105
|
+
let addedDefaults = 0;
|
|
106
|
+
for (const [k, v] of Object.entries(defaults)) {
|
|
107
|
+
if (!(k in ashlr)) {
|
|
108
|
+
ashlr[k] = v;
|
|
109
|
+
addedDefaults++;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (addedDefaults > 0) actions.push(`seeded ${addedDefaults} ashlr default toggle(s)`);
|
|
113
|
+
|
|
114
|
+
writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
115
|
+
|
|
116
|
+
const verb = existed ? "updated" : "created";
|
|
117
|
+
const verbColored = isColorEnabled() ? c.brightGreen(c.bold(verb)) : verb;
|
|
118
|
+
const pathColored = isColorEnabled() ? c.cyan(SETTINGS_PATH) : SETTINGS_PATH;
|
|
119
|
+
console.log(`${prefix.ok(`${verbColored} ${pathColored}`)}`);
|
|
120
|
+
for (const a of actions) {
|
|
121
|
+
const dotGlyph = isColorEnabled() ? c.magenta(sym.bullet) : "-";
|
|
122
|
+
console.log(` ${dotGlyph} ${a}`);
|
|
123
|
+
}
|
|
124
|
+
const scriptLabel = isColorEnabled() ? c.dim("status-line script:") : "status-line script:";
|
|
125
|
+
const scriptColored = isColorEnabled() ? c.cyan(SCRIPT_PATH) : SCRIPT_PATH;
|
|
126
|
+
console.log(`${scriptLabel} ${scriptColored}`);
|
|
127
|
+
|
|
128
|
+
// On a TTY, include a small summary box so the install feels complete.
|
|
129
|
+
if (isColorEnabled()) {
|
|
130
|
+
const body = [
|
|
131
|
+
`${prefix.ok("status line wired")}`,
|
|
132
|
+
` reload Claude Code to see it`,
|
|
133
|
+
` toggle anytime via ${c.cyan("/ashlr-settings")}`,
|
|
134
|
+
].join("\n");
|
|
135
|
+
console.log("");
|
|
136
|
+
console.log(box(body, { title: "ashlr status line", color: c.green }));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (import.meta.main) {
|
|
141
|
+
try {
|
|
142
|
+
main();
|
|
143
|
+
} catch (err) {
|
|
144
|
+
const head = isColorEnabled()
|
|
145
|
+
? `${c.red(sym.cross)} ${c.bold("install-status-line failed:")}`
|
|
146
|
+
: "install-status-line failed:";
|
|
147
|
+
console.error(`${head} ${(err as Error).message}`);
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ashlr-plugin MCP server entrypoint (LEGACY — Unix-only ports).
|
|
3
|
+
#
|
|
4
|
+
# NOTE: Claude Code itself no longer uses this script. As of v1.15 the
|
|
5
|
+
# canonical entrypoint is `scripts/bootstrap.mjs`, which hands off to
|
|
6
|
+
# `scripts/mcp-entrypoint.ts`. Both run on Windows without Git Bash.
|
|
7
|
+
#
|
|
8
|
+
# This `.sh` is retained ONLY for the Unix-only `ports/` distributions
|
|
9
|
+
# (Cursor, Goose — see `ports/cursor/mcp.json` and `ports/README.md`).
|
|
10
|
+
# If you are on Windows and something invoked this file, that is a bug:
|
|
11
|
+
# your plugin config should point at `scripts/bootstrap.mjs` instead.
|
|
12
|
+
#
|
|
13
|
+
# Wraps every MCP server launch with idempotent self-healing:
|
|
14
|
+
# 1. cd to the plugin root
|
|
15
|
+
# 2. if node_modules is missing, run `bun install` (once; subsequent launches skip)
|
|
16
|
+
# 3. opportunistically drop stale sibling versioned cache dirs (best-effort)
|
|
17
|
+
# 4. exec `bun run <server.ts>` with any passed args
|
|
18
|
+
#
|
|
19
|
+
# Usage (ports distributions only):
|
|
20
|
+
# "command": "bash",
|
|
21
|
+
# "args": ["${ASHLR_PLUGIN_ROOT}/scripts/mcp-entrypoint.sh", "servers/foo-server.ts"]
|
|
22
|
+
#
|
|
23
|
+
# All output is suppressed to stdout (since stdio is the MCP protocol channel).
|
|
24
|
+
# Logs go to stderr, which Claude Code surfaces in its transcript.
|
|
25
|
+
|
|
26
|
+
# Hard guard: if somehow invoked on Windows, redirect the caller to the
|
|
27
|
+
# bun/node-native entrypoint. MSYS/MINGW/CYGWIN all set OSTYPE accordingly.
|
|
28
|
+
case "${OSTYPE:-}" in
|
|
29
|
+
msys*|cygwin*|win32*)
|
|
30
|
+
echo "[ashlr] mcp-entrypoint.sh is Unix-only." >&2
|
|
31
|
+
echo "[ashlr] On Windows, point your MCP config at scripts/bootstrap.mjs instead:" >&2
|
|
32
|
+
echo "[ashlr] node \"\${CLAUDE_PLUGIN_ROOT}/scripts/bootstrap.mjs\" servers/<server>.ts" >&2
|
|
33
|
+
exit 1
|
|
34
|
+
;;
|
|
35
|
+
esac
|
|
36
|
+
|
|
37
|
+
set -e
|
|
38
|
+
|
|
39
|
+
# Resolve plugin root from the entrypoint's own path (never trust cwd).
|
|
40
|
+
PLUGIN_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
41
|
+
cd "$PLUGIN_ROOT"
|
|
42
|
+
|
|
43
|
+
# 1. Self-install deps if missing. Idempotent.
|
|
44
|
+
if [ ! -d "node_modules/@modelcontextprotocol/sdk" ]; then
|
|
45
|
+
echo "[ashlr] first-run: installing dependencies in $PLUGIN_ROOT" >&2
|
|
46
|
+
if ! bun install --silent >&2 2>&1; then
|
|
47
|
+
echo "[ashlr] bun install failed. Ensure bun is on PATH and network is available." >&2
|
|
48
|
+
echo "[ashlr] Manual fix: cd \"$PLUGIN_ROOT\" && bun install" >&2
|
|
49
|
+
exit 1
|
|
50
|
+
fi
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
# 2. Opportunistically drop stale sibling version caches. Safe: strict semver
|
|
54
|
+
# guard + skip current dir. Non-version dirs (latest, dev-branch) survive.
|
|
55
|
+
CURRENT_VERSION="$(basename "$PLUGIN_ROOT")"
|
|
56
|
+
PARENT="$(dirname "$PLUGIN_ROOT")"
|
|
57
|
+
if [[ "$CURRENT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [ -d "$PARENT" ] && [[ "$PARENT" == */plugins/cache/* ]]; then
|
|
58
|
+
for sib in "$PARENT"/*/; do
|
|
59
|
+
sib="${sib%/}"
|
|
60
|
+
name="$(basename "$sib")"
|
|
61
|
+
if [[ "$name" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [ "$name" != "$CURRENT_VERSION" ]; then
|
|
62
|
+
rm -rf "$sib" 2>/dev/null && echo "[ashlr] removed stale cache: $name" >&2 || true
|
|
63
|
+
fi
|
|
64
|
+
done
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# 3. Forward Claude Code's session id so MCP servers can attribute savings to
|
|
68
|
+
# the correct per-session bucket in ~/.ashlr/stats.json. Without this, the
|
|
69
|
+
# status line's "session +N" number gets clobbered across concurrent
|
|
70
|
+
# terminals. We export both the canonical name and a mirror so any tool in
|
|
71
|
+
# the subprocess tree can read it.
|
|
72
|
+
if [ -n "${CLAUDE_SESSION_ID:-}" ]; then
|
|
73
|
+
export CLAUDE_SESSION_ID
|
|
74
|
+
export ASHLR_SESSION_ID="$CLAUDE_SESSION_ID"
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
# 4. Exec the requested server script with any remaining args.
|
|
78
|
+
exec bun run "$@"
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Bun-native MCP server entrypoint. Replaces `scripts/mcp-entrypoint.sh`
|
|
4
|
+
* so the plugin works on Windows without Git Bash.
|
|
5
|
+
*
|
|
6
|
+
* Responsibilities (in order):
|
|
7
|
+
* 1. Resolve PLUGIN_ROOT from __dirname (never trust cwd).
|
|
8
|
+
* 2. Self-install deps if the MCP SDK cannot be resolved from the plugin.
|
|
9
|
+
* 3. Opportunistically drop stale sibling versioned cache dirs.
|
|
10
|
+
* 4. Forward CLAUDE_SESSION_ID so savings bucket to the right session.
|
|
11
|
+
* 5. Spawn `bun run <server.ts>` as a child and forward stdio 1:1 so the
|
|
12
|
+
* MCP protocol continues to own stdin/stdout/stderr.
|
|
13
|
+
*
|
|
14
|
+
* Why not `await import()` the server directly? Bun would share the import
|
|
15
|
+
* cache with this bootstrapping module, which subtly breaks servers that
|
|
16
|
+
* assume they own `process.argv` or call `process.exit`. A dedicated child
|
|
17
|
+
* keeps the MCP process cleanly isolated.
|
|
18
|
+
*
|
|
19
|
+
* Usage (in .claude-plugin/plugin.json mcpServers entries):
|
|
20
|
+
* "command": "bun",
|
|
21
|
+
* "args": ["run", "${CLAUDE_PLUGIN_ROOT}/scripts/mcp-entrypoint.ts", "servers/_router.ts"]
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { existsSync, readdirSync, rmSync, statSync } from "node:fs";
|
|
25
|
+
import { basename, dirname, resolve } from "node:path";
|
|
26
|
+
import { fileURLToPath } from "node:url";
|
|
27
|
+
|
|
28
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
29
|
+
const PLUGIN_ROOT = resolve(dirname(__filename), "..");
|
|
30
|
+
process.chdir(PLUGIN_ROOT);
|
|
31
|
+
|
|
32
|
+
// 1. Self-install deps if missing. Idempotent — `bun install` is a no-op once
|
|
33
|
+
// node_modules is populated.
|
|
34
|
+
// npm may hoist dependencies into an ancestor node_modules directory. Resolve
|
|
35
|
+
// the exact SDK modules used by the router, from this plugin's location, rather
|
|
36
|
+
// than treating the absence of a nested directory as a missing dependency.
|
|
37
|
+
// Resolution does not execute third-party code or consult a caller-selected cwd.
|
|
38
|
+
let sdkReady = false;
|
|
39
|
+
try {
|
|
40
|
+
for (const specifier of [
|
|
41
|
+
"@modelcontextprotocol/sdk/server/index.js",
|
|
42
|
+
"@modelcontextprotocol/sdk/server/stdio.js",
|
|
43
|
+
"@modelcontextprotocol/sdk/types.js",
|
|
44
|
+
]) {
|
|
45
|
+
Bun.resolveSync(specifier, PLUGIN_ROOT);
|
|
46
|
+
}
|
|
47
|
+
sdkReady = true;
|
|
48
|
+
} catch {
|
|
49
|
+
// Preserve the existing first-run recovery for genuinely missing SDK modules.
|
|
50
|
+
}
|
|
51
|
+
if (!sdkReady) {
|
|
52
|
+
console.error(`[ashlr] first-run: installing dependencies in ${PLUGIN_ROOT}`);
|
|
53
|
+
const result = Bun.spawnSync(["bun", "install", "--silent"], {
|
|
54
|
+
cwd: PLUGIN_ROOT,
|
|
55
|
+
stdio: ["ignore", "inherit", "inherit"],
|
|
56
|
+
});
|
|
57
|
+
if (!result.success) {
|
|
58
|
+
console.error(`[ashlr] bun install failed. Ensure bun is on PATH and network is available.`);
|
|
59
|
+
console.error(`[ashlr] Manual fix: cd "${PLUGIN_ROOT}" && bun install`);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 2. Opportunistically drop stale sibling version caches. Safe: strict semver
|
|
65
|
+
// guard + skip current dir. Non-version dirs (latest, dev-branch) survive.
|
|
66
|
+
// Handles both Unix and Windows path separators for the "plugins/cache"
|
|
67
|
+
// marker so it fires correctly inside %USERPROFILE%\.claude\plugins\cache\.
|
|
68
|
+
const currentVersion = basename(PLUGIN_ROOT);
|
|
69
|
+
const parent = dirname(PLUGIN_ROOT);
|
|
70
|
+
const SEMVER = /^\d+\.\d+\.\d+$/;
|
|
71
|
+
const inCacheDir =
|
|
72
|
+
parent.includes(`${resolve("/").slice(0, 1)}plugins${resolve("/").slice(0, 1)}cache`) ||
|
|
73
|
+
parent.includes("/plugins/cache/") ||
|
|
74
|
+
parent.includes("\\plugins\\cache\\");
|
|
75
|
+
if (SEMVER.test(currentVersion) && existsSync(parent) && inCacheDir) {
|
|
76
|
+
try {
|
|
77
|
+
for (const sib of readdirSync(parent)) {
|
|
78
|
+
if (!SEMVER.test(sib) || sib === currentVersion) continue;
|
|
79
|
+
const sibPath = resolve(parent, sib);
|
|
80
|
+
try {
|
|
81
|
+
if (statSync(sibPath).isDirectory()) {
|
|
82
|
+
rmSync(sibPath, { recursive: true, force: true });
|
|
83
|
+
console.error(`[ashlr] removed stale cache: ${sib}`);
|
|
84
|
+
}
|
|
85
|
+
} catch {
|
|
86
|
+
// Best-effort — if a rm fails (permissions, busy files on Windows),
|
|
87
|
+
// skip it. The cache still works; just keeps a bit of extra disk.
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} catch {
|
|
91
|
+
// readdirSync of the parent failed — not fatal; proceed.
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 3. Forward Claude Code's session id so MCP servers attribute savings to the
|
|
96
|
+
// correct per-session bucket in ~/.ashlr/stats.json. Without this, the
|
|
97
|
+
// status-line "session +N" number gets clobbered across concurrent
|
|
98
|
+
// terminals. Mirror under ASHLR_SESSION_ID for subprocesses to read.
|
|
99
|
+
if (process.env["CLAUDE_SESSION_ID"]) {
|
|
100
|
+
process.env["ASHLR_SESSION_ID"] = process.env["CLAUDE_SESSION_ID"];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 4. Exec the requested server script. Any remaining argv are passed through
|
|
104
|
+
// to `bun run <script> [...args]`, preserving compatibility with the bash
|
|
105
|
+
// entrypoint's `exec bun run "$@"` behavior.
|
|
106
|
+
const args = process.argv.slice(2);
|
|
107
|
+
if (args.length === 0) {
|
|
108
|
+
console.error(`[ashlr] usage: mcp-entrypoint.ts <server.ts> [...args]`);
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const child = Bun.spawn(["bun", "run", ...args], {
|
|
113
|
+
cwd: PLUGIN_ROOT,
|
|
114
|
+
stdio: ["inherit", "inherit", "inherit"],
|
|
115
|
+
env: process.env,
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Propagate SIGINT/SIGTERM so a plugin reload or shutdown cleans up cleanly.
|
|
119
|
+
for (const signal of ["SIGINT", "SIGTERM"] as const) {
|
|
120
|
+
process.on(signal, () => {
|
|
121
|
+
try {
|
|
122
|
+
child.kill(signal);
|
|
123
|
+
} catch {
|
|
124
|
+
// Child may already be gone; ignore.
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const exitCode = await child.exited;
|
|
130
|
+
process.exit(exitCode);
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* mdx-angle-bracket-lint.ts — flag unbacked `<placeholder>` tokens in body
|
|
4
|
+
* prose of `commands/*.md` and `site/content/docs/skills/*.mdx`.
|
|
5
|
+
*
|
|
6
|
+
* Why: Fumadocs' MDX parser interprets bare angle-bracket tokens
|
|
7
|
+
* (e.g. `<task>`, `<amount>`, `<level>`) as JSX tags. The Vercel docs build
|
|
8
|
+
* fails when these appear in prose. The convention is to wrap them in inline
|
|
9
|
+
* backticks so MDX renders them as literal `<task>` text.
|
|
10
|
+
*
|
|
11
|
+
* Strategy:
|
|
12
|
+
* - Read every target file
|
|
13
|
+
* - Skip code fences (``` ... ```), inline-code spans (`...`), HTML comments
|
|
14
|
+
* - Skip frontmatter (--- ... ---) and YAML inside fences
|
|
15
|
+
* - For remaining content, flag any `<word-or-placeholder>` not preceded by
|
|
16
|
+
* a real-tag whitelist (e.g. `<br>`, `<details>`, `<summary>`, `<a ...>`,
|
|
17
|
+
* `<img ...>`, etc.)
|
|
18
|
+
*
|
|
19
|
+
* Usage:
|
|
20
|
+
* bun run scripts/mdx-angle-bracket-lint.ts # lint all targets, exit non-zero on fail
|
|
21
|
+
* bun run scripts/mdx-angle-bracket-lint.ts <file>... # lint specific files
|
|
22
|
+
* bun run scripts/mdx-angle-bracket-lint.ts --quiet # exit code only, no per-file output
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { readFileSync, readdirSync, statSync } from "fs";
|
|
26
|
+
import { join, resolve } from "path";
|
|
27
|
+
|
|
28
|
+
const KNOWN_HTML_TAGS = new Set([
|
|
29
|
+
"a", "abbr", "address", "article", "aside", "audio", "b", "blockquote", "br",
|
|
30
|
+
"button", "canvas", "caption", "code", "col", "colgroup", "data", "datalist",
|
|
31
|
+
"dd", "del", "details", "dfn", "dialog", "div", "dl", "dt", "em", "embed",
|
|
32
|
+
"fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4",
|
|
33
|
+
"h5", "h6", "head", "header", "hr", "html", "i", "iframe", "img", "input",
|
|
34
|
+
"ins", "kbd", "label", "legend", "li", "main", "mark", "menu", "meta",
|
|
35
|
+
"meter", "nav", "noscript", "object", "ol", "optgroup", "option", "output",
|
|
36
|
+
"p", "param", "picture", "pre", "progress", "q", "rp", "rt", "ruby", "s",
|
|
37
|
+
"samp", "script", "section", "select", "small", "source", "span", "strong",
|
|
38
|
+
"style", "sub", "summary", "sup", "svg", "table", "tbody", "td", "template",
|
|
39
|
+
"textarea", "tfoot", "th", "thead", "time", "title", "tr", "track", "u",
|
|
40
|
+
"ul", "var", "video", "wbr",
|
|
41
|
+
// Closing tags appear as </tag>; allow common patterns
|
|
42
|
+
"br/", "hr/",
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
interface LintError {
|
|
46
|
+
file: string;
|
|
47
|
+
line: number;
|
|
48
|
+
col: number;
|
|
49
|
+
match: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Strip code fences and inline-code spans from a line array, in-place. */
|
|
53
|
+
export function stripFences(content: string): string {
|
|
54
|
+
// Remove fenced code blocks first.
|
|
55
|
+
let out = content.replace(/```[\s\S]*?```/g, (m) => m.replace(/[^\n]/g, " "));
|
|
56
|
+
// Remove inline code spans `...`
|
|
57
|
+
out = out.replace(/`[^`\n]+`/g, (m) => m.replace(/[^\n]/g, " "));
|
|
58
|
+
// Remove HTML comments
|
|
59
|
+
out = out.replace(/<!--[\s\S]*?-->/g, (m) => m.replace(/[^\n]/g, " "));
|
|
60
|
+
// Strip YAML frontmatter at top of file (--- through ---)
|
|
61
|
+
out = out.replace(/^---\n[\s\S]*?\n---\n/, (m) => m.replace(/[^\n]/g, " "));
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Lint a single file's content. Returns array of errors (empty == ok). */
|
|
66
|
+
export function lintContent(file: string, content: string): LintError[] {
|
|
67
|
+
const stripped = stripFences(content);
|
|
68
|
+
const errors: LintError[] = [];
|
|
69
|
+
const lines = stripped.split("\n");
|
|
70
|
+
// Match `<word>` and `<word>...</word>` opening, but NOT real HTML/JSX tags
|
|
71
|
+
// (those have attributes or are in known list).
|
|
72
|
+
// We're conservative: any `<NAME>` where NAME is lowercase letters or has
|
|
73
|
+
// hyphens but no `=`, no `/`, no spaces, and not in the known tag set.
|
|
74
|
+
const TOKEN_RE = /<([a-z][a-z0-9_-]*)>/gi;
|
|
75
|
+
|
|
76
|
+
for (let i = 0; i < lines.length; i++) {
|
|
77
|
+
const line = lines[i]!;
|
|
78
|
+
let m: RegExpExecArray | null;
|
|
79
|
+
TOKEN_RE.lastIndex = 0;
|
|
80
|
+
while ((m = TOKEN_RE.exec(line)) !== null) {
|
|
81
|
+
const tag = m[1]!.toLowerCase();
|
|
82
|
+
if (KNOWN_HTML_TAGS.has(tag)) continue;
|
|
83
|
+
errors.push({ file, line: i + 1, col: m.index + 1, match: m[0] });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return errors;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function listMdAndMdx(dir: string): string[] {
|
|
90
|
+
const out: string[] = [];
|
|
91
|
+
if (!statSafe(dir)) return out;
|
|
92
|
+
const stack: string[] = [dir];
|
|
93
|
+
while (stack.length > 0) {
|
|
94
|
+
const cur = stack.pop()!;
|
|
95
|
+
for (const entry of readdirSync(cur, { withFileTypes: true })) {
|
|
96
|
+
const full = join(cur, entry.name);
|
|
97
|
+
if (entry.isDirectory()) stack.push(full);
|
|
98
|
+
else if (entry.isFile() && (full.endsWith(".md") || full.endsWith(".mdx"))) out.push(full);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function statSafe(p: string): boolean {
|
|
105
|
+
try { return statSync(p).isDirectory(); } catch { return false; }
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async function main(): Promise<void> {
|
|
109
|
+
const args = process.argv.slice(2);
|
|
110
|
+
const quiet = args.includes("--quiet");
|
|
111
|
+
const explicit = args.filter((a) => !a.startsWith("--"));
|
|
112
|
+
|
|
113
|
+
const cwd = process.cwd();
|
|
114
|
+
const targets: string[] = [];
|
|
115
|
+
if (explicit.length > 0) {
|
|
116
|
+
for (const t of explicit) targets.push(resolve(cwd, t));
|
|
117
|
+
} else {
|
|
118
|
+
targets.push(...listMdAndMdx(join(cwd, "commands")));
|
|
119
|
+
targets.push(...listMdAndMdx(join(cwd, "site", "content", "docs", "skills")));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
let totalErrors = 0;
|
|
123
|
+
const seenFiles = new Set<string>();
|
|
124
|
+
for (const file of targets) {
|
|
125
|
+
if (seenFiles.has(file)) continue;
|
|
126
|
+
seenFiles.add(file);
|
|
127
|
+
let content: string;
|
|
128
|
+
try { content = readFileSync(file, "utf-8"); } catch { continue; }
|
|
129
|
+
const errors = lintContent(file, content);
|
|
130
|
+
if (errors.length === 0) continue;
|
|
131
|
+
totalErrors += errors.length;
|
|
132
|
+
if (!quiet) {
|
|
133
|
+
for (const e of errors) {
|
|
134
|
+
process.stderr.write(`${e.file}:${e.line}:${e.col} unwrapped angle-bracket token: ${e.match}\n`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (totalErrors === 0) {
|
|
140
|
+
if (!quiet) process.stdout.write(`mdx-lint: ok (${seenFiles.size} files scanned)\n`);
|
|
141
|
+
process.exit(0);
|
|
142
|
+
}
|
|
143
|
+
if (!quiet) {
|
|
144
|
+
process.stderr.write(`\nmdx-lint: ${totalErrors} unwrapped angle-bracket token(s) across ${seenFiles.size} files.\n`);
|
|
145
|
+
process.stderr.write(`Fix: wrap them in backticks (e.g. \`<level>\`) so MDX renders them as literal text.\n`);
|
|
146
|
+
}
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (import.meta.main) {
|
|
151
|
+
void main();
|
|
152
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* measure-cold-start — time how long the ashlr-router takes from process
|
|
4
|
+
* launch to a valid `initialize` response over stdio.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* bun run scripts/measure-cold-start.ts # single run, prints ms
|
|
8
|
+
* bun run scripts/measure-cold-start.ts --runs 5 # average of N runs
|
|
9
|
+
* bun run scripts/measure-cold-start.ts --assert # exit 1 if p95 >= 100ms
|
|
10
|
+
*
|
|
11
|
+
* The measurement starts at spawn() and ends when the first valid JSON line
|
|
12
|
+
* appears on stdout (the initialize response). This captures the full
|
|
13
|
+
* cold-start path: Bun startup + module evaluation + handler registration +
|
|
14
|
+
* MCP stdio handshake.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { spawn } from "bun";
|
|
18
|
+
import { resolve } from "path";
|
|
19
|
+
|
|
20
|
+
const ROUTER = resolve(import.meta.dir, "..", "servers", "_router.ts");
|
|
21
|
+
|
|
22
|
+
const INIT_REQUEST =
|
|
23
|
+
JSON.stringify({
|
|
24
|
+
jsonrpc: "2.0",
|
|
25
|
+
id: 1,
|
|
26
|
+
method: "initialize",
|
|
27
|
+
params: {
|
|
28
|
+
protocolVersion: "2024-11-05",
|
|
29
|
+
capabilities: {},
|
|
30
|
+
clientInfo: { name: "cold-start-measure", version: "1" },
|
|
31
|
+
},
|
|
32
|
+
}) + "\n";
|
|
33
|
+
|
|
34
|
+
/** Measure one cold-start. Returns elapsed milliseconds. */
|
|
35
|
+
async function measureOnce(): Promise<number> {
|
|
36
|
+
const t0 = performance.now();
|
|
37
|
+
|
|
38
|
+
const proc = spawn({
|
|
39
|
+
cmd: ["bun", "run", ROUTER],
|
|
40
|
+
cwd: resolve(import.meta.dir, ".."),
|
|
41
|
+
stdin: "pipe",
|
|
42
|
+
stdout: "pipe",
|
|
43
|
+
stderr: "pipe",
|
|
44
|
+
env: {
|
|
45
|
+
...process.env,
|
|
46
|
+
ASHLR_STATS_SYNC: "1",
|
|
47
|
+
ASHLR_SESSION_LOG: "0",
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
proc.stdin.write(INIT_REQUEST);
|
|
52
|
+
await proc.stdin.end();
|
|
53
|
+
|
|
54
|
+
// Read lines until we get the initialize response.
|
|
55
|
+
const reader = proc.stdout.getReader();
|
|
56
|
+
let buf = "";
|
|
57
|
+
let elapsed = -1;
|
|
58
|
+
|
|
59
|
+
outer: while (true) {
|
|
60
|
+
const { done, value } = await reader.read();
|
|
61
|
+
if (done) break;
|
|
62
|
+
buf += new TextDecoder().decode(value);
|
|
63
|
+
const lines = buf.split("\n");
|
|
64
|
+
buf = lines.pop() ?? "";
|
|
65
|
+
for (const line of lines) {
|
|
66
|
+
if (!line.trim()) continue;
|
|
67
|
+
try {
|
|
68
|
+
const msg = JSON.parse(line);
|
|
69
|
+
if (msg?.result?.serverInfo?.name === "ashlr-router") {
|
|
70
|
+
elapsed = performance.now() - t0;
|
|
71
|
+
break outer;
|
|
72
|
+
}
|
|
73
|
+
} catch {
|
|
74
|
+
// not JSON yet — keep reading
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
reader.cancel();
|
|
80
|
+
await proc.exited;
|
|
81
|
+
|
|
82
|
+
if (elapsed < 0) throw new Error("Router did not emit an initialize response");
|
|
83
|
+
return elapsed;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
// CLI
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
|
|
90
|
+
const args = process.argv.slice(2);
|
|
91
|
+
const runsArg = args.indexOf("--runs");
|
|
92
|
+
const runs = runsArg >= 0 ? parseInt(args[runsArg + 1] ?? "5", 10) : 1;
|
|
93
|
+
const shouldAssert = args.includes("--assert");
|
|
94
|
+
const TARGET_MS = 100;
|
|
95
|
+
|
|
96
|
+
const samples: number[] = [];
|
|
97
|
+
for (let i = 0; i < runs; i++) {
|
|
98
|
+
const ms = await measureOnce();
|
|
99
|
+
samples.push(ms);
|
|
100
|
+
process.stdout.write(` run ${i + 1}/${runs}: ${ms.toFixed(1)}ms\n`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
samples.sort((a, b) => a - b);
|
|
104
|
+
const avg = samples.reduce((s, v) => s + v, 0) / samples.length;
|
|
105
|
+
const p50 = samples[Math.floor(samples.length * 0.5)]!;
|
|
106
|
+
const p95 = samples[Math.floor(samples.length * 0.95)]!;
|
|
107
|
+
const max = samples[samples.length - 1]!;
|
|
108
|
+
|
|
109
|
+
process.stdout.write(
|
|
110
|
+
`\nashlr-router cold-start (${runs} run${runs === 1 ? "" : "s"})\n` +
|
|
111
|
+
` avg ${avg.toFixed(1)}ms\n` +
|
|
112
|
+
` p50 ${p50.toFixed(1)}ms\n` +
|
|
113
|
+
` p95 ${p95.toFixed(1)}ms\n` +
|
|
114
|
+
` max ${max.toFixed(1)}ms\n` +
|
|
115
|
+
` target: < ${TARGET_MS}ms\n`,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
if (shouldAssert) {
|
|
119
|
+
if (p95 >= TARGET_MS) {
|
|
120
|
+
process.stderr.write(
|
|
121
|
+
`[measure-cold-start] FAIL: p95=${p95.toFixed(1)}ms >= ${TARGET_MS}ms target\n`,
|
|
122
|
+
);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
process.stdout.write(`[measure-cold-start] PASS: p95=${p95.toFixed(1)}ms < ${TARGET_MS}ms\n`);
|
|
126
|
+
}
|