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,479 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* _genome-search.ts — Inverted-index layer over .ashlrcode/genome/knowledge/*.md
|
|
3
|
+
*
|
|
4
|
+
* Builds a token → sections map from the genome knowledge corpus. The index
|
|
5
|
+
* is cached to ~/.ashlr/genome-index-<repoSha>.cache (JSON) and invalidated
|
|
6
|
+
* when the genome dir's mtime, file count, or sample filenames change.
|
|
7
|
+
*
|
|
8
|
+
* Design constraints:
|
|
9
|
+
* - Pure mechanical — zero LLM calls.
|
|
10
|
+
* - Build cost < 50ms for the 248KB corpus.
|
|
11
|
+
* - Thread-safe via a simple per-repoRoot in-process singleton.
|
|
12
|
+
* - Never throws — callers should degrade gracefully on index failure.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { createHash } from "crypto";
|
|
16
|
+
import {
|
|
17
|
+
existsSync,
|
|
18
|
+
mkdirSync,
|
|
19
|
+
readFileSync,
|
|
20
|
+
statSync,
|
|
21
|
+
writeFileSync,
|
|
22
|
+
} from "fs";
|
|
23
|
+
import { readdirSync } from "fs";
|
|
24
|
+
import { homedir } from "os";
|
|
25
|
+
import { dirname, join } from "path";
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Public types
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
export interface GenomeSearchResult {
|
|
32
|
+
/** The section header (e.g. "## Architecture decisions") */
|
|
33
|
+
section: string;
|
|
34
|
+
/** Absolute path to the .md file */
|
|
35
|
+
file: string;
|
|
36
|
+
/** 1-based line number of the section header */
|
|
37
|
+
line: number;
|
|
38
|
+
/** First non-empty content line(s) of the section (up to 200 chars) */
|
|
39
|
+
snippet: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface GenomeSearchIndex {
|
|
43
|
+
lookup(pattern: string | RegExp): GenomeSearchResult[];
|
|
44
|
+
isComplete(): boolean;
|
|
45
|
+
invalidate(): void;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// Internal types
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
|
|
52
|
+
interface IndexEntry {
|
|
53
|
+
token: string;
|
|
54
|
+
results: GenomeSearchResult[];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface CacheShape {
|
|
58
|
+
/** Fingerprint of the genome dir state when this cache was built. */
|
|
59
|
+
fingerprint: string;
|
|
60
|
+
/** Map of lowercased token → results. Stored as entries array for JSON. */
|
|
61
|
+
entries: IndexEntry[];
|
|
62
|
+
builtAt: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface InMemoryIndex {
|
|
66
|
+
fingerprint: string;
|
|
67
|
+
map: Map<string, GenomeSearchResult[]>;
|
|
68
|
+
complete: boolean;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// Constants
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
const CACHE_DIR = join(process.env.HOME ?? homedir(), ".ashlr");
|
|
76
|
+
const MIN_TOKEN_LEN = 3;
|
|
77
|
+
const MAX_SNIPPET_LEN = 200;
|
|
78
|
+
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Fingerprinting
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Compute a cheap fingerprint of the genome knowledge dir:
|
|
85
|
+
* SHA-256 of (total mtime of all md files + file count + sorted filenames sample)
|
|
86
|
+
*/
|
|
87
|
+
function fingerprintGenomeDir(knowledgeDir: string): string {
|
|
88
|
+
try {
|
|
89
|
+
if (!existsSync(knowledgeDir)) return "empty";
|
|
90
|
+
const files = listMdFiles(knowledgeDir);
|
|
91
|
+
if (files.length === 0) return "empty";
|
|
92
|
+
let mtimeSum = 0;
|
|
93
|
+
for (const f of files) {
|
|
94
|
+
try {
|
|
95
|
+
mtimeSum += statSync(f).mtimeMs;
|
|
96
|
+
} catch {
|
|
97
|
+
// ignore
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const sampleNames = files
|
|
101
|
+
.slice(0, 10)
|
|
102
|
+
.map((f) => f.split("/").pop() ?? "")
|
|
103
|
+
.sort()
|
|
104
|
+
.join("|");
|
|
105
|
+
const raw = `${mtimeSum}:${files.length}:${sampleNames}`;
|
|
106
|
+
return createHash("sha256").update(raw).digest("hex").slice(0, 16);
|
|
107
|
+
} catch {
|
|
108
|
+
return "error";
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function listMdFiles(dir: string): string[] {
|
|
113
|
+
const results: string[] = [];
|
|
114
|
+
try {
|
|
115
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
116
|
+
for (const e of entries) {
|
|
117
|
+
const full = join(dir, e.name);
|
|
118
|
+
if (e.isDirectory()) {
|
|
119
|
+
results.push(...listMdFiles(full));
|
|
120
|
+
} else if (e.isFile() && e.name.endsWith(".md")) {
|
|
121
|
+
results.push(full);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
} catch {
|
|
125
|
+
// ignore unreadable dirs
|
|
126
|
+
}
|
|
127
|
+
return results.sort();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
// Cache path (per-repo, keyed by SHA of repo root path)
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
function cachePathFor(repoRoot: string): string {
|
|
135
|
+
const repoSha = createHash("sha256").update(repoRoot).digest("hex").slice(0, 12);
|
|
136
|
+
return join(CACHE_DIR, `genome-index-${repoSha}.cache`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
// Index building
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Parse a single .md file into sections. Each section starts at a `##` header
|
|
145
|
+
* (we skip `#` top-level titles). Returns array of parsed sections.
|
|
146
|
+
*/
|
|
147
|
+
function parseMdSections(
|
|
148
|
+
filePath: string,
|
|
149
|
+
): Array<{ header: string; line: number; body: string }> {
|
|
150
|
+
let raw: string;
|
|
151
|
+
try {
|
|
152
|
+
raw = readFileSync(filePath, "utf-8");
|
|
153
|
+
} catch {
|
|
154
|
+
return [];
|
|
155
|
+
}
|
|
156
|
+
const lines = raw.split("\n");
|
|
157
|
+
const sections: Array<{ header: string; line: number; body: string }> = [];
|
|
158
|
+
let current: { header: string; line: number; bodyLines: string[] } | null = null;
|
|
159
|
+
|
|
160
|
+
for (let i = 0; i < lines.length; i++) {
|
|
161
|
+
const line = lines[i]!;
|
|
162
|
+
// Match ## or deeper headers
|
|
163
|
+
if (/^#{2,}\s+/.test(line)) {
|
|
164
|
+
if (current) {
|
|
165
|
+
sections.push({
|
|
166
|
+
header: current.header,
|
|
167
|
+
line: current.line,
|
|
168
|
+
body: current.bodyLines.join("\n"),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
current = { header: line.replace(/^#+\s+/, "").trim(), line: i + 1, bodyLines: [] };
|
|
172
|
+
} else if (current) {
|
|
173
|
+
current.bodyLines.push(line);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (current) {
|
|
177
|
+
sections.push({
|
|
178
|
+
header: current.header,
|
|
179
|
+
line: current.line,
|
|
180
|
+
body: current.bodyLines.join("\n"),
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
return sections;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Tokenize a string into lowercase alpha-numeric tokens of length >= MIN_TOKEN_LEN.
|
|
188
|
+
*/
|
|
189
|
+
function tokenize(text: string): string[] {
|
|
190
|
+
return text
|
|
191
|
+
.toLowerCase()
|
|
192
|
+
.split(/[^a-z0-9_\-]+/)
|
|
193
|
+
.filter((t) => t.length >= MIN_TOKEN_LEN);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function extractSnippet(body: string): string {
|
|
197
|
+
const firstMeaningfulLine = body
|
|
198
|
+
.split("\n")
|
|
199
|
+
.map((l) => l.trim())
|
|
200
|
+
.find((l) => l.length > 0 && !l.startsWith("#") && !l.startsWith("```"));
|
|
201
|
+
if (!firstMeaningfulLine) return "";
|
|
202
|
+
return firstMeaningfulLine.slice(0, MAX_SNIPPET_LEN);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Build the full inverted index from the knowledge dir.
|
|
207
|
+
* Returns a Map<token, GenomeSearchResult[]>.
|
|
208
|
+
*/
|
|
209
|
+
function buildIndex(knowledgeDir: string): Map<string, GenomeSearchResult[]> {
|
|
210
|
+
const map = new Map<string, GenomeSearchResult[]>();
|
|
211
|
+
const files = listMdFiles(knowledgeDir);
|
|
212
|
+
|
|
213
|
+
for (const file of files) {
|
|
214
|
+
const sections = parseMdSections(file);
|
|
215
|
+
for (const sec of sections) {
|
|
216
|
+
const result: GenomeSearchResult = {
|
|
217
|
+
section: sec.header,
|
|
218
|
+
file,
|
|
219
|
+
line: sec.line,
|
|
220
|
+
snippet: extractSnippet(sec.body),
|
|
221
|
+
};
|
|
222
|
+
// Index tokens from both header and body
|
|
223
|
+
const tokens = new Set([
|
|
224
|
+
...tokenize(sec.header),
|
|
225
|
+
...tokenize(sec.body),
|
|
226
|
+
]);
|
|
227
|
+
for (const token of tokens) {
|
|
228
|
+
const existing = map.get(token);
|
|
229
|
+
if (existing) {
|
|
230
|
+
existing.push(result);
|
|
231
|
+
} else {
|
|
232
|
+
map.set(token, [result]);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return map;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
// Cache persistence
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
|
|
244
|
+
function loadCache(cachePath: string): CacheShape | null {
|
|
245
|
+
try {
|
|
246
|
+
if (!existsSync(cachePath)) return null;
|
|
247
|
+
const raw = readFileSync(cachePath, "utf-8");
|
|
248
|
+
return JSON.parse(raw) as CacheShape;
|
|
249
|
+
} catch {
|
|
250
|
+
return null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function saveCache(cachePath: string, fingerprint: string, map: Map<string, GenomeSearchResult[]>): void {
|
|
255
|
+
try {
|
|
256
|
+
mkdirSync(dirname(cachePath), { recursive: true });
|
|
257
|
+
const entries: IndexEntry[] = [];
|
|
258
|
+
for (const [token, results] of map.entries()) {
|
|
259
|
+
entries.push({ token, results });
|
|
260
|
+
}
|
|
261
|
+
const shape: CacheShape = {
|
|
262
|
+
fingerprint,
|
|
263
|
+
entries,
|
|
264
|
+
builtAt: Date.now(),
|
|
265
|
+
};
|
|
266
|
+
writeFileSync(cachePath, JSON.stringify(shape), "utf-8");
|
|
267
|
+
} catch {
|
|
268
|
+
// Cache write failure is non-fatal — index is still usable in memory.
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function cacheToMap(cache: CacheShape): Map<string, GenomeSearchResult[]> {
|
|
273
|
+
const map = new Map<string, GenomeSearchResult[]>();
|
|
274
|
+
for (const entry of cache.entries) {
|
|
275
|
+
map.set(entry.token, entry.results);
|
|
276
|
+
}
|
|
277
|
+
return map;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// ---------------------------------------------------------------------------
|
|
281
|
+
// Per-repoRoot singleton registry
|
|
282
|
+
// ---------------------------------------------------------------------------
|
|
283
|
+
|
|
284
|
+
const _indexRegistry = new Map<string, InMemoryIndex>();
|
|
285
|
+
|
|
286
|
+
function getOrBuildIndex(repoRoot: string): InMemoryIndex {
|
|
287
|
+
const knowledgeDir = join(repoRoot, ".ashlrcode", "genome", "knowledge");
|
|
288
|
+
const fingerprint = fingerprintGenomeDir(knowledgeDir);
|
|
289
|
+
const cachePath = cachePathFor(repoRoot);
|
|
290
|
+
|
|
291
|
+
const existing = _indexRegistry.get(repoRoot);
|
|
292
|
+
if (existing && existing.fingerprint === fingerprint && existing.complete) {
|
|
293
|
+
return existing;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Try loading from disk cache.
|
|
297
|
+
const cached = loadCache(cachePath);
|
|
298
|
+
if (cached && cached.fingerprint === fingerprint) {
|
|
299
|
+
const map = cacheToMap(cached);
|
|
300
|
+
const idx: InMemoryIndex = { fingerprint, map, complete: true };
|
|
301
|
+
_indexRegistry.set(repoRoot, idx);
|
|
302
|
+
return idx;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Cache miss or stale — rebuild.
|
|
306
|
+
const map = buildIndex(knowledgeDir);
|
|
307
|
+
saveCache(cachePath, fingerprint, map);
|
|
308
|
+
const idx: InMemoryIndex = { fingerprint, map, complete: true };
|
|
309
|
+
_indexRegistry.set(repoRoot, idx);
|
|
310
|
+
return idx;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// ---------------------------------------------------------------------------
|
|
314
|
+
// Public API
|
|
315
|
+
// ---------------------------------------------------------------------------
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Deduplicate results by (file, line) to avoid returning the same section
|
|
319
|
+
* multiple times when multiple tokens from a pattern match it.
|
|
320
|
+
*/
|
|
321
|
+
function dedupeResults(results: GenomeSearchResult[]): GenomeSearchResult[] {
|
|
322
|
+
const seen = new Set<string>();
|
|
323
|
+
return results.filter((r) => {
|
|
324
|
+
const key = `${r.file}:${r.line}`;
|
|
325
|
+
if (seen.has(key)) return false;
|
|
326
|
+
seen.add(key);
|
|
327
|
+
return true;
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* v1.34: TF-IDF re-ranking using the inverted index's own token frequencies.
|
|
333
|
+
* IDF = log((N+1)/(df+1)) + 1 (BM25-style smoothed, N = total distinct tokens).
|
|
334
|
+
* Additive: empty/cold corpus (map.size===0) → all scores 0 → original order preserved.
|
|
335
|
+
* Also expands camelCase/snake_case query tokens for better single-token coverage.
|
|
336
|
+
*/
|
|
337
|
+
function tfidfRerank(
|
|
338
|
+
results: GenomeSearchResult[],
|
|
339
|
+
queryTokens: string[],
|
|
340
|
+
indexMap: Map<string, GenomeSearchResult[]>,
|
|
341
|
+
): GenomeSearchResult[] {
|
|
342
|
+
if (results.length <= 1 || queryTokens.length === 0 || indexMap.size === 0) return results;
|
|
343
|
+
|
|
344
|
+
// Expand: camelCase + snake_case → sub-tokens
|
|
345
|
+
const expandedTokens = new Set<string>();
|
|
346
|
+
for (const t of queryTokens) {
|
|
347
|
+
expandedTokens.add(t);
|
|
348
|
+
for (const p of t.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase().split(/\s+/))
|
|
349
|
+
if (p.length >= 3) expandedTokens.add(p);
|
|
350
|
+
for (const p of t.split("_")) if (p.length >= 3) expandedTokens.add(p.toLowerCase());
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const N = indexMap.size; // total distinct tokens as doc-count proxy
|
|
354
|
+
const scores = new Map<string, number>();
|
|
355
|
+
for (const token of expandedTokens) {
|
|
356
|
+
const postings = indexMap.get(token);
|
|
357
|
+
if (!postings || postings.length === 0) continue;
|
|
358
|
+
const idf = Math.log((N + 1) / (postings.length + 1)) + 1;
|
|
359
|
+
const postingKeys = new Set(postings.map((r) => `${r.file}:${r.line}`));
|
|
360
|
+
for (const r of results) {
|
|
361
|
+
const key = `${r.file}:${r.line}`;
|
|
362
|
+
if (postingKeys.has(key)) scores.set(key, (scores.get(key) ?? 0) + idf);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return results.slice().sort((a, b) => {
|
|
367
|
+
const sa = scores.get(`${a.file}:${a.line}`) ?? 0;
|
|
368
|
+
const sb = scores.get(`${b.file}:${b.line}`) ?? 0;
|
|
369
|
+
return sb - sa; // ties preserve original (stable sort)
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export function getGenomeSearchIndex(repoRoot: string): GenomeSearchIndex {
|
|
374
|
+
return {
|
|
375
|
+
lookup(pattern: string | RegExp): GenomeSearchResult[] {
|
|
376
|
+
try {
|
|
377
|
+
const idx = getOrBuildIndex(repoRoot);
|
|
378
|
+
const results: GenomeSearchResult[] = [];
|
|
379
|
+
|
|
380
|
+
if (pattern instanceof RegExp) {
|
|
381
|
+
// For RegExp: scan all tokens whose key matches the pattern, or
|
|
382
|
+
// do a full scan of all results for content matching.
|
|
383
|
+
for (const [token, entries] of idx.map.entries()) {
|
|
384
|
+
if (pattern.test(token)) {
|
|
385
|
+
results.push(...entries);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
// Also filter by testing snippet + section against the regex
|
|
389
|
+
const byContent: GenomeSearchResult[] = [];
|
|
390
|
+
const seen = new Set<string>();
|
|
391
|
+
for (const [, entries] of idx.map.entries()) {
|
|
392
|
+
for (const entry of entries) {
|
|
393
|
+
const key = `${entry.file}:${entry.line}`;
|
|
394
|
+
if (seen.has(key)) continue;
|
|
395
|
+
if (pattern.test(entry.section) || pattern.test(entry.snippet)) {
|
|
396
|
+
seen.add(key);
|
|
397
|
+
byContent.push(entry);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
results.push(...byContent);
|
|
402
|
+
} else {
|
|
403
|
+
// String pattern: tokenize it, then intersect (AND semantics for
|
|
404
|
+
// multi-token patterns; OR fallback for single token).
|
|
405
|
+
const tokens = tokenize(pattern);
|
|
406
|
+
if (tokens.length === 0) return [];
|
|
407
|
+
|
|
408
|
+
if (tokens.length === 1) {
|
|
409
|
+
const token = tokens[0]!;
|
|
410
|
+
// Exact match first, then prefix match.
|
|
411
|
+
const exact = idx.map.get(token) ?? [];
|
|
412
|
+
results.push(...exact);
|
|
413
|
+
// Also search for the raw pattern as substring in section/snippet
|
|
414
|
+
const lower = pattern.toLowerCase();
|
|
415
|
+
for (const [, entries] of idx.map.entries()) {
|
|
416
|
+
for (const entry of entries) {
|
|
417
|
+
if (
|
|
418
|
+
entry.section.toLowerCase().includes(lower) ||
|
|
419
|
+
entry.snippet.toLowerCase().includes(lower)
|
|
420
|
+
) {
|
|
421
|
+
results.push(entry);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
} else {
|
|
426
|
+
// Multi-token: find results that appear in ALL token sets (AND).
|
|
427
|
+
const sets = tokens.map((t) => new Set((idx.map.get(t) ?? []).map((r) => `${r.file}:${r.line}`)));
|
|
428
|
+
const intersection = sets.reduce((a, b) => new Set([...a].filter((x) => b.has(x))));
|
|
429
|
+
for (const key of intersection) {
|
|
430
|
+
// Retrieve one result for this key from any set.
|
|
431
|
+
const entry = (idx.map.get(tokens[0]!) ?? []).find((r) => `${r.file}:${r.line}` === key);
|
|
432
|
+
if (entry) results.push(entry);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const deduped = dedupeResults(results);
|
|
438
|
+
// v1.34: TF-IDF re-rank for string queries (RegExp keeps document order).
|
|
439
|
+
if (typeof pattern === "string") {
|
|
440
|
+
const qTokens = tokenize(pattern);
|
|
441
|
+
return tfidfRerank(deduped, qTokens, idx.map);
|
|
442
|
+
}
|
|
443
|
+
return deduped;
|
|
444
|
+
} catch {
|
|
445
|
+
return [];
|
|
446
|
+
}
|
|
447
|
+
},
|
|
448
|
+
|
|
449
|
+
isComplete(): boolean {
|
|
450
|
+
const existing = _indexRegistry.get(repoRoot);
|
|
451
|
+
return existing?.complete ?? false;
|
|
452
|
+
},
|
|
453
|
+
|
|
454
|
+
invalidate(): void {
|
|
455
|
+
_indexRegistry.delete(repoRoot);
|
|
456
|
+
// Also remove disk cache.
|
|
457
|
+
try {
|
|
458
|
+
const cachePath = cachePathFor(repoRoot);
|
|
459
|
+
if (existsSync(cachePath)) {
|
|
460
|
+
require("fs").unlinkSync(cachePath);
|
|
461
|
+
}
|
|
462
|
+
} catch {
|
|
463
|
+
// best-effort
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// ---------------------------------------------------------------------------
|
|
470
|
+
// Warm-start helper — called once on server startup (fire-and-forget)
|
|
471
|
+
// ---------------------------------------------------------------------------
|
|
472
|
+
|
|
473
|
+
export function warmGenomeIndex(repoRoot: string): void {
|
|
474
|
+
try {
|
|
475
|
+
getOrBuildIndex(repoRoot);
|
|
476
|
+
} catch {
|
|
477
|
+
// warmup must never throw
|
|
478
|
+
}
|
|
479
|
+
}
|