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,194 @@
|
|
|
1
|
+
# ashlr-plugin Telemetry
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
ashlr-plugin includes an **opt-in, privacy-first** telemetry pipeline that helps the maintainer tune heuristics (edit thresholds, embedding similarity cutoffs, LLM routing) with real-world data instead of guesses.
|
|
6
|
+
|
|
7
|
+
**Default: OFF.** Nothing is ever collected unless you explicitly enable it.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## How to opt in
|
|
12
|
+
|
|
13
|
+
**Via environment variable (session-scoped):**
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
export ASHLR_TELEMETRY=on
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Via config file (persistent):**
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
// ~/.ashlr/config.json
|
|
23
|
+
{
|
|
24
|
+
"telemetry": "opt-in"
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
On first opt-in, a one-line notice is printed at session start confirming what is collected and how to disable.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## How to opt out
|
|
33
|
+
|
|
34
|
+
**Environment variable (highest priority — overrides config):**
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
export ASHLR_TELEMETRY=off
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Config file:**
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
// ~/.ashlr/config.json
|
|
44
|
+
{
|
|
45
|
+
"telemetry": "off"
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Either method immediately disables collection and flushing. No data is sent after the kill switch is set. The local buffer at `~/.ashlr/telemetry-buffer.jsonl` can be deleted manually at any time.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## What is collected
|
|
54
|
+
|
|
55
|
+
Only anonymized, aggregate-friendly event shapes. **No file paths, no grep patterns, no command content, no user identifiers, no repo names.**
|
|
56
|
+
|
|
57
|
+
### Event types
|
|
58
|
+
|
|
59
|
+
| Kind | Fields |
|
|
60
|
+
|------|--------|
|
|
61
|
+
| `tool_call` | `tool`, `rawBytes`, `compactBytes`, `fellBack`, `providerUsed`, `durationMs` |
|
|
62
|
+
| `pretooluse_block` | `tool`, `blockedTo`, `sizeRange` (`small`/`medium`/`large` bucket — never raw bytes) |
|
|
63
|
+
| `pretooluse_passthrough` | `tool`, `reason` (`below-threshold` / `out-of-cwd` / `plugin-tree` / `micro-edit` / `bypass`) |
|
|
64
|
+
| `version` | `pluginVersion`, `bunVersion`, `platform`, `arch` |
|
|
65
|
+
|
|
66
|
+
All events also include:
|
|
67
|
+
|
|
68
|
+
- `ts` — epoch seconds (not milliseconds, to save bytes)
|
|
69
|
+
- `kind` — event type string
|
|
70
|
+
- `sessionId` — a per-session opaque hex string (SHA-256 fold of a random seed; re-generated each session)
|
|
71
|
+
|
|
72
|
+
### What `sessionId` is
|
|
73
|
+
|
|
74
|
+
A 16-character hex string derived from a random seed at session start. It is deleted at session end. It allows the maintainer to correlate events *within* one session without identifying the user across sessions or installations. Re-installs and new sessions always generate a fresh value.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## What is NEVER collected
|
|
79
|
+
|
|
80
|
+
- File paths (absolute or relative)
|
|
81
|
+
- Grep search patterns
|
|
82
|
+
- File content, command arguments, or any user-authored text
|
|
83
|
+
- User names, email addresses, or identifiers
|
|
84
|
+
- Repo names, organization names, or project paths
|
|
85
|
+
- IP addresses (the server receives them transiently in HTTP headers but they are not stored)
|
|
86
|
+
|
|
87
|
+
A path-safety guard in the buffer writer (`looksLikePath`) rejects any event whose string values look like an absolute filesystem path. Events that fail this check are silently dropped rather than written.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Local buffer
|
|
92
|
+
|
|
93
|
+
Events are buffered locally at:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
~/.ashlr/telemetry-buffer.jsonl
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The buffer is capped at **5,000 lines**. Older entries are evicted when the cap is exceeded. The buffer is a plain JSONL file — you can inspect it at any time:
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
cat ~/.ashlr/telemetry-buffer.jsonl | head -5
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Flusher
|
|
108
|
+
|
|
109
|
+
The buffer is flushed to the maintainer's collection endpoint:
|
|
110
|
+
|
|
111
|
+
1. **On session end** — spawned from the `session-end-consolidate` hook.
|
|
112
|
+
2. **On demand** — `bun run scripts/telemetry-flush.ts`.
|
|
113
|
+
|
|
114
|
+
The flusher has a **10-second network timeout**. On failure (network error, non-2xx response) the buffer is left untouched and retried on the next flush cycle. Failures are logged to stderr but never surfaced to the user.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Endpoint contract
|
|
119
|
+
|
|
120
|
+
### POST `/v1/events`
|
|
121
|
+
|
|
122
|
+
**URL:** `https://telemetry.ashlr.ai/v1/events` (override with `ASHLR_TELEMETRY_URL` env var)
|
|
123
|
+
|
|
124
|
+
**Request:**
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"sessionId": "a1b2c3d4e5f6a7b8",
|
|
129
|
+
"events": [
|
|
130
|
+
{
|
|
131
|
+
"ts": 1720000000,
|
|
132
|
+
"kind": "tool_call",
|
|
133
|
+
"sessionId": "a1b2c3d4e5f6a7b8",
|
|
134
|
+
"tool": "ashlr__read",
|
|
135
|
+
"rawBytes": 8200,
|
|
136
|
+
"compactBytes": 1100,
|
|
137
|
+
"fellBack": false,
|
|
138
|
+
"providerUsed": "anthropic",
|
|
139
|
+
"durationMs": 42
|
|
140
|
+
}
|
|
141
|
+
]
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Response (2xx):**
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{ "accepted": 1 }
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
On `2xx`, the flusher truncates the buffer to entries newer than the flush horizon (the `ts` of the last event in the batch). On any other status or network error, the buffer is left intact.
|
|
152
|
+
|
|
153
|
+
### Server-side requirements (for the maintainer)
|
|
154
|
+
|
|
155
|
+
To start receiving events, stand up a simple HTTPS function (Vercel/Cloudflare Workers/etc.) that:
|
|
156
|
+
|
|
157
|
+
1. Accepts `POST /v1/events` with `Content-Type: application/json`.
|
|
158
|
+
2. Parses `{ sessionId, events }` from the body.
|
|
159
|
+
3. Validates that no event field contains path-like strings (defense-in-depth).
|
|
160
|
+
4. Appends events to a time-series store (e.g. Tinybird, ClickHouse, Postgres `jsonb`).
|
|
161
|
+
5. Returns `{ accepted: N }` with status `200`.
|
|
162
|
+
6. Does NOT log request IP addresses to permanent storage.
|
|
163
|
+
|
|
164
|
+
**The endpoint does not need to exist for the plugin to function.** When the endpoint is unreachable, events are buffered locally and retried silently.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Data retention promise
|
|
169
|
+
|
|
170
|
+
- **Raw events:** purged from the server after **30 days**.
|
|
171
|
+
- **Aggregate statistics** (e.g., p50 raw/compact byte ratios per tool per week): retained indefinitely for heuristic tuning.
|
|
172
|
+
- **Session IDs:** not cross-referenced with any user identity. Treated as opaque correlation tokens within a single session.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Viewing telemetry status
|
|
177
|
+
|
|
178
|
+
Run `/ashlr-status` in Claude Code. The `## Telemetry snapshot` section includes:
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
opt-in telemetry: OFF (default) · to enable: ASHLR_TELEMETRY=on
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
or when enabled:
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
opt-in telemetry: ON · buffer: 42 events · to disable: ASHLR_TELEMETRY=off
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## `/ashlr-settings telemetry off`
|
|
193
|
+
|
|
194
|
+
Running `/ashlr-settings telemetry off` writes `{ "telemetry": "off" }` into `~/.ashlr/config.json`, which disables collection and flushing for all future sessions.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Test Isolation in the ashlr-plugin Suite
|
|
2
|
+
|
|
3
|
+
## Why Bun shares module state across test files
|
|
4
|
+
|
|
5
|
+
Bun runs all test files in a single worker process (by default). Every `import`
|
|
6
|
+
resolves against a shared module cache, so a module imported by `a.test.ts` and
|
|
7
|
+
then imported again by `b.test.ts` returns the *same* object — not a fresh copy.
|
|
8
|
+
|
|
9
|
+
Consequences:
|
|
10
|
+
|
|
11
|
+
- **Module-level variables** (caches, flags, counters) survive between files.
|
|
12
|
+
- **`mock.module(specifier, factory)`** replaces the module in that shared cache
|
|
13
|
+
and is *not* automatically restored when the test file finishes. Bun's
|
|
14
|
+
`mock.restore()` only clears `mockFn` spies, not `mock.module` overrides.
|
|
15
|
+
- **`process.env` mutations** are visible to all subsequent imports and code that
|
|
16
|
+
reads env at call-time.
|
|
17
|
+
|
|
18
|
+
## Patterns to follow
|
|
19
|
+
|
|
20
|
+
### 1. Save and restore `process.env` in outer scope
|
|
21
|
+
|
|
22
|
+
If a test must set an env var, capture the original value before `beforeEach`
|
|
23
|
+
and restore it in `afterEach`:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
let origHome: string | undefined;
|
|
27
|
+
|
|
28
|
+
beforeEach(() => { origHome = process.env.HOME; process.env.HOME = tmpDir; });
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
if (origHome !== undefined) process.env.HOME = origHome;
|
|
31
|
+
else delete process.env.HOME;
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Never use `mock.module` for shared packages
|
|
36
|
+
|
|
37
|
+
`mock.module` leaks permanently into the module cache. Prefer **dependency
|
|
38
|
+
injection**: add an optional `retriever` / `logger` / `handler` parameter to
|
|
39
|
+
the production function, defaulting to the real implementation. Tests pass
|
|
40
|
+
stubs via that parameter — no module patching needed.
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
// production code
|
|
44
|
+
export async function retrieveCached(
|
|
45
|
+
root: string, pattern: string, limit: number,
|
|
46
|
+
retriever: Retriever = _retrieveSectionsV2, // real default
|
|
47
|
+
) { ... }
|
|
48
|
+
|
|
49
|
+
// test code — no mock.module
|
|
50
|
+
await retrieveCached(root, "foo", 4000, stubRetriever);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3. Clear module-level caches in `beforeEach`
|
|
54
|
+
|
|
55
|
+
Any module that exposes a `_clearCache()` / `_resetXxx()` test hook must be
|
|
56
|
+
called in `beforeEach`, not just `afterEach`. Running it only in `afterEach`
|
|
57
|
+
leaves stale state if the previous test in another file did not clean up.
|
|
58
|
+
|
|
59
|
+
### 4. Use `ASHLR_STATS_SYNC=1` when asserting on-disk state
|
|
60
|
+
|
|
61
|
+
`_stats.ts` debounces file writes by 250 ms. Tests that assert a stats file was
|
|
62
|
+
written must either:
|
|
63
|
+
|
|
64
|
+
- set `ASHLR_STATS_SYNC=1` in the test environment (disables debounce), or
|
|
65
|
+
- poll with a bounded wait loop after the action.
|
|
66
|
+
|
|
67
|
+
### 5. Spawn subprocesses with a minimal env
|
|
68
|
+
|
|
69
|
+
When a test spawns an MCP server subprocess to verify event emission, pass only
|
|
70
|
+
the env vars the subprocess actually needs:
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
env: { HOME: isolatedTmpDir, PATH: process.env.PATH ?? "/usr/bin:/bin" }
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Stripping the full `process.env` prevents a previously mutated `HOME` or
|
|
77
|
+
`ASHLR_SESSION_LOG_PATH` from leaking into the subprocess.
|
|
78
|
+
|
|
79
|
+
## Fixes applied in this repo
|
|
80
|
+
|
|
81
|
+
### Leaker: `__tests__/genome-cache.test.ts`
|
|
82
|
+
|
|
83
|
+
**What leaked:** A top-level `mock.module("@ashlr/core-efficiency", ...)` call
|
|
84
|
+
that replaced the entire package — including `estimateTokensFromString: () => 0`
|
|
85
|
+
— in Bun's shared module cache. Every test file loaded after
|
|
86
|
+
`genome-cache.test.ts` (alphabetically: `genome-init`, `genome-live`, …,
|
|
87
|
+
`run-benchmark`, …) received the stubbed module. `run-benchmark.test.ts`
|
|
88
|
+
calls `estimateTokensFromString` to measure token savings; with the stub
|
|
89
|
+
returning 0, every ratio computed as `0 / 0 → 1`, making the
|
|
90
|
+
`medium/large ratio < 1` assertion fail.
|
|
91
|
+
|
|
92
|
+
**Fix:** Refactored `servers/_genome-cache.ts` to accept an optional `retriever`
|
|
93
|
+
parameter (defaulting to the real `retrieveSectionsV2`). Rewrote
|
|
94
|
+
`genome-cache.test.ts` to pass a stub directly — no `mock.module` needed.
|
|
95
|
+
|
|
96
|
+
### Affected skip removed: `run-benchmark.test.ts`
|
|
97
|
+
|
|
98
|
+
`test.skip("ashlr__edit medium and large samples have ratio < 1 …")` was
|
|
99
|
+
un-skipped once the `genome-cache.test.ts` leak was fixed. The test passes
|
|
100
|
+
reliably in both isolation and the full suite.
|
package/docs/upgrade.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# ashlr upgrade — terminal-native free-to-pro flow
|
|
2
|
+
|
|
3
|
+
Run `/ashlr-upgrade` inside Claude Code to go from free to Pro or Team in
|
|
4
|
+
under 90 seconds without leaving the terminal.
|
|
5
|
+
|
|
6
|
+
## Quick start
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
/ashlr-upgrade
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
That's it. The flow handles sign-in, plan selection, Stripe checkout, and
|
|
13
|
+
activation confirmation automatically.
|
|
14
|
+
|
|
15
|
+
## What happens step by step
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
╔══════════════════════════════════╗
|
|
19
|
+
║ ashlr · upgrade ║
|
|
20
|
+
╚══════════════════════════════════╝
|
|
21
|
+
|
|
22
|
+
▬▬▬ STEP 1/5: Checking current tier ▬▬▬
|
|
23
|
+
✓ Not signed in yet.
|
|
24
|
+
|
|
25
|
+
▬▬▬ STEP 2/5: Sign in ▬▬▬
|
|
26
|
+
No active Pro token found. Let's sign you in first.
|
|
27
|
+
[ASHLR_PROMPT: Email to sign in?] you@example.com
|
|
28
|
+
✓ Magic link sent to you@example.com. Check your inbox — click the link to continue.
|
|
29
|
+
Waiting for you to click the link (up to 3 minutes)...
|
|
30
|
+
Waiting ...
|
|
31
|
+
✓ Sign-in confirmed.
|
|
32
|
+
✓ Token saved to ~/.ashlr/pro-token and ~/.ashlr/env (auto-loaded on next session).
|
|
33
|
+
|
|
34
|
+
▬▬▬ STEP 3/5: Choose your plan ▬▬▬
|
|
35
|
+
|
|
36
|
+
1) Pro · $12/mo [default]
|
|
37
|
+
2) Pro · $120/yr (save 17%)
|
|
38
|
+
3) Team · $24/user/mo
|
|
39
|
+
4) Team · $240/user/yr (save 17%)
|
|
40
|
+
|
|
41
|
+
[ASHLR_PROMPT: Choose a plan (1-4, default 1):] 1
|
|
42
|
+
✓ Selected: Pro · $12/mo
|
|
43
|
+
|
|
44
|
+
▬▬▬ STEP 4/5: Open Stripe checkout ▬▬▬
|
|
45
|
+
✓ Opened checkout in your browser. Complete payment to activate Pro.
|
|
46
|
+
|
|
47
|
+
▬▬▬ STEP 5/5: Waiting for payment confirmation ▬▬▬
|
|
48
|
+
Polling for payment confirmation (up to 10 minutes)...
|
|
49
|
+
Waiting ...
|
|
50
|
+
|
|
51
|
+
ashlr Pro is now active.
|
|
52
|
+
Your API token is saved locally. All Pro features are unlocked.
|
|
53
|
+
|
|
54
|
+
What just changed:
|
|
55
|
+
- Hosted LLM summarizer — Ollama not required
|
|
56
|
+
- Cross-machine stats sync
|
|
57
|
+
- Leaderboard participation
|
|
58
|
+
- Priority support at support@ashlr.ai
|
|
59
|
+
|
|
60
|
+
Next: run /ashlr-dashboard to see your usage.
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Already on Pro
|
|
64
|
+
|
|
65
|
+
If `ASHLR_PRO_TOKEN` is set and your account is already Pro or Team, the
|
|
66
|
+
flow exits immediately:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
▬▬▬ STEP 1/5: Checking current tier ▬▬▬
|
|
70
|
+
✓ You're already on Pro.
|
|
71
|
+
Run /ashlr-dashboard to see usage.
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Flags
|
|
75
|
+
|
|
76
|
+
| Flag | Effect |
|
|
77
|
+
|------|--------|
|
|
78
|
+
| `--tier pro\|team` | Pre-select tier, skip the plan prompt |
|
|
79
|
+
| `--annual` | Pre-select annual billing |
|
|
80
|
+
| `--email <addr>` | Pre-supply email, skip the email prompt |
|
|
81
|
+
| `--no-poll` | Skip the activation polling step (useful for testing or CI) |
|
|
82
|
+
|
|
83
|
+
Example — skip all interactive prompts:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
/ashlr-upgrade --tier pro --annual --email you@example.com
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Headless / SSH sessions (no browser)
|
|
90
|
+
|
|
91
|
+
Set `ASHLR_NO_BROWSER=1` to suppress the automatic browser open. The
|
|
92
|
+
checkout URL is printed to the terminal instead:
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
ASHLR_NO_BROWSER=1
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Then copy the printed URL and open it in a browser on any device.
|
|
99
|
+
|
|
100
|
+
## If the browser fails to open
|
|
101
|
+
|
|
102
|
+
If `open` / `xdg-open` / `start` is not available (remote server, Docker,
|
|
103
|
+
minimal Linux), the flow falls back gracefully:
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
! Could not open a browser automatically.
|
|
107
|
+
|
|
108
|
+
Open this URL manually:
|
|
109
|
+
|
|
110
|
+
https://checkout.stripe.com/c/pay/cs_live_...
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The activation poller continues running. Complete payment in your browser and
|
|
114
|
+
the terminal will detect it automatically.
|
|
115
|
+
|
|
116
|
+
## Manually pasting a token
|
|
117
|
+
|
|
118
|
+
If you already have an API token (from the web dashboard at
|
|
119
|
+
plugin.ashlr.ai), you can skip the magic-link flow entirely:
|
|
120
|
+
|
|
121
|
+
1. Save the token: `echo "export ASHLR_PRO_TOKEN=<token>" >> ~/.ashlr/env`
|
|
122
|
+
2. Source it: `source ~/.ashlr/env`
|
|
123
|
+
3. Verify: `/ashlr-upgrade` will see your Pro status and exit immediately.
|
|
124
|
+
|
|
125
|
+
## What happens if the poll times out
|
|
126
|
+
|
|
127
|
+
After you open checkout, the script polls `/billing/status` every 5 seconds
|
|
128
|
+
for up to 10 minutes. If payment isn't detected within that window, you'll see:
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
! Haven't detected payment yet.
|
|
132
|
+
Once you complete checkout, run /ashlr-upgrade again to verify and activate.
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Run `/ashlr-upgrade` again after completing payment — step 1 will detect the
|
|
136
|
+
new tier and exit immediately.
|
|
137
|
+
|
|
138
|
+
## Token storage
|
|
139
|
+
|
|
140
|
+
After sign-in the API token is saved in two places:
|
|
141
|
+
|
|
142
|
+
| File | Purpose |
|
|
143
|
+
|------|---------|
|
|
144
|
+
| `~/.ashlr/pro-token` | Raw token (mode 0600) |
|
|
145
|
+
| `~/.ashlr/env` | `export ASHLR_PRO_TOKEN=<token>` — sourced by the SessionStart hook |
|
|
146
|
+
|
|
147
|
+
The SessionStart hook reads `~/.ashlr/env` on every new Claude Code session,
|
|
148
|
+
so `ASHLR_PRO_TOKEN` is available automatically without a shell restart.
|
|
149
|
+
|
|
150
|
+
## Pro features unlocked
|
|
151
|
+
|
|
152
|
+
| Feature | Free | Pro |
|
|
153
|
+
|---------|------|-----|
|
|
154
|
+
| Hosted LLM summarizer | No (local Ollama required) | Yes |
|
|
155
|
+
| Cross-machine stats sync | No | Yes |
|
|
156
|
+
| Leaderboard | No | Yes |
|
|
157
|
+
| Priority support | No | Yes (support@ashlr.ai) |
|
|
158
|
+
|
|
159
|
+
See [billing.md](billing.md) for full tier comparison and lifecycle details.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* _hook-errors.ts — shared error-surfacing helper for hooks.
|
|
3
|
+
*
|
|
4
|
+
* Hooks are best-effort and never block tool calls, but silent catches make
|
|
5
|
+
* production failures undebuggable. This helper surfaces errors two ways:
|
|
6
|
+
* 1. stderr — visible in `claude --debug` and most harness log captures
|
|
7
|
+
* 2. ~/.ashlr/hook-errors.jsonl — persistent ring buffer (cap 1000 lines)
|
|
8
|
+
*
|
|
9
|
+
* Never throws. Never blocks. Safe to call from any catch block.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
13
|
+
import { homedir } from "os";
|
|
14
|
+
import { dirname, join } from "path";
|
|
15
|
+
|
|
16
|
+
const MAX_LINES = 1000;
|
|
17
|
+
const TRIM_TO = 800;
|
|
18
|
+
|
|
19
|
+
function errorsPath(): string {
|
|
20
|
+
const home =
|
|
21
|
+
process.env.ASHLR_HOME_OVERRIDE?.trim() ||
|
|
22
|
+
process.env.HOME ||
|
|
23
|
+
homedir();
|
|
24
|
+
return join(home, ".ashlr", "hook-errors.jsonl");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function trimIfOversized(p: string): void {
|
|
28
|
+
try {
|
|
29
|
+
const raw = readFileSync(p, "utf-8");
|
|
30
|
+
const lines = raw.split("\n");
|
|
31
|
+
if (lines.length <= MAX_LINES) return;
|
|
32
|
+
const kept = lines.slice(lines.length - TRIM_TO).join("\n");
|
|
33
|
+
writeFileSync(p, kept, "utf-8");
|
|
34
|
+
} catch {
|
|
35
|
+
/* best-effort */
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Safe JSON.parse wrapper — the canonical helper for all hook stdin / config
|
|
41
|
+
* file parsing. Returns `fallback` on any parse error and optionally records
|
|
42
|
+
* the failure via `noteHookError` so it shows up in hook-errors.jsonl.
|
|
43
|
+
*
|
|
44
|
+
* Usage:
|
|
45
|
+
* const payload = safeParse<MyType>(raw, {}, "my-hook", "stdin");
|
|
46
|
+
*
|
|
47
|
+
* @param raw - Raw string to parse (may be empty, truncated, or garbage).
|
|
48
|
+
* @param fallback - Value to return when parsing fails.
|
|
49
|
+
* @param hook - Hook name for error logging (optional; omit to skip logging).
|
|
50
|
+
* @param context - Context label for error logging (optional).
|
|
51
|
+
*/
|
|
52
|
+
export function safeParse<T>(
|
|
53
|
+
raw: string,
|
|
54
|
+
fallback: T,
|
|
55
|
+
hook?: string,
|
|
56
|
+
context?: string,
|
|
57
|
+
): T {
|
|
58
|
+
try {
|
|
59
|
+
return JSON.parse(raw) as T;
|
|
60
|
+
} catch (e) {
|
|
61
|
+
if (hook) noteHookError(hook, context ?? "JSON.parse", e);
|
|
62
|
+
return fallback;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function noteHookError(hook: string, context: string, error: unknown): void {
|
|
67
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
68
|
+
try {
|
|
69
|
+
process.stderr.write(`[ashlr ${hook}] ${context}: ${msg}\n`);
|
|
70
|
+
} catch {
|
|
71
|
+
/* stderr may be closed in some hook harnesses — swallow */
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
const p = errorsPath();
|
|
75
|
+
mkdirSync(dirname(p), { recursive: true });
|
|
76
|
+
const line = JSON.stringify({
|
|
77
|
+
ts: new Date().toISOString(),
|
|
78
|
+
hook,
|
|
79
|
+
context,
|
|
80
|
+
error: msg,
|
|
81
|
+
});
|
|
82
|
+
appendFileSync(p, line + "\n", "utf-8");
|
|
83
|
+
if (Math.random() < 0.01) trimIfOversized(p);
|
|
84
|
+
} catch {
|
|
85
|
+
/* persistence is best-effort */
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* _hook-perf-emit.ts — SessionEnd helper: read hook-timings.jsonl,
|
|
4
|
+
* compute per-hook p50/p99, and emit one `hook_perf` telemetry event per hook.
|
|
5
|
+
*
|
|
6
|
+
* Called from session-end-consolidate.ts (fire-and-forget). Also exported
|
|
7
|
+
* for direct use in tests and future callers.
|
|
8
|
+
*
|
|
9
|
+
* Privacy: only hook names and latency percentiles are emitted — no file
|
|
10
|
+
* paths, no tool arguments, no content.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { readHookTimings, computeAggregates } from "../scripts/hook-timings-report";
|
|
14
|
+
import { logHookPerfEvent, isTelemetryEnabled } from "../servers/_telemetry";
|
|
15
|
+
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// p99 helper (computeAggregates only exposes p95; we need p99 for the spec)
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
function percentile(sorted: number[], p: number): number {
|
|
21
|
+
if (sorted.length === 0) return 0;
|
|
22
|
+
if (sorted.length === 1) return sorted[0]!;
|
|
23
|
+
const idx = (p / 100) * (sorted.length - 1);
|
|
24
|
+
const lo = Math.floor(idx);
|
|
25
|
+
const hi = Math.ceil(idx);
|
|
26
|
+
if (lo === hi) return sorted[lo]!;
|
|
27
|
+
const frac = idx - lo;
|
|
28
|
+
return Math.round(sorted[lo]! + frac * (sorted[hi]! - sorted[lo]!));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Public API
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
export interface HookPerfSummary {
|
|
36
|
+
hook_name: string;
|
|
37
|
+
p50_ms: number;
|
|
38
|
+
p99_ms: number;
|
|
39
|
+
count: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Read hook-timings.jsonl from `timingsPath` (default: ~/.ashlr/hook-timings.jsonl),
|
|
44
|
+
* compute per-hook p50/p99 over the last `windowHours` hours, and return summaries.
|
|
45
|
+
*/
|
|
46
|
+
export function computeHookPerfSummaries(opts: {
|
|
47
|
+
timingsPath?: string;
|
|
48
|
+
windowHours?: number;
|
|
49
|
+
} = {}): HookPerfSummary[] {
|
|
50
|
+
const { timingsPath, windowHours = 24 } = opts;
|
|
51
|
+
const records = readHookTimings(timingsPath);
|
|
52
|
+
if (records.length === 0) return [];
|
|
53
|
+
|
|
54
|
+
// Use computeAggregates for the p50 + grouping, then recompute p99
|
|
55
|
+
// from the raw records since the aggregate only exposes p95.
|
|
56
|
+
const aggregates = computeAggregates(records, windowHours);
|
|
57
|
+
|
|
58
|
+
// Build a map: hook → sorted durations (within the window)
|
|
59
|
+
const cutoff = Date.now() - windowHours * 3_600_000;
|
|
60
|
+
const byHook = new Map<string, number[]>();
|
|
61
|
+
for (const rec of records) {
|
|
62
|
+
const t = new Date(rec.ts).getTime();
|
|
63
|
+
if (isNaN(t) || t < cutoff) continue;
|
|
64
|
+
const arr = byHook.get(rec.hook) ?? [];
|
|
65
|
+
arr.push(rec.durationMs);
|
|
66
|
+
byHook.set(rec.hook, arr);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return aggregates.map((agg) => {
|
|
70
|
+
const durations = (byHook.get(agg.hook) ?? []).sort((a, b) => a - b);
|
|
71
|
+
return {
|
|
72
|
+
hook_name: agg.hook,
|
|
73
|
+
p50_ms: agg.p50,
|
|
74
|
+
p99_ms: percentile(durations, 99),
|
|
75
|
+
count: agg.calls,
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Emit one `hook_perf` telemetry event per hook. No-op when telemetry is off.
|
|
82
|
+
* Returns the number of events emitted (0 when telemetry off or no records).
|
|
83
|
+
*/
|
|
84
|
+
export function emitHookPerfEvents(opts: {
|
|
85
|
+
timingsPath?: string;
|
|
86
|
+
windowHours?: number;
|
|
87
|
+
homeDir?: string;
|
|
88
|
+
} = {}): number {
|
|
89
|
+
if (!isTelemetryEnabled(opts.homeDir)) return 0;
|
|
90
|
+
const summaries = computeHookPerfSummaries(opts);
|
|
91
|
+
for (const s of summaries) {
|
|
92
|
+
logHookPerfEvent({
|
|
93
|
+
hook_name: s.hook_name,
|
|
94
|
+
p50_ms: s.p50_ms,
|
|
95
|
+
p99_ms: s.p99_ms,
|
|
96
|
+
count: s.count,
|
|
97
|
+
}, opts.homeDir);
|
|
98
|
+
}
|
|
99
|
+
return summaries.length;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// CLI entry (called from session-end-consolidate.ts as fire-and-forget)
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
if (import.meta.main) {
|
|
107
|
+
try {
|
|
108
|
+
emitHookPerfEvents();
|
|
109
|
+
} catch {
|
|
110
|
+
// best-effort — never disturb session exit
|
|
111
|
+
}
|
|
112
|
+
process.exit(0);
|
|
113
|
+
}
|