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.
Files changed (499) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/.claude-plugin/marketplace.json +39 -0
  3. package/.claude-plugin/plugin.json +36 -0
  4. package/.codex/agents/README.md +9 -0
  5. package/.codex/agents/ashlr-explorer.md +36 -0
  6. package/.codex/agents/ashlr-worker.md +38 -0
  7. package/.codex-plugin/plugin.json +45 -0
  8. package/.mcp.json +14 -0
  9. package/LICENSE +21 -0
  10. package/README.md +311 -0
  11. package/agents/ashlr-code.md +69 -0
  12. package/agents/ashlr-explore.md +44 -0
  13. package/agents/ashlr-plan.md +54 -0
  14. package/bench/fixtures/notebook-large.ipynb +660 -0
  15. package/bench/fixtures/notebook-small.ipynb +39 -0
  16. package/bench/fixtures/tasklist-closed.json +62 -0
  17. package/bench/fixtures/tasklist-large-mixed.json +27 -0
  18. package/bench/fixtures/tasklist-sprint-open.json +79 -0
  19. package/bench/fixtures/websearch-bun-runtime.json +32 -0
  20. package/bench/fixtures/websearch-react-hooks-patterns.json +32 -0
  21. package/bench/fixtures/websearch-typescript-generics.json +38 -0
  22. package/bench/refs/node-sdk/.refrev +1 -0
  23. package/bench/refs/node-sdk/README.md +17 -0
  24. package/bench/refs/node-sdk/src/agent/agent.ts +163 -0
  25. package/bench/refs/node-sdk/src/agent/create-agent-ui-stream.ts +83 -0
  26. package/bench/refs/node-sdk/src/agent/tool-loop-agent.ts +238 -0
  27. package/bench/refs/node-sdk/src/embed/embed-many.ts +409 -0
  28. package/bench/refs/node-sdk/src/embed/embed-result.ts +50 -0
  29. package/bench/refs/node-sdk/src/embed/embed.ts +257 -0
  30. package/bench/refs/node-sdk/src/error/invalid-argument-error.ts +34 -0
  31. package/bench/refs/node-sdk/src/error/invalid-tool-input-error.ts +33 -0
  32. package/bench/refs/node-sdk/src/error/no-object-generated-error.ts +70 -0
  33. package/bench/refs/node-sdk/src/generate-image/generate-image-result.ts +42 -0
  34. package/bench/refs/node-sdk/src/generate-image/generate-image.ts +362 -0
  35. package/bench/refs/node-sdk/src/generate-object/generate-object-result.ts +67 -0
  36. package/bench/refs/node-sdk/src/generate-object/generate-object.ts +501 -0
  37. package/bench/refs/node-sdk/src/generate-object/inject-json-instruction.ts +30 -0
  38. package/bench/refs/node-sdk/src/generate-object/output-strategy.ts +415 -0
  39. package/bench/refs/node-sdk/src/generate-object/repair-text.ts +12 -0
  40. package/bench/refs/node-sdk/src/generate-object/stream-object.ts +960 -0
  41. package/bench/refs/node-sdk/src/generate-speech/generate-speech.ts +191 -0
  42. package/bench/refs/node-sdk/src/generate-text/generate-text.ts +1484 -0
  43. package/bench/refs/node-sdk/src/generate-text/stream-text.ts +2708 -0
  44. package/bench/refs/node-sdk/src/generate-text/tool-call.ts +59 -0
  45. package/bench/refs/node-sdk/src/generate-text/tool-result.ts +36 -0
  46. package/bench/refs/node-sdk/src/telemetry/create-telemetry-dispatcher.ts +146 -0
  47. package/bench/refs/node-sdk/src/telemetry/telemetry-registry.ts +15 -0
  48. package/bench/refs/node-sdk/src/telemetry/telemetry.ts +223 -0
  49. package/bench/refs/node-sdk/src/util/async-iterable-stream.ts +94 -0
  50. package/bench/refs/node-sdk/src/util/consume-stream.ts +31 -0
  51. package/bench/refs/node-sdk/src/util/create-stitchable-stream.ts +112 -0
  52. package/bench/refs/node-sdk/src/util/download/download.ts +74 -0
  53. package/bench/refs/node-sdk/src/util/error-handler.ts +1 -0
  54. package/bench/refs/node-sdk/src/util/fix-json.ts +401 -0
  55. package/bench/refs/node-sdk/src/util/merge-objects.ts +79 -0
  56. package/bench/refs/python-lib/.refrev +1 -0
  57. package/bench/refs/python-lib/README.md +18 -0
  58. package/bench/refs/python-lib/pandas/core/_numba/executor.py +249 -0
  59. package/bench/refs/python-lib/pandas/core/_numba/extensions.py +586 -0
  60. package/bench/refs/python-lib/pandas/core/_numba/kernels/mean_.py +198 -0
  61. package/bench/refs/python-lib/pandas/core/_numba/kernels/min_max_.py +178 -0
  62. package/bench/refs/python-lib/pandas/core/_numba/kernels/sum_.py +255 -0
  63. package/bench/refs/python-lib/pandas/core/_numba/kernels/var_.py +251 -0
  64. package/bench/refs/python-lib/pandas/core/accessor.py +520 -0
  65. package/bench/refs/python-lib/pandas/core/api.py +138 -0
  66. package/bench/refs/python-lib/pandas/core/array_algos/masked_accumulations.py +97 -0
  67. package/bench/refs/python-lib/pandas/core/array_algos/masked_reductions.py +252 -0
  68. package/bench/refs/python-lib/pandas/core/array_algos/putmask.py +150 -0
  69. package/bench/refs/python-lib/pandas/core/array_algos/quantile.py +232 -0
  70. package/bench/refs/python-lib/pandas/core/array_algos/replace.py +159 -0
  71. package/bench/refs/python-lib/pandas/core/array_algos/take.py +609 -0
  72. package/bench/refs/python-lib/pandas/core/arraylike.py +534 -0
  73. package/bench/refs/python-lib/pandas/core/arrays/_arrow_string_mixins.py +434 -0
  74. package/bench/refs/python-lib/pandas/core/arrays/_mixins.py +630 -0
  75. package/bench/refs/python-lib/pandas/core/arrays/_ranges.py +276 -0
  76. package/bench/refs/python-lib/pandas/core/arrays/_utils.py +77 -0
  77. package/bench/refs/python-lib/pandas/core/arrays/arrow/accessors.py +521 -0
  78. package/bench/refs/python-lib/pandas/core/arrays/arrow/extension_types.py +174 -0
  79. package/bench/refs/python-lib/pandas/core/arrays/boolean.py +454 -0
  80. package/bench/refs/python-lib/pandas/core/arrays/floating.py +192 -0
  81. package/bench/refs/python-lib/pandas/core/arrays/integer.py +296 -0
  82. package/bench/refs/python-lib/pandas/core/arrays/masked.py +2140 -0
  83. package/bench/refs/python-lib/pandas/core/arrays/numeric.py +305 -0
  84. package/bench/refs/python-lib/pandas/core/arrays/numpy_.py +701 -0
  85. package/bench/refs/python-lib/pandas/core/arrays/period.py +1586 -0
  86. package/bench/refs/python-lib/pandas/core/arrays/sparse/accessor.py +505 -0
  87. package/bench/refs/python-lib/pandas/core/arrays/sparse/scipy_sparse.py +208 -0
  88. package/bench/refs/rust-project/.refrev +1 -0
  89. package/bench/refs/rust-project/README.md +17 -0
  90. package/bench/refs/rust-project/tokio/src/doc/os.rs +68 -0
  91. package/bench/refs/rust-project/tokio/src/fs/dir_builder.rs +129 -0
  92. package/bench/refs/rust-project/tokio/src/fs/file.rs +1113 -0
  93. package/bench/refs/rust-project/tokio/src/fs/mocks.rs +176 -0
  94. package/bench/refs/rust-project/tokio/src/fs/mod.rs +324 -0
  95. package/bench/refs/rust-project/tokio/src/fs/open_options.rs +856 -0
  96. package/bench/refs/rust-project/tokio/src/fs/read.rs +80 -0
  97. package/bench/refs/rust-project/tokio/src/fs/read_dir.rs +357 -0
  98. package/bench/refs/rust-project/tokio/src/fs/write.rs +99 -0
  99. package/bench/refs/rust-project/tokio/src/future/maybe_done.rs +123 -0
  100. package/bench/refs/rust-project/tokio/src/future/try_join.rs +82 -0
  101. package/bench/refs/rust-project/tokio/src/io/async_buf_read.rs +117 -0
  102. package/bench/refs/rust-project/tokio/src/io/async_read.rs +133 -0
  103. package/bench/refs/rust-project/tokio/src/io/async_seek.rs +96 -0
  104. package/bench/refs/rust-project/tokio/src/io/async_write.rs +402 -0
  105. package/bench/refs/rust-project/tokio/src/io/blocking.rs +339 -0
  106. package/bench/refs/rust-project/tokio/src/io/interest.rs +345 -0
  107. package/bench/refs/rust-project/tokio/src/io/join.rs +130 -0
  108. package/bench/refs/rust-project/tokio/src/io/mod.rs +308 -0
  109. package/bench/refs/rust-project/tokio/src/io/poll_evented.rs +319 -0
  110. package/bench/refs/rust-project/tokio/src/io/read_buf.rs +344 -0
  111. package/bench/refs/rust-project/tokio/src/io/ready.rs +322 -0
  112. package/bench/refs/rust-project/tokio/src/io/split.rs +166 -0
  113. package/bench/refs/rust-project/tokio/src/io/stderr.rs +148 -0
  114. package/bench/refs/rust-project/tokio/src/io/stdin.rs +98 -0
  115. package/bench/refs/rust-project/tokio/src/io/stdio_common.rs +222 -0
  116. package/bench/refs/rust-project/tokio/src/io/stdout.rs +197 -0
  117. package/bench/refs/rust-project/tokio/src/io/util/buf_reader.rs +311 -0
  118. package/bench/refs/rust-project/tokio/src/io/util/buf_stream.rs +207 -0
  119. package/bench/refs/rust-project/tokio/src/io/util/buf_writer.rs +310 -0
  120. package/bench/refs/rust-project/tokio/src/io/util/chain.rs +144 -0
  121. package/commands/_spawn-patterns.json +32 -0
  122. package/commands/ashlr-allow.md +21 -0
  123. package/commands/ashlr-benchmark.md +53 -0
  124. package/commands/ashlr-brief.md +97 -0
  125. package/commands/ashlr-budget.md +76 -0
  126. package/commands/ashlr-compact.md +54 -0
  127. package/commands/ashlr-dashboard.md +37 -0
  128. package/commands/ashlr-doctor.md +56 -0
  129. package/commands/ashlr-eco-mode.md +92 -0
  130. package/commands/ashlr-genome-init.md +24 -0
  131. package/commands/ashlr-genome-keygen.md +36 -0
  132. package/commands/ashlr-genome-loop.md +118 -0
  133. package/commands/ashlr-genome-push.md +36 -0
  134. package/commands/ashlr-genome-rewrap.md +48 -0
  135. package/commands/ashlr-genome-team-init.md +67 -0
  136. package/commands/ashlr-handoff.md +23 -0
  137. package/commands/ashlr-help.md +86 -0
  138. package/commands/ashlr-hook-timings.md +30 -0
  139. package/commands/ashlr-leaderboard.md +50 -0
  140. package/commands/ashlr-ollama-setup.md +39 -0
  141. package/commands/ashlr-orchestrate-status.md +72 -0
  142. package/commands/ashlr-orchestrate.md +83 -0
  143. package/commands/ashlr-parallelize.md +63 -0
  144. package/commands/ashlr-report-crash.md +33 -0
  145. package/commands/ashlr-resume.md +72 -0
  146. package/commands/ashlr-savings.md +24 -0
  147. package/commands/ashlr-settings.md +50 -0
  148. package/commands/ashlr-spawn.md +61 -0
  149. package/commands/ashlr-start.md +60 -0
  150. package/commands/ashlr-status.md +64 -0
  151. package/commands/ashlr-team-invite.md +47 -0
  152. package/commands/ashlr-tier.md +122 -0
  153. package/commands/ashlr-tour.md +60 -0
  154. package/commands/ashlr-update.md +155 -0
  155. package/commands/ashlr-upgrade.md +96 -0
  156. package/commands/goal.md +58 -0
  157. package/commands/loop.md +40 -0
  158. package/docs/CNAME +1 -0
  159. package/docs/PRO_TIER.md +104 -0
  160. package/docs/README.md +21 -0
  161. package/docs/architecture.md +415 -0
  162. package/docs/ashlr-pipe.md +161 -0
  163. package/docs/assets/logo.svg +19 -0
  164. package/docs/assets/og.png +0 -0
  165. package/docs/assets/og.svg +41 -0
  166. package/docs/benchmarks-v2.json +355 -0
  167. package/docs/benchmarks.json +102 -0
  168. package/docs/benchmarks.md +211 -0
  169. package/docs/billing.md +185 -0
  170. package/docs/cloud-genome.md +155 -0
  171. package/docs/competitive-wozcode.md +92 -0
  172. package/docs/deploy.md +325 -0
  173. package/docs/email-templates.md +113 -0
  174. package/docs/embed-tuning.md +103 -0
  175. package/docs/genome.md +120 -0
  176. package/docs/github-oauth-onboarding.md +127 -0
  177. package/docs/hero-video-script.md +129 -0
  178. package/docs/index.html +2262 -0
  179. package/docs/install-prompt.md +78 -0
  180. package/docs/install-windows.md +132 -0
  181. package/docs/install.ps1 +171 -0
  182. package/docs/install.sh +146 -0
  183. package/docs/launch/README.md +114 -0
  184. package/docs/launch/hn.md +49 -0
  185. package/docs/launch/reddit.md +45 -0
  186. package/docs/launch/x.md +65 -0
  187. package/docs/launch-post.md +112 -0
  188. package/docs/legal.md +78 -0
  189. package/docs/llm-providers.md +99 -0
  190. package/docs/multi-host-mcp.md +217 -0
  191. package/docs/multi-turn-architecture.md +108 -0
  192. package/docs/operations/deployment.md +108 -0
  193. package/docs/operations/error-monitoring.md +70 -0
  194. package/docs/operations/weekly-digest.md +70 -0
  195. package/docs/operations.md +494 -0
  196. package/docs/platform-support.md +133 -0
  197. package/docs/policy-packs.md +188 -0
  198. package/docs/press-kit/fact-sheet.md +78 -0
  199. package/docs/press-kit/founder-bio.md +3 -0
  200. package/docs/press-kit/logo.svg +33 -0
  201. package/docs/press-kit/screenshots.md +146 -0
  202. package/docs/pricing.md +251 -0
  203. package/docs/pro-backend-architecture.md +523 -0
  204. package/docs/producthunt.md +52 -0
  205. package/docs/router-migration.md +110 -0
  206. package/docs/session-log-schema.md +68 -0
  207. package/docs/social.md +95 -0
  208. package/docs/team-genome.md +528 -0
  209. package/docs/telemetry.md +194 -0
  210. package/docs/test-isolation.md +100 -0
  211. package/docs/upgrade.md +159 -0
  212. package/hooks/_hook-errors.ts +87 -0
  213. package/hooks/_hook-perf-emit.ts +113 -0
  214. package/hooks/_hook-timing-ledger.ts +1133 -0
  215. package/hooks/_nudge-throttle.ts +127 -0
  216. package/hooks/_recent-blocks.ts +127 -0
  217. package/hooks/audit-upload.ts +86 -0
  218. package/hooks/codex-hooks.json +171 -0
  219. package/hooks/commit-attribution.ts +179 -0
  220. package/hooks/edit-batching-nudge.ts +154 -0
  221. package/hooks/genome-scribe-hook.ts +219 -0
  222. package/hooks/hooks.json +294 -0
  223. package/hooks/orient-nudge-hook.ts +242 -0
  224. package/hooks/policy-enforce.ts +214 -0
  225. package/hooks/post-tool-use-embedding.ts +93 -0
  226. package/hooks/post-tool-use-genome.sh +37 -0
  227. package/hooks/post-tool-use-genome.ts +69 -0
  228. package/hooks/posttooluse-correlate.ts +122 -0
  229. package/hooks/posttooluse-dedupe-output.ts +241 -0
  230. package/hooks/posttooluse-genome-refresh.ts +223 -0
  231. package/hooks/posttooluse-native-nudge.ts +205 -0
  232. package/hooks/posttooluse-stale-result.ts +277 -0
  233. package/hooks/pretooluse-bash.ts +63 -0
  234. package/hooks/pretooluse-budget-guard.ts +318 -0
  235. package/hooks/pretooluse-common.ts +985 -0
  236. package/hooks/pretooluse-eco-router.ts +196 -0
  237. package/hooks/pretooluse-edit.sh +93 -0
  238. package/hooks/pretooluse-edit.ts +197 -0
  239. package/hooks/pretooluse-glob.ts +70 -0
  240. package/hooks/pretooluse-grep.sh +85 -0
  241. package/hooks/pretooluse-grep.ts +96 -0
  242. package/hooks/pretooluse-notebookedit.ts +121 -0
  243. package/hooks/pretooluse-read.sh +118 -0
  244. package/hooks/pretooluse-read.ts +118 -0
  245. package/hooks/pretooluse-task.ts +130 -0
  246. package/hooks/pretooluse-webfetch.ts +66 -0
  247. package/hooks/pretooluse-websearch.ts +85 -0
  248. package/hooks/pretooluse-write.ts +128 -0
  249. package/hooks/pulse-emit.ts +197 -0
  250. package/hooks/session-end-consolidate.sh +35 -0
  251. package/hooks/session-end-consolidate.ts +188 -0
  252. package/hooks/session-end-stats-gc.ts +80 -0
  253. package/hooks/session-log-append.sh +94 -0
  254. package/hooks/session-log-append.ts +116 -0
  255. package/hooks/session-start.ts +993 -0
  256. package/hooks/sessionend-hook-health-nudge.ts +451 -0
  257. package/hooks/sessionend-savings-nudge.ts +318 -0
  258. package/hooks/sessionend-status-line-nudge.ts +296 -0
  259. package/hooks/sessionstart-brief.ts +140 -0
  260. package/hooks/sessionstart-cost-refactor.ts +95 -0
  261. package/hooks/sessionstart-efficient.ts +110 -0
  262. package/hooks/sessionstart-genome-author.ts +93 -0
  263. package/hooks/sessionstart-lean-tools.ts +98 -0
  264. package/hooks/sessionstart-search.ts +97 -0
  265. package/hooks/stop-accounting.ts +152 -0
  266. package/hooks/subagent-stop-rollup.ts +162 -0
  267. package/hooks/userpromptsubmit-brief-trigger.ts +156 -0
  268. package/package.json +56 -0
  269. package/ports/README.md +108 -0
  270. package/ports/cursor/mcp.json +11 -0
  271. package/ports/goose/recipe.yaml +26 -0
  272. package/scripts/ashlr-mcp.ts +40 -0
  273. package/scripts/auto-update.ts +177 -0
  274. package/scripts/baseline-scan.ts +831 -0
  275. package/scripts/bench-orchestrate.ts +377 -0
  276. package/scripts/benchmark-refs.ts +292 -0
  277. package/scripts/bootstrap.mjs +100 -0
  278. package/scripts/brief-eval.ts +234 -0
  279. package/scripts/bump-version.ts +82 -0
  280. package/scripts/bun-resolve.d.mts +11 -0
  281. package/scripts/bun-resolve.mjs +59 -0
  282. package/scripts/calibrate-grep.ts +467 -0
  283. package/scripts/capture-grep-workload.ts +260 -0
  284. package/scripts/check-tier.ts +61 -0
  285. package/scripts/check-version-sync.ts +97 -0
  286. package/scripts/cli-orchestrate-status.ts +386 -0
  287. package/scripts/cli-orchestrate.ts +303 -0
  288. package/scripts/cli.ts +478 -0
  289. package/scripts/cloud-smoke-test.ts +313 -0
  290. package/scripts/coach-report.ts +373 -0
  291. package/scripts/context-db-migrate.ts +137 -0
  292. package/scripts/context-status.ts +43 -0
  293. package/scripts/demo-run.ts +255 -0
  294. package/scripts/deploy-smoke.sh +140 -0
  295. package/scripts/doctor.ts +992 -0
  296. package/scripts/embed-file-worker.ts +104 -0
  297. package/scripts/embed-tune.ts +308 -0
  298. package/scripts/errors-report.ts +428 -0
  299. package/scripts/find-test-leak.ts +69 -0
  300. package/scripts/generate-badge.ts +357 -0
  301. package/scripts/genome-auto-consolidate.ts +533 -0
  302. package/scripts/genome-auto-propose.ts +578 -0
  303. package/scripts/genome-cloud-pull.ts +363 -0
  304. package/scripts/genome-cloud-push.ts +382 -0
  305. package/scripts/genome-cloud-sync.ts +587 -0
  306. package/scripts/genome-commit-watcher.ts +295 -0
  307. package/scripts/genome-init.ts +986 -0
  308. package/scripts/genome-key.ts +233 -0
  309. package/scripts/genome-keygen.ts +168 -0
  310. package/scripts/genome-link.ts +59 -0
  311. package/scripts/genome-refresh-worker.ts +364 -0
  312. package/scripts/genome-rewrap.ts +90 -0
  313. package/scripts/genome-synthesizer.ts +679 -0
  314. package/scripts/genome-team-init.ts +312 -0
  315. package/scripts/handoff-pack.ts +438 -0
  316. package/scripts/hook-bootstrap.mjs +75 -0
  317. package/scripts/hook-timing-reader.ts +371 -0
  318. package/scripts/hook-timings-report.ts +554 -0
  319. package/scripts/install-genome-hooks.ts +196 -0
  320. package/scripts/install-onnx-model.ts +154 -0
  321. package/scripts/install-permissions.ts +276 -0
  322. package/scripts/install-status-line.ts +150 -0
  323. package/scripts/mcp-entrypoint.sh +78 -0
  324. package/scripts/mcp-entrypoint.ts +130 -0
  325. package/scripts/mdx-angle-bracket-lint.ts +152 -0
  326. package/scripts/measure-cold-start.ts +126 -0
  327. package/scripts/migrate-stats-to-sqlite.ts +86 -0
  328. package/scripts/ollama-setup.ts +498 -0
  329. package/scripts/onboarding-wizard.ts +1691 -0
  330. package/scripts/orchestrate-emit-telemetry.ts +177 -0
  331. package/scripts/orchestrate-expand.ts +517 -0
  332. package/scripts/orchestrate-run.ts +744 -0
  333. package/scripts/print-legend.ts +50 -0
  334. package/scripts/product-metadata.ts +38 -0
  335. package/scripts/prune-old-memories.ts +208 -0
  336. package/scripts/publish.sh +88 -0
  337. package/scripts/read-calibration.ts +122 -0
  338. package/scripts/report-crash.ts +226 -0
  339. package/scripts/run-benchmark.ts +750 -0
  340. package/scripts/run-root-tests.ts +28 -0
  341. package/scripts/savings-dashboard.ts +1258 -0
  342. package/scripts/savings-report-extras.ts +447 -0
  343. package/scripts/savings-status-line.ts +873 -0
  344. package/scripts/session-event-emit.ts +266 -0
  345. package/scripts/session-greet.ts +686 -0
  346. package/scripts/session-log-report.ts +551 -0
  347. package/scripts/session-resume.ts +614 -0
  348. package/scripts/set-hook-mode.ts +83 -0
  349. package/scripts/smoke-cross-platform.ts +117 -0
  350. package/scripts/smoke-realtime.ts +257 -0
  351. package/scripts/smoke-tools.ts +21 -0
  352. package/scripts/stats-cloud-pull.ts +213 -0
  353. package/scripts/stats-cloud-sync.ts +261 -0
  354. package/scripts/telemetry-flush.ts +160 -0
  355. package/scripts/telemetry-status.ts +266 -0
  356. package/scripts/timing-budget.ts +35 -0
  357. package/scripts/ui-animation.ts +120 -0
  358. package/scripts/ui.ts +431 -0
  359. package/scripts/upgrade-flow.ts +775 -0
  360. package/scripts/weekly-digest.ts +394 -0
  361. package/servers/_accounting.ts +78 -0
  362. package/servers/_ask-router.ts +84 -0
  363. package/servers/_ast-chunker.ts +434 -0
  364. package/servers/_ast-helpers.ts +183 -0
  365. package/servers/_ast-languages.ts +153 -0
  366. package/servers/_ast-refactor/_shared.ts +221 -0
  367. package/servers/_ast-refactor/cross-file-rename.ts +560 -0
  368. package/servers/_ast-refactor/extract-function.ts +357 -0
  369. package/servers/_ast-refactor/file-local-rename.ts +172 -0
  370. package/servers/_ast-refactor.ts +41 -0
  371. package/servers/_ast-skeleton.ts +107 -0
  372. package/servers/_bash-summarizers-registry.ts +1096 -0
  373. package/servers/_crash-dump.ts +210 -0
  374. package/servers/_cwd-clamp.ts +342 -0
  375. package/servers/_edit-log.ts +28 -0
  376. package/servers/_edit-match.ts +236 -0
  377. package/servers/_edit-validate.ts +196 -0
  378. package/servers/_embed-calibration.ts +123 -0
  379. package/servers/_embedding-cache.ts +401 -0
  380. package/servers/_embedding-model.ts +329 -0
  381. package/servers/_events.ts +113 -0
  382. package/servers/_genome-cache.ts +154 -0
  383. package/servers/_genome-commits.ts +172 -0
  384. package/servers/_genome-crypto-v2.ts +242 -0
  385. package/servers/_genome-crypto.ts +259 -0
  386. package/servers/_genome-discoveries.ts +140 -0
  387. package/servers/_genome-embed-populator.ts +216 -0
  388. package/servers/_genome-freshness.ts +134 -0
  389. package/servers/_genome-issues.ts +171 -0
  390. package/servers/_genome-live.ts +263 -0
  391. package/servers/_genome-prs.ts +188 -0
  392. package/servers/_genome-search.ts +479 -0
  393. package/servers/_genome-sync.ts +297 -0
  394. package/servers/_history-tracker.ts +279 -0
  395. package/servers/_http-helpers.ts +151 -0
  396. package/servers/_identity-hash.ts +151 -0
  397. package/servers/_llm-providers/anthropic.ts +132 -0
  398. package/servers/_llm-providers/cloud.ts +195 -0
  399. package/servers/_llm-providers/index.ts +350 -0
  400. package/servers/_llm-providers/local.ts +127 -0
  401. package/servers/_llm-providers/onnx.ts +393 -0
  402. package/servers/_llm-providers/types.ts +27 -0
  403. package/servers/_manifest-v2.ts +447 -0
  404. package/servers/_mcp-host.ts +93 -0
  405. package/servers/_nudge-events.ts +451 -0
  406. package/servers/_orchestrate-executor.ts +316 -0
  407. package/servers/_prefetch.ts +435 -0
  408. package/servers/_pricing.ts +256 -0
  409. package/servers/_pro.ts +381 -0
  410. package/servers/_read-cache.ts +44 -0
  411. package/servers/_router-handlers.ts +46 -0
  412. package/servers/_router.ts +55 -0
  413. package/servers/_run-with-timeout.ts +173 -0
  414. package/servers/_savings-render.ts +214 -0
  415. package/servers/_stats-sqlite.ts +640 -0
  416. package/servers/_stats.ts +1183 -0
  417. package/servers/_status-line-cells.ts +469 -0
  418. package/servers/_streaks.ts +162 -0
  419. package/servers/_summarize.ts +208 -0
  420. package/servers/_task-graph-render.ts +217 -0
  421. package/servers/_task-graph.ts +545 -0
  422. package/servers/_telemetry.ts +719 -0
  423. package/servers/_test-parsers.ts +530 -0
  424. package/servers/_test-watch.ts +626 -0
  425. package/servers/_text-helpers.ts +37 -0
  426. package/servers/_token-measure.ts +160 -0
  427. package/servers/_tool-base.ts +248 -0
  428. package/servers/_weekly-digest.ts +391 -0
  429. package/servers/ask-server-handlers.ts +49 -0
  430. package/servers/ask-server.ts +174 -0
  431. package/servers/bash-server-handlers.ts +138 -0
  432. package/servers/bash-server.ts +1136 -0
  433. package/servers/bench.ts +186 -0
  434. package/servers/diff-semantic-server-handlers.ts +39 -0
  435. package/servers/diff-semantic-server.ts +566 -0
  436. package/servers/diff-server-handlers.ts +317 -0
  437. package/servers/diff-server.ts +20 -0
  438. package/servers/edit-server-handlers.ts +31 -0
  439. package/servers/edit-server.ts +209 -0
  440. package/servers/edit-structural-server-handlers.ts +322 -0
  441. package/servers/efficiency-server-handlers.ts +161 -0
  442. package/servers/efficiency-server.ts +1135 -0
  443. package/servers/flush-server-handlers.ts +21 -0
  444. package/servers/flush-server.ts +19 -0
  445. package/servers/genome-server-handlers.ts +118 -0
  446. package/servers/genome-server.ts +397 -0
  447. package/servers/github-server-handlers.ts +187 -0
  448. package/servers/github-server.ts +856 -0
  449. package/servers/glob-server-handlers.ts +233 -0
  450. package/servers/glob-server.ts +20 -0
  451. package/servers/grep-server-handlers.ts +61 -0
  452. package/servers/grep-server.ts +564 -0
  453. package/servers/http-server-handlers.ts +36 -0
  454. package/servers/http-server.ts +149 -0
  455. package/servers/logs-server-handlers.ts +42 -0
  456. package/servers/logs-server.ts +359 -0
  457. package/servers/ls-server-handlers.ts +166 -0
  458. package/servers/ls-server.ts +20 -0
  459. package/servers/multi-edit-server-handlers.ts +51 -0
  460. package/servers/multi-edit-server.ts +422 -0
  461. package/servers/notebook-edit-server-handlers.ts +34 -0
  462. package/servers/notebook-edit-server.ts +181 -0
  463. package/servers/orient-server-handlers.ts +52 -0
  464. package/servers/orient-server.ts +436 -0
  465. package/servers/pipe-server-handlers.ts +68 -0
  466. package/servers/pipe-server.ts +300 -0
  467. package/servers/read-server-handlers.ts +42 -0
  468. package/servers/read-server.ts +206 -0
  469. package/servers/rename-file-server-handlers.ts +67 -0
  470. package/servers/rename-file-server.ts +699 -0
  471. package/servers/savings-server-handlers.ts +27 -0
  472. package/servers/savings-server.ts +54 -0
  473. package/servers/search-replace-regex-server-handlers.ts +96 -0
  474. package/servers/search-replace-regex-server.ts +751 -0
  475. package/servers/sql-server-handlers.ts +58 -0
  476. package/servers/sql-server.ts +505 -0
  477. package/servers/task-server-handlers.ts +358 -0
  478. package/servers/task-server.ts +24 -0
  479. package/servers/test-server-handlers.ts +351 -0
  480. package/servers/test-server.ts +20 -0
  481. package/servers/tree-server-handlers.ts +503 -0
  482. package/servers/tree-server.ts +20 -0
  483. package/servers/webfetch-server-handlers.ts +166 -0
  484. package/servers/webfetch-server.ts +20 -0
  485. package/servers/websearch-server-handlers.ts +215 -0
  486. package/servers/websearch-server.ts +19 -0
  487. package/servers/write-server-handlers.ts +27 -0
  488. package/servers/write-server.ts +97 -0
  489. package/skills/ashlr-brief/SKILL.md +80 -0
  490. package/skills/ashlr-codex-doctor/SKILL.md +21 -0
  491. package/skills/ashlr-codex-efficient-tools/SKILL.md +17 -0
  492. package/skills/ashlr-codex-genome-refresh/SKILL.md +20 -0
  493. package/skills/ashlr-codex-parallel-explore/SKILL.md +20 -0
  494. package/skills/ashlr-codex-savings/SKILL.md +17 -0
  495. package/skills/ashlr-cost-refactor/SKILL.md +50 -0
  496. package/skills/ashlr-efficient/SKILL.md +64 -0
  497. package/skills/ashlr-genome-author/SKILL.md +43 -0
  498. package/skills/ashlr-lean-tools/SKILL.md +43 -0
  499. 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
+ }