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,428 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * ashlr errors-report — reads ~/.ashlr/ashlr.log (+ rotated .1) and
4
+ * ~/.ashlr/session-log.jsonl and produces a deduped error summary.
5
+ *
6
+ * Exported surface:
7
+ * buildErrorsReport(opts?) → formatted string, never throws.
8
+ * normalizeMessage(msg) → canonical signature string (exported for tests).
9
+ *
10
+ * CLI: `bun run scripts/errors-report.ts [--hours N]`
11
+ * Exits 0 always.
12
+ */
13
+
14
+ import { existsSync, readdirSync, readFileSync } from "fs";
15
+ import { homedir } from "os";
16
+ import { join } from "path";
17
+
18
+ // ---------------------------------------------------------------------------
19
+ // Types
20
+ // ---------------------------------------------------------------------------
21
+
22
+ export interface ErrorsReportOptions {
23
+ /** Override $HOME for testing. */
24
+ home?: string;
25
+ /** Window in hours (default: 168 = last week). */
26
+ hours?: number;
27
+ /** Override Date.now() for deterministic tests. */
28
+ now?: number;
29
+ }
30
+
31
+ interface RawLogLine {
32
+ ts: Date;
33
+ level: string;
34
+ message: string;
35
+ source: "log" | "session-log";
36
+ tool?: string;
37
+ }
38
+
39
+ export interface ErrorSignature {
40
+ signature: string;
41
+ count: number;
42
+ firstSeen: Date;
43
+ lastSeen: Date;
44
+ sample: string;
45
+ }
46
+
47
+ export interface ToolErrorCount {
48
+ tool: string;
49
+ count: number;
50
+ }
51
+
52
+ export interface ErrorsReportData {
53
+ totalErrors: number;
54
+ uniqueSignatures: number;
55
+ windowHours: number;
56
+ timeRangeStart: Date | null;
57
+ timeRangeEnd: Date | null;
58
+ topSignatures: ErrorSignature[];
59
+ toolBreakdown: ToolErrorCount[];
60
+ }
61
+
62
+ // ---------------------------------------------------------------------------
63
+ // Log parsing
64
+ // ---------------------------------------------------------------------------
65
+
66
+ /**
67
+ * Parse a single line from ashlr.log.
68
+ * Formats seen in the wild:
69
+ * "2026-03-06 17:49:22,059 \e[33mWARNING\e[0m ashlr message"
70
+ * "[2026-03-06T17:49:22Z] ERROR message"
71
+ * "ERROR: bare message without timestamp"
72
+ * "2026-03-06 17:49:22,059 INFO aiohttp.access ..."
73
+ *
74
+ * Returns null for lines that don't look like errors/warnings.
75
+ */
76
+ function parseLogLine(raw: string): RawLogLine | null {
77
+ // Strip ANSI escape sequences.
78
+ const clean = raw.replace(/\x1b\[[0-9;]*m/g, "").trim();
79
+ if (!clean) return null;
80
+
81
+ // Detect level keywords — we only care about WARNING and ERROR lines.
82
+ const levelMatch = clean.match(/\b(ERROR|WARNING|WARN|CRITICAL|FATAL)\b/i);
83
+ if (!levelMatch) return null;
84
+ const level = levelMatch[1].toUpperCase();
85
+
86
+ // Try to extract a timestamp.
87
+ let ts: Date | null = null;
88
+
89
+ // "YYYY-MM-DD HH:MM:SS,mmm" or "YYYY-MM-DD HH:MM:SS.mmm"
90
+ const sqlTs = clean.match(/^(\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}[,.]?\d*)/);
91
+ if (sqlTs) {
92
+ ts = new Date(sqlTs[1].replace(",", ".").replace(" ", "T"));
93
+ }
94
+
95
+ // "[ISO-timestamp]" prefix
96
+ if (!ts) {
97
+ const isoTs = clean.match(/^\[(\d{4}-\d{2}-\d{2}T[\d:.Z+-]+)\]/);
98
+ if (isoTs) ts = new Date(isoTs[1]);
99
+ }
100
+
101
+ if (!ts || isNaN(ts.getTime())) {
102
+ // No parseable timestamp — treat as "now" so it passes window filtering
103
+ // only if caller uses a lenient window. We use epoch 0 to mark unknown.
104
+ ts = new Date(0);
105
+ }
106
+
107
+ // Extract the message portion: everything after the level keyword.
108
+ const afterLevel = clean.slice(clean.indexOf(levelMatch[0]) + levelMatch[0].length).trim();
109
+ // Drop leading logger-name tokens (e.g., "ashlr ", "aiohttp.access ")
110
+ const message = afterLevel.replace(/^[\w.]+ /, "").trim() || clean;
111
+
112
+ return { ts, level, message, source: "log" };
113
+ }
114
+
115
+ /**
116
+ * Parse session-log.jsonl lines looking for tool_error events.
117
+ */
118
+ function parseSessionLogLine(raw: string): RawLogLine | null {
119
+ if (!raw.trim()) return null;
120
+ try {
121
+ const rec = JSON.parse(raw);
122
+ if (rec.event !== "tool_error") return null;
123
+ const ts = rec.ts ? new Date(rec.ts) : new Date(0);
124
+ return {
125
+ ts,
126
+ level: "ERROR",
127
+ message: rec.error ?? rec.message ?? "tool error",
128
+ source: "session-log",
129
+ tool: rec.tool,
130
+ };
131
+ } catch {
132
+ return null;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Parse a ~/.ashlr/crashes/*.jsonl record into the shared RawLogLine shape
138
+ * so crashes surface alongside normal errors in the aggregated report.
139
+ */
140
+ function parseCrashDumpLine(raw: string): RawLogLine | null {
141
+ if (!raw.trim()) return null;
142
+ try {
143
+ const rec = JSON.parse(raw);
144
+ if (!rec || typeof rec !== "object") return null;
145
+ const ts = rec.ts ? new Date(rec.ts) : new Date(0);
146
+ const message = typeof rec.message === "string" && rec.message.length > 0
147
+ ? rec.message
148
+ : "handler crashed";
149
+ return {
150
+ ts,
151
+ level: "ERROR",
152
+ message,
153
+ source: "session-log", // reuse existing source tag so tool breakdown includes crashes
154
+ tool: typeof rec.tool === "string" ? rec.tool : undefined,
155
+ };
156
+ } catch {
157
+ return null;
158
+ }
159
+ }
160
+
161
+ // ---------------------------------------------------------------------------
162
+ // Deduplication / normalization
163
+ // ---------------------------------------------------------------------------
164
+
165
+ /**
166
+ * Normalize an error message to a stable signature for deduplication.
167
+ *
168
+ * Strips:
169
+ * - Timestamps in various formats
170
+ * - Absolute paths → <path>
171
+ * - PIDs and numeric IDs → <N>
172
+ * - Hex strings / hashes → <hex>
173
+ * - IP addresses → <ip>
174
+ * - UUIDs → <uuid>
175
+ * - HTTP status codes remain (useful for grouping)
176
+ * - Collapses whitespace
177
+ */
178
+ export function normalizeMessage(msg: string): string {
179
+ return msg
180
+ // ISO timestamps
181
+ .replace(/\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}[.,\d]*(Z|[+-]\d{2}:?\d{2})?/g, "<ts>")
182
+ // Unix timestamps (10 or 13 digits)
183
+ .replace(/\b\d{10,13}\b/g, "<ts>")
184
+ // UUIDs
185
+ .replace(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, "<uuid>")
186
+ // Hex strings ≥ 8 chars (hashes, addresses)
187
+ .replace(/\b[0-9a-f]{8,}\b/gi, "<hex>")
188
+ // Absolute paths (Unix + Windows)
189
+ .replace(/\/[^\s"']+/g, "<path>")
190
+ .replace(/[A-Za-z]:\\[^\s"']*/g, "<path>")
191
+ // IP addresses
192
+ .replace(/\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g, "<ip>")
193
+ // Remaining standalone numbers > 3 digits (port-ish, PID-ish)
194
+ .replace(/\b\d{4,}\b/g, "<N>")
195
+ // Collapse whitespace
196
+ .replace(/\s+/g, " ")
197
+ .trim()
198
+ .toLowerCase();
199
+ }
200
+
201
+ // ---------------------------------------------------------------------------
202
+ // Aggregation
203
+ // ---------------------------------------------------------------------------
204
+
205
+ function readLines(filePath: string): string[] {
206
+ if (!existsSync(filePath)) return [];
207
+ try {
208
+ return readFileSync(filePath, "utf8").split("\n");
209
+ } catch {
210
+ return [];
211
+ }
212
+ }
213
+
214
+ function aggregateErrors(lines: RawLogLine[], windowMs: number, now: number): ErrorsReportData {
215
+ const cutoff = now - windowMs;
216
+
217
+ // Filter to window. Lines with epoch-0 ts (no timestamp found) are kept
218
+ // only if the window is "all time" (cutoff ≤ 0). Otherwise they'd pollute
219
+ // results — skip them silently.
220
+ const inWindow = lines.filter((l) => {
221
+ const t = l.ts.getTime();
222
+ if (t === 0) return false; // unknown timestamp — exclude
223
+ return t >= cutoff && t <= now;
224
+ });
225
+
226
+ if (inWindow.length === 0) {
227
+ return {
228
+ totalErrors: 0,
229
+ uniqueSignatures: 0,
230
+ windowHours: windowMs / 3_600_000,
231
+ timeRangeStart: null,
232
+ timeRangeEnd: null,
233
+ topSignatures: [],
234
+ toolBreakdown: [],
235
+ };
236
+ }
237
+
238
+ // Signature map
239
+ const sigMap = new Map<string, ErrorSignature>();
240
+ for (const line of inWindow) {
241
+ const sig = normalizeMessage(line.message);
242
+ const existing = sigMap.get(sig);
243
+ if (existing) {
244
+ existing.count++;
245
+ if (line.ts < existing.firstSeen) existing.firstSeen = line.ts;
246
+ if (line.ts > existing.lastSeen) existing.lastSeen = line.ts;
247
+ } else {
248
+ sigMap.set(sig, {
249
+ signature: sig,
250
+ count: 1,
251
+ firstSeen: line.ts,
252
+ lastSeen: line.ts,
253
+ sample: line.message.slice(0, 120),
254
+ });
255
+ }
256
+ }
257
+
258
+ // Tool breakdown from session-log tool_error events
259
+ const toolMap = new Map<string, number>();
260
+ for (const line of inWindow) {
261
+ if (line.source === "session-log" && line.tool) {
262
+ toolMap.set(line.tool, (toolMap.get(line.tool) ?? 0) + 1);
263
+ }
264
+ }
265
+
266
+ const allTs = inWindow.map((l) => l.ts.getTime());
267
+ const timeRangeStart = new Date(Math.min(...allTs));
268
+ const timeRangeEnd = new Date(Math.max(...allTs));
269
+
270
+ const topSignatures = [...sigMap.values()]
271
+ .sort((a, b) => b.count - a.count)
272
+ .slice(0, 10);
273
+
274
+ const toolBreakdown = [...toolMap.entries()]
275
+ .map(([tool, count]) => ({ tool, count }))
276
+ .sort((a, b) => b.count - a.count);
277
+
278
+ return {
279
+ totalErrors: inWindow.length,
280
+ uniqueSignatures: sigMap.size,
281
+ windowHours: windowMs / 3_600_000,
282
+ timeRangeStart,
283
+ timeRangeEnd,
284
+ topSignatures,
285
+ toolBreakdown,
286
+ };
287
+ }
288
+
289
+ // ---------------------------------------------------------------------------
290
+ // Rendering
291
+ // ---------------------------------------------------------------------------
292
+
293
+ function rule(): string {
294
+ return "─".repeat(60);
295
+ }
296
+
297
+ function fmtDate(d: Date): string {
298
+ return d.toISOString().replace("T", " ").slice(0, 19) + " UTC";
299
+ }
300
+
301
+ function renderReport(data: ErrorsReportData): string {
302
+ if (data.totalErrors === 0) {
303
+ return [
304
+ rule(),
305
+ ` ashlr error report · window: last ${data.windowHours}h`,
306
+ rule(),
307
+ "",
308
+ ` (no errors recorded in the last ${data.windowHours}h)`,
309
+ "",
310
+ rule(),
311
+ ].join("\n");
312
+ }
313
+
314
+ const parts: string[] = [];
315
+
316
+ // Header
317
+ parts.push(rule());
318
+ parts.push(` ashlr error report · window: last ${data.windowHours}h`);
319
+ parts.push(rule());
320
+ parts.push("");
321
+ parts.push(` total errors ${String(data.totalErrors).padStart(6)}`);
322
+ parts.push(` unique signatures ${String(data.uniqueSignatures).padStart(6)}`);
323
+ if (data.timeRangeStart && data.timeRangeEnd) {
324
+ parts.push(` from ${fmtDate(data.timeRangeStart)}`);
325
+ parts.push(` to ${fmtDate(data.timeRangeEnd)}`);
326
+ }
327
+ parts.push("");
328
+
329
+ // Top signatures
330
+ parts.push(" Top error signatures by frequency");
331
+ parts.push(" " + "─".repeat(58));
332
+ for (const sig of data.topSignatures) {
333
+ const countCol = String(sig.count).padStart(5);
334
+ parts.push(` ${countCol}x ${sig.sample}`);
335
+ parts.push(` first ${fmtDate(sig.firstSeen)} last ${fmtDate(sig.lastSeen)}`);
336
+ parts.push("");
337
+ }
338
+
339
+ // Per-tool breakdown
340
+ if (data.toolBreakdown.length > 0) {
341
+ parts.push(" Per-tool error breakdown (from session-log tool_error events)");
342
+ parts.push(" " + "─".repeat(58));
343
+ for (const { tool, count } of data.toolBreakdown) {
344
+ parts.push(` ${String(count).padStart(5)}x ${tool}`);
345
+ }
346
+ parts.push("");
347
+ }
348
+
349
+ parts.push(rule());
350
+
351
+ return parts.join("\n");
352
+ }
353
+
354
+ // ---------------------------------------------------------------------------
355
+ // Public entry point
356
+ // ---------------------------------------------------------------------------
357
+
358
+ export function buildErrorsReport(opts: ErrorsReportOptions = {}): string {
359
+ const home = opts.home ?? process.env.HOME ?? homedir();
360
+ const windowHours = opts.hours ?? 168;
361
+ const now = opts.now ?? Date.now();
362
+ const windowMs = windowHours * 3_600_000;
363
+
364
+ const ashlrDir = join(home, ".ashlr");
365
+ const logPath = join(ashlrDir, "ashlr.log");
366
+ const logPath1 = join(ashlrDir, "ashlr.log.1");
367
+ const sessionLogPath = join(ashlrDir, "session-log.jsonl");
368
+ const crashesDir = join(ashlrDir, "crashes");
369
+
370
+ // Collect raw lines from all sources
371
+ const rawLines: RawLogLine[] = [];
372
+
373
+ // ashlr.log + rotated .1
374
+ for (const p of [logPath1, logPath]) {
375
+ for (const line of readLines(p)) {
376
+ const parsed = parseLogLine(line);
377
+ if (parsed) rawLines.push(parsed);
378
+ }
379
+ }
380
+
381
+ // session-log.jsonl tool_error events
382
+ for (const line of readLines(sessionLogPath)) {
383
+ const parsed = parseSessionLogLine(line);
384
+ if (parsed) rawLines.push(parsed);
385
+ }
386
+
387
+ // crashes/*.jsonl — one record per handler crash (written by _tool-base.ts)
388
+ if (existsSync(crashesDir)) {
389
+ let files: string[] = [];
390
+ try {
391
+ files = readdirSync(crashesDir).filter((f) => f.endsWith(".jsonl"));
392
+ } catch {
393
+ files = [];
394
+ }
395
+ for (const f of files) {
396
+ for (const line of readLines(join(crashesDir, f))) {
397
+ const parsed = parseCrashDumpLine(line);
398
+ if (parsed) rawLines.push(parsed);
399
+ }
400
+ }
401
+ }
402
+
403
+ const data = aggregateErrors(rawLines, windowMs, now);
404
+ return renderReport(data);
405
+ }
406
+
407
+ // ---------------------------------------------------------------------------
408
+ // CLI entry
409
+ // ---------------------------------------------------------------------------
410
+
411
+ if (import.meta.main) {
412
+ // Parse --hours N
413
+ let hours = 168;
414
+ const argv = process.argv.slice(2);
415
+ const hi = argv.indexOf("--hours");
416
+ if (hi !== -1 && argv[hi + 1]) {
417
+ const parsed = parseInt(argv[hi + 1], 10);
418
+ if (!isNaN(parsed) && parsed > 0) hours = parsed;
419
+ }
420
+
421
+ try {
422
+ process.stdout.write(buildErrorsReport({ hours }) + "\n");
423
+ } catch (err) {
424
+ const msg = err instanceof Error ? err.message : String(err);
425
+ process.stdout.write(`errors-report failed: ${msg}\n`);
426
+ }
427
+ process.exit(0);
428
+ }
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Bisect helper: find which test file causes a target test to fail.
4
+ * Usage: bun run scripts/find-test-leak.ts <target-test-file>
5
+ *
6
+ * Runs a modified version of the target test (with skip removed) after each
7
+ * sibling test file, reports which combination causes failure.
8
+ */
9
+
10
+ import { spawnSync } from "child_process";
11
+ import { readdirSync, writeFileSync, readFileSync, unlinkSync } from "fs";
12
+ import { join, relative, resolve } from "path";
13
+
14
+ const target = process.argv[2];
15
+ if (!target) {
16
+ console.error("Usage: bun run scripts/find-test-leak.ts <target-test-file>");
17
+ process.exit(1);
18
+ }
19
+
20
+ const targetPath = resolve(target);
21
+ const testsDir = join(import.meta.dir, "../__tests__");
22
+
23
+ // Build unskipped version of target
24
+ const originalContent = readFileSync(targetPath, "utf-8");
25
+ const unskippedContent = originalContent.replace(
26
+ /test\.skip\(/g,
27
+ "test(",
28
+ );
29
+ const unskippedPath = targetPath.replace(/\.test\.ts$/, "-UNSKIPPED.test.ts");
30
+ writeFileSync(unskippedPath, unskippedContent);
31
+
32
+ // Get all sibling test files (flat only, skip integration/quality subdirs)
33
+ const siblings = readdirSync(testsDir)
34
+ .filter(f => f.endsWith(".test.ts") && join(testsDir, f) !== targetPath && join(testsDir, f) !== unskippedPath)
35
+ .sort()
36
+ .map(f => join(testsDir, f));
37
+
38
+ console.log(`Target: ${targetPath}`);
39
+ console.log(`Unskipped copy: ${unskippedPath}`);
40
+ console.log(`Testing ${siblings.length} siblings...\n`);
41
+
42
+ let found: string[] = [];
43
+
44
+ for (const sibling of siblings) {
45
+ process.stdout.write(` ${relative(testsDir, sibling)} ... `);
46
+ const result = spawnSync(
47
+ "bun",
48
+ ["test", sibling, unskippedPath],
49
+ { encoding: "utf-8", timeout: 60_000, cwd: join(import.meta.dir, "..") }
50
+ );
51
+ const out = (result.stdout ?? "") + (result.stderr ?? "");
52
+ // Only count as a leaker if there is an actual test failure (not a "0 tests matched" exit).
53
+ if (result.status !== 0 && out.includes(" fail")) {
54
+ console.log("FAIL <-- LEAKER");
55
+ found.push(sibling);
56
+ } else {
57
+ console.log("pass");
58
+ }
59
+ }
60
+
61
+ unlinkSync(unskippedPath);
62
+
63
+ console.log("\n--- Result ---");
64
+ if (found.length === 0) {
65
+ console.log("No single-file leaker found. The leak may require multiple files.");
66
+ } else {
67
+ console.log("Leaking files:");
68
+ for (const f of found) console.log(" ", relative(testsDir, f));
69
+ }