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,560 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* _ast-refactor/cross-file-rename.ts — Cross-file AST rename with
|
|
3
|
+
* anchor-scoped import detection.
|
|
4
|
+
*
|
|
5
|
+
* Exports:
|
|
6
|
+
* planCrossFileRename — ripgrep-based multi-file candidate discovery +
|
|
7
|
+
* per-file rename planning
|
|
8
|
+
* applyCrossFileRenameEdits — apply the planned edits atomically to disk
|
|
9
|
+
*
|
|
10
|
+
* Scope rules (v1.18.1):
|
|
11
|
+
* - If `anchorFile` is provided, importers are detected via AST: we look for
|
|
12
|
+
* `import_specifier`, `import_clause` (default), `namespace_import`, and CJS
|
|
13
|
+
* `require` destructuring calls whose source string resolves to `anchorFile`.
|
|
14
|
+
* - `ns.oldName` (namespace-qualified access) is also renamed when the
|
|
15
|
+
* namespace binding points at `anchorFile`.
|
|
16
|
+
* - Module path strings (e.g., `"./foo"`) are NEVER rewritten.
|
|
17
|
+
* - Without `anchorFile`, legacy behavior: every file containing the identifier
|
|
18
|
+
* is a rename candidate (v1.13 semantics).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { writeFile } from "fs/promises";
|
|
22
|
+
import { dirname, isAbsolute, resolve as pathResolve } from "path";
|
|
23
|
+
import { runWithTimeout } from "../_run-with-timeout";
|
|
24
|
+
import { parseFile, walkNodes, walkSubtree } from "../_ast-helpers";
|
|
25
|
+
import type Parser from "web-tree-sitter";
|
|
26
|
+
import { planRenameInFile, planRenameFromParsed } from "./file-local-rename";
|
|
27
|
+
import { type RangeEdit, type RefactorKind } from "./_shared";
|
|
28
|
+
|
|
29
|
+
/** Hard cap on the number of candidate files a cross-file rename may touch. */
|
|
30
|
+
const CROSS_FILE_MAX_CANDIDATES = 200;
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Public types
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
export interface CrossFileRenameOptions {
|
|
37
|
+
kind?: RefactorKind;
|
|
38
|
+
/** Glob patterns relative to rootDir; default: **\/*.{ts,tsx,js,jsx} */
|
|
39
|
+
include?: string[];
|
|
40
|
+
exclude?: string[];
|
|
41
|
+
/**
|
|
42
|
+
* Absolute path of the file that declares + exports the symbol. If provided,
|
|
43
|
+
* only files that import the symbol from this anchor (directly, via
|
|
44
|
+
* destructured `require`, or via a `import * as ns` namespace where `ns.X`
|
|
45
|
+
* is accessed) are candidates for rename. If omitted, every file in the
|
|
46
|
+
* search that contains the identifier is renamed (legacy v1.13 behavior).
|
|
47
|
+
*/
|
|
48
|
+
anchorFile?: string;
|
|
49
|
+
/** Override the hard file cap (default 200). */
|
|
50
|
+
maxFiles?: number;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface CrossFileFileEdit {
|
|
54
|
+
path: string;
|
|
55
|
+
edits: RangeEdit[];
|
|
56
|
+
source: string;
|
|
57
|
+
references: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type CrossFileRenameResult =
|
|
61
|
+
| {
|
|
62
|
+
ok: true;
|
|
63
|
+
fileEdits: CrossFileFileEdit[];
|
|
64
|
+
warnings: string[];
|
|
65
|
+
/** Files that were candidates but skipped (reason recorded in warnings). */
|
|
66
|
+
skipped: number;
|
|
67
|
+
}
|
|
68
|
+
| { ok: false; reason: string };
|
|
69
|
+
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// resolveRg — locate ripgrep binary
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
function resolveRg(): string {
|
|
75
|
+
const candidates = [
|
|
76
|
+
"/opt/homebrew/bin/rg",
|
|
77
|
+
"/usr/local/bin/rg",
|
|
78
|
+
"/usr/bin/rg",
|
|
79
|
+
// codex vendor bundle (present on some macOS dev machines)
|
|
80
|
+
"/opt/homebrew/lib/node_modules/@openai/codex/node_modules/@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/path/rg",
|
|
81
|
+
];
|
|
82
|
+
return (
|
|
83
|
+
(typeof (globalThis as { Bun?: { which(bin: string): string | null } }).Bun !== "undefined"
|
|
84
|
+
? (globalThis as { Bun: { which(bin: string): string | null } }).Bun.which("rg")
|
|
85
|
+
: null) ??
|
|
86
|
+
candidates.find((p) => {
|
|
87
|
+
try {
|
|
88
|
+
require("fs").accessSync(p);
|
|
89
|
+
return true;
|
|
90
|
+
} catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}) ??
|
|
94
|
+
"rg"
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// Public API
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Plan a cross-file rename of `oldName` → `newName` across all files in
|
|
104
|
+
* `rootDir` matching the include globs.
|
|
105
|
+
*/
|
|
106
|
+
export async function planCrossFileRename(
|
|
107
|
+
rootDir: string,
|
|
108
|
+
oldName: string,
|
|
109
|
+
newName: string,
|
|
110
|
+
options: CrossFileRenameOptions = {},
|
|
111
|
+
): Promise<CrossFileRenameResult> {
|
|
112
|
+
const kind: RefactorKind = options.kind ?? "value";
|
|
113
|
+
const maxFiles = options.maxFiles ?? CROSS_FILE_MAX_CANDIDATES;
|
|
114
|
+
const anchorFile = options.anchorFile
|
|
115
|
+
? pathResolve(options.anchorFile)
|
|
116
|
+
: undefined;
|
|
117
|
+
|
|
118
|
+
// Build rg args: search for the literal symbol text, list files only.
|
|
119
|
+
const rgArgs: string[] = [
|
|
120
|
+
"--files-with-matches",
|
|
121
|
+
"--fixed-strings",
|
|
122
|
+
oldName,
|
|
123
|
+
rootDir,
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
// Include globs: use caller-provided ones, or default to TS/JS extensions.
|
|
127
|
+
const includes = options.include ?? ["**/*.{ts,tsx,js,jsx}"];
|
|
128
|
+
for (const g of includes) {
|
|
129
|
+
rgArgs.push("--glob", g);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Exclude globs
|
|
133
|
+
const excludes = options.exclude ?? [];
|
|
134
|
+
for (const g of excludes) {
|
|
135
|
+
rgArgs.push("--glob", `!${g}`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const rgRes = await runWithTimeout({ command: resolveRg(), args: rgArgs, timeoutMs: 15_000 });
|
|
139
|
+
// rg exits 0 = matches found, 1 = no matches, 2 = error
|
|
140
|
+
if (rgRes.exitCode === 2 || (rgRes.exitCode === -1 && !rgRes.stdout)) {
|
|
141
|
+
return { ok: false, reason: `ripgrep failed in ${rootDir}: ${rgRes.stderr ?? "unknown error"}` };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
let candidateFiles = (rgRes.stdout ?? "")
|
|
145
|
+
.split("\n")
|
|
146
|
+
.map((l) => l.trim())
|
|
147
|
+
.filter(Boolean);
|
|
148
|
+
|
|
149
|
+
if (candidateFiles.length === 0) {
|
|
150
|
+
return {
|
|
151
|
+
ok: false,
|
|
152
|
+
reason: `no candidates for '${oldName}' under ${rootDir} — symbol absent or filtered by include/exclude globs`,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const warnings: string[] = [];
|
|
157
|
+
if (candidateFiles.length > maxFiles) {
|
|
158
|
+
warnings.push(
|
|
159
|
+
`rootDir '${rootDir}': ripgrep returned ${candidateFiles.length} candidate files but cap is ${maxFiles} — truncating; narrow the scope with a more specific rootDir or include glob to rename every site.`,
|
|
160
|
+
);
|
|
161
|
+
candidateFiles = candidateFiles.slice(0, maxFiles);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const fileEdits: CrossFileFileEdit[] = [];
|
|
165
|
+
let skipped = 0;
|
|
166
|
+
|
|
167
|
+
for (const filePath of candidateFiles) {
|
|
168
|
+
const abs = pathResolve(filePath);
|
|
169
|
+
// When scoped to an anchor file, use AST-level import detection to decide
|
|
170
|
+
// whether to include this file. The anchor itself always participates.
|
|
171
|
+
if (anchorFile && abs !== anchorFile) {
|
|
172
|
+
const scope = await scopedRenameFile(abs, anchorFile, oldName, newName, kind);
|
|
173
|
+
if (scope.kind === "skip") {
|
|
174
|
+
if (scope.reason) warnings.push(`${filePath}: skipped — ${scope.reason}`);
|
|
175
|
+
else skipped++;
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (scope.kind === "error") {
|
|
179
|
+
warnings.push(`${filePath}: skipped — ${scope.reason}`);
|
|
180
|
+
skipped++;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
for (const w of scope.warnings) warnings.push(`${filePath}: ${w}`);
|
|
184
|
+
fileEdits.push({
|
|
185
|
+
path: filePath,
|
|
186
|
+
edits: scope.edits,
|
|
187
|
+
source: scope.source,
|
|
188
|
+
references: scope.references,
|
|
189
|
+
});
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Anchor file OR unscoped mode: full rename within the file.
|
|
194
|
+
const result = await planRenameInFile(filePath, oldName, newName, { kind });
|
|
195
|
+
if (!result.ok) {
|
|
196
|
+
warnings.push(`${filePath}: skipped — ${result.reason}`);
|
|
197
|
+
skipped++;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
for (const w of result.warnings) {
|
|
201
|
+
warnings.push(`${filePath}: ${w}`);
|
|
202
|
+
}
|
|
203
|
+
fileEdits.push({
|
|
204
|
+
path: filePath,
|
|
205
|
+
edits: result.edits,
|
|
206
|
+
source: result.source,
|
|
207
|
+
references: result.references,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (fileEdits.length === 0) {
|
|
212
|
+
return {
|
|
213
|
+
ok: false,
|
|
214
|
+
reason: `no safe rename sites found — either the symbol doesn't exist or all candidates have shadowing collisions (see warnings: ${warnings.slice(0, 3).join("; ") || "none"})`,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return { ok: true, fileEdits, warnings, skipped };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Apply cross-file rename edits: reads each file's stored source, applies
|
|
223
|
+
* edits, writes atomically. Returns count of files written.
|
|
224
|
+
*/
|
|
225
|
+
export async function applyCrossFileRenameEdits(
|
|
226
|
+
fileEdits: Array<{ path: string; edits: RangeEdit[]; source: string }>,
|
|
227
|
+
): Promise<number> {
|
|
228
|
+
let count = 0;
|
|
229
|
+
for (const fe of fileEdits) {
|
|
230
|
+
const after = applyRangeEditsLocal(fe.source, fe.edits);
|
|
231
|
+
if (after !== fe.source) {
|
|
232
|
+
await writeFile(fe.path, after, "utf-8");
|
|
233
|
+
count++;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return count;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
// Anchor-scoped per-file rename (AST import detection)
|
|
241
|
+
// ---------------------------------------------------------------------------
|
|
242
|
+
|
|
243
|
+
type ScopedRename =
|
|
244
|
+
| { kind: "skip"; reason?: string }
|
|
245
|
+
| { kind: "error"; reason: string }
|
|
246
|
+
| {
|
|
247
|
+
kind: "rename";
|
|
248
|
+
edits: RangeEdit[];
|
|
249
|
+
source: string;
|
|
250
|
+
references: number;
|
|
251
|
+
warnings: string[];
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* For a file that is NOT the anchor: parse it, find which local binding (if
|
|
256
|
+
* any) corresponds to the symbol imported from `anchorFile`, then compute
|
|
257
|
+
* byte-range edits for every reference to that binding (including
|
|
258
|
+
* `ns.oldName` accesses when imported via `import * as ns`). Returns
|
|
259
|
+
* `skip` if the file doesn't import from the anchor at all.
|
|
260
|
+
*/
|
|
261
|
+
async function scopedRenameFile(
|
|
262
|
+
filePath: string,
|
|
263
|
+
anchorFile: string,
|
|
264
|
+
oldName: string,
|
|
265
|
+
newName: string,
|
|
266
|
+
kind: RefactorKind,
|
|
267
|
+
): Promise<ScopedRename> {
|
|
268
|
+
const parsed = await parseFile(filePath);
|
|
269
|
+
if (!parsed) {
|
|
270
|
+
return { kind: "skip", reason: "unsupported language or grammar not wired" };
|
|
271
|
+
}
|
|
272
|
+
const { tree, source } = parsed;
|
|
273
|
+
|
|
274
|
+
const filesDir = dirname(filePath);
|
|
275
|
+
|
|
276
|
+
// Collect each import statement and its resolved target.
|
|
277
|
+
// We return up to two kinds of matches:
|
|
278
|
+
// - bindings whose local name IS `oldName` (plain named / default import)
|
|
279
|
+
// - namespace bindings whose namespace name is some `ns`, for which we
|
|
280
|
+
// later rewrite `ns.oldName` → `ns.newName`.
|
|
281
|
+
const directBindings: Array<{ nameRange: [number, number] }> = [];
|
|
282
|
+
const namespaceNames = new Set<string>();
|
|
283
|
+
let anchorImportsFound = 0;
|
|
284
|
+
|
|
285
|
+
walkNodes(tree, (n) => {
|
|
286
|
+
// ESM: import ... from "..."
|
|
287
|
+
if (n.type === "import_statement") {
|
|
288
|
+
const moduleStr = findStringChild(n);
|
|
289
|
+
if (!moduleStr) return;
|
|
290
|
+
if (!modulePathResolvesToAnchor(moduleStr, filesDir, anchorFile)) return;
|
|
291
|
+
anchorImportsFound++;
|
|
292
|
+
collectBindingsFromImport(n, oldName, directBindings, namespaceNames, source);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
// CJS: const {X} = require("...") / const X = require("...")
|
|
296
|
+
if (n.type === "lexical_declaration" || n.type === "variable_declaration") {
|
|
297
|
+
for (let i = 0; i < n.namedChildCount; i++) {
|
|
298
|
+
const declarator = n.namedChild(i);
|
|
299
|
+
if (!declarator || declarator.type !== "variable_declarator") continue;
|
|
300
|
+
const requireCall = findRequireCall(declarator);
|
|
301
|
+
if (!requireCall) continue;
|
|
302
|
+
const moduleStr = findRequireArg(requireCall);
|
|
303
|
+
if (!moduleStr) continue;
|
|
304
|
+
if (!modulePathResolvesToAnchor(moduleStr, filesDir, anchorFile)) continue;
|
|
305
|
+
anchorImportsFound++;
|
|
306
|
+
collectBindingsFromRequire(declarator, oldName, directBindings, namespaceNames);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
if (anchorImportsFound === 0) {
|
|
312
|
+
return { kind: "skip" };
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (directBindings.length === 0 && namespaceNames.size === 0) {
|
|
316
|
+
// Imported module from anchor, but didn't import `oldName` from it
|
|
317
|
+
// (e.g., `import { other } from "./a"` when we're renaming `foo`).
|
|
318
|
+
return { kind: "skip", reason: `imports from anchor but not '${oldName}'` };
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Collect rename edits for this file.
|
|
322
|
+
const edits: RangeEdit[] = [];
|
|
323
|
+
const warnings: string[] = [];
|
|
324
|
+
|
|
325
|
+
// 1) Every direct-binding identifier + its same-named references within
|
|
326
|
+
// the file. Safest approach: run the file-local rename and rely on its
|
|
327
|
+
// collision / shadowing guard. We only accept the plan if the number of
|
|
328
|
+
// declaration sites matches our collected directBindings.
|
|
329
|
+
if (directBindings.length > 0) {
|
|
330
|
+
const plan = planRenameFromParsed(parsed, oldName, newName, kind, false);
|
|
331
|
+
if (!plan.ok) {
|
|
332
|
+
return { kind: "error", reason: plan.reason };
|
|
333
|
+
}
|
|
334
|
+
for (const e of plan.edits) edits.push(e);
|
|
335
|
+
for (const w of plan.warnings) warnings.push(w);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// 2) For namespace bindings: rewrite `ns.oldName` member-access sites.
|
|
339
|
+
if (namespaceNames.size > 0) {
|
|
340
|
+
walkNodes(tree, (n) => {
|
|
341
|
+
if (n.type !== "member_expression") return;
|
|
342
|
+
// member_expression structure: object '.' property_identifier
|
|
343
|
+
const obj = n.namedChild(0);
|
|
344
|
+
const prop = n.childForFieldName ? n.childForFieldName("property") : null;
|
|
345
|
+
const propNode = prop ?? n.namedChild(1);
|
|
346
|
+
if (!obj || !propNode) return;
|
|
347
|
+
if (!namespaceNames.has(obj.text)) return;
|
|
348
|
+
if (propNode.type !== "property_identifier") return;
|
|
349
|
+
if (propNode.text !== oldName) return;
|
|
350
|
+
edits.push({
|
|
351
|
+
start: propNode.startIndex,
|
|
352
|
+
end: propNode.endIndex,
|
|
353
|
+
replacement: newName,
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (edits.length === 0) {
|
|
359
|
+
return { kind: "skip", reason: `no references to '${oldName}' found` };
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// De-dupe overlapping ranges (shouldn't happen, but be safe).
|
|
363
|
+
const seen = new Set<string>();
|
|
364
|
+
const dedup: RangeEdit[] = [];
|
|
365
|
+
for (const e of edits) {
|
|
366
|
+
const key = `${e.start}:${e.end}`;
|
|
367
|
+
if (seen.has(key)) continue;
|
|
368
|
+
seen.add(key);
|
|
369
|
+
dedup.push(e);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return {
|
|
373
|
+
kind: "rename",
|
|
374
|
+
edits: dedup,
|
|
375
|
+
source,
|
|
376
|
+
references: dedup.length,
|
|
377
|
+
warnings,
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// ---------------------------------------------------------------------------
|
|
382
|
+
// Import/require AST helpers
|
|
383
|
+
// ---------------------------------------------------------------------------
|
|
384
|
+
|
|
385
|
+
/** Return the first string literal child of a node (for `from "..."`). */
|
|
386
|
+
function findStringChild(node: Parser.SyntaxNode): string | null {
|
|
387
|
+
for (let i = 0; i < node.namedChildCount; i++) {
|
|
388
|
+
const c = node.namedChild(i);
|
|
389
|
+
if (!c) continue;
|
|
390
|
+
if (c.type === "string") {
|
|
391
|
+
// Strip quotes.
|
|
392
|
+
const raw = c.text;
|
|
393
|
+
if (raw.length >= 2) return raw.slice(1, -1);
|
|
394
|
+
return "";
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* True iff a relative or absolute module-path string resolves to the same
|
|
402
|
+
* on-disk file as `anchorFile` (with TS/TSX/JS/JSX extensions tried).
|
|
403
|
+
*/
|
|
404
|
+
function modulePathResolvesToAnchor(
|
|
405
|
+
modulePath: string,
|
|
406
|
+
fromDir: string,
|
|
407
|
+
anchorFile: string,
|
|
408
|
+
): boolean {
|
|
409
|
+
if (!modulePath.startsWith(".") && !isAbsolute(modulePath)) {
|
|
410
|
+
// Bare package specifiers never resolve to a project-local anchor.
|
|
411
|
+
return false;
|
|
412
|
+
}
|
|
413
|
+
const base = isAbsolute(modulePath)
|
|
414
|
+
? modulePath
|
|
415
|
+
: pathResolve(fromDir, modulePath);
|
|
416
|
+
const anchor = pathResolve(anchorFile);
|
|
417
|
+
// Strip extension from anchor to compare: `./a` should resolve to `a.ts`.
|
|
418
|
+
const anchorNoExt = anchor.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/, "");
|
|
419
|
+
const baseNoExt = base.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/, "");
|
|
420
|
+
return baseNoExt === anchorNoExt || baseNoExt + "/index" === anchorNoExt;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function findRequireCall(declarator: Parser.SyntaxNode): Parser.SyntaxNode | null {
|
|
424
|
+
// const X = require("...") → variable_declarator [name=X, value=call_expression(require, string)]
|
|
425
|
+
const val = declarator.childForFieldName
|
|
426
|
+
? declarator.childForFieldName("value")
|
|
427
|
+
: null;
|
|
428
|
+
const cand = val ?? declarator.namedChild(declarator.namedChildCount - 1);
|
|
429
|
+
if (!cand || cand.type !== "call_expression") return null;
|
|
430
|
+
const fn = cand.namedChild(0);
|
|
431
|
+
if (!fn || fn.text !== "require") return null;
|
|
432
|
+
return cand;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function findRequireArg(callExpr: Parser.SyntaxNode): string | null {
|
|
436
|
+
const args = callExpr.childForFieldName
|
|
437
|
+
? callExpr.childForFieldName("arguments")
|
|
438
|
+
: null;
|
|
439
|
+
const a = args ?? callExpr.namedChild(1);
|
|
440
|
+
if (!a) return null;
|
|
441
|
+
for (let i = 0; i < a.namedChildCount; i++) {
|
|
442
|
+
const c = a.namedChild(i);
|
|
443
|
+
if (!c) continue;
|
|
444
|
+
if (c.type === "string") {
|
|
445
|
+
const raw = c.text;
|
|
446
|
+
if (raw.length >= 2) return raw.slice(1, -1);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
return null;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
function collectBindingsFromImport(
|
|
453
|
+
importStmt: Parser.SyntaxNode,
|
|
454
|
+
oldName: string,
|
|
455
|
+
directBindings: Array<{ nameRange: [number, number] }>,
|
|
456
|
+
namespaceNames: Set<string>,
|
|
457
|
+
_source: string,
|
|
458
|
+
): void {
|
|
459
|
+
walkSubtree(
|
|
460
|
+
importStmt,
|
|
461
|
+
(n) => {
|
|
462
|
+
if (n.type === "import_specifier") {
|
|
463
|
+
// Shape: import { X } or import { X as Y }
|
|
464
|
+
// children: name (identifier), optional "as", alias (identifier)
|
|
465
|
+
const name = n.childForFieldName ? n.childForFieldName("name") : null;
|
|
466
|
+
const alias = n.childForFieldName ? n.childForFieldName("alias") : null;
|
|
467
|
+
const imported = name ?? n.namedChild(0);
|
|
468
|
+
const local = alias ?? imported;
|
|
469
|
+
if (!imported || !local) return;
|
|
470
|
+
if (imported.text !== oldName) return;
|
|
471
|
+
// If aliased (import { foo as bar }), renaming `foo` means rewriting
|
|
472
|
+
// only the imported-name half, not the local alias.
|
|
473
|
+
if (alias && alias.text !== imported.text) {
|
|
474
|
+
directBindings.push({ nameRange: [imported.startIndex, imported.endIndex] });
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
// Unaliased: local name === oldName; file-local rename will catch all
|
|
478
|
+
// references, but we explicitly record the decl site too.
|
|
479
|
+
directBindings.push({ nameRange: [imported.startIndex, imported.endIndex] });
|
|
480
|
+
} else if (n.type === "import_clause") {
|
|
481
|
+
// import X from "..."
|
|
482
|
+
// Only counts if the default binding name equals oldName.
|
|
483
|
+
for (let i = 0; i < n.namedChildCount; i++) {
|
|
484
|
+
const c = n.namedChild(i);
|
|
485
|
+
if (!c) continue;
|
|
486
|
+
if (c.type === "identifier" && c.text === oldName) {
|
|
487
|
+
directBindings.push({ nameRange: [c.startIndex, c.endIndex] });
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
} else if (n.type === "namespace_import") {
|
|
491
|
+
// import * as ns from "..."
|
|
492
|
+
for (let i = 0; i < n.namedChildCount; i++) {
|
|
493
|
+
const c = n.namedChild(i);
|
|
494
|
+
if (c && c.type === "identifier") namespaceNames.add(c.text);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
},
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function collectBindingsFromRequire(
|
|
502
|
+
declarator: Parser.SyntaxNode,
|
|
503
|
+
oldName: string,
|
|
504
|
+
directBindings: Array<{ nameRange: [number, number] }>,
|
|
505
|
+
namespaceNames: Set<string>,
|
|
506
|
+
): void {
|
|
507
|
+
const nameNode = declarator.childForFieldName
|
|
508
|
+
? declarator.childForFieldName("name")
|
|
509
|
+
: declarator.namedChild(0);
|
|
510
|
+
if (!nameNode) return;
|
|
511
|
+
// const X = require(...) → nameNode is identifier; treat X as namespace binding.
|
|
512
|
+
if (nameNode.type === "identifier") {
|
|
513
|
+
namespaceNames.add(nameNode.text);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
// const { X } = require(...) → object_pattern
|
|
517
|
+
if (nameNode.type === "object_pattern") {
|
|
518
|
+
walkSubtree(nameNode, (c) => {
|
|
519
|
+
if (
|
|
520
|
+
c.type === "shorthand_property_identifier_pattern" &&
|
|
521
|
+
c.text === oldName
|
|
522
|
+
) {
|
|
523
|
+
directBindings.push({ nameRange: [c.startIndex, c.endIndex] });
|
|
524
|
+
}
|
|
525
|
+
// const { X: Y } = require(...) — pair_pattern
|
|
526
|
+
if (c.type === "pair_pattern") {
|
|
527
|
+
const key = c.childForFieldName ? c.childForFieldName("key") : c.namedChild(0);
|
|
528
|
+
const val = c.childForFieldName ? c.childForFieldName("value") : c.namedChild(1);
|
|
529
|
+
if (key && key.text === oldName && val && val.type === "identifier") {
|
|
530
|
+
directBindings.push({ nameRange: [key.startIndex, key.endIndex] });
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// ---------------------------------------------------------------------------
|
|
538
|
+
// Internal applyRangeEdits (avoids circular import; same logic as _shared.ts)
|
|
539
|
+
// ---------------------------------------------------------------------------
|
|
540
|
+
|
|
541
|
+
function applyRangeEditsLocal(source: string, edits: RangeEdit[]): string {
|
|
542
|
+
const sorted = [...edits].sort((a, b) => b.start - a.start);
|
|
543
|
+
let out = source;
|
|
544
|
+
let prevStart: number | null = null;
|
|
545
|
+
for (const edit of sorted) {
|
|
546
|
+
if (edit.start < 0 || edit.end > source.length || edit.start > edit.end) {
|
|
547
|
+
throw new Error(
|
|
548
|
+
`applyRangeEdits: invalid range [${edit.start}, ${edit.end}] for source of length ${source.length}`,
|
|
549
|
+
);
|
|
550
|
+
}
|
|
551
|
+
if (prevStart !== null && edit.end > prevStart) {
|
|
552
|
+
throw new Error(
|
|
553
|
+
`applyRangeEdits: overlapping edits at [${edit.start}, ${edit.end}] vs prior start ${prevStart}`,
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
out = out.slice(0, edit.start) + edit.replacement + out.slice(edit.end);
|
|
557
|
+
prevStart = edit.start;
|
|
558
|
+
}
|
|
559
|
+
return out;
|
|
560
|
+
}
|