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,467 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * ashlr grep calibration harness.
4
+ *
5
+ * Measures the empirical ratio between raw ripgrep output size and the genome-
6
+ * compressed size returned by ashlr__grep. Writes results to
7
+ * ~/.ashlr/calibration.json so efficiency-server.ts can replace its
8
+ * hardcoded 4× multiplier with a data-driven value.
9
+ *
10
+ * Usage:
11
+ * bun run scripts/calibrate-grep.ts
12
+ * bun run scripts/calibrate-grep.ts --workload /path/to/workload.jsonl
13
+ * bun run scripts/calibrate-grep.ts --out /path/to/calibration.json
14
+ *
15
+ * Workload format (~/.ashlr/calibration-workload.jsonl):
16
+ * { "cwd": "/path/to/project", "pattern": "someSymbol" }
17
+ * { "cwd": "/path/to/other", "pattern": "anotherPattern" }
18
+ *
19
+ * If no workload file is found, a bundled synthetic fixture is used instead
20
+ * (runs rg against the ashlr-plugin source tree itself).
21
+ */
22
+
23
+ import { spawnSync } from "child_process";
24
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
25
+ import { homedir } from "os";
26
+ import { dirname, join, resolve } from "path";
27
+
28
+ import { type CalibrationFile, type CalibrationSample } from "./read-calibration";
29
+
30
+ // ---------------------------------------------------------------------------
31
+ // Types
32
+ // ---------------------------------------------------------------------------
33
+
34
+ interface Workload {
35
+ cwd: string;
36
+ pattern: string;
37
+ }
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // Helpers
41
+ // ---------------------------------------------------------------------------
42
+
43
+ function resolveRg(): string {
44
+ // Mirror the same resolution logic as efficiency-server.ts so we run the
45
+ // same binary.
46
+ return (
47
+ (typeof (globalThis as { Bun?: { which(b: string): string | null } }).Bun !== "undefined"
48
+ ? (globalThis as { Bun: { which(b: string): string | null } }).Bun.which("rg")
49
+ : null) ??
50
+ ["/opt/homebrew/bin/rg", "/usr/local/bin/rg", "/usr/bin/rg"].find((p) => {
51
+ try {
52
+ require("fs").accessSync(p);
53
+ return true;
54
+ } catch {
55
+ return false;
56
+ }
57
+ }) ??
58
+ "rg"
59
+ );
60
+ }
61
+
62
+ /**
63
+ * Run `rg --json <pattern> <cwd>` and return the raw stdout bytes.
64
+ * Returns null if rg is unavailable or the call times out.
65
+ */
66
+ function rgRawBytes(pattern: string, cwd: string): number | null {
67
+ try {
68
+ // `--` stops rg flag parsing so a workload with a pattern starting with
69
+ // `-` or `--` can't smuggle in flags like --invert-match or -uuu.
70
+ const res = spawnSync(resolveRg(), ["--json", "-n", "--", pattern, cwd], {
71
+ encoding: "buffer",
72
+ timeout: 10_000,
73
+ maxBuffer: 64 * 1024 * 1024,
74
+ });
75
+ // status 0 = matches found, status 1 = no matches — both are valid.
76
+ if (res.status !== 0 && res.status !== 1) return null;
77
+ const buf = res.stdout as Buffer | null;
78
+ return buf ? buf.length : 0;
79
+ } catch {
80
+ return null;
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Try to load genome helpers and retrieve compressed output size.
86
+ * Returns null when the genome is absent or the import fails.
87
+ *
88
+ * Root-cause fix (v1.29): the genome is a project-knowledge store (vision,
89
+ * strategies, milestones). Its TF-IDF scorer filters out any section with
90
+ * score === 0. Code-level patterns like "recordSaving" or "spawnSync" never
91
+ * appear in section tags/titles/summaries, so retrieveSectionsV2 returns [] for
92
+ * every synthetic workload pattern — causing the caller to fall through to the
93
+ * syntheticSampleNoGenome() 4× estimate.
94
+ *
95
+ * Fix: when retrieveSectionsV2 returns 0 sections (pattern has no genome match),
96
+ * retry with an empty query to get the *core* genome sections (north-star,
97
+ * current milestone, active strategies). These are what the real ashlr__grep
98
+ * tool returns for any query that scores zero sections — they represent the
99
+ * actual compressed output the tool would emit, giving a real measurement
100
+ * rather than the synthetic rawBytes/4 fallback.
101
+ *
102
+ * We try the @ashlr/core-efficiency import dynamically so the script still
103
+ * runs (in synthetic-fixture mode) on machines where the module is absent.
104
+ */
105
+ async function genomeCompressedBytes(
106
+ pattern: string,
107
+ cwd: string,
108
+ ): Promise<{ bytes: number; wasCoreFallback: boolean } | null> {
109
+ try {
110
+ // Dynamic imports so a missing genome doesn't throw at module load time.
111
+ const { genomeExists, retrieveSectionsV2, retrieveSections, formatGenomeForPrompt } =
112
+ await import("@ashlr/core-efficiency");
113
+ const { findParentGenome } = await import("./genome-link");
114
+
115
+ let genomeRoot: string | null = null;
116
+ if (genomeExists(cwd)) {
117
+ genomeRoot = cwd;
118
+ } else {
119
+ const parent = findParentGenome(cwd);
120
+ if (parent) genomeRoot = parent;
121
+ }
122
+
123
+ if (!genomeRoot) return null;
124
+
125
+ // First: try pattern-matched retrieval (semantic + TF-IDF).
126
+ let sections = await retrieveSectionsV2(genomeRoot, pattern, 4000);
127
+ let wasCoreFallback = false;
128
+
129
+ if (sections.length === 0) {
130
+ // Pattern scored 0 against all genome sections (expected for code-symbol
131
+ // patterns against a project-knowledge genome). Fall back to core sections
132
+ // (empty-query path in retrieveSections) — these are the actual bytes the
133
+ // real grep tool returns for unmatched queries. This gives a real ratio
134
+ // measurement rather than the synthetic rawBytes/4 estimate.
135
+ sections = await retrieveSections(genomeRoot, "", 4000);
136
+ wasCoreFallback = true;
137
+ }
138
+
139
+ if (sections.length === 0) return null;
140
+ const formatted = formatGenomeForPrompt(sections);
141
+ return { bytes: formatted.length, wasCoreFallback };
142
+ } catch {
143
+ return null;
144
+ }
145
+ }
146
+
147
+ // ---------------------------------------------------------------------------
148
+ // Synthetic fixture (used when no real workload is available)
149
+ // ---------------------------------------------------------------------------
150
+
151
+ /**
152
+ * Build a synthetic workload that runs rg against the ashlr-plugin source
153
+ * tree. These patterns are representative of typical agent queries.
154
+ */
155
+ function syntheticWorkload(): Workload[] {
156
+ // Use __dirname-equivalent: the directory of this script.
157
+ const pluginRoot = resolve(dirname(new URL(import.meta.url).pathname), "..");
158
+ return [
159
+ { cwd: pluginRoot, pattern: "recordSaving" },
160
+ { cwd: pluginRoot, pattern: "retrieveSectionsV2" },
161
+ { cwd: pluginRoot, pattern: "genomeExists" },
162
+ { cwd: pluginRoot, pattern: "spawnSync" },
163
+ { cwd: pluginRoot, pattern: "estimateTokens" },
164
+ { cwd: pluginRoot, pattern: "tokensSaved" },
165
+ { cwd: pluginRoot, pattern: "formatBaseline" },
166
+ { cwd: pluginRoot, pattern: "snipCompact" },
167
+ ];
168
+ }
169
+
170
+ /**
171
+ * Build a synthetic workload using only rg raw sizes (no genome required).
172
+ * Used when genome isn't available — we still measure rg output sizes so the
173
+ * calibration data is available for future use once a genome is created.
174
+ *
175
+ * In this mode we compute ratio = rawBytes / (rawBytes / 4) = 4.0 as a
176
+ * passthrough. The sample is flagged quality="synthetic" so callers can
177
+ * detect and warn about the bogus estimate.
178
+ */
179
+ function syntheticSampleNoGenome(w: Workload, rawBytes: number): CalibrationSample {
180
+ // Without a genome we can't compress, so we estimate compressed = raw/4.
181
+ // quality="synthetic" lets the report warn about low-quality samples.
182
+ const compressedBytes = Math.max(1, Math.round(rawBytes / 4));
183
+ return {
184
+ cwd: w.cwd,
185
+ pattern: w.pattern,
186
+ rawBytes,
187
+ compressedBytes,
188
+ ratio: rawBytes / compressedBytes,
189
+ quality: "synthetic",
190
+ };
191
+ }
192
+
193
+ // ---------------------------------------------------------------------------
194
+ // Stats helpers
195
+ // ---------------------------------------------------------------------------
196
+
197
+ function percentile(sorted: number[], p: number): number {
198
+ if (sorted.length === 0) return 0;
199
+ const idx = Math.min(
200
+ sorted.length - 1,
201
+ Math.floor((p / 100) * sorted.length),
202
+ );
203
+ return sorted[idx]!;
204
+ }
205
+
206
+ function mean(values: number[]): number {
207
+ if (values.length === 0) return 0;
208
+ return values.reduce((s, v) => s + v, 0) / values.length;
209
+ }
210
+
211
+ // ---------------------------------------------------------------------------
212
+ // Report rendering
213
+ // ---------------------------------------------------------------------------
214
+
215
+ function renderReport(
216
+ samples: CalibrationSample[],
217
+ meanRatio: number,
218
+ p50: number,
219
+ p90: number,
220
+ outPath: string,
221
+ measuredMean?: number,
222
+ syntheticMean?: number,
223
+ measuredCount?: number,
224
+ coreFallbackMean?: number,
225
+ coreFallbackCount?: number,
226
+ ): string {
227
+ const lines: string[] = [];
228
+ lines.push("ashlr grep calibration report");
229
+ lines.push("═".repeat(50));
230
+ lines.push("");
231
+
232
+ if (samples.length === 0) {
233
+ lines.push("No samples collected. Check that rg is installed and patterns match files.");
234
+ return lines.join("\n");
235
+ }
236
+
237
+ // Per-sample table
238
+ lines.push("samples:");
239
+ const hdr = " pattern".padEnd(30) + "raw bytes".padEnd(12) + "compressed".padEnd(13) + "ratio".padEnd(9) + "quality";
240
+ lines.push(hdr);
241
+ lines.push(" " + "─".repeat(72));
242
+ for (const s of samples) {
243
+ const pat = s.pattern.slice(0, 26).padEnd(28);
244
+ const raw = s.rawBytes.toLocaleString().padEnd(10);
245
+ const comp = s.compressedBytes.toLocaleString().padEnd(11);
246
+ const ratio = (s.ratio.toFixed(2) + "×").padEnd(7);
247
+ const quality = s.quality ?? "synthetic";
248
+ lines.push(` ${pat} ${raw} ${comp} ${ratio} ${quality}`);
249
+ }
250
+
251
+ // Counts: prefer caller-supplied; otherwise derive from samples to stay
252
+ // consistent with the per-sample quality flags.
253
+ const cfCount = coreFallbackCount ?? samples.filter((s) => s.quality === "core-fallback").length;
254
+ const synCount =
255
+ samples.length - (measuredCount ?? samples.filter((s) => s.quality === "measured").length) - cfCount;
256
+ const syntheticPct = ((synCount / samples.length) * 100).toFixed(0);
257
+
258
+ lines.push("");
259
+ lines.push("aggregate:");
260
+ lines.push(` samples ${samples.length}`);
261
+ if ((measuredCount ?? 0) > 0) {
262
+ lines.push(` measured ${measuredCount ?? 0} (pattern-matched genome retrieval)`);
263
+ }
264
+ if (cfCount > 0) {
265
+ lines.push(` core-fallback ${cfCount} (no pattern match — constant core-section output)`);
266
+ }
267
+ if (synCount > 0) {
268
+ lines.push(` synthetic ${synCount} (${syntheticPct}% — 4× estimate, no genome present)`);
269
+ }
270
+ if ((measuredCount ?? 0) > 0 && measuredMean !== undefined) {
271
+ lines.push(` measuredMean ${measuredMean.toFixed(2)}× ← used by efficiency-server`);
272
+ }
273
+ if (cfCount > 0 && coreFallbackMean !== undefined) {
274
+ lines.push(` coreFbMean ${coreFallbackMean.toFixed(2)}×`);
275
+ }
276
+ if (synCount > 0 && syntheticMean !== undefined) {
277
+ lines.push(` syntheticMean ${syntheticMean.toFixed(2)}×`);
278
+ }
279
+ lines.push(` overallMean ${meanRatio.toFixed(2)}×`);
280
+ lines.push(` p50 ${p50.toFixed(2)}×`);
281
+ lines.push(` p90 ${p90.toFixed(2)}×`);
282
+
283
+ if (synCount > 0 && synCount > (samples.length / 2)) {
284
+ lines.push("");
285
+ lines.push(
286
+ ` WARNING: ${syntheticPct}% of samples are synthetic (no genome match). ` +
287
+ `Run /ashlr-genome-init to index this project's code for real measurements.`,
288
+ );
289
+ }
290
+ if (cfCount > 0 && (measuredCount ?? 0) === 0) {
291
+ lines.push("");
292
+ lines.push(
293
+ ` NOTE: every genome-engaged sample fell to core-fallback. The mean ratio ` +
294
+ `reflects ashlr__grep behavior on non-matching queries, not pattern-specific ` +
295
+ `compression. Refresh the genome to improve pattern match rates.`,
296
+ );
297
+ }
298
+
299
+ lines.push("");
300
+ lines.push(`written → ${outPath}`);
301
+ lines.push("");
302
+ lines.push(
303
+ `To activate: efficiency-server will read this file automatically on next start.`,
304
+ );
305
+ return lines.join("\n");
306
+ }
307
+
308
+ // ---------------------------------------------------------------------------
309
+ // CLI argument parsing
310
+ // ---------------------------------------------------------------------------
311
+
312
+ interface CliArgs {
313
+ workloadPath?: string;
314
+ outPath: string;
315
+ }
316
+
317
+ function parseArgs(argv: string[]): CliArgs {
318
+ let workloadPath: string | undefined;
319
+ let outPath = join(homedir(), ".ashlr", "calibration.json");
320
+ for (let i = 0; i < argv.length; i++) {
321
+ const a = argv[i];
322
+ if ((a === "--workload" || a === "-w") && argv[i + 1]) {
323
+ workloadPath = argv[++i];
324
+ } else if ((a === "--out" || a === "-o") && argv[i + 1]) {
325
+ outPath = argv[++i];
326
+ }
327
+ }
328
+ return { workloadPath, outPath };
329
+ }
330
+
331
+ // ---------------------------------------------------------------------------
332
+ // Main
333
+ // ---------------------------------------------------------------------------
334
+
335
+ export async function runCalibration(opts: {
336
+ workloadPath?: string;
337
+ outPath?: string;
338
+ }): Promise<CalibrationFile> {
339
+ const outPath = opts.outPath ?? join(homedir(), ".ashlr", "calibration.json");
340
+
341
+ // 1. Load workload
342
+ let workloads: Workload[];
343
+ const defaultWorkloadPath = join(homedir(), ".ashlr", "calibration-workload.jsonl");
344
+
345
+ const resolvedWorkloadPath = opts.workloadPath ?? (existsSync(defaultWorkloadPath) ? defaultWorkloadPath : null);
346
+ if (resolvedWorkloadPath && existsSync(resolvedWorkloadPath)) {
347
+ const raw = readFileSync(resolvedWorkloadPath, "utf-8");
348
+ workloads = raw
349
+ .split("\n")
350
+ .map((l) => l.trim())
351
+ .filter((l) => l.length > 0)
352
+ .map((l) => JSON.parse(l) as Workload);
353
+ process.stdout.write(`Loaded ${workloads.length} workload(s) from ${resolvedWorkloadPath}\n`);
354
+ } else {
355
+ workloads = syntheticWorkload();
356
+ process.stdout.write(`No workload file found — using ${workloads.length} synthetic fixture(s)\n`);
357
+ }
358
+
359
+ // 2. Run each workload
360
+ const samples: CalibrationSample[] = [];
361
+ process.stdout.write(`\nRunning calibration against ${workloads.length} pattern(s)...\n`);
362
+
363
+ for (const w of workloads) {
364
+ const cwdAbs = resolve(w.cwd);
365
+ process.stdout.write(` rg ${JSON.stringify(w.pattern)} in ${cwdAbs} ... `);
366
+
367
+ const rawBytes = rgRawBytes(w.pattern, cwdAbs);
368
+ if (rawBytes === null) {
369
+ process.stdout.write("rg unavailable, skipped\n");
370
+ continue;
371
+ }
372
+ if (rawBytes === 0) {
373
+ process.stdout.write("no matches, skipped\n");
374
+ continue;
375
+ }
376
+
377
+ // Try genome path first
378
+ const genomeResult = await genomeCompressedBytes(w.pattern, cwdAbs);
379
+ if (genomeResult !== null && genomeResult.bytes > 0) {
380
+ const { bytes: compressedBytes, wasCoreFallback } = genomeResult;
381
+ const ratio = rawBytes / compressedBytes;
382
+ const qualityNote = wasCoreFallback ? " (core-fallback)" : "";
383
+ samples.push({
384
+ cwd: cwdAbs,
385
+ pattern: w.pattern,
386
+ rawBytes,
387
+ compressedBytes,
388
+ ratio,
389
+ quality: wasCoreFallback ? "core-fallback" : "measured",
390
+ });
391
+ process.stdout.write(
392
+ `raw=${rawBytes} compressed=${compressedBytes} ratio=${ratio.toFixed(2)}×${qualityNote}\n`,
393
+ );
394
+ } else {
395
+ // No genome — use synthetic estimate so we still have a data point
396
+ const s = syntheticSampleNoGenome(w, rawBytes);
397
+ samples.push(s);
398
+ process.stdout.write(`raw=${rawBytes} (no genome, estimated ratio=${s.ratio.toFixed(2)}×)\n`);
399
+ }
400
+ }
401
+
402
+ // 3. Compute stats — split measured / core-fallback / synthetic. "measured"
403
+ // is reserved for pattern-matched genome retrievals; core-fallback samples
404
+ // reflect real ashlr__grep behavior for non-matching queries but their
405
+ // ratio is dominated by a constant numerator, so we surface them
406
+ // separately rather than letting them inflate `measuredMean`.
407
+ const measuredSamples = samples.filter((s) => s.quality === "measured");
408
+ const coreFallbackSamples = samples.filter((s) => s.quality === "core-fallback");
409
+ const syntheticSamples = samples.filter((s) => s.quality === "synthetic");
410
+
411
+ const allRatios = samples.map((s) => s.ratio).sort((a, b) => a - b);
412
+ const measuredRatios = measuredSamples.map((s) => s.ratio);
413
+ const coreFallbackRatios = coreFallbackSamples.map((s) => s.ratio);
414
+ const syntheticRatios = syntheticSamples.map((s) => s.ratio);
415
+
416
+ const meanRatio = mean(allRatios);
417
+ const measuredMean = measuredRatios.length > 0 ? mean(measuredRatios) : undefined;
418
+ const coreFallbackMean = coreFallbackRatios.length > 0 ? mean(coreFallbackRatios) : undefined;
419
+ const syntheticMean = syntheticRatios.length > 0 ? mean(syntheticRatios) : undefined;
420
+ const p50 = percentile(allRatios, 50);
421
+ const p90 = percentile(allRatios, 90);
422
+
423
+ // 4. Write calibration.json
424
+ const result: CalibrationFile = {
425
+ updatedAt: new Date().toISOString(),
426
+ samples,
427
+ meanRatio: samples.length > 0 ? meanRatio : 4,
428
+ p50: samples.length > 0 ? p50 : 4,
429
+ p90: samples.length > 0 ? p90 : 4,
430
+ measuredMean,
431
+ syntheticMean,
432
+ measuredCount: measuredSamples.length,
433
+ coreFallbackMean,
434
+ coreFallbackCount: coreFallbackSamples.length,
435
+ };
436
+
437
+ mkdirSync(dirname(outPath), { recursive: true });
438
+ writeFileSync(outPath, JSON.stringify(result, null, 2));
439
+
440
+ // 5. Print report
441
+ process.stdout.write(
442
+ "\n" +
443
+ renderReport(
444
+ samples,
445
+ result.meanRatio,
446
+ result.p50,
447
+ result.p90,
448
+ outPath,
449
+ measuredMean,
450
+ syntheticMean,
451
+ measuredSamples.length,
452
+ coreFallbackMean,
453
+ coreFallbackSamples.length,
454
+ ) +
455
+ "\n",
456
+ );
457
+
458
+ return result;
459
+ }
460
+
461
+ // Exported for tests
462
+ export { percentile, mean, renderReport, syntheticWorkload, syntheticSampleNoGenome };
463
+
464
+ if (import.meta.main) {
465
+ const args = parseArgs(process.argv.slice(2));
466
+ await runCalibration({ workloadPath: args.workloadPath, outPath: args.outPath });
467
+ }