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,357 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* _ast-refactor/extract-function.ts — AST-aware extract-function operation.
|
|
3
|
+
*
|
|
4
|
+
* Exports:
|
|
5
|
+
* planExtractFunction — plan a byte-range extract into a new function
|
|
6
|
+
*
|
|
7
|
+
* Three shapes of extract (v1.18.1):
|
|
8
|
+
* 1. Single expression → `function extracted() { return <expr>; }` +
|
|
9
|
+
* call site replaces range with `extracted(args)`.
|
|
10
|
+
* 2. Statements whose internals are not read after the range → no return;
|
|
11
|
+
* call site becomes `extracted(args);` (bare expression statement).
|
|
12
|
+
* 3. Statements where exactly one value declared-or-written-inside is read
|
|
13
|
+
* later in the enclosing scope → `return x;` and call site
|
|
14
|
+
* `const x = extracted(args);` (or `let` if the binding was reassigned).
|
|
15
|
+
* Multiple outputs → `return { a, b };` + `const { a, b } = extracted(args);`.
|
|
16
|
+
*
|
|
17
|
+
* Constraints:
|
|
18
|
+
* - Refuses ranges containing `return`, `throw`, `await`, or `yield`.
|
|
19
|
+
* - Params are typed `unknown` (no type-checker).
|
|
20
|
+
* - Inserts extracted function BEFORE the enclosing top-level scope.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { extractIdentifiers, walkNodes } from "../_ast-helpers";
|
|
24
|
+
import type { ParseResult } from "../_ast-helpers";
|
|
25
|
+
import type Parser from "web-tree-sitter";
|
|
26
|
+
import {
|
|
27
|
+
validateIdentifier,
|
|
28
|
+
isDeclarationSite,
|
|
29
|
+
type RangeEdit,
|
|
30
|
+
} from "./_shared";
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Public types
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
export interface ExtractFunctionOptions {
|
|
37
|
+
newFunctionName: string;
|
|
38
|
+
/** Byte range of the expression/statement block to extract. */
|
|
39
|
+
start: number;
|
|
40
|
+
end: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface ExtractFunctionResult {
|
|
44
|
+
ok: boolean;
|
|
45
|
+
edits?: RangeEdit[];
|
|
46
|
+
source?: string;
|
|
47
|
+
reason?: string;
|
|
48
|
+
/** Soft warnings the caller should surface to the user (only set on ok:true). */
|
|
49
|
+
warnings?: string[];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Public API
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* File-local extract-function with return-value detection (v1.18.1).
|
|
58
|
+
*
|
|
59
|
+
* Outputs are always written as `const { a, b } = …` destructuring so the
|
|
60
|
+
* call-site stays readable. If the binding already existed and was only
|
|
61
|
+
* reassigned (not declared) inside the range, we emit `({ a, b } = …)` form
|
|
62
|
+
* instead to avoid redeclaration — flagged as a warning for now since we
|
|
63
|
+
* don't yet distinguish declaration vs. re-assignment rigorously.
|
|
64
|
+
*/
|
|
65
|
+
export function planExtractFunction(
|
|
66
|
+
parsed: ParseResult,
|
|
67
|
+
options: ExtractFunctionOptions,
|
|
68
|
+
): ExtractFunctionResult {
|
|
69
|
+
const { tree, source } = parsed;
|
|
70
|
+
const { newFunctionName, start, end } = options;
|
|
71
|
+
|
|
72
|
+
// Validate new function name
|
|
73
|
+
const nameErr = validateIdentifier(newFunctionName);
|
|
74
|
+
if (nameErr) return { ok: false, reason: nameErr };
|
|
75
|
+
|
|
76
|
+
if (start >= end) {
|
|
77
|
+
return { ok: false, reason: "extract range is empty (start >= end)" };
|
|
78
|
+
}
|
|
79
|
+
if (start < 0 || end > source.length) {
|
|
80
|
+
return { ok: false, reason: `extract range [${start}, ${end}] is out of source bounds` };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const body = source.slice(start, end);
|
|
84
|
+
|
|
85
|
+
if (/\breturn\b/.test(body)) {
|
|
86
|
+
return { ok: false, reason: "extracted range contains 'return' — extract does not support early returns from the target block" };
|
|
87
|
+
}
|
|
88
|
+
if (/\bthrow\b/.test(body)) {
|
|
89
|
+
return { ok: false, reason: "extracted range contains 'throw' — extract does not support throw statements" };
|
|
90
|
+
}
|
|
91
|
+
if (/\bawait\b/.test(body)) {
|
|
92
|
+
return { ok: false, reason: "extracted range contains 'await' — extract does not support async/await (the enclosing fn would need to become async too)" };
|
|
93
|
+
}
|
|
94
|
+
if (/\byield\b/.test(body)) {
|
|
95
|
+
return { ok: false, reason: "extracted range contains 'yield' — extract does not support generator yields" };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Find the smallest node that fully contains the range
|
|
99
|
+
let targetNode: Parser.SyntaxNode | null = null;
|
|
100
|
+
walkNodes(tree, (n) => {
|
|
101
|
+
if (n.startIndex <= start && n.endIndex >= end) {
|
|
102
|
+
if (targetNode === null || (n.endIndex - n.startIndex) < (targetNode.endIndex - targetNode.startIndex)) {
|
|
103
|
+
targetNode = n;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (!targetNode) {
|
|
109
|
+
return { ok: false, reason: "could not find an enclosing node for the given range" };
|
|
110
|
+
}
|
|
111
|
+
const tn = targetNode as Parser.SyntaxNode;
|
|
112
|
+
|
|
113
|
+
const EXPRESSION_TYPES = new Set([
|
|
114
|
+
"binary_expression", "call_expression", "member_expression",
|
|
115
|
+
"ternary_expression", "unary_expression", "update_expression",
|
|
116
|
+
"parenthesized_expression", "identifier", "property_identifier",
|
|
117
|
+
"number", "string", "template_string", "true", "false", "null",
|
|
118
|
+
"object", "array", "arrow_function", "new_expression",
|
|
119
|
+
"subscript_expression", "type_assertion", "as_expression",
|
|
120
|
+
"non_null_expression", "regex",
|
|
121
|
+
]);
|
|
122
|
+
const STATEMENT_TYPES = new Set([
|
|
123
|
+
"expression_statement", "lexical_declaration", "variable_declaration",
|
|
124
|
+
"if_statement", "for_statement", "for_in_statement", "while_statement",
|
|
125
|
+
"do_statement", "switch_statement", "try_statement", "block",
|
|
126
|
+
"statement_block", "assignment_expression",
|
|
127
|
+
]);
|
|
128
|
+
|
|
129
|
+
const isExpression = EXPRESSION_TYPES.has(tn.type);
|
|
130
|
+
const isStatementish = STATEMENT_TYPES.has(tn.type);
|
|
131
|
+
|
|
132
|
+
if (!isExpression && !isStatementish) {
|
|
133
|
+
return {
|
|
134
|
+
ok: false,
|
|
135
|
+
reason: `range encloses node type '${tn.type}' which is neither an expression nor a statement — extract not supported for this shape`,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// --- Identifier analysis ------------------------------------------------
|
|
140
|
+
const allRefs = extractIdentifiers(tree, source);
|
|
141
|
+
const refsInRange = allRefs.filter(
|
|
142
|
+
(r) => r.kind === "value" && r.range[0] >= start && r.range[1] <= end,
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
// Names declared/written inside the range (via variable declarators, assignments,
|
|
146
|
+
// destructuring patterns, parameter defaults etc.).
|
|
147
|
+
const declaredInRange = new Set<string>();
|
|
148
|
+
walkNodes(tree, (n) => {
|
|
149
|
+
if (n.startIndex < start || n.endIndex > end) return;
|
|
150
|
+
if (n.type === "identifier" && isDeclarationSite(n, "value")) {
|
|
151
|
+
declaredInRange.add(n.text);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
// Names written (assigned / updated) inside the range — captures non-declaration
|
|
155
|
+
// reassignment cases like `x = 5;` / `x += 1;`. We track both the declarations
|
|
156
|
+
// and these writes to decide what could possibly be "output" of the extracted fn.
|
|
157
|
+
const writtenInRange = new Set<string>(declaredInRange);
|
|
158
|
+
walkNodes(tree, (n) => {
|
|
159
|
+
if (n.startIndex < start || n.endIndex > end) return;
|
|
160
|
+
if (n.type === "assignment_expression") {
|
|
161
|
+
const lhs = n.childForFieldName ? n.childForFieldName("left") : n.namedChild(0);
|
|
162
|
+
if (lhs && lhs.type === "identifier") writtenInRange.add(lhs.text);
|
|
163
|
+
}
|
|
164
|
+
if (n.type === "update_expression") {
|
|
165
|
+
const arg = n.namedChild(0);
|
|
166
|
+
if (arg && arg.type === "identifier") writtenInRange.add(arg.text);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Parameters = identifiers referenced in range but not *declared* in range
|
|
171
|
+
// and not the new function name itself. (We use declaredInRange, not
|
|
172
|
+
// writtenInRange — a plain `x = 5` inside the range where `x` came from
|
|
173
|
+
// outside is an outer-scope reference; `x` must be a parameter AND an output.)
|
|
174
|
+
const paramNames = new Set<string>();
|
|
175
|
+
for (const ref of refsInRange) {
|
|
176
|
+
if (!declaredInRange.has(ref.name) && ref.name !== newFunctionName) {
|
|
177
|
+
paramNames.add(ref.name);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const params = [...paramNames].map((p) => `${p}: unknown`);
|
|
181
|
+
const paramCall = [...paramNames].join(", ");
|
|
182
|
+
|
|
183
|
+
// --- Return-value detection (statement form only) ----------------------
|
|
184
|
+
// Find the enclosing scope to check "used after range". Scope = nearest
|
|
185
|
+
// function/method body or root.
|
|
186
|
+
const enclosingScope = findEnclosingScope(tree, start, end);
|
|
187
|
+
const readsAfterRange = new Set<string>();
|
|
188
|
+
if (isStatementish && enclosingScope) {
|
|
189
|
+
const scopeStart = enclosingScope.startIndex;
|
|
190
|
+
const scopeEnd = enclosingScope.endIndex;
|
|
191
|
+
for (const ref of allRefs) {
|
|
192
|
+
if (ref.kind !== "value") continue;
|
|
193
|
+
if (ref.range[0] < end) continue; // must be AFTER the range
|
|
194
|
+
if (ref.range[0] >= scopeEnd) continue; // must be within enclosing scope
|
|
195
|
+
if (ref.range[0] < scopeStart) continue;
|
|
196
|
+
if (writtenInRange.has(ref.name)) {
|
|
197
|
+
// Skip if this "read" is itself a declaration site (e.g., re-declares
|
|
198
|
+
// the name in a later block) — that's not a real read.
|
|
199
|
+
readsAfterRange.add(ref.name);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Outputs that need to be returned from the extracted fn.
|
|
205
|
+
const outputs = [...readsAfterRange].sort();
|
|
206
|
+
const declaredOutputs = outputs.filter((n) => declaredInRange.has(n));
|
|
207
|
+
const reassignedOutputs = outputs.filter((n) => !declaredInRange.has(n));
|
|
208
|
+
|
|
209
|
+
// --- Build extracted function body ---------------------------------------
|
|
210
|
+
let funcBody: string;
|
|
211
|
+
let callSiteExpr: string;
|
|
212
|
+
const warnings: string[] = [];
|
|
213
|
+
|
|
214
|
+
if (isExpression) {
|
|
215
|
+
// Single expression extract — wrap in return.
|
|
216
|
+
funcBody = ` return ${body.trim()};`;
|
|
217
|
+
callSiteExpr = `${newFunctionName}(${paramCall})`;
|
|
218
|
+
} else if (outputs.length === 0) {
|
|
219
|
+
// Statement(s) with no outputs.
|
|
220
|
+
funcBody = body.replace(/^\n|\n$/g, "").split("\n").map((l) => " " + l).join("\n");
|
|
221
|
+
callSiteExpr = `${newFunctionName}(${paramCall})`;
|
|
222
|
+
} else if (outputs.length === 1) {
|
|
223
|
+
const name = outputs[0]!;
|
|
224
|
+
const indented = body.replace(/^\n|\n$/g, "").split("\n").map((l) => " " + l).join("\n");
|
|
225
|
+
funcBody = `${indented}\n return ${name};`;
|
|
226
|
+
if (declaredInRange.has(name)) {
|
|
227
|
+
callSiteExpr = `const ${name} = ${newFunctionName}(${paramCall})`;
|
|
228
|
+
} else {
|
|
229
|
+
// Variable is outer-scope — reassign via expression so no redeclare.
|
|
230
|
+
callSiteExpr = `${name} = ${newFunctionName}(${paramCall})`;
|
|
231
|
+
}
|
|
232
|
+
} else {
|
|
233
|
+
// Multiple outputs → object return.
|
|
234
|
+
const indented = body.replace(/^\n|\n$/g, "").split("\n").map((l) => " " + l).join("\n");
|
|
235
|
+
funcBody = `${indented}\n return { ${outputs.join(", ")} };`;
|
|
236
|
+
if (reassignedOutputs.length > 0 && declaredOutputs.length === 0) {
|
|
237
|
+
// All bindings pre-exist; destructure-assign.
|
|
238
|
+
callSiteExpr = `({ ${outputs.join(", ")} } = ${newFunctionName}(${paramCall}))`;
|
|
239
|
+
} else if (declaredOutputs.length === outputs.length) {
|
|
240
|
+
// All freshly declared inside range — safe to `const`-destructure.
|
|
241
|
+
callSiteExpr = `const { ${outputs.join(", ")} } = ${newFunctionName}(${paramCall})`;
|
|
242
|
+
} else {
|
|
243
|
+
// Mixed: some declared inside range, some outer-scope reassigned.
|
|
244
|
+
// A `const { a, b } = ...` destructure would shadow the outer-scope names
|
|
245
|
+
// of the reassigned bindings. Detect this and refuse rather than emit a
|
|
246
|
+
// silent advisory.
|
|
247
|
+
//
|
|
248
|
+
// Shadowing detector: for every name in reassignedOutputs, check whether
|
|
249
|
+
// it is already declared (or is a parameter) in the enclosing scope
|
|
250
|
+
// *outside* the extraction range. If so, `const { name } = ...` at the
|
|
251
|
+
// call site would introduce a new binding that shadows it.
|
|
252
|
+
const enclosingScopeBindings = new Set<string>();
|
|
253
|
+
if (enclosingScope) {
|
|
254
|
+
walkNodes(tree, (n) => {
|
|
255
|
+
// Only look at nodes inside the enclosing scope but outside the range
|
|
256
|
+
if (n.startIndex >= start && n.startIndex < end) return;
|
|
257
|
+
if (n.startIndex < enclosingScope.startIndex) return;
|
|
258
|
+
if (n.startIndex >= enclosingScope.endIndex) return;
|
|
259
|
+
if (n.type === "identifier" && isDeclarationSite(n, "value")) {
|
|
260
|
+
enclosingScopeBindings.add(n.text);
|
|
261
|
+
}
|
|
262
|
+
// Enclosing function parameters
|
|
263
|
+
if (
|
|
264
|
+
n.type === "identifier" &&
|
|
265
|
+
n.parent?.type === "formal_parameters"
|
|
266
|
+
) {
|
|
267
|
+
enclosingScopeBindings.add(n.text);
|
|
268
|
+
}
|
|
269
|
+
// Destructuring params: { a, b } in parameter position
|
|
270
|
+
if (
|
|
271
|
+
n.type === "identifier" &&
|
|
272
|
+
n.parent?.type === "shorthand_property_identifier_pattern"
|
|
273
|
+
) {
|
|
274
|
+
enclosingScopeBindings.add(n.text);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
const shadowedNames = reassignedOutputs.filter((n) => enclosingScopeBindings.has(n));
|
|
279
|
+
if (shadowedNames.length > 0) {
|
|
280
|
+
return {
|
|
281
|
+
ok: false,
|
|
282
|
+
reason: `extract-function: would shadow outer-scope binding${shadowedNames.length > 1 ? "s" : ""} [${shadowedNames.join(", ")}] — use destructure-assign form manually or rename the extracted outputs.`,
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
// No detected shadowing — emit const destructure and note the mixed shape.
|
|
286
|
+
callSiteExpr = `const { ${outputs.join(", ")} } = ${newFunctionName}(${paramCall})`;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Terminator: statement form needs a trailing `;`; expression-replacing
|
|
291
|
+
// form that's replacing an expression inside a larger expression shouldn't
|
|
292
|
+
// append one.
|
|
293
|
+
const replacement = isExpression ? callSiteExpr : `${callSiteExpr};`;
|
|
294
|
+
|
|
295
|
+
// --- Insert location ----------------------------------------------------
|
|
296
|
+
const root = tree.rootNode;
|
|
297
|
+
let insertBeforeNode: Parser.SyntaxNode | null = null;
|
|
298
|
+
for (let i = 0; i < root.childCount; i++) {
|
|
299
|
+
const child = root.child(i)!;
|
|
300
|
+
if (child.startIndex <= start && child.endIndex >= end) {
|
|
301
|
+
insertBeforeNode = child;
|
|
302
|
+
break;
|
|
303
|
+
}
|
|
304
|
+
if (child.startIndex > start) break;
|
|
305
|
+
}
|
|
306
|
+
const insertAt = insertBeforeNode ? insertBeforeNode.startIndex : 0;
|
|
307
|
+
|
|
308
|
+
const funcText = `function ${newFunctionName}(${params.join(", ")}) {\n${funcBody}\n}\n\n`;
|
|
309
|
+
|
|
310
|
+
const edits: RangeEdit[] = [
|
|
311
|
+
{ start: insertAt, end: insertAt, replacement: funcText },
|
|
312
|
+
{ start, end, replacement },
|
|
313
|
+
];
|
|
314
|
+
|
|
315
|
+
if (insertAt > start && insertAt < end) {
|
|
316
|
+
return { ok: false, reason: "internal error: insert point overlaps with extracted range" };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return { ok: true, edits, source, warnings };
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// ---------------------------------------------------------------------------
|
|
323
|
+
// findEnclosingScope
|
|
324
|
+
// ---------------------------------------------------------------------------
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Find the nearest enclosing function/method body or arrow function scope
|
|
328
|
+
* for a byte range. Used by extract-function to decide the "used after"
|
|
329
|
+
* analysis boundary. Falls back to the root.
|
|
330
|
+
*/
|
|
331
|
+
function findEnclosingScope(
|
|
332
|
+
tree: Parser.Tree,
|
|
333
|
+
start: number,
|
|
334
|
+
end: number,
|
|
335
|
+
): Parser.SyntaxNode {
|
|
336
|
+
const SCOPE_TYPES = new Set([
|
|
337
|
+
"function_declaration",
|
|
338
|
+
"function_expression",
|
|
339
|
+
"arrow_function",
|
|
340
|
+
"method_definition",
|
|
341
|
+
"generator_function_declaration",
|
|
342
|
+
"generator_function",
|
|
343
|
+
]);
|
|
344
|
+
let best: Parser.SyntaxNode = tree.rootNode;
|
|
345
|
+
let bestSize = Infinity;
|
|
346
|
+
walkNodes(tree, (n) => {
|
|
347
|
+
if (!SCOPE_TYPES.has(n.type)) return;
|
|
348
|
+
if (n.startIndex <= start && n.endIndex >= end) {
|
|
349
|
+
const size = n.endIndex - n.startIndex;
|
|
350
|
+
if (size < bestSize) {
|
|
351
|
+
best = n;
|
|
352
|
+
bestSize = size;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
return best;
|
|
357
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* _ast-refactor/file-local-rename.ts — File-local AST rename operations.
|
|
3
|
+
*
|
|
4
|
+
* Exports:
|
|
5
|
+
* planRenameInFile — load + parse + plan rename for a file path
|
|
6
|
+
* planRenameFromParsed — pure variant operating on a pre-parsed tree (test-friendly)
|
|
7
|
+
*
|
|
8
|
+
* Invariants:
|
|
9
|
+
* - Never writes the file. Returns byte-range edits; the caller applies them.
|
|
10
|
+
* - Always refuses rather than producing a subtly-wrong rename.
|
|
11
|
+
* - Pure AST logic — no file-system side-effects beyond reading the source.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { parseFile, extractIdentifiers } from "../_ast-helpers";
|
|
15
|
+
import type { ParseResult } from "../_ast-helpers";
|
|
16
|
+
import {
|
|
17
|
+
applyRangeEdits as _applyRangeEdits, // re-exported via facade
|
|
18
|
+
validateIdentifier,
|
|
19
|
+
isDeclarationSite,
|
|
20
|
+
rangesToNodes,
|
|
21
|
+
type RangeEdit,
|
|
22
|
+
type RefactorKind,
|
|
23
|
+
} from "./_shared";
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Public types
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
export type { RangeEdit, RefactorKind };
|
|
30
|
+
|
|
31
|
+
export interface RenameInFileOptions {
|
|
32
|
+
/**
|
|
33
|
+
* If set, only rename identifiers of this kind. Defaults to "value".
|
|
34
|
+
* Use `"type"` to rename a type-only symbol (interface, type alias, etc.).
|
|
35
|
+
*/
|
|
36
|
+
kind?: RefactorKind;
|
|
37
|
+
/**
|
|
38
|
+
* If true, ignore the shadowing guard and rename anyway. Default false.
|
|
39
|
+
* Reserved for tests and advanced callers who've already verified safety.
|
|
40
|
+
*/
|
|
41
|
+
force?: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type RenameInFileResult =
|
|
45
|
+
| {
|
|
46
|
+
ok: true;
|
|
47
|
+
edits: RangeEdit[];
|
|
48
|
+
warnings: string[];
|
|
49
|
+
references: number;
|
|
50
|
+
/**
|
|
51
|
+
* The exact source string the tree was parsed from. Callers applying
|
|
52
|
+
* the edits MUST use this string (not a fresh re-read of the file) so
|
|
53
|
+
* byte offsets stay aligned — a concurrent write between the initial
|
|
54
|
+
* read and the rewrite would otherwise produce silently corrupt output.
|
|
55
|
+
*/
|
|
56
|
+
source: string;
|
|
57
|
+
}
|
|
58
|
+
| {
|
|
59
|
+
ok: false;
|
|
60
|
+
reason: string;
|
|
61
|
+
warnings?: string[];
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// Public API
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Plan a file-local rename.
|
|
70
|
+
*
|
|
71
|
+
* Loads + parses the file, collects identifier references matching
|
|
72
|
+
* `{name, kind}`, checks the shadowing guard, and returns a list of byte
|
|
73
|
+
* ranges to replace with `newName`.
|
|
74
|
+
*/
|
|
75
|
+
export async function planRenameInFile(
|
|
76
|
+
filePath: string,
|
|
77
|
+
oldName: string,
|
|
78
|
+
newName: string,
|
|
79
|
+
options: RenameInFileOptions = {},
|
|
80
|
+
): Promise<RenameInFileResult> {
|
|
81
|
+
const kind: RefactorKind = options.kind ?? "value";
|
|
82
|
+
|
|
83
|
+
const nameError = validateIdentifier(newName);
|
|
84
|
+
if (nameError) return { ok: false, reason: nameError };
|
|
85
|
+
if (oldName === newName) {
|
|
86
|
+
return { ok: false, reason: "old and new names are identical" };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const parsed = await parseFile(filePath);
|
|
90
|
+
if (!parsed) {
|
|
91
|
+
return {
|
|
92
|
+
ok: false,
|
|
93
|
+
reason: "unsupported language or grammar not wired (ashlr__edit_structural supports .ts/.tsx/.js/.jsx today)",
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return planRenameFromParsed(parsed, oldName, newName, kind, options.force === true);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Pure variant of {@link planRenameInFile} that operates on a pre-parsed
|
|
102
|
+
* tree. Convenient for tests.
|
|
103
|
+
*/
|
|
104
|
+
export function planRenameFromParsed(
|
|
105
|
+
parsed: ParseResult,
|
|
106
|
+
oldName: string,
|
|
107
|
+
newName: string,
|
|
108
|
+
kind: RefactorKind,
|
|
109
|
+
force = false,
|
|
110
|
+
): RenameInFileResult {
|
|
111
|
+
const { tree, source } = parsed;
|
|
112
|
+
|
|
113
|
+
const allRefs = extractIdentifiers(tree, source);
|
|
114
|
+
const matches = allRefs.filter((r) => r.name === oldName && r.kind === kind);
|
|
115
|
+
|
|
116
|
+
if (matches.length === 0) {
|
|
117
|
+
return {
|
|
118
|
+
ok: false,
|
|
119
|
+
reason: `no ${kind}-position identifier named '${oldName}' found in file`,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Shadowing guard: count unique declaration sites. >1 means the same name
|
|
124
|
+
// introduces multiple bindings (e.g., outer function + inner parameter).
|
|
125
|
+
// Until we have proper scope resolution, refuse rather than silently
|
|
126
|
+
// collide all of them.
|
|
127
|
+
const warnings: string[] = [];
|
|
128
|
+
const declarationMatches = rangesToNodes(tree, matches.map((m) => m.range)).filter(
|
|
129
|
+
(n) => isDeclarationSite(n, kind),
|
|
130
|
+
);
|
|
131
|
+
const declarationCount = declarationMatches.length;
|
|
132
|
+
|
|
133
|
+
if (declarationCount > 1 && !force) {
|
|
134
|
+
return {
|
|
135
|
+
ok: false,
|
|
136
|
+
reason: `'${oldName}' has ${declarationCount} declaration sites in this file — rename refused to avoid shadowing collisions. Rename each scope individually or pass force:true after verifying safety.`,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
if (declarationCount === 0) {
|
|
140
|
+
warnings.push(
|
|
141
|
+
`no ${kind}-position declaration of '${oldName}' detected — identifier may be bound in an outer scope (imported / global). Rename applied only to the occurrences in this file.`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Check the new name doesn't already collide with a declaration of the
|
|
146
|
+
// same kind in the file.
|
|
147
|
+
if (!force) {
|
|
148
|
+
const collision = allRefs.some(
|
|
149
|
+
(r) => r.name === newName && r.kind === kind,
|
|
150
|
+
);
|
|
151
|
+
if (collision) {
|
|
152
|
+
return {
|
|
153
|
+
ok: false,
|
|
154
|
+
reason: `'${newName}' already exists as a ${kind}-position identifier in this file — would collide. Rename to a different name, or pass force:true.`,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const edits: RangeEdit[] = matches.map((m) => ({
|
|
160
|
+
start: m.range[0],
|
|
161
|
+
end: m.range[1],
|
|
162
|
+
replacement: newName,
|
|
163
|
+
}));
|
|
164
|
+
|
|
165
|
+
return {
|
|
166
|
+
ok: true,
|
|
167
|
+
edits,
|
|
168
|
+
warnings,
|
|
169
|
+
references: matches.length,
|
|
170
|
+
source,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* _ast-refactor.ts — Facade re-exporting the public API of the AST-refactor
|
|
3
|
+
* module family (Track D, v1.24).
|
|
4
|
+
*
|
|
5
|
+
* The implementation has been decomposed into focused sub-modules:
|
|
6
|
+
* _ast-refactor/_shared.ts — common types, helpers, applyRangeEdits
|
|
7
|
+
* _ast-refactor/file-local-rename.ts — planRenameInFile + planRenameFromParsed
|
|
8
|
+
* _ast-refactor/cross-file-rename.ts — planCrossFileRename + applyCrossFileRenameEdits
|
|
9
|
+
* _ast-refactor/extract-function.ts — planExtractFunction
|
|
10
|
+
*
|
|
11
|
+
* All public signatures are identical to the monolithic v1.18.1 version.
|
|
12
|
+
* Callers (edit-structural-server-handlers.ts, tests) are unaffected.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export type { RangeEdit, RefactorKind } from "./_ast-refactor/_shared";
|
|
16
|
+
export { applyRangeEdits } from "./_ast-refactor/_shared";
|
|
17
|
+
|
|
18
|
+
export type {
|
|
19
|
+
RenameInFileOptions,
|
|
20
|
+
RenameInFileResult,
|
|
21
|
+
} from "./_ast-refactor/file-local-rename";
|
|
22
|
+
export {
|
|
23
|
+
planRenameInFile,
|
|
24
|
+
planRenameFromParsed,
|
|
25
|
+
} from "./_ast-refactor/file-local-rename";
|
|
26
|
+
|
|
27
|
+
export type {
|
|
28
|
+
CrossFileRenameOptions,
|
|
29
|
+
CrossFileFileEdit,
|
|
30
|
+
CrossFileRenameResult,
|
|
31
|
+
} from "./_ast-refactor/cross-file-rename";
|
|
32
|
+
export {
|
|
33
|
+
planCrossFileRename,
|
|
34
|
+
applyCrossFileRenameEdits,
|
|
35
|
+
} from "./_ast-refactor/cross-file-rename";
|
|
36
|
+
|
|
37
|
+
export type {
|
|
38
|
+
ExtractFunctionOptions,
|
|
39
|
+
ExtractFunctionResult,
|
|
40
|
+
} from "./_ast-refactor/extract-function";
|
|
41
|
+
export { planExtractFunction } from "./_ast-refactor/extract-function";
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* _ast-skeleton.ts — AST-truncated skeleton renderer for ashlr__read.
|
|
3
|
+
*
|
|
4
|
+
* For large wired-language files (TS/TSX/JS), instead of snipCompact head+tail
|
|
5
|
+
* truncation we return a SKELETON: import/export-from lines verbatim at the top,
|
|
6
|
+
* followed by every top-level symbol's docstring + signature + a one-line body
|
|
7
|
+
* elision marker. Typical savings: 60–80% vs full source.
|
|
8
|
+
*
|
|
9
|
+
* Contract:
|
|
10
|
+
* - Returns null on ANY failure — callers MUST fall through to snipCompact.
|
|
11
|
+
* - Never throws.
|
|
12
|
+
* - Deterministic (no Date.now / Math.random).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { resolveLanguage } from "./_ast-languages";
|
|
16
|
+
import { splitFileIntoChunks } from "./_ast-chunker";
|
|
17
|
+
|
|
18
|
+
/** Languages fully wired for AST skeleton rendering. */
|
|
19
|
+
const WIRED_SKELETON_LANGUAGES = new Set(["typescript", "tsx", "javascript"]);
|
|
20
|
+
|
|
21
|
+
/** Regex that matches import / export-from / re-export lines. */
|
|
22
|
+
const IMPORT_EXPORT_RE =
|
|
23
|
+
/^\s*(import\b|export\s+(?:\*|\{|type\b).*\bfrom\b|export\s+\{)/;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Render an AST skeleton for `filePath`.
|
|
27
|
+
*
|
|
28
|
+
* Returns null when:
|
|
29
|
+
* - Language is not in the wired JS/TS set.
|
|
30
|
+
* - splitFileIntoChunks returns null or an empty array.
|
|
31
|
+
* - Any unexpected error occurs.
|
|
32
|
+
*/
|
|
33
|
+
export async function renderAstSkeleton(
|
|
34
|
+
filePath: string,
|
|
35
|
+
content: string,
|
|
36
|
+
): Promise<string | null> {
|
|
37
|
+
try {
|
|
38
|
+
// Guard: only wired languages get AST treatment.
|
|
39
|
+
const lang = resolveLanguage(filePath);
|
|
40
|
+
if (!lang || !WIRED_SKELETON_LANGUAGES.has(lang)) return null;
|
|
41
|
+
|
|
42
|
+
// Parse the file into top-level chunks.
|
|
43
|
+
const chunks = await splitFileIntoChunks(filePath);
|
|
44
|
+
if (!chunks || chunks.length === 0) return null;
|
|
45
|
+
|
|
46
|
+
// -----------------------------------------------------------------------
|
|
47
|
+
// Extract import / export-from lines via line scan (no AST needed — these
|
|
48
|
+
// are always verbatim and the regex is reliable for TS/JS).
|
|
49
|
+
// -----------------------------------------------------------------------
|
|
50
|
+
const importLines: string[] = [];
|
|
51
|
+
for (const line of content.split("\n")) {
|
|
52
|
+
if (IMPORT_EXPORT_RE.test(line)) {
|
|
53
|
+
importLines.push(line);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// -----------------------------------------------------------------------
|
|
58
|
+
// Build the skeleton body: one block per chunk in source order.
|
|
59
|
+
// -----------------------------------------------------------------------
|
|
60
|
+
const parts: string[] = [];
|
|
61
|
+
|
|
62
|
+
// Import block at the top (if any).
|
|
63
|
+
if (importLines.length > 0) {
|
|
64
|
+
parts.push(importLines.join("\n"));
|
|
65
|
+
parts.push(""); // blank separator
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// One block per chunk, preserving source order (splitFileIntoChunks already
|
|
69
|
+
// returns chunks in tree-sitter traversal = source order).
|
|
70
|
+
for (const chunk of chunks) {
|
|
71
|
+
const block: string[] = [];
|
|
72
|
+
if (chunk.docstring) {
|
|
73
|
+
block.push(chunk.docstring);
|
|
74
|
+
}
|
|
75
|
+
// Enums are small and their MEMBERS are the signal (the whole point of an
|
|
76
|
+
// enum is its variants), so render them in full rather than eliding the
|
|
77
|
+
// body. Everything else gets signature + a body-elision marker.
|
|
78
|
+
if (chunk.kind === "enum") {
|
|
79
|
+
block.push(content.slice(chunk.startByte, chunk.endByte));
|
|
80
|
+
} else if (chunk.kind === "class" && chunk.members && chunk.members.length > 0) {
|
|
81
|
+
// Show the class shape: header + member signatures (method bodies elided).
|
|
82
|
+
block.push(`${chunk.signature} {`);
|
|
83
|
+
for (const m of chunk.members) block.push(` ${m}`);
|
|
84
|
+
block.push("}");
|
|
85
|
+
} else {
|
|
86
|
+
block.push(chunk.signature);
|
|
87
|
+
block.push(
|
|
88
|
+
` // … body elided (L${chunk.startLine}–L${chunk.endLine})`,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
parts.push(block.join("\n"));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// -----------------------------------------------------------------------
|
|
95
|
+
// Footer note so agents know how to recover the full file.
|
|
96
|
+
// -----------------------------------------------------------------------
|
|
97
|
+
parts.push(
|
|
98
|
+
"\n// [ast-skeleton] Signatures only — bodies elided for token efficiency." +
|
|
99
|
+
"\n// To read the full file: pass bypassSummary:true to ashlr__read.",
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
return parts.join("\n\n");
|
|
103
|
+
} catch {
|
|
104
|
+
// Tree-sitter can timeout on macOS cold-start; any other error also falls back.
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|