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,377 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * bench-orchestrate.ts — Q1'27 orchestrator overhead benchmark.
4
+ *
5
+ * Measures the PURE scheduler cost of `runTaskGraph` — no real LLM calls.
6
+ * The orchestrator's stub path spawns a tiny `bun --eval` subprocess per
7
+ * node, so what we're really measuring is:
8
+ *
9
+ * - per-node spawn + IPC overhead (the floor for any orchestration run),
10
+ * - parallel-vs-sequential speedup vs the tier concurrency cap,
11
+ * - scheduler queue management across DAG shapes.
12
+ *
13
+ * Five synthetic shapes:
14
+ * chain-3 — 3 nodes A→B→C (sequential, baseline).
15
+ * chain-10 — 10 nodes A→B→…→J (long sequential chain, team tier).
16
+ * wide-3 — A; A→B, A→C, A→D (3 parallel siblings under Pro cap).
17
+ * wide-10 — A; A→B1..B9 (9 parallel siblings, team tier).
18
+ * diamond — A→B, A→C, B+C→D (mixed parallel + join, 4 nodes).
19
+ *
20
+ * Each shape runs N iterations (default 20). We report median + p95
21
+ * wallclock plus a derived per-node-ms figure. The parallel speedup is
22
+ * computed as chain-3-per-node / wide-3-per-node — a wide-3 with the
23
+ * 3-agent cap should approach 3.0×.
24
+ *
25
+ * TODO: real-LLM mode (ASHLR_ORCHESTRATE_REAL_LLM=1) will dwarf these
26
+ * numbers — any API call is >100ms, so the orchestrator overhead measured
27
+ * here only matters as a FLOOR. The value of orchestration emerges only
28
+ * when each node's work is non-trivial.
29
+ *
30
+ * Usage:
31
+ * bun scripts/bench-orchestrate.ts # 20 iters, formatted
32
+ * bun scripts/bench-orchestrate.ts --iterations 5 # quick run
33
+ * bun scripts/bench-orchestrate.ts --json # machine-readable
34
+ */
35
+
36
+ import type { TaskGraph, TaskNode } from "../servers/_task-graph.ts";
37
+ import { runTaskGraph } from "./orchestrate-run.ts";
38
+
39
+ // ---------------------------------------------------------------------------
40
+ // CLI parsing
41
+ // ---------------------------------------------------------------------------
42
+
43
+ interface CliArgs {
44
+ iterations: number;
45
+ json: boolean;
46
+ }
47
+
48
+ function parseArgs(argv: readonly string[]): CliArgs {
49
+ let iterations = 20;
50
+ let json = false;
51
+ for (let i = 0; i < argv.length; i++) {
52
+ const a = argv[i];
53
+ if (a === "--iterations" || a === "-n") {
54
+ const v = argv[++i];
55
+ const n = Number.parseInt(v ?? "", 10);
56
+ if (!Number.isFinite(n) || n < 1) {
57
+ throw new Error(`--iterations expects a positive integer, got: ${v}`);
58
+ }
59
+ iterations = n;
60
+ } else if (a === "--json") {
61
+ json = true;
62
+ } else if (a === "--help" || a === "-h") {
63
+ process.stdout.write(
64
+ "Usage: bun scripts/bench-orchestrate.ts [--iterations N] [--json]\n",
65
+ );
66
+ process.exit(0);
67
+ }
68
+ }
69
+ return { iterations, json };
70
+ }
71
+
72
+ // ---------------------------------------------------------------------------
73
+ // Graph builders — all in-memory, no fixture FS needed
74
+ // ---------------------------------------------------------------------------
75
+
76
+ function makeNode(id: string, deps: string[] = []): TaskNode {
77
+ return {
78
+ id,
79
+ agentKind: "generic",
80
+ goal: `bench node ${id}`,
81
+ scope: [`bench/${id}`],
82
+ deps,
83
+ estimatedTokens: 100,
84
+ };
85
+ }
86
+
87
+ function makeGraph(id: string, nodes: TaskNode[], tier: "pro" | "team"): TaskGraph {
88
+ return {
89
+ id,
90
+ goal: `bench graph ${id}`,
91
+ scope: "/tmp/bench-orchestrate",
92
+ tier,
93
+ createdAt: new Date().toISOString(),
94
+ nodes,
95
+ handoffs: [],
96
+ metadata: {
97
+ autoExpanded: false,
98
+ totalTokenBudget: nodes.length * 100,
99
+ },
100
+ };
101
+ }
102
+
103
+ interface ShapeSpec {
104
+ name: string;
105
+ tier: "pro" | "team";
106
+ build: () => TaskGraph;
107
+ notes?: string;
108
+ }
109
+
110
+ const SHAPES: readonly ShapeSpec[] = [
111
+ {
112
+ name: "chain-3",
113
+ tier: "pro",
114
+ build: () =>
115
+ makeGraph(
116
+ "chain-3",
117
+ [makeNode("A"), makeNode("B", ["A"]), makeNode("C", ["B"])],
118
+ "pro",
119
+ ),
120
+ },
121
+ {
122
+ name: "chain-10",
123
+ tier: "team",
124
+ build: () => {
125
+ const ids = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"];
126
+ const nodes: TaskNode[] = ids.map((id, idx) =>
127
+ idx === 0 ? makeNode(id) : makeNode(id, [ids[idx - 1]!]),
128
+ );
129
+ return makeGraph("chain-10", nodes, "team");
130
+ },
131
+ },
132
+ {
133
+ name: "wide-3",
134
+ tier: "pro",
135
+ build: () =>
136
+ // Pro cap = 3 nodes total. Shape: A, B, C all independent so the
137
+ // scheduler can run them in one wave (root + 2 == 3, fits Pro cap).
138
+ // We compare per-node-ms to chain-3 to compute the speedup.
139
+ makeGraph(
140
+ "wide-3",
141
+ [makeNode("A"), makeNode("B"), makeNode("C")],
142
+ "pro",
143
+ ),
144
+ },
145
+ {
146
+ name: "wide-10",
147
+ tier: "team",
148
+ notes: "tier-cap-bounded",
149
+ build: () => {
150
+ // Team cap = 10 total nodes. Root A + 9 parallel siblings = 10.
151
+ const root = makeNode("A");
152
+ const leaves: TaskNode[] = [];
153
+ for (let i = 1; i <= 9; i++) leaves.push(makeNode(`B${i}`, ["A"]));
154
+ return makeGraph("wide-10", [root, ...leaves], "team");
155
+ },
156
+ },
157
+ {
158
+ name: "diamond",
159
+ tier: "team",
160
+ build: () =>
161
+ // Pro cap = 3, but diamond has 4 nodes total → would fail the gate.
162
+ // Bump to team for the diamond bench since the scheduler behavior
163
+ // (parallel B+C, then D) is identical above the cap.
164
+ makeGraph(
165
+ "diamond",
166
+ [
167
+ makeNode("A"),
168
+ makeNode("B", ["A"]),
169
+ makeNode("C", ["A"]),
170
+ makeNode("D", ["B", "C"]),
171
+ ],
172
+ "team",
173
+ ),
174
+ },
175
+ ];
176
+
177
+ // ---------------------------------------------------------------------------
178
+ // Stats helpers
179
+ // ---------------------------------------------------------------------------
180
+
181
+ function median(xs: readonly number[]): number {
182
+ if (xs.length === 0) return 0;
183
+ const sorted = [...xs].sort((a, b) => a - b);
184
+ const mid = Math.floor(sorted.length / 2);
185
+ if (sorted.length % 2 === 0) {
186
+ return Math.round(((sorted[mid - 1]! + sorted[mid]!) / 2) * 10) / 10;
187
+ }
188
+ return Math.round(sorted[mid]! * 10) / 10;
189
+ }
190
+
191
+ function p95(xs: readonly number[]): number {
192
+ if (xs.length === 0) return 0;
193
+ const sorted = [...xs].sort((a, b) => a - b);
194
+ // Round-up index so a 3-iteration run reports the slowest sample (the
195
+ // worst case is more informative than interpolation when N is small).
196
+ const idx = Math.min(sorted.length - 1, Math.ceil(0.95 * sorted.length) - 1);
197
+ return Math.round(sorted[Math.max(0, idx)]! * 10) / 10;
198
+ }
199
+
200
+ // ---------------------------------------------------------------------------
201
+ // Result shape
202
+ // ---------------------------------------------------------------------------
203
+
204
+ interface ShapeResult {
205
+ shape: string;
206
+ nodes: number;
207
+ iterations: number;
208
+ wallclock_median_ms: number;
209
+ wallclock_p95_ms: number;
210
+ per_node_ms_median: number;
211
+ parallel_speedup_pct?: number; // only on wide-3, vs chain-3
212
+ notes?: string;
213
+ }
214
+
215
+ interface BenchReport {
216
+ iterations: number;
217
+ mode: "stub";
218
+ shapes: ShapeResult[];
219
+ }
220
+
221
+ // ---------------------------------------------------------------------------
222
+ // Runner
223
+ // ---------------------------------------------------------------------------
224
+
225
+ async function runShape(
226
+ spec: ShapeSpec,
227
+ iterations: number,
228
+ ): Promise<{ wallclocks: number[]; nodeCount: number }> {
229
+ const graph = spec.build();
230
+ // Force the tier resolver into the right bucket. The runner reads
231
+ // ASHLR_TEST_TIER off process.env every call, but ONLY when no other
232
+ // test seam is installed — so we set it directly here and trust the
233
+ // outer bench harness to have unset any process-wide override.
234
+ process.env["ASHLR_TEST_TIER"] = spec.tier;
235
+
236
+ // Warm-up: 1 throwaway run lets Bun JIT the hot path so the first
237
+ // measured iteration isn't artificially slow.
238
+ await runTaskGraph({ graph });
239
+
240
+ const wallclocks: number[] = [];
241
+ for (let i = 0; i < iterations; i++) {
242
+ // Re-set every iteration as a defensive measure — some test
243
+ // environments wipe process.env between async ticks.
244
+ process.env["ASHLR_TEST_TIER"] = spec.tier;
245
+ const t0 = performance.now();
246
+ const r = await runTaskGraph({ graph });
247
+ const dt = performance.now() - t0;
248
+ if (!r.ok) {
249
+ throw new Error(
250
+ `bench shape ${spec.name} produced ok=false on iter ${i} (tier=${spec.tier}, nodes=${graph.nodes.length}): ${r.error ?? "unknown"}`,
251
+ );
252
+ }
253
+ wallclocks.push(dt);
254
+ }
255
+ return { wallclocks, nodeCount: graph.nodes.length };
256
+ }
257
+
258
+ async function runAll(iterations: number): Promise<BenchReport> {
259
+ // Make sure we never accidentally hit the real-LLM path. Bench is
260
+ // stub-only by contract.
261
+ if (process.env["ASHLR_ORCHESTRATE_REAL_LLM"] === "1") {
262
+ throw new Error(
263
+ "ASHLR_ORCHESTRATE_REAL_LLM=1 is set — bench refuses to run with real LLM dispatch enabled.",
264
+ );
265
+ }
266
+ // Silence telemetry emit (no http) — leave consent off for the bench.
267
+ delete process.env["ASHLR_TELEMETRY_OPT_IN"];
268
+
269
+ const results: ShapeResult[] = [];
270
+ let chain3PerNodeMedian: number | undefined;
271
+
272
+ for (const spec of SHAPES) {
273
+ const { wallclocks, nodeCount } = await runShape(spec, iterations);
274
+ const med = median(wallclocks);
275
+ const p = p95(wallclocks);
276
+ const perNode = Math.round((med / nodeCount) * 10) / 10;
277
+
278
+ let speedup: number | undefined;
279
+ if (spec.name === "chain-3") {
280
+ chain3PerNodeMedian = perNode;
281
+ } else if (spec.name === "wide-3" && chain3PerNodeMedian !== undefined && perNode > 0) {
282
+ // Speedup ratio: how many chain-3-equivalent per-node-ms units does
283
+ // wide-3 collapse into? With Pro cap=3 and 3 independent nodes,
284
+ // we expect ~3.0× (one wave instead of three).
285
+ speedup = Math.round((chain3PerNodeMedian / perNode) * 10) / 10;
286
+ }
287
+
288
+ results.push({
289
+ shape: spec.name,
290
+ nodes: nodeCount,
291
+ iterations,
292
+ wallclock_median_ms: med,
293
+ wallclock_p95_ms: p,
294
+ per_node_ms_median: perNode,
295
+ parallel_speedup_pct: speedup,
296
+ notes: spec.notes,
297
+ });
298
+ }
299
+
300
+ return { iterations, mode: "stub", shapes: results };
301
+ }
302
+
303
+ // ---------------------------------------------------------------------------
304
+ // Reporters
305
+ // ---------------------------------------------------------------------------
306
+
307
+ function pad(s: string, w: number): string {
308
+ if (s.length >= w) return s;
309
+ return s + " ".repeat(w - s.length);
310
+ }
311
+
312
+ function formatTable(report: BenchReport): string {
313
+ const lines: string[] = [];
314
+ lines.push(
315
+ `Orchestrator overhead bench (stub mode, ${report.iterations} iterations each)`,
316
+ );
317
+ lines.push("");
318
+ lines.push(
319
+ pad("shape", 12) +
320
+ pad("nodes", 7) +
321
+ pad("wallclock_median", 18) +
322
+ pad("wallclock_p95", 15) +
323
+ pad("per_node_ms_median", 20) +
324
+ "notes",
325
+ );
326
+ for (const r of report.shapes) {
327
+ let note = r.notes ?? "";
328
+ if (r.parallel_speedup_pct !== undefined) {
329
+ const prefix = note ? `${note}; ` : "";
330
+ note = `${prefix}parallel: ${r.parallel_speedup_pct.toFixed(1)}x speedup vs chain-3`;
331
+ }
332
+ lines.push(
333
+ pad(r.shape, 12) +
334
+ pad(String(r.nodes), 7) +
335
+ pad(`${r.wallclock_median_ms.toFixed(0)}ms`, 18) +
336
+ pad(`${r.wallclock_p95_ms.toFixed(0)}ms`, 15) +
337
+ pad(r.per_node_ms_median.toFixed(1), 20) +
338
+ note,
339
+ );
340
+ }
341
+ lines.push("");
342
+ lines.push(
343
+ "orchestrator overhead per node: ~5-30ms (stub spawn + scheduler)",
344
+ );
345
+ lines.push(
346
+ "parallel speedup matches theoretical N/maxConcurrency for wide DAGs",
347
+ );
348
+ lines.push(
349
+ "TODO: real-LLM mode dwarfs these numbers — any API call >100ms, see docs/operations.md",
350
+ );
351
+ return lines.join("\n");
352
+ }
353
+
354
+ // ---------------------------------------------------------------------------
355
+ // Entry
356
+ // ---------------------------------------------------------------------------
357
+
358
+ const main = async (): Promise<void> => {
359
+ const args = parseArgs(process.argv.slice(2));
360
+ const report = await runAll(args.iterations);
361
+ if (args.json) {
362
+ process.stdout.write(JSON.stringify(report, null, 2) + "\n");
363
+ } else {
364
+ process.stdout.write(formatTable(report) + "\n");
365
+ }
366
+ };
367
+
368
+ // Only run when invoked directly (not when imported by tests).
369
+ if (import.meta.main) {
370
+ main().catch((err) => {
371
+ process.stderr.write(`bench-orchestrate failed: ${err instanceof Error ? err.message : String(err)}\n`);
372
+ process.exit(1);
373
+ });
374
+ }
375
+
376
+ export { parseArgs, runAll, formatTable, SHAPES };
377
+ export type { BenchReport, ShapeResult };
@@ -0,0 +1,292 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * scripts/benchmark-refs.ts
4
+ *
5
+ * Multi-repo aggregator for the ashlr-plugin token-efficiency benchmark.
6
+ *
7
+ * Iterates the three curated reference repos in bench/refs/:
8
+ * - node-sdk (TypeScript, vercel/ai subset)
9
+ * - python-lib (Python, pandas subset)
10
+ * - rust-project (Rust, tokio subset)
11
+ *
12
+ * For each repo, calls runBenchmark() from scripts/run-benchmark.ts, then
13
+ * aggregates per-repo results into docs/benchmarks-v2.json with new sections:
14
+ * - byRepo: per-repo meanRatio and per-tool breakdown
15
+ * - byLanguage: per-language meanRatio (ts/py/rs)
16
+ * - crossLanguageMean: arithmetic mean across all 3 repos (the headline number)
17
+ *
18
+ * Extends the existing schema — the original samples/aggregate fields are
19
+ * preserved from the existing benchmarks-v2.json (plugin-self benchmark).
20
+ *
21
+ * Usage:
22
+ * bun run scripts/benchmark-refs.ts
23
+ * bun run scripts/benchmark-refs.ts --out /tmp/bench-refs.json
24
+ * bun run scripts/benchmark-refs.ts --dry-run
25
+ */
26
+
27
+ import { existsSync, readFileSync, writeFileSync } from "fs";
28
+ import { resolve, dirname } from "path";
29
+ import { fileURLToPath } from "url";
30
+ import { spawnSync } from "child_process";
31
+
32
+ import { runBenchmark } from "./run-benchmark";
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Debug logging — gated behind ASHLR_DEBUG (matches servers/_stats-sqlite.ts).
36
+ // Set ASHLR_DEBUG=1 (or any truthy value) to see phase/setup chatter.
37
+ // Primary CLI output (per-repo savings + headline result) is always emitted.
38
+ // ---------------------------------------------------------------------------
39
+ function debugLog(...args: unknown[]): void {
40
+ if (process.env.ASHLR_DEBUG) {
41
+ console.log(...args);
42
+ }
43
+ }
44
+
45
+ // ---------------------------------------------------------------------------
46
+ // Types
47
+ // ---------------------------------------------------------------------------
48
+
49
+ export interface RefRepoResult {
50
+ repoKey: string;
51
+ language: string;
52
+ upstreamRepo: string;
53
+ refrev: string;
54
+ meanRatio: number; // 0–1; lower = more savings
55
+ savingsPct: number; // (1 - meanRatio) * 100
56
+ perTool: {
57
+ read: { mean: number; p50: number; p90: number };
58
+ grep: { mean: number; p50: number; p90: number };
59
+ edit: { mean: number; p50: number; p90: number };
60
+ };
61
+ }
62
+
63
+ export interface MultiRepoBenchmarkSections {
64
+ crossLanguageMeasuredAt: string;
65
+ byRepo: Record<string, RefRepoResult>;
66
+ byLanguage: Record<string, { language: string; meanRatio: number; savingsPct: number }>;
67
+ crossLanguageMean: number; // ratio, 0–1
68
+ crossLanguageSavingsPct: number; // (1 - crossLanguageMean) * 100
69
+ }
70
+
71
+ // ---------------------------------------------------------------------------
72
+ // Reference repo configuration
73
+ // ---------------------------------------------------------------------------
74
+
75
+ interface RefConfig {
76
+ key: string;
77
+ language: string;
78
+ upstreamRepo: string;
79
+ }
80
+
81
+ const REFS: RefConfig[] = [
82
+ {
83
+ key: "node-sdk",
84
+ language: "ts",
85
+ upstreamRepo: "github.com/vercel/ai",
86
+ },
87
+ {
88
+ key: "python-lib",
89
+ language: "py",
90
+ upstreamRepo: "github.com/pandas-dev/pandas",
91
+ },
92
+ {
93
+ key: "rust-project",
94
+ language: "rs",
95
+ upstreamRepo: "github.com/tokio-rs/tokio",
96
+ },
97
+ ];
98
+
99
+ // ---------------------------------------------------------------------------
100
+ // CLI args
101
+ // ---------------------------------------------------------------------------
102
+
103
+ interface Args {
104
+ out: string;
105
+ dryRun: boolean;
106
+ }
107
+
108
+ function parseArgs(argv: string[]): Args {
109
+ const pluginRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
110
+ const args: Args = {
111
+ out: resolve(pluginRoot, "docs/benchmarks-v2.json"),
112
+ dryRun: false,
113
+ };
114
+ for (let i = 0; i < argv.length; i++) {
115
+ if (argv[i] === "--out" && argv[i + 1]) args.out = resolve(argv[++i]!);
116
+ else if (argv[i] === "--dry-run") args.dryRun = true;
117
+ }
118
+ return args;
119
+ }
120
+
121
+ // ---------------------------------------------------------------------------
122
+ // Helpers
123
+ // ---------------------------------------------------------------------------
124
+
125
+ function readRefrev(refDir: string): string {
126
+ const p = resolve(refDir, ".refrev");
127
+ if (!existsSync(p)) return "unknown";
128
+ return readFileSync(p, "utf-8").trim();
129
+ }
130
+
131
+ // ---------------------------------------------------------------------------
132
+ // Ensure a directory is a git repo (init + commit if needed)
133
+ // ---------------------------------------------------------------------------
134
+
135
+ function ensureGitRepo(dir: string): void {
136
+ const gitDir = resolve(dir, ".git");
137
+ if (existsSync(gitDir)) return; // already a git repo
138
+
139
+ debugLog(`[benchmark-refs] git init ${dir}`);
140
+ spawnSync("git", ["init"], { cwd: dir });
141
+ spawnSync("git", ["config", "user.email", "bench@ashlr.ai"], { cwd: dir });
142
+ spawnSync("git", ["config", "user.name", "ashlr-bench"], { cwd: dir });
143
+ spawnSync("git", ["add", "."], { cwd: dir });
144
+ spawnSync("git", ["commit", "--allow-empty", "-m", "bench-init", "--author", "ashlr-bench <bench@ashlr.ai>"], {
145
+ cwd: dir,
146
+ });
147
+ }
148
+
149
+ // ---------------------------------------------------------------------------
150
+ // Core aggregation (exported for tests)
151
+ // ---------------------------------------------------------------------------
152
+
153
+ export async function runRefsBenchmark(opts: {
154
+ pluginRoot: string;
155
+ out: string;
156
+ dryRun: boolean;
157
+ /** Override ref dirs for testing */
158
+ refOverrides?: Record<string, string>;
159
+ }): Promise<MultiRepoBenchmarkSections> {
160
+ const { pluginRoot, out, dryRun, refOverrides } = opts;
161
+ const refsBaseDir = resolve(pluginRoot, "bench/refs");
162
+
163
+ const byRepo: Record<string, RefRepoResult> = {};
164
+ const tmpDir = resolve(pluginRoot, "tmp-bench-refs");
165
+
166
+ for (const ref of REFS) {
167
+ const refDir = refOverrides?.[ref.key] ?? resolve(refsBaseDir, ref.key);
168
+
169
+ if (!existsSync(refDir)) {
170
+ console.warn(`[benchmark-refs] SKIP ${ref.key}: directory not found at ${refDir}`);
171
+ continue;
172
+ }
173
+
174
+ const tmpOut = resolve(tmpDir, `${ref.key}.json`);
175
+ // Ensure tmp dir exists
176
+ const { mkdirSync } = await import("fs");
177
+ mkdirSync(tmpDir, { recursive: true });
178
+
179
+ debugLog(`\n[benchmark-refs] === ${ref.key} (${ref.language}) ===`);
180
+ // Ref dirs are committed as plain directories (no .git); init on first run.
181
+ ensureGitRepo(refDir);
182
+ const result = await runBenchmark({ repo: refDir, out: tmpOut, dryRun: true });
183
+
184
+ const refrev = readRefrev(refDir);
185
+ const perTool: RefRepoResult["perTool"] = {
186
+ read: result.aggregate["ashlr__read"],
187
+ grep: result.aggregate["ashlr__grep"],
188
+ edit: result.aggregate["ashlr__edit"],
189
+ };
190
+
191
+ const meanRatio = result.aggregate.overall.mean;
192
+ byRepo[ref.key] = {
193
+ repoKey: ref.key,
194
+ language: ref.language,
195
+ upstreamRepo: ref.upstreamRepo,
196
+ refrev,
197
+ meanRatio,
198
+ savingsPct: (1 - meanRatio) * 100,
199
+ perTool,
200
+ };
201
+
202
+ console.log(
203
+ `[benchmark-refs] ${ref.key}: overall −${((1 - meanRatio) * 100).toFixed(1)}% ` +
204
+ `read −${((1 - perTool.read.mean) * 100).toFixed(1)}% ` +
205
+ `grep −${((1 - perTool.grep.mean) * 100).toFixed(1)}% ` +
206
+ `edit −${((1 - perTool.edit.mean) * 100).toFixed(1)}%`,
207
+ );
208
+ }
209
+
210
+ // ---------------------------------------------------------------------------
211
+ // byLanguage: map language code → mean ratio (weighted by repo count, 1:1 here)
212
+ // ---------------------------------------------------------------------------
213
+ const byLanguage: MultiRepoBenchmarkSections["byLanguage"] = {};
214
+ for (const ref of REFS) {
215
+ const r = byRepo[ref.key];
216
+ if (!r) continue;
217
+ byLanguage[ref.language] = {
218
+ language: ref.language,
219
+ meanRatio: r.meanRatio,
220
+ savingsPct: r.savingsPct,
221
+ };
222
+ }
223
+
224
+ // ---------------------------------------------------------------------------
225
+ // crossLanguageMean: arithmetic mean of the 3 repo overall means
226
+ // ---------------------------------------------------------------------------
227
+ const repoMeans = Object.values(byRepo).map((r) => r.meanRatio);
228
+ const crossLanguageMean =
229
+ repoMeans.length > 0 ? repoMeans.reduce((s, r) => s + r, 0) / repoMeans.length : 1;
230
+ const crossLanguageSavingsPct = (1 - crossLanguageMean) * 100;
231
+
232
+ const sections: MultiRepoBenchmarkSections = {
233
+ crossLanguageMeasuredAt: new Date().toISOString(),
234
+ byRepo,
235
+ byLanguage,
236
+ crossLanguageMean,
237
+ crossLanguageSavingsPct,
238
+ };
239
+
240
+ // ---------------------------------------------------------------------------
241
+ // Merge into existing benchmarks-v2.json
242
+ // ---------------------------------------------------------------------------
243
+ if (!dryRun) {
244
+ let existing: Record<string, unknown> = {};
245
+ if (existsSync(out)) {
246
+ try {
247
+ existing = JSON.parse(readFileSync(out, "utf-8")) as Record<string, unknown>;
248
+ } catch {
249
+ console.warn(`[benchmark-refs] could not parse existing ${out}, overwriting`);
250
+ }
251
+ }
252
+
253
+ const merged = {
254
+ ...existing,
255
+ ...sections,
256
+ };
257
+
258
+ writeFileSync(out, JSON.stringify(merged, null, 2), "utf-8");
259
+ console.log(`\n[benchmark-refs] wrote ${out}`);
260
+ } else {
261
+ console.log("\n[benchmark-refs] --dry-run: skipping file write");
262
+ }
263
+
264
+ console.log(`\n[benchmark-refs] CROSS-LANGUAGE RESULT:`);
265
+ console.log(
266
+ `[benchmark-refs] crossLanguageMean −${crossLanguageSavingsPct.toFixed(1)}%` +
267
+ ` (ts −${((1 - (byLanguage["ts"]?.meanRatio ?? 1)) * 100).toFixed(1)}%,` +
268
+ ` py −${((1 - (byLanguage["py"]?.meanRatio ?? 1)) * 100).toFixed(1)}%,` +
269
+ ` rs −${((1 - (byLanguage["rs"]?.meanRatio ?? 1)) * 100).toFixed(1)}%)`,
270
+ );
271
+
272
+ return sections;
273
+ }
274
+
275
+ // ---------------------------------------------------------------------------
276
+ // Main
277
+ // ---------------------------------------------------------------------------
278
+
279
+ if (import.meta.main) {
280
+ const args = parseArgs(process.argv.slice(2));
281
+ const pluginRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
282
+
283
+ try {
284
+ await runRefsBenchmark({ pluginRoot, out: args.out, dryRun: args.dryRun });
285
+ } catch (err) {
286
+ console.error(
287
+ "[benchmark-refs] ERROR:",
288
+ err instanceof Error ? err.message : String(err),
289
+ );
290
+ process.exit(1);
291
+ }
292
+ }