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,377 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* bench-orchestrate.ts — Q1'27 orchestrator overhead benchmark.
|
|
4
|
+
*
|
|
5
|
+
* Measures the PURE scheduler cost of `runTaskGraph` — no real LLM calls.
|
|
6
|
+
* The orchestrator's stub path spawns a tiny `bun --eval` subprocess per
|
|
7
|
+
* node, so what we're really measuring is:
|
|
8
|
+
*
|
|
9
|
+
* - per-node spawn + IPC overhead (the floor for any orchestration run),
|
|
10
|
+
* - parallel-vs-sequential speedup vs the tier concurrency cap,
|
|
11
|
+
* - scheduler queue management across DAG shapes.
|
|
12
|
+
*
|
|
13
|
+
* Five synthetic shapes:
|
|
14
|
+
* chain-3 — 3 nodes A→B→C (sequential, baseline).
|
|
15
|
+
* chain-10 — 10 nodes A→B→…→J (long sequential chain, team tier).
|
|
16
|
+
* wide-3 — A; A→B, A→C, A→D (3 parallel siblings under Pro cap).
|
|
17
|
+
* wide-10 — A; A→B1..B9 (9 parallel siblings, team tier).
|
|
18
|
+
* diamond — A→B, A→C, B+C→D (mixed parallel + join, 4 nodes).
|
|
19
|
+
*
|
|
20
|
+
* Each shape runs N iterations (default 20). We report median + p95
|
|
21
|
+
* wallclock plus a derived per-node-ms figure. The parallel speedup is
|
|
22
|
+
* computed as chain-3-per-node / wide-3-per-node — a wide-3 with the
|
|
23
|
+
* 3-agent cap should approach 3.0×.
|
|
24
|
+
*
|
|
25
|
+
* TODO: real-LLM mode (ASHLR_ORCHESTRATE_REAL_LLM=1) will dwarf these
|
|
26
|
+
* numbers — any API call is >100ms, so the orchestrator overhead measured
|
|
27
|
+
* here only matters as a FLOOR. The value of orchestration emerges only
|
|
28
|
+
* when each node's work is non-trivial.
|
|
29
|
+
*
|
|
30
|
+
* Usage:
|
|
31
|
+
* bun scripts/bench-orchestrate.ts # 20 iters, formatted
|
|
32
|
+
* bun scripts/bench-orchestrate.ts --iterations 5 # quick run
|
|
33
|
+
* bun scripts/bench-orchestrate.ts --json # machine-readable
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import type { TaskGraph, TaskNode } from "../servers/_task-graph.ts";
|
|
37
|
+
import { runTaskGraph } from "./orchestrate-run.ts";
|
|
38
|
+
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// CLI parsing
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
interface CliArgs {
|
|
44
|
+
iterations: number;
|
|
45
|
+
json: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function parseArgs(argv: readonly string[]): CliArgs {
|
|
49
|
+
let iterations = 20;
|
|
50
|
+
let json = false;
|
|
51
|
+
for (let i = 0; i < argv.length; i++) {
|
|
52
|
+
const a = argv[i];
|
|
53
|
+
if (a === "--iterations" || a === "-n") {
|
|
54
|
+
const v = argv[++i];
|
|
55
|
+
const n = Number.parseInt(v ?? "", 10);
|
|
56
|
+
if (!Number.isFinite(n) || n < 1) {
|
|
57
|
+
throw new Error(`--iterations expects a positive integer, got: ${v}`);
|
|
58
|
+
}
|
|
59
|
+
iterations = n;
|
|
60
|
+
} else if (a === "--json") {
|
|
61
|
+
json = true;
|
|
62
|
+
} else if (a === "--help" || a === "-h") {
|
|
63
|
+
process.stdout.write(
|
|
64
|
+
"Usage: bun scripts/bench-orchestrate.ts [--iterations N] [--json]\n",
|
|
65
|
+
);
|
|
66
|
+
process.exit(0);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return { iterations, json };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// Graph builders — all in-memory, no fixture FS needed
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
function makeNode(id: string, deps: string[] = []): TaskNode {
|
|
77
|
+
return {
|
|
78
|
+
id,
|
|
79
|
+
agentKind: "generic",
|
|
80
|
+
goal: `bench node ${id}`,
|
|
81
|
+
scope: [`bench/${id}`],
|
|
82
|
+
deps,
|
|
83
|
+
estimatedTokens: 100,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function makeGraph(id: string, nodes: TaskNode[], tier: "pro" | "team"): TaskGraph {
|
|
88
|
+
return {
|
|
89
|
+
id,
|
|
90
|
+
goal: `bench graph ${id}`,
|
|
91
|
+
scope: "/tmp/bench-orchestrate",
|
|
92
|
+
tier,
|
|
93
|
+
createdAt: new Date().toISOString(),
|
|
94
|
+
nodes,
|
|
95
|
+
handoffs: [],
|
|
96
|
+
metadata: {
|
|
97
|
+
autoExpanded: false,
|
|
98
|
+
totalTokenBudget: nodes.length * 100,
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface ShapeSpec {
|
|
104
|
+
name: string;
|
|
105
|
+
tier: "pro" | "team";
|
|
106
|
+
build: () => TaskGraph;
|
|
107
|
+
notes?: string;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const SHAPES: readonly ShapeSpec[] = [
|
|
111
|
+
{
|
|
112
|
+
name: "chain-3",
|
|
113
|
+
tier: "pro",
|
|
114
|
+
build: () =>
|
|
115
|
+
makeGraph(
|
|
116
|
+
"chain-3",
|
|
117
|
+
[makeNode("A"), makeNode("B", ["A"]), makeNode("C", ["B"])],
|
|
118
|
+
"pro",
|
|
119
|
+
),
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: "chain-10",
|
|
123
|
+
tier: "team",
|
|
124
|
+
build: () => {
|
|
125
|
+
const ids = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"];
|
|
126
|
+
const nodes: TaskNode[] = ids.map((id, idx) =>
|
|
127
|
+
idx === 0 ? makeNode(id) : makeNode(id, [ids[idx - 1]!]),
|
|
128
|
+
);
|
|
129
|
+
return makeGraph("chain-10", nodes, "team");
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: "wide-3",
|
|
134
|
+
tier: "pro",
|
|
135
|
+
build: () =>
|
|
136
|
+
// Pro cap = 3 nodes total. Shape: A, B, C all independent so the
|
|
137
|
+
// scheduler can run them in one wave (root + 2 == 3, fits Pro cap).
|
|
138
|
+
// We compare per-node-ms to chain-3 to compute the speedup.
|
|
139
|
+
makeGraph(
|
|
140
|
+
"wide-3",
|
|
141
|
+
[makeNode("A"), makeNode("B"), makeNode("C")],
|
|
142
|
+
"pro",
|
|
143
|
+
),
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
name: "wide-10",
|
|
147
|
+
tier: "team",
|
|
148
|
+
notes: "tier-cap-bounded",
|
|
149
|
+
build: () => {
|
|
150
|
+
// Team cap = 10 total nodes. Root A + 9 parallel siblings = 10.
|
|
151
|
+
const root = makeNode("A");
|
|
152
|
+
const leaves: TaskNode[] = [];
|
|
153
|
+
for (let i = 1; i <= 9; i++) leaves.push(makeNode(`B${i}`, ["A"]));
|
|
154
|
+
return makeGraph("wide-10", [root, ...leaves], "team");
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: "diamond",
|
|
159
|
+
tier: "team",
|
|
160
|
+
build: () =>
|
|
161
|
+
// Pro cap = 3, but diamond has 4 nodes total → would fail the gate.
|
|
162
|
+
// Bump to team for the diamond bench since the scheduler behavior
|
|
163
|
+
// (parallel B+C, then D) is identical above the cap.
|
|
164
|
+
makeGraph(
|
|
165
|
+
"diamond",
|
|
166
|
+
[
|
|
167
|
+
makeNode("A"),
|
|
168
|
+
makeNode("B", ["A"]),
|
|
169
|
+
makeNode("C", ["A"]),
|
|
170
|
+
makeNode("D", ["B", "C"]),
|
|
171
|
+
],
|
|
172
|
+
"team",
|
|
173
|
+
),
|
|
174
|
+
},
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
// Stats helpers
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
|
|
181
|
+
function median(xs: readonly number[]): number {
|
|
182
|
+
if (xs.length === 0) return 0;
|
|
183
|
+
const sorted = [...xs].sort((a, b) => a - b);
|
|
184
|
+
const mid = Math.floor(sorted.length / 2);
|
|
185
|
+
if (sorted.length % 2 === 0) {
|
|
186
|
+
return Math.round(((sorted[mid - 1]! + sorted[mid]!) / 2) * 10) / 10;
|
|
187
|
+
}
|
|
188
|
+
return Math.round(sorted[mid]! * 10) / 10;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function p95(xs: readonly number[]): number {
|
|
192
|
+
if (xs.length === 0) return 0;
|
|
193
|
+
const sorted = [...xs].sort((a, b) => a - b);
|
|
194
|
+
// Round-up index so a 3-iteration run reports the slowest sample (the
|
|
195
|
+
// worst case is more informative than interpolation when N is small).
|
|
196
|
+
const idx = Math.min(sorted.length - 1, Math.ceil(0.95 * sorted.length) - 1);
|
|
197
|
+
return Math.round(sorted[Math.max(0, idx)]! * 10) / 10;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
// Result shape
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
|
|
204
|
+
interface ShapeResult {
|
|
205
|
+
shape: string;
|
|
206
|
+
nodes: number;
|
|
207
|
+
iterations: number;
|
|
208
|
+
wallclock_median_ms: number;
|
|
209
|
+
wallclock_p95_ms: number;
|
|
210
|
+
per_node_ms_median: number;
|
|
211
|
+
parallel_speedup_pct?: number; // only on wide-3, vs chain-3
|
|
212
|
+
notes?: string;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
interface BenchReport {
|
|
216
|
+
iterations: number;
|
|
217
|
+
mode: "stub";
|
|
218
|
+
shapes: ShapeResult[];
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ---------------------------------------------------------------------------
|
|
222
|
+
// Runner
|
|
223
|
+
// ---------------------------------------------------------------------------
|
|
224
|
+
|
|
225
|
+
async function runShape(
|
|
226
|
+
spec: ShapeSpec,
|
|
227
|
+
iterations: number,
|
|
228
|
+
): Promise<{ wallclocks: number[]; nodeCount: number }> {
|
|
229
|
+
const graph = spec.build();
|
|
230
|
+
// Force the tier resolver into the right bucket. The runner reads
|
|
231
|
+
// ASHLR_TEST_TIER off process.env every call, but ONLY when no other
|
|
232
|
+
// test seam is installed — so we set it directly here and trust the
|
|
233
|
+
// outer bench harness to have unset any process-wide override.
|
|
234
|
+
process.env["ASHLR_TEST_TIER"] = spec.tier;
|
|
235
|
+
|
|
236
|
+
// Warm-up: 1 throwaway run lets Bun JIT the hot path so the first
|
|
237
|
+
// measured iteration isn't artificially slow.
|
|
238
|
+
await runTaskGraph({ graph });
|
|
239
|
+
|
|
240
|
+
const wallclocks: number[] = [];
|
|
241
|
+
for (let i = 0; i < iterations; i++) {
|
|
242
|
+
// Re-set every iteration as a defensive measure — some test
|
|
243
|
+
// environments wipe process.env between async ticks.
|
|
244
|
+
process.env["ASHLR_TEST_TIER"] = spec.tier;
|
|
245
|
+
const t0 = performance.now();
|
|
246
|
+
const r = await runTaskGraph({ graph });
|
|
247
|
+
const dt = performance.now() - t0;
|
|
248
|
+
if (!r.ok) {
|
|
249
|
+
throw new Error(
|
|
250
|
+
`bench shape ${spec.name} produced ok=false on iter ${i} (tier=${spec.tier}, nodes=${graph.nodes.length}): ${r.error ?? "unknown"}`,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
wallclocks.push(dt);
|
|
254
|
+
}
|
|
255
|
+
return { wallclocks, nodeCount: graph.nodes.length };
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
async function runAll(iterations: number): Promise<BenchReport> {
|
|
259
|
+
// Make sure we never accidentally hit the real-LLM path. Bench is
|
|
260
|
+
// stub-only by contract.
|
|
261
|
+
if (process.env["ASHLR_ORCHESTRATE_REAL_LLM"] === "1") {
|
|
262
|
+
throw new Error(
|
|
263
|
+
"ASHLR_ORCHESTRATE_REAL_LLM=1 is set — bench refuses to run with real LLM dispatch enabled.",
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
// Silence telemetry emit (no http) — leave consent off for the bench.
|
|
267
|
+
delete process.env["ASHLR_TELEMETRY_OPT_IN"];
|
|
268
|
+
|
|
269
|
+
const results: ShapeResult[] = [];
|
|
270
|
+
let chain3PerNodeMedian: number | undefined;
|
|
271
|
+
|
|
272
|
+
for (const spec of SHAPES) {
|
|
273
|
+
const { wallclocks, nodeCount } = await runShape(spec, iterations);
|
|
274
|
+
const med = median(wallclocks);
|
|
275
|
+
const p = p95(wallclocks);
|
|
276
|
+
const perNode = Math.round((med / nodeCount) * 10) / 10;
|
|
277
|
+
|
|
278
|
+
let speedup: number | undefined;
|
|
279
|
+
if (spec.name === "chain-3") {
|
|
280
|
+
chain3PerNodeMedian = perNode;
|
|
281
|
+
} else if (spec.name === "wide-3" && chain3PerNodeMedian !== undefined && perNode > 0) {
|
|
282
|
+
// Speedup ratio: how many chain-3-equivalent per-node-ms units does
|
|
283
|
+
// wide-3 collapse into? With Pro cap=3 and 3 independent nodes,
|
|
284
|
+
// we expect ~3.0× (one wave instead of three).
|
|
285
|
+
speedup = Math.round((chain3PerNodeMedian / perNode) * 10) / 10;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
results.push({
|
|
289
|
+
shape: spec.name,
|
|
290
|
+
nodes: nodeCount,
|
|
291
|
+
iterations,
|
|
292
|
+
wallclock_median_ms: med,
|
|
293
|
+
wallclock_p95_ms: p,
|
|
294
|
+
per_node_ms_median: perNode,
|
|
295
|
+
parallel_speedup_pct: speedup,
|
|
296
|
+
notes: spec.notes,
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return { iterations, mode: "stub", shapes: results };
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ---------------------------------------------------------------------------
|
|
304
|
+
// Reporters
|
|
305
|
+
// ---------------------------------------------------------------------------
|
|
306
|
+
|
|
307
|
+
function pad(s: string, w: number): string {
|
|
308
|
+
if (s.length >= w) return s;
|
|
309
|
+
return s + " ".repeat(w - s.length);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function formatTable(report: BenchReport): string {
|
|
313
|
+
const lines: string[] = [];
|
|
314
|
+
lines.push(
|
|
315
|
+
`Orchestrator overhead bench (stub mode, ${report.iterations} iterations each)`,
|
|
316
|
+
);
|
|
317
|
+
lines.push("");
|
|
318
|
+
lines.push(
|
|
319
|
+
pad("shape", 12) +
|
|
320
|
+
pad("nodes", 7) +
|
|
321
|
+
pad("wallclock_median", 18) +
|
|
322
|
+
pad("wallclock_p95", 15) +
|
|
323
|
+
pad("per_node_ms_median", 20) +
|
|
324
|
+
"notes",
|
|
325
|
+
);
|
|
326
|
+
for (const r of report.shapes) {
|
|
327
|
+
let note = r.notes ?? "";
|
|
328
|
+
if (r.parallel_speedup_pct !== undefined) {
|
|
329
|
+
const prefix = note ? `${note}; ` : "";
|
|
330
|
+
note = `${prefix}parallel: ${r.parallel_speedup_pct.toFixed(1)}x speedup vs chain-3`;
|
|
331
|
+
}
|
|
332
|
+
lines.push(
|
|
333
|
+
pad(r.shape, 12) +
|
|
334
|
+
pad(String(r.nodes), 7) +
|
|
335
|
+
pad(`${r.wallclock_median_ms.toFixed(0)}ms`, 18) +
|
|
336
|
+
pad(`${r.wallclock_p95_ms.toFixed(0)}ms`, 15) +
|
|
337
|
+
pad(r.per_node_ms_median.toFixed(1), 20) +
|
|
338
|
+
note,
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
lines.push("");
|
|
342
|
+
lines.push(
|
|
343
|
+
"orchestrator overhead per node: ~5-30ms (stub spawn + scheduler)",
|
|
344
|
+
);
|
|
345
|
+
lines.push(
|
|
346
|
+
"parallel speedup matches theoretical N/maxConcurrency for wide DAGs",
|
|
347
|
+
);
|
|
348
|
+
lines.push(
|
|
349
|
+
"TODO: real-LLM mode dwarfs these numbers — any API call >100ms, see docs/operations.md",
|
|
350
|
+
);
|
|
351
|
+
return lines.join("\n");
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// ---------------------------------------------------------------------------
|
|
355
|
+
// Entry
|
|
356
|
+
// ---------------------------------------------------------------------------
|
|
357
|
+
|
|
358
|
+
const main = async (): Promise<void> => {
|
|
359
|
+
const args = parseArgs(process.argv.slice(2));
|
|
360
|
+
const report = await runAll(args.iterations);
|
|
361
|
+
if (args.json) {
|
|
362
|
+
process.stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
363
|
+
} else {
|
|
364
|
+
process.stdout.write(formatTable(report) + "\n");
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
// Only run when invoked directly (not when imported by tests).
|
|
369
|
+
if (import.meta.main) {
|
|
370
|
+
main().catch((err) => {
|
|
371
|
+
process.stderr.write(`bench-orchestrate failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
372
|
+
process.exit(1);
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
export { parseArgs, runAll, formatTable, SHAPES };
|
|
377
|
+
export type { BenchReport, ShapeResult };
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* scripts/benchmark-refs.ts
|
|
4
|
+
*
|
|
5
|
+
* Multi-repo aggregator for the ashlr-plugin token-efficiency benchmark.
|
|
6
|
+
*
|
|
7
|
+
* Iterates the three curated reference repos in bench/refs/:
|
|
8
|
+
* - node-sdk (TypeScript, vercel/ai subset)
|
|
9
|
+
* - python-lib (Python, pandas subset)
|
|
10
|
+
* - rust-project (Rust, tokio subset)
|
|
11
|
+
*
|
|
12
|
+
* For each repo, calls runBenchmark() from scripts/run-benchmark.ts, then
|
|
13
|
+
* aggregates per-repo results into docs/benchmarks-v2.json with new sections:
|
|
14
|
+
* - byRepo: per-repo meanRatio and per-tool breakdown
|
|
15
|
+
* - byLanguage: per-language meanRatio (ts/py/rs)
|
|
16
|
+
* - crossLanguageMean: arithmetic mean across all 3 repos (the headline number)
|
|
17
|
+
*
|
|
18
|
+
* Extends the existing schema — the original samples/aggregate fields are
|
|
19
|
+
* preserved from the existing benchmarks-v2.json (plugin-self benchmark).
|
|
20
|
+
*
|
|
21
|
+
* Usage:
|
|
22
|
+
* bun run scripts/benchmark-refs.ts
|
|
23
|
+
* bun run scripts/benchmark-refs.ts --out /tmp/bench-refs.json
|
|
24
|
+
* bun run scripts/benchmark-refs.ts --dry-run
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
28
|
+
import { resolve, dirname } from "path";
|
|
29
|
+
import { fileURLToPath } from "url";
|
|
30
|
+
import { spawnSync } from "child_process";
|
|
31
|
+
|
|
32
|
+
import { runBenchmark } from "./run-benchmark";
|
|
33
|
+
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Debug logging — gated behind ASHLR_DEBUG (matches servers/_stats-sqlite.ts).
|
|
36
|
+
// Set ASHLR_DEBUG=1 (or any truthy value) to see phase/setup chatter.
|
|
37
|
+
// Primary CLI output (per-repo savings + headline result) is always emitted.
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
function debugLog(...args: unknown[]): void {
|
|
40
|
+
if (process.env.ASHLR_DEBUG) {
|
|
41
|
+
console.log(...args);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Types
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
export interface RefRepoResult {
|
|
50
|
+
repoKey: string;
|
|
51
|
+
language: string;
|
|
52
|
+
upstreamRepo: string;
|
|
53
|
+
refrev: string;
|
|
54
|
+
meanRatio: number; // 0–1; lower = more savings
|
|
55
|
+
savingsPct: number; // (1 - meanRatio) * 100
|
|
56
|
+
perTool: {
|
|
57
|
+
read: { mean: number; p50: number; p90: number };
|
|
58
|
+
grep: { mean: number; p50: number; p90: number };
|
|
59
|
+
edit: { mean: number; p50: number; p90: number };
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface MultiRepoBenchmarkSections {
|
|
64
|
+
crossLanguageMeasuredAt: string;
|
|
65
|
+
byRepo: Record<string, RefRepoResult>;
|
|
66
|
+
byLanguage: Record<string, { language: string; meanRatio: number; savingsPct: number }>;
|
|
67
|
+
crossLanguageMean: number; // ratio, 0–1
|
|
68
|
+
crossLanguageSavingsPct: number; // (1 - crossLanguageMean) * 100
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// Reference repo configuration
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
interface RefConfig {
|
|
76
|
+
key: string;
|
|
77
|
+
language: string;
|
|
78
|
+
upstreamRepo: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const REFS: RefConfig[] = [
|
|
82
|
+
{
|
|
83
|
+
key: "node-sdk",
|
|
84
|
+
language: "ts",
|
|
85
|
+
upstreamRepo: "github.com/vercel/ai",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
key: "python-lib",
|
|
89
|
+
language: "py",
|
|
90
|
+
upstreamRepo: "github.com/pandas-dev/pandas",
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
key: "rust-project",
|
|
94
|
+
language: "rs",
|
|
95
|
+
upstreamRepo: "github.com/tokio-rs/tokio",
|
|
96
|
+
},
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// CLI args
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
interface Args {
|
|
104
|
+
out: string;
|
|
105
|
+
dryRun: boolean;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function parseArgs(argv: string[]): Args {
|
|
109
|
+
const pluginRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
110
|
+
const args: Args = {
|
|
111
|
+
out: resolve(pluginRoot, "docs/benchmarks-v2.json"),
|
|
112
|
+
dryRun: false,
|
|
113
|
+
};
|
|
114
|
+
for (let i = 0; i < argv.length; i++) {
|
|
115
|
+
if (argv[i] === "--out" && argv[i + 1]) args.out = resolve(argv[++i]!);
|
|
116
|
+
else if (argv[i] === "--dry-run") args.dryRun = true;
|
|
117
|
+
}
|
|
118
|
+
return args;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
// Helpers
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
|
|
125
|
+
function readRefrev(refDir: string): string {
|
|
126
|
+
const p = resolve(refDir, ".refrev");
|
|
127
|
+
if (!existsSync(p)) return "unknown";
|
|
128
|
+
return readFileSync(p, "utf-8").trim();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
// Ensure a directory is a git repo (init + commit if needed)
|
|
133
|
+
// ---------------------------------------------------------------------------
|
|
134
|
+
|
|
135
|
+
function ensureGitRepo(dir: string): void {
|
|
136
|
+
const gitDir = resolve(dir, ".git");
|
|
137
|
+
if (existsSync(gitDir)) return; // already a git repo
|
|
138
|
+
|
|
139
|
+
debugLog(`[benchmark-refs] git init ${dir}`);
|
|
140
|
+
spawnSync("git", ["init"], { cwd: dir });
|
|
141
|
+
spawnSync("git", ["config", "user.email", "bench@ashlr.ai"], { cwd: dir });
|
|
142
|
+
spawnSync("git", ["config", "user.name", "ashlr-bench"], { cwd: dir });
|
|
143
|
+
spawnSync("git", ["add", "."], { cwd: dir });
|
|
144
|
+
spawnSync("git", ["commit", "--allow-empty", "-m", "bench-init", "--author", "ashlr-bench <bench@ashlr.ai>"], {
|
|
145
|
+
cwd: dir,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
// Core aggregation (exported for tests)
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
|
|
153
|
+
export async function runRefsBenchmark(opts: {
|
|
154
|
+
pluginRoot: string;
|
|
155
|
+
out: string;
|
|
156
|
+
dryRun: boolean;
|
|
157
|
+
/** Override ref dirs for testing */
|
|
158
|
+
refOverrides?: Record<string, string>;
|
|
159
|
+
}): Promise<MultiRepoBenchmarkSections> {
|
|
160
|
+
const { pluginRoot, out, dryRun, refOverrides } = opts;
|
|
161
|
+
const refsBaseDir = resolve(pluginRoot, "bench/refs");
|
|
162
|
+
|
|
163
|
+
const byRepo: Record<string, RefRepoResult> = {};
|
|
164
|
+
const tmpDir = resolve(pluginRoot, "tmp-bench-refs");
|
|
165
|
+
|
|
166
|
+
for (const ref of REFS) {
|
|
167
|
+
const refDir = refOverrides?.[ref.key] ?? resolve(refsBaseDir, ref.key);
|
|
168
|
+
|
|
169
|
+
if (!existsSync(refDir)) {
|
|
170
|
+
console.warn(`[benchmark-refs] SKIP ${ref.key}: directory not found at ${refDir}`);
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const tmpOut = resolve(tmpDir, `${ref.key}.json`);
|
|
175
|
+
// Ensure tmp dir exists
|
|
176
|
+
const { mkdirSync } = await import("fs");
|
|
177
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
178
|
+
|
|
179
|
+
debugLog(`\n[benchmark-refs] === ${ref.key} (${ref.language}) ===`);
|
|
180
|
+
// Ref dirs are committed as plain directories (no .git); init on first run.
|
|
181
|
+
ensureGitRepo(refDir);
|
|
182
|
+
const result = await runBenchmark({ repo: refDir, out: tmpOut, dryRun: true });
|
|
183
|
+
|
|
184
|
+
const refrev = readRefrev(refDir);
|
|
185
|
+
const perTool: RefRepoResult["perTool"] = {
|
|
186
|
+
read: result.aggregate["ashlr__read"],
|
|
187
|
+
grep: result.aggregate["ashlr__grep"],
|
|
188
|
+
edit: result.aggregate["ashlr__edit"],
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const meanRatio = result.aggregate.overall.mean;
|
|
192
|
+
byRepo[ref.key] = {
|
|
193
|
+
repoKey: ref.key,
|
|
194
|
+
language: ref.language,
|
|
195
|
+
upstreamRepo: ref.upstreamRepo,
|
|
196
|
+
refrev,
|
|
197
|
+
meanRatio,
|
|
198
|
+
savingsPct: (1 - meanRatio) * 100,
|
|
199
|
+
perTool,
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
console.log(
|
|
203
|
+
`[benchmark-refs] ${ref.key}: overall −${((1 - meanRatio) * 100).toFixed(1)}% ` +
|
|
204
|
+
`read −${((1 - perTool.read.mean) * 100).toFixed(1)}% ` +
|
|
205
|
+
`grep −${((1 - perTool.grep.mean) * 100).toFixed(1)}% ` +
|
|
206
|
+
`edit −${((1 - perTool.edit.mean) * 100).toFixed(1)}%`,
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ---------------------------------------------------------------------------
|
|
211
|
+
// byLanguage: map language code → mean ratio (weighted by repo count, 1:1 here)
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
const byLanguage: MultiRepoBenchmarkSections["byLanguage"] = {};
|
|
214
|
+
for (const ref of REFS) {
|
|
215
|
+
const r = byRepo[ref.key];
|
|
216
|
+
if (!r) continue;
|
|
217
|
+
byLanguage[ref.language] = {
|
|
218
|
+
language: ref.language,
|
|
219
|
+
meanRatio: r.meanRatio,
|
|
220
|
+
savingsPct: r.savingsPct,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// ---------------------------------------------------------------------------
|
|
225
|
+
// crossLanguageMean: arithmetic mean of the 3 repo overall means
|
|
226
|
+
// ---------------------------------------------------------------------------
|
|
227
|
+
const repoMeans = Object.values(byRepo).map((r) => r.meanRatio);
|
|
228
|
+
const crossLanguageMean =
|
|
229
|
+
repoMeans.length > 0 ? repoMeans.reduce((s, r) => s + r, 0) / repoMeans.length : 1;
|
|
230
|
+
const crossLanguageSavingsPct = (1 - crossLanguageMean) * 100;
|
|
231
|
+
|
|
232
|
+
const sections: MultiRepoBenchmarkSections = {
|
|
233
|
+
crossLanguageMeasuredAt: new Date().toISOString(),
|
|
234
|
+
byRepo,
|
|
235
|
+
byLanguage,
|
|
236
|
+
crossLanguageMean,
|
|
237
|
+
crossLanguageSavingsPct,
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
// Merge into existing benchmarks-v2.json
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
if (!dryRun) {
|
|
244
|
+
let existing: Record<string, unknown> = {};
|
|
245
|
+
if (existsSync(out)) {
|
|
246
|
+
try {
|
|
247
|
+
existing = JSON.parse(readFileSync(out, "utf-8")) as Record<string, unknown>;
|
|
248
|
+
} catch {
|
|
249
|
+
console.warn(`[benchmark-refs] could not parse existing ${out}, overwriting`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const merged = {
|
|
254
|
+
...existing,
|
|
255
|
+
...sections,
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
writeFileSync(out, JSON.stringify(merged, null, 2), "utf-8");
|
|
259
|
+
console.log(`\n[benchmark-refs] wrote ${out}`);
|
|
260
|
+
} else {
|
|
261
|
+
console.log("\n[benchmark-refs] --dry-run: skipping file write");
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
console.log(`\n[benchmark-refs] CROSS-LANGUAGE RESULT:`);
|
|
265
|
+
console.log(
|
|
266
|
+
`[benchmark-refs] crossLanguageMean −${crossLanguageSavingsPct.toFixed(1)}%` +
|
|
267
|
+
` (ts −${((1 - (byLanguage["ts"]?.meanRatio ?? 1)) * 100).toFixed(1)}%,` +
|
|
268
|
+
` py −${((1 - (byLanguage["py"]?.meanRatio ?? 1)) * 100).toFixed(1)}%,` +
|
|
269
|
+
` rs −${((1 - (byLanguage["rs"]?.meanRatio ?? 1)) * 100).toFixed(1)}%)`,
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
return sections;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// ---------------------------------------------------------------------------
|
|
276
|
+
// Main
|
|
277
|
+
// ---------------------------------------------------------------------------
|
|
278
|
+
|
|
279
|
+
if (import.meta.main) {
|
|
280
|
+
const args = parseArgs(process.argv.slice(2));
|
|
281
|
+
const pluginRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
282
|
+
|
|
283
|
+
try {
|
|
284
|
+
await runRefsBenchmark({ pluginRoot, out: args.out, dryRun: args.dryRun });
|
|
285
|
+
} catch (err) {
|
|
286
|
+
console.error(
|
|
287
|
+
"[benchmark-refs] ERROR:",
|
|
288
|
+
err instanceof Error ? err.message : String(err),
|
|
289
|
+
);
|
|
290
|
+
process.exit(1);
|
|
291
|
+
}
|
|
292
|
+
}
|