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,122 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * posttooluse-correlate.ts — Correlate ashlr__* calls with prior native-tool
4
+ * blocks to measure redirect conversion.
5
+ *
6
+ * PostToolUse hook. When an ashlr__read / ashlr__grep / ashlr__edit /
7
+ * ashlr__multi_edit call completes, this hook reads the recent-blocks log
8
+ * written by the pretooluse-* hooks. For every block within the 10-second
9
+ * window, it emits a `tool_called_after_block` event with correlation metadata
10
+ * and then prunes the consumed entries from the log.
11
+ *
12
+ * Design:
13
+ * - Best-effort only. Any error → silent continue, exit 0.
14
+ * - Kill switch: ASHLR_SESSION_LOG=0 disables all telemetry.
15
+ * - Window: 10 seconds (configurable via ASHLR_BLOCK_WINDOW_MS).
16
+ * - Only fires for tools that are known ashlr equivalents.
17
+ */
18
+
19
+ import { join, dirname } from "path";
20
+ import { fileURLToPath } from "url";
21
+ import { flushHookTimings, recordHookTiming } from "./pretooluse-common";
22
+ import { readRecentBlocks, pruneOldBlocks } from "./_recent-blocks";
23
+
24
+ const hookStartedAt = Date.now();
25
+
26
+ async function exit(code: number, outcome: "ok" | "error" = "ok"): Promise<never> {
27
+ recordHookTiming({
28
+ hook: "posttooluse-correlate",
29
+ durationMs: Date.now() - hookStartedAt,
30
+ outcome,
31
+ });
32
+ await flushHookTimings();
33
+ process.exit(code);
34
+ }
35
+
36
+ // Kill switch
37
+ if (process.env.ASHLR_SESSION_LOG === "0") await exit(0);
38
+
39
+ // Correlation window (default 10s)
40
+ const WINDOW_MS = (() => {
41
+ const raw = process.env.ASHLR_BLOCK_WINDOW_MS;
42
+ if (!raw) return 10_000;
43
+ const n = parseInt(raw, 10);
44
+ return Number.isFinite(n) && n > 0 ? n : 10_000;
45
+ })();
46
+
47
+ // Map from ashlr tool → native tool it replaces (for correlation)
48
+ const ASHLR_TO_NATIVE: Record<string, string[]> = {
49
+ "ashlr__read": ["Read"],
50
+ "ashlr__grep": ["Grep"],
51
+ "ashlr__edit": ["Edit", "Write"],
52
+ "ashlr__multi_edit": ["MultiEdit"],
53
+ // Wave-1 tools (Track B/C) — reference them but they may not exist yet.
54
+ "ashlr__websearch": ["WebSearch"],
55
+ "ashlr__notebook_edit": ["NotebookEdit"],
56
+ "ashlr__write": ["Write"],
57
+ };
58
+
59
+ // Read stdin
60
+ const chunks: Buffer[] = [];
61
+ process.stdin.on("data", (c: Buffer) => chunks.push(c));
62
+ process.stdin.on("end", async () => {
63
+ let payload: Record<string, unknown> = {};
64
+ try {
65
+ payload = JSON.parse(Buffer.concat(chunks).toString("utf-8")) as Record<string, unknown>;
66
+ } catch {
67
+ await exit(0);
68
+ }
69
+
70
+ const toolName = payload.tool_name as string | undefined;
71
+ if (!toolName) await exit(0);
72
+ // After the guard above, toolName is narrowed to string within the
73
+ // same block — but TypeScript can't narrow across the async exit(0)
74
+ // boundary. Use a local const to carry the narrowed type forward.
75
+ const resolvedToolName: string = toolName!;
76
+
77
+ // Only process known ashlr tools
78
+ const nativeEquivalents = ASHLR_TO_NATIVE[resolvedToolName];
79
+ if (!nativeEquivalents) await exit(0);
80
+
81
+ const now = Date.now();
82
+ const cutoff = now - WINDOW_MS;
83
+
84
+ // After nativeEquivalents guard, TypeScript can't narrow across async boundary.
85
+ const resolvedNative: string[] = nativeEquivalents!;
86
+
87
+ // Read recent blocks and find matches within window
88
+ const blocks = readRecentBlocks();
89
+ const matches = blocks.filter(
90
+ (b) => b.ts >= cutoff && resolvedNative.includes(b.toolName)
91
+ );
92
+
93
+ if (matches.length === 0) {
94
+ // Still prune stale entries
95
+ pruneOldBlocks(WINDOW_MS * 2);
96
+ await exit(0);
97
+ }
98
+
99
+ // Emit one event per matched block
100
+ try {
101
+ const { logEvent } = await import("../servers/_events");
102
+ for (const match of matches) {
103
+ await logEvent("tool_called_after_block", {
104
+ tool: resolvedToolName,
105
+ extra: {
106
+ nativeToolBlocked: match.toolName,
107
+ blockTs: match.ts,
108
+ latencyMs: now - match.ts,
109
+ pattern: match.pattern,
110
+ filePath: match.filePath,
111
+ },
112
+ });
113
+ }
114
+ } catch {
115
+ // Telemetry must never surface errors.
116
+ }
117
+
118
+ // Prune old entries (keep any that are still within the window but unmatched)
119
+ pruneOldBlocks(WINDOW_MS * 2);
120
+
121
+ await exit(0);
122
+ });
@@ -0,0 +1,241 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * posttooluse-dedupe-output.ts — Elide duplicate tool results across turns.
4
+ *
5
+ * PostToolUse hook for Read / Grep / ashlr__read / ashlr__grep.
6
+ *
7
+ * When the same content (identified by contentSha8) was already seen from the
8
+ * same tool class (Read↔ashlr__read, Grep↔ashlr__grep) within the last 8
9
+ * turns of the current session, the result is elided in additionalContext so
10
+ * the model doesn't re-ingest redundant bytes.
11
+ *
12
+ * Design:
13
+ * - Best-effort — never throws, always exits 0.
14
+ * - Kill switch: ASHLR_SESSION_LOG=0 disables everything.
15
+ * - Uses the same session-history JSONL written by posttooluse-stale-result.
16
+ *
17
+ * Hook contract (PostToolUse):
18
+ * stdin → { tool_name, tool_input?, tool_result? }
19
+ * stdout → { hookSpecificOutput: { hookEventName: "PostToolUse",
20
+ * additionalContext?: string } }
21
+ */
22
+
23
+ import { existsSync, mkdirSync, readFileSync, appendFileSync } from "fs";
24
+ import { homedir } from "os";
25
+ import { dirname, join } from "path";
26
+
27
+ import {
28
+ readHistory,
29
+ resolveSessionId,
30
+ sha8,
31
+ historyDir,
32
+ historyPath,
33
+ readCurrentTurn,
34
+ type HistoryEntry,
35
+ } from "../servers/_history-tracker";
36
+
37
+ // ---------------------------------------------------------------------------
38
+ // Constants
39
+ // ---------------------------------------------------------------------------
40
+
41
+ /** How many recent turns to scan for duplicates. */
42
+ const DEDUP_LOOKBACK_TURNS = 8;
43
+
44
+ // ---------------------------------------------------------------------------
45
+ // Tool class normalisation — Read↔ashlr__read, Grep↔ashlr__grep
46
+ // ---------------------------------------------------------------------------
47
+
48
+ type ToolClass = "read" | "grep" | "other";
49
+
50
+ const TRACKED_TOOLS = new Set([
51
+ "Read",
52
+ "Grep",
53
+ "mcp__ashlr-efficiency__ashlr__read",
54
+ "mcp__ashlr-efficiency__ashlr__grep",
55
+ "mcp__plugin_ashlr_ashlr__ashlr__read",
56
+ "mcp__plugin_ashlr_ashlr__ashlr__grep",
57
+ "ashlr__read",
58
+ "ashlr__grep",
59
+ ]);
60
+
61
+ function toolClass(toolName: string): ToolClass {
62
+ const t = toolName.toLowerCase();
63
+ if (t === "read" || t.endsWith("ashlr__read")) return "read";
64
+ if (t === "grep" || t.endsWith("ashlr__grep")) return "grep";
65
+ return "other";
66
+ }
67
+
68
+ // ---------------------------------------------------------------------------
69
+ // Content extraction
70
+ // ---------------------------------------------------------------------------
71
+
72
+ function extractContent(payload: Record<string, unknown>): string {
73
+ const result = payload.tool_result ?? payload.tool_response ?? payload.tool_output;
74
+ if (result == null) return "";
75
+ if (typeof result === "string") return result;
76
+ try { return JSON.stringify(result); } catch { return ""; }
77
+ }
78
+
79
+ // ---------------------------------------------------------------------------
80
+ // Hook output type
81
+ // ---------------------------------------------------------------------------
82
+
83
+ interface HookOutput {
84
+ hookSpecificOutput: {
85
+ hookEventName: "PostToolUse";
86
+ additionalContext?: string;
87
+ };
88
+ }
89
+
90
+ function passThrough(): HookOutput {
91
+ return { hookSpecificOutput: { hookEventName: "PostToolUse" } };
92
+ }
93
+
94
+ // ---------------------------------------------------------------------------
95
+ // Dedup stats path (for bytesSaved accumulation)
96
+ // ---------------------------------------------------------------------------
97
+
98
+ export function dedupStatsPath(homeDir: string): string {
99
+ return join(homeDir, ".ashlr", "dedupe-stats.json");
100
+ }
101
+
102
+ export interface DedupeStats {
103
+ bytesSaved: number;
104
+ dedupeCount: number;
105
+ }
106
+
107
+ function loadDedupeStats(homeDir: string): DedupeStats {
108
+ try {
109
+ const p = dedupStatsPath(homeDir);
110
+ if (!existsSync(p)) return { bytesSaved: 0, dedupeCount: 0 };
111
+ return JSON.parse(readFileSync(p, "utf-8")) as DedupeStats;
112
+ } catch {
113
+ return { bytesSaved: 0, dedupeCount: 0 };
114
+ }
115
+ }
116
+
117
+ function saveDedupeStats(stats: DedupeStats, homeDir: string): void {
118
+ try {
119
+ const p = dedupStatsPath(homeDir);
120
+ mkdirSync(dirname(p), { recursive: true });
121
+ const { writeFileSync } = require("fs") as typeof import("fs");
122
+ writeFileSync(p, JSON.stringify(stats), "utf-8");
123
+ } catch {
124
+ // Best-effort.
125
+ }
126
+ }
127
+
128
+ function accumulateBytesSaved(bytes: number, homeDir: string): void {
129
+ try {
130
+ const stats = loadDedupeStats(homeDir);
131
+ stats.bytesSaved += bytes;
132
+ stats.dedupeCount += 1;
133
+ saveDedupeStats(stats, homeDir);
134
+ } catch {
135
+ // Best-effort.
136
+ }
137
+ }
138
+
139
+ // ---------------------------------------------------------------------------
140
+ // Main decision function (exported for tests)
141
+ // ---------------------------------------------------------------------------
142
+
143
+ export interface DecideOpts {
144
+ home?: string;
145
+ sessionId?: string;
146
+ now?: number;
147
+ }
148
+
149
+ export function decide(
150
+ payload: Record<string, unknown>,
151
+ opts: DecideOpts = {},
152
+ ): HookOutput {
153
+ if (process.env.ASHLR_SESSION_LOG === "0") return passThrough();
154
+
155
+ const toolName = payload?.tool_name;
156
+ if (typeof toolName !== "string" || !TRACKED_TOOLS.has(toolName)) {
157
+ return passThrough();
158
+ }
159
+
160
+ const klass = toolClass(toolName);
161
+ if (klass === "other") return passThrough();
162
+
163
+ const homeDir =
164
+ opts.home ??
165
+ (process.env.ASHLR_HOME_OVERRIDE?.trim() || process.env.HOME || homedir());
166
+ const sessionId = opts.sessionId ?? resolveSessionId();
167
+
168
+ const content = extractContent(payload);
169
+ if (!content) return passThrough();
170
+
171
+ const contentHash = sha8(content);
172
+ const contentBytes = Buffer.byteLength(content, "utf-8");
173
+
174
+ // Read last DEDUP_LOOKBACK_TURNS entries from session history.
175
+ const history = readHistory(sessionId, homeDir);
176
+ if (history.length === 0) return passThrough();
177
+
178
+ const currentTurn = history.length;
179
+ const lookbackStart = Math.max(0, currentTurn - DEDUP_LOOKBACK_TURNS);
180
+ const recentEntries = history.slice(lookbackStart);
181
+
182
+ // Find a prior turn with matching tool class AND same contentSha8.
183
+ const match = recentEntries.find(
184
+ (e: HistoryEntry) =>
185
+ toolClass(e.tool) === klass &&
186
+ e.contentSha8 === contentHash &&
187
+ e.turn < currentTurn,
188
+ );
189
+
190
+ if (!match) return passThrough();
191
+
192
+ // Duplicate found — elide and report.
193
+ accumulateBytesSaved(contentBytes, homeDir);
194
+
195
+ const elision =
196
+ `[ashlr-dedupe] identical to turn ${match.turn} result ` +
197
+ `(sha8=${contentHash}); content elided to save ${contentBytes}B`;
198
+
199
+ return {
200
+ hookSpecificOutput: {
201
+ hookEventName: "PostToolUse",
202
+ additionalContext: elision,
203
+ },
204
+ };
205
+ }
206
+
207
+ // ---------------------------------------------------------------------------
208
+ // Stdin reading
209
+ // ---------------------------------------------------------------------------
210
+
211
+ async function readStdin(): Promise<string> {
212
+ const chunks: Buffer[] = [];
213
+ for await (const chunk of process.stdin as AsyncIterable<Buffer | string>) {
214
+ chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
215
+ }
216
+ return Buffer.concat(chunks).toString("utf-8");
217
+ }
218
+
219
+ // ---------------------------------------------------------------------------
220
+ // Entry point
221
+ // ---------------------------------------------------------------------------
222
+
223
+ async function main(): Promise<void> {
224
+ let payload: Record<string, unknown> = {};
225
+ try {
226
+ const raw = await readStdin();
227
+ if (raw.trim()) payload = JSON.parse(raw) as Record<string, unknown>;
228
+ } catch {
229
+ process.stdout.write(JSON.stringify(passThrough()));
230
+ return;
231
+ }
232
+ try {
233
+ process.stdout.write(JSON.stringify(decide(payload)));
234
+ } catch {
235
+ process.stdout.write(JSON.stringify(passThrough()));
236
+ }
237
+ }
238
+
239
+ if (import.meta.main) {
240
+ await main();
241
+ }
@@ -0,0 +1,223 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * posttooluse-genome-refresh.ts — PostToolUse hook that records edited file
4
+ * paths to ~/.ashlr/pending-genome-refresh.txt for incremental genome refresh.
5
+ *
6
+ * Triggers on Edit, Write, MultiEdit, NotebookEdit, and all ashlr MCP edit
7
+ * variants. Appends the absolute file path (deduped) so the genome-refresh-
8
+ * worker can process them at session end.
9
+ *
10
+ * Design rules:
11
+ * - Never throws, never blocks. Best-effort fire-and-forget.
12
+ * - Exits 0 always.
13
+ * - No stdout — must not pollute the hook channel.
14
+ * - Kill switch: ASHLR_GENOME_AUTO=0
15
+ */
16
+
17
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
18
+ import { homedir } from "os";
19
+ import { join, dirname, resolve, isAbsolute } from "path";
20
+
21
+ import { noteHookError } from "./_hook-errors";
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Constants
25
+ // ---------------------------------------------------------------------------
26
+
27
+ export const PENDING_FILE_NAME = "pending-genome-refresh.txt";
28
+
29
+ function pendingPath(home: string = homedir()): string {
30
+ return join(home, ".ashlr", PENDING_FILE_NAME);
31
+ }
32
+
33
+ // ---------------------------------------------------------------------------
34
+ // Tool name detection — mirrors genome-scribe-hook.ts EDIT_TOOL_NAMES
35
+ // ---------------------------------------------------------------------------
36
+
37
+ export const WRITE_TOOL_NAMES = new Set<string>([
38
+ "Edit",
39
+ "Write",
40
+ "MultiEdit",
41
+ "NotebookEdit",
42
+ ]);
43
+
44
+ export function isWriteTool(name: string | undefined): boolean {
45
+ if (!name) return false;
46
+ if (WRITE_TOOL_NAMES.has(name)) return true;
47
+ // mcp__plugin_ashlr_ashlr__ashlr__edit etc.
48
+ if (!name.startsWith("mcp__")) return false;
49
+ return (
50
+ name.endsWith("ashlr__edit") ||
51
+ name.endsWith("ashlr__write") ||
52
+ name.endsWith("ashlr__multi_edit") ||
53
+ name.endsWith("ashlr__notebook_edit") ||
54
+ name.endsWith("ashlr__edit_structural") ||
55
+ name.endsWith("ashlr__rename_file")
56
+ );
57
+ }
58
+
59
+ // ---------------------------------------------------------------------------
60
+ // Path extraction from tool_input
61
+ // ---------------------------------------------------------------------------
62
+
63
+ interface ToolInput {
64
+ file_path?: unknown;
65
+ path?: unknown;
66
+ // rename_file uses old_path / new_path
67
+ old_path?: unknown;
68
+ new_path?: unknown;
69
+ // MultiEdit uses edits[]
70
+ edits?: Array<{ file_path?: unknown }>;
71
+ }
72
+
73
+ export function extractFilePaths(toolInput: unknown): string[] {
74
+ if (!toolInput || typeof toolInput !== "object") return [];
75
+ const inp = toolInput as ToolInput;
76
+ const paths: string[] = [];
77
+
78
+ // Single file: file_path or path
79
+ for (const key of ["file_path", "path", "old_path", "new_path"] as const) {
80
+ const v = inp[key];
81
+ if (typeof v === "string" && v.trim()) paths.push(v.trim());
82
+ }
83
+
84
+ // MultiEdit: edits[].file_path
85
+ if (Array.isArray(inp.edits)) {
86
+ for (const e of inp.edits) {
87
+ if (e && typeof e === "object") {
88
+ const fp = (e as { file_path?: unknown }).file_path;
89
+ if (typeof fp === "string" && fp.trim()) paths.push(fp.trim());
90
+ }
91
+ }
92
+ }
93
+
94
+ // Deduplicate within this payload
95
+ return [...new Set(paths)];
96
+ }
97
+
98
+ // ---------------------------------------------------------------------------
99
+ // Pending-list writer
100
+ // ---------------------------------------------------------------------------
101
+
102
+ /**
103
+ * Append absolute paths to the pending file, deduped.
104
+ * Returns true if any paths were added.
105
+ */
106
+ export function appendToPending(paths: string[], home?: string): boolean {
107
+ if (paths.length === 0) return false;
108
+ const file = pendingPath(home);
109
+ try {
110
+ mkdirSync(dirname(file), { recursive: true });
111
+ } catch {
112
+ return false;
113
+ }
114
+
115
+ // Read existing set
116
+ const existing = new Set<string>();
117
+ if (existsSync(file)) {
118
+ try {
119
+ for (const line of readFileSync(file, "utf-8").split("\n")) {
120
+ const t = line.trim();
121
+ if (t) existing.add(t);
122
+ }
123
+ } catch (e) {
124
+ noteHookError("posttooluse-genome-refresh", "read-pending-list", e);
125
+ }
126
+ }
127
+
128
+ // Resolve to absolute paths and filter new-only
129
+ const toAdd: string[] = [];
130
+ for (const p of paths) {
131
+ const abs = isAbsolute(p) ? p : resolve(p);
132
+ if (!existing.has(abs)) {
133
+ existing.add(abs);
134
+ toAdd.push(abs);
135
+ }
136
+ }
137
+
138
+ if (toAdd.length === 0) return false;
139
+
140
+ try {
141
+ const content = [...existing].filter(Boolean).join("\n") + "\n";
142
+ writeFileSync(file, content, "utf-8");
143
+ return true;
144
+ } catch (e) {
145
+ noteHookError("posttooluse-genome-refresh", "write-pending-list", e);
146
+ return false;
147
+ }
148
+ }
149
+
150
+ // ---------------------------------------------------------------------------
151
+ // Payload type
152
+ // ---------------------------------------------------------------------------
153
+
154
+ interface PostToolUsePayload {
155
+ tool_name?: string;
156
+ tool_input?: unknown;
157
+ tool_response?: Record<string, unknown>;
158
+ }
159
+
160
+ function editSucceeded(toolResponse: Record<string, unknown> | undefined): boolean {
161
+ if (!toolResponse) return true;
162
+ if (toolResponse.isError === true) return false;
163
+ if (toolResponse.is_error === true) return false;
164
+ if (typeof toolResponse.success === "boolean") return toolResponse.success;
165
+ return true;
166
+ }
167
+
168
+ // ---------------------------------------------------------------------------
169
+ // Hook output (pass-through — we never block)
170
+ // ---------------------------------------------------------------------------
171
+
172
+ interface HookOutput {
173
+ hookSpecificOutput: { hookEventName: "PostToolUse"; additionalContext?: string };
174
+ }
175
+
176
+ export function passThrough(): HookOutput {
177
+ return { hookSpecificOutput: { hookEventName: "PostToolUse" } };
178
+ }
179
+
180
+ // ---------------------------------------------------------------------------
181
+ // Core logic
182
+ // ---------------------------------------------------------------------------
183
+
184
+ export function handle(payload: PostToolUsePayload, home?: string): HookOutput {
185
+ try {
186
+ if (process.env.ASHLR_GENOME_AUTO === "0") return passThrough();
187
+ if (!isWriteTool(payload?.tool_name)) return passThrough();
188
+ if (!editSucceeded(payload.tool_response)) return passThrough();
189
+
190
+ const paths = extractFilePaths(payload.tool_input);
191
+ appendToPending(paths, home ?? homedir());
192
+ } catch (e) {
193
+ noteHookError("posttooluse-genome-refresh", "handle", e);
194
+ }
195
+ return passThrough();
196
+ }
197
+
198
+ // ---------------------------------------------------------------------------
199
+ // Stdio entry point
200
+ // ---------------------------------------------------------------------------
201
+
202
+ async function main(): Promise<void> {
203
+ const chunks: Buffer[] = [];
204
+ for await (const chunk of process.stdin as AsyncIterable<Buffer | string>) {
205
+ chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
206
+ }
207
+ const raw = Buffer.concat(chunks).toString("utf-8").trim();
208
+
209
+ let payload: PostToolUsePayload = {};
210
+ if (raw) {
211
+ try {
212
+ payload = JSON.parse(raw) as PostToolUsePayload;
213
+ } catch {
214
+ /* bad input — pass-through */
215
+ }
216
+ }
217
+
218
+ process.stdout.write(JSON.stringify(handle(payload)));
219
+ }
220
+
221
+ if (import.meta.main) {
222
+ await main();
223
+ }