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,194 @@
1
+ # ashlr-plugin Telemetry
2
+
3
+ ## Overview
4
+
5
+ ashlr-plugin includes an **opt-in, privacy-first** telemetry pipeline that helps the maintainer tune heuristics (edit thresholds, embedding similarity cutoffs, LLM routing) with real-world data instead of guesses.
6
+
7
+ **Default: OFF.** Nothing is ever collected unless you explicitly enable it.
8
+
9
+ ---
10
+
11
+ ## How to opt in
12
+
13
+ **Via environment variable (session-scoped):**
14
+
15
+ ```sh
16
+ export ASHLR_TELEMETRY=on
17
+ ```
18
+
19
+ **Via config file (persistent):**
20
+
21
+ ```json
22
+ // ~/.ashlr/config.json
23
+ {
24
+ "telemetry": "opt-in"
25
+ }
26
+ ```
27
+
28
+ On first opt-in, a one-line notice is printed at session start confirming what is collected and how to disable.
29
+
30
+ ---
31
+
32
+ ## How to opt out
33
+
34
+ **Environment variable (highest priority — overrides config):**
35
+
36
+ ```sh
37
+ export ASHLR_TELEMETRY=off
38
+ ```
39
+
40
+ **Config file:**
41
+
42
+ ```json
43
+ // ~/.ashlr/config.json
44
+ {
45
+ "telemetry": "off"
46
+ }
47
+ ```
48
+
49
+ Either method immediately disables collection and flushing. No data is sent after the kill switch is set. The local buffer at `~/.ashlr/telemetry-buffer.jsonl` can be deleted manually at any time.
50
+
51
+ ---
52
+
53
+ ## What is collected
54
+
55
+ Only anonymized, aggregate-friendly event shapes. **No file paths, no grep patterns, no command content, no user identifiers, no repo names.**
56
+
57
+ ### Event types
58
+
59
+ | Kind | Fields |
60
+ |------|--------|
61
+ | `tool_call` | `tool`, `rawBytes`, `compactBytes`, `fellBack`, `providerUsed`, `durationMs` |
62
+ | `pretooluse_block` | `tool`, `blockedTo`, `sizeRange` (`small`/`medium`/`large` bucket — never raw bytes) |
63
+ | `pretooluse_passthrough` | `tool`, `reason` (`below-threshold` / `out-of-cwd` / `plugin-tree` / `micro-edit` / `bypass`) |
64
+ | `version` | `pluginVersion`, `bunVersion`, `platform`, `arch` |
65
+
66
+ All events also include:
67
+
68
+ - `ts` — epoch seconds (not milliseconds, to save bytes)
69
+ - `kind` — event type string
70
+ - `sessionId` — a per-session opaque hex string (SHA-256 fold of a random seed; re-generated each session)
71
+
72
+ ### What `sessionId` is
73
+
74
+ A 16-character hex string derived from a random seed at session start. It is deleted at session end. It allows the maintainer to correlate events *within* one session without identifying the user across sessions or installations. Re-installs and new sessions always generate a fresh value.
75
+
76
+ ---
77
+
78
+ ## What is NEVER collected
79
+
80
+ - File paths (absolute or relative)
81
+ - Grep search patterns
82
+ - File content, command arguments, or any user-authored text
83
+ - User names, email addresses, or identifiers
84
+ - Repo names, organization names, or project paths
85
+ - IP addresses (the server receives them transiently in HTTP headers but they are not stored)
86
+
87
+ A path-safety guard in the buffer writer (`looksLikePath`) rejects any event whose string values look like an absolute filesystem path. Events that fail this check are silently dropped rather than written.
88
+
89
+ ---
90
+
91
+ ## Local buffer
92
+
93
+ Events are buffered locally at:
94
+
95
+ ```
96
+ ~/.ashlr/telemetry-buffer.jsonl
97
+ ```
98
+
99
+ The buffer is capped at **5,000 lines**. Older entries are evicted when the cap is exceeded. The buffer is a plain JSONL file — you can inspect it at any time:
100
+
101
+ ```sh
102
+ cat ~/.ashlr/telemetry-buffer.jsonl | head -5
103
+ ```
104
+
105
+ ---
106
+
107
+ ## Flusher
108
+
109
+ The buffer is flushed to the maintainer's collection endpoint:
110
+
111
+ 1. **On session end** — spawned from the `session-end-consolidate` hook.
112
+ 2. **On demand** — `bun run scripts/telemetry-flush.ts`.
113
+
114
+ The flusher has a **10-second network timeout**. On failure (network error, non-2xx response) the buffer is left untouched and retried on the next flush cycle. Failures are logged to stderr but never surfaced to the user.
115
+
116
+ ---
117
+
118
+ ## Endpoint contract
119
+
120
+ ### POST `/v1/events`
121
+
122
+ **URL:** `https://telemetry.ashlr.ai/v1/events` (override with `ASHLR_TELEMETRY_URL` env var)
123
+
124
+ **Request:**
125
+
126
+ ```json
127
+ {
128
+ "sessionId": "a1b2c3d4e5f6a7b8",
129
+ "events": [
130
+ {
131
+ "ts": 1720000000,
132
+ "kind": "tool_call",
133
+ "sessionId": "a1b2c3d4e5f6a7b8",
134
+ "tool": "ashlr__read",
135
+ "rawBytes": 8200,
136
+ "compactBytes": 1100,
137
+ "fellBack": false,
138
+ "providerUsed": "anthropic",
139
+ "durationMs": 42
140
+ }
141
+ ]
142
+ }
143
+ ```
144
+
145
+ **Response (2xx):**
146
+
147
+ ```json
148
+ { "accepted": 1 }
149
+ ```
150
+
151
+ On `2xx`, the flusher truncates the buffer to entries newer than the flush horizon (the `ts` of the last event in the batch). On any other status or network error, the buffer is left intact.
152
+
153
+ ### Server-side requirements (for the maintainer)
154
+
155
+ To start receiving events, stand up a simple HTTPS function (Vercel/Cloudflare Workers/etc.) that:
156
+
157
+ 1. Accepts `POST /v1/events` with `Content-Type: application/json`.
158
+ 2. Parses `{ sessionId, events }` from the body.
159
+ 3. Validates that no event field contains path-like strings (defense-in-depth).
160
+ 4. Appends events to a time-series store (e.g. Tinybird, ClickHouse, Postgres `jsonb`).
161
+ 5. Returns `{ accepted: N }` with status `200`.
162
+ 6. Does NOT log request IP addresses to permanent storage.
163
+
164
+ **The endpoint does not need to exist for the plugin to function.** When the endpoint is unreachable, events are buffered locally and retried silently.
165
+
166
+ ---
167
+
168
+ ## Data retention promise
169
+
170
+ - **Raw events:** purged from the server after **30 days**.
171
+ - **Aggregate statistics** (e.g., p50 raw/compact byte ratios per tool per week): retained indefinitely for heuristic tuning.
172
+ - **Session IDs:** not cross-referenced with any user identity. Treated as opaque correlation tokens within a single session.
173
+
174
+ ---
175
+
176
+ ## Viewing telemetry status
177
+
178
+ Run `/ashlr-status` in Claude Code. The `## Telemetry snapshot` section includes:
179
+
180
+ ```
181
+ opt-in telemetry: OFF (default) · to enable: ASHLR_TELEMETRY=on
182
+ ```
183
+
184
+ or when enabled:
185
+
186
+ ```
187
+ opt-in telemetry: ON · buffer: 42 events · to disable: ASHLR_TELEMETRY=off
188
+ ```
189
+
190
+ ---
191
+
192
+ ## `/ashlr-settings telemetry off`
193
+
194
+ Running `/ashlr-settings telemetry off` writes `{ "telemetry": "off" }` into `~/.ashlr/config.json`, which disables collection and flushing for all future sessions.
@@ -0,0 +1,100 @@
1
+ # Test Isolation in the ashlr-plugin Suite
2
+
3
+ ## Why Bun shares module state across test files
4
+
5
+ Bun runs all test files in a single worker process (by default). Every `import`
6
+ resolves against a shared module cache, so a module imported by `a.test.ts` and
7
+ then imported again by `b.test.ts` returns the *same* object — not a fresh copy.
8
+
9
+ Consequences:
10
+
11
+ - **Module-level variables** (caches, flags, counters) survive between files.
12
+ - **`mock.module(specifier, factory)`** replaces the module in that shared cache
13
+ and is *not* automatically restored when the test file finishes. Bun's
14
+ `mock.restore()` only clears `mockFn` spies, not `mock.module` overrides.
15
+ - **`process.env` mutations** are visible to all subsequent imports and code that
16
+ reads env at call-time.
17
+
18
+ ## Patterns to follow
19
+
20
+ ### 1. Save and restore `process.env` in outer scope
21
+
22
+ If a test must set an env var, capture the original value before `beforeEach`
23
+ and restore it in `afterEach`:
24
+
25
+ ```ts
26
+ let origHome: string | undefined;
27
+
28
+ beforeEach(() => { origHome = process.env.HOME; process.env.HOME = tmpDir; });
29
+ afterEach(() => {
30
+ if (origHome !== undefined) process.env.HOME = origHome;
31
+ else delete process.env.HOME;
32
+ });
33
+ ```
34
+
35
+ ### 2. Never use `mock.module` for shared packages
36
+
37
+ `mock.module` leaks permanently into the module cache. Prefer **dependency
38
+ injection**: add an optional `retriever` / `logger` / `handler` parameter to
39
+ the production function, defaulting to the real implementation. Tests pass
40
+ stubs via that parameter — no module patching needed.
41
+
42
+ ```ts
43
+ // production code
44
+ export async function retrieveCached(
45
+ root: string, pattern: string, limit: number,
46
+ retriever: Retriever = _retrieveSectionsV2, // real default
47
+ ) { ... }
48
+
49
+ // test code — no mock.module
50
+ await retrieveCached(root, "foo", 4000, stubRetriever);
51
+ ```
52
+
53
+ ### 3. Clear module-level caches in `beforeEach`
54
+
55
+ Any module that exposes a `_clearCache()` / `_resetXxx()` test hook must be
56
+ called in `beforeEach`, not just `afterEach`. Running it only in `afterEach`
57
+ leaves stale state if the previous test in another file did not clean up.
58
+
59
+ ### 4. Use `ASHLR_STATS_SYNC=1` when asserting on-disk state
60
+
61
+ `_stats.ts` debounces file writes by 250 ms. Tests that assert a stats file was
62
+ written must either:
63
+
64
+ - set `ASHLR_STATS_SYNC=1` in the test environment (disables debounce), or
65
+ - poll with a bounded wait loop after the action.
66
+
67
+ ### 5. Spawn subprocesses with a minimal env
68
+
69
+ When a test spawns an MCP server subprocess to verify event emission, pass only
70
+ the env vars the subprocess actually needs:
71
+
72
+ ```ts
73
+ env: { HOME: isolatedTmpDir, PATH: process.env.PATH ?? "/usr/bin:/bin" }
74
+ ```
75
+
76
+ Stripping the full `process.env` prevents a previously mutated `HOME` or
77
+ `ASHLR_SESSION_LOG_PATH` from leaking into the subprocess.
78
+
79
+ ## Fixes applied in this repo
80
+
81
+ ### Leaker: `__tests__/genome-cache.test.ts`
82
+
83
+ **What leaked:** A top-level `mock.module("@ashlr/core-efficiency", ...)` call
84
+ that replaced the entire package — including `estimateTokensFromString: () => 0`
85
+ — in Bun's shared module cache. Every test file loaded after
86
+ `genome-cache.test.ts` (alphabetically: `genome-init`, `genome-live`, …,
87
+ `run-benchmark`, …) received the stubbed module. `run-benchmark.test.ts`
88
+ calls `estimateTokensFromString` to measure token savings; with the stub
89
+ returning 0, every ratio computed as `0 / 0 → 1`, making the
90
+ `medium/large ratio < 1` assertion fail.
91
+
92
+ **Fix:** Refactored `servers/_genome-cache.ts` to accept an optional `retriever`
93
+ parameter (defaulting to the real `retrieveSectionsV2`). Rewrote
94
+ `genome-cache.test.ts` to pass a stub directly — no `mock.module` needed.
95
+
96
+ ### Affected skip removed: `run-benchmark.test.ts`
97
+
98
+ `test.skip("ashlr__edit medium and large samples have ratio < 1 …")` was
99
+ un-skipped once the `genome-cache.test.ts` leak was fixed. The test passes
100
+ reliably in both isolation and the full suite.
@@ -0,0 +1,159 @@
1
+ # ashlr upgrade — terminal-native free-to-pro flow
2
+
3
+ Run `/ashlr-upgrade` inside Claude Code to go from free to Pro or Team in
4
+ under 90 seconds without leaving the terminal.
5
+
6
+ ## Quick start
7
+
8
+ ```
9
+ /ashlr-upgrade
10
+ ```
11
+
12
+ That's it. The flow handles sign-in, plan selection, Stripe checkout, and
13
+ activation confirmation automatically.
14
+
15
+ ## What happens step by step
16
+
17
+ ```
18
+ ╔══════════════════════════════════╗
19
+ ║ ashlr · upgrade ║
20
+ ╚══════════════════════════════════╝
21
+
22
+ ▬▬▬ STEP 1/5: Checking current tier ▬▬▬
23
+ ✓ Not signed in yet.
24
+
25
+ ▬▬▬ STEP 2/5: Sign in ▬▬▬
26
+ No active Pro token found. Let's sign you in first.
27
+ [ASHLR_PROMPT: Email to sign in?] you@example.com
28
+ ✓ Magic link sent to you@example.com. Check your inbox — click the link to continue.
29
+ Waiting for you to click the link (up to 3 minutes)...
30
+ Waiting ...
31
+ ✓ Sign-in confirmed.
32
+ ✓ Token saved to ~/.ashlr/pro-token and ~/.ashlr/env (auto-loaded on next session).
33
+
34
+ ▬▬▬ STEP 3/5: Choose your plan ▬▬▬
35
+
36
+ 1) Pro · $12/mo [default]
37
+ 2) Pro · $120/yr (save 17%)
38
+ 3) Team · $24/user/mo
39
+ 4) Team · $240/user/yr (save 17%)
40
+
41
+ [ASHLR_PROMPT: Choose a plan (1-4, default 1):] 1
42
+ ✓ Selected: Pro · $12/mo
43
+
44
+ ▬▬▬ STEP 4/5: Open Stripe checkout ▬▬▬
45
+ ✓ Opened checkout in your browser. Complete payment to activate Pro.
46
+
47
+ ▬▬▬ STEP 5/5: Waiting for payment confirmation ▬▬▬
48
+ Polling for payment confirmation (up to 10 minutes)...
49
+ Waiting ...
50
+
51
+ ashlr Pro is now active.
52
+ Your API token is saved locally. All Pro features are unlocked.
53
+
54
+ What just changed:
55
+ - Hosted LLM summarizer — Ollama not required
56
+ - Cross-machine stats sync
57
+ - Leaderboard participation
58
+ - Priority support at support@ashlr.ai
59
+
60
+ Next: run /ashlr-dashboard to see your usage.
61
+ ```
62
+
63
+ ## Already on Pro
64
+
65
+ If `ASHLR_PRO_TOKEN` is set and your account is already Pro or Team, the
66
+ flow exits immediately:
67
+
68
+ ```
69
+ ▬▬▬ STEP 1/5: Checking current tier ▬▬▬
70
+ ✓ You're already on Pro.
71
+ Run /ashlr-dashboard to see usage.
72
+ ```
73
+
74
+ ## Flags
75
+
76
+ | Flag | Effect |
77
+ |------|--------|
78
+ | `--tier pro\|team` | Pre-select tier, skip the plan prompt |
79
+ | `--annual` | Pre-select annual billing |
80
+ | `--email <addr>` | Pre-supply email, skip the email prompt |
81
+ | `--no-poll` | Skip the activation polling step (useful for testing or CI) |
82
+
83
+ Example — skip all interactive prompts:
84
+
85
+ ```
86
+ /ashlr-upgrade --tier pro --annual --email you@example.com
87
+ ```
88
+
89
+ ## Headless / SSH sessions (no browser)
90
+
91
+ Set `ASHLR_NO_BROWSER=1` to suppress the automatic browser open. The
92
+ checkout URL is printed to the terminal instead:
93
+
94
+ ```sh
95
+ ASHLR_NO_BROWSER=1
96
+ ```
97
+
98
+ Then copy the printed URL and open it in a browser on any device.
99
+
100
+ ## If the browser fails to open
101
+
102
+ If `open` / `xdg-open` / `start` is not available (remote server, Docker,
103
+ minimal Linux), the flow falls back gracefully:
104
+
105
+ ```
106
+ ! Could not open a browser automatically.
107
+
108
+ Open this URL manually:
109
+
110
+ https://checkout.stripe.com/c/pay/cs_live_...
111
+ ```
112
+
113
+ The activation poller continues running. Complete payment in your browser and
114
+ the terminal will detect it automatically.
115
+
116
+ ## Manually pasting a token
117
+
118
+ If you already have an API token (from the web dashboard at
119
+ plugin.ashlr.ai), you can skip the magic-link flow entirely:
120
+
121
+ 1. Save the token: `echo "export ASHLR_PRO_TOKEN=<token>" >> ~/.ashlr/env`
122
+ 2. Source it: `source ~/.ashlr/env`
123
+ 3. Verify: `/ashlr-upgrade` will see your Pro status and exit immediately.
124
+
125
+ ## What happens if the poll times out
126
+
127
+ After you open checkout, the script polls `/billing/status` every 5 seconds
128
+ for up to 10 minutes. If payment isn't detected within that window, you'll see:
129
+
130
+ ```
131
+ ! Haven't detected payment yet.
132
+ Once you complete checkout, run /ashlr-upgrade again to verify and activate.
133
+ ```
134
+
135
+ Run `/ashlr-upgrade` again after completing payment — step 1 will detect the
136
+ new tier and exit immediately.
137
+
138
+ ## Token storage
139
+
140
+ After sign-in the API token is saved in two places:
141
+
142
+ | File | Purpose |
143
+ |------|---------|
144
+ | `~/.ashlr/pro-token` | Raw token (mode 0600) |
145
+ | `~/.ashlr/env` | `export ASHLR_PRO_TOKEN=<token>` — sourced by the SessionStart hook |
146
+
147
+ The SessionStart hook reads `~/.ashlr/env` on every new Claude Code session,
148
+ so `ASHLR_PRO_TOKEN` is available automatically without a shell restart.
149
+
150
+ ## Pro features unlocked
151
+
152
+ | Feature | Free | Pro |
153
+ |---------|------|-----|
154
+ | Hosted LLM summarizer | No (local Ollama required) | Yes |
155
+ | Cross-machine stats sync | No | Yes |
156
+ | Leaderboard | No | Yes |
157
+ | Priority support | No | Yes (support@ashlr.ai) |
158
+
159
+ See [billing.md](billing.md) for full tier comparison and lifecycle details.
@@ -0,0 +1,87 @@
1
+ /**
2
+ * _hook-errors.ts — shared error-surfacing helper for hooks.
3
+ *
4
+ * Hooks are best-effort and never block tool calls, but silent catches make
5
+ * production failures undebuggable. This helper surfaces errors two ways:
6
+ * 1. stderr — visible in `claude --debug` and most harness log captures
7
+ * 2. ~/.ashlr/hook-errors.jsonl — persistent ring buffer (cap 1000 lines)
8
+ *
9
+ * Never throws. Never blocks. Safe to call from any catch block.
10
+ */
11
+
12
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
13
+ import { homedir } from "os";
14
+ import { dirname, join } from "path";
15
+
16
+ const MAX_LINES = 1000;
17
+ const TRIM_TO = 800;
18
+
19
+ function errorsPath(): string {
20
+ const home =
21
+ process.env.ASHLR_HOME_OVERRIDE?.trim() ||
22
+ process.env.HOME ||
23
+ homedir();
24
+ return join(home, ".ashlr", "hook-errors.jsonl");
25
+ }
26
+
27
+ function trimIfOversized(p: string): void {
28
+ try {
29
+ const raw = readFileSync(p, "utf-8");
30
+ const lines = raw.split("\n");
31
+ if (lines.length <= MAX_LINES) return;
32
+ const kept = lines.slice(lines.length - TRIM_TO).join("\n");
33
+ writeFileSync(p, kept, "utf-8");
34
+ } catch {
35
+ /* best-effort */
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Safe JSON.parse wrapper — the canonical helper for all hook stdin / config
41
+ * file parsing. Returns `fallback` on any parse error and optionally records
42
+ * the failure via `noteHookError` so it shows up in hook-errors.jsonl.
43
+ *
44
+ * Usage:
45
+ * const payload = safeParse<MyType>(raw, {}, "my-hook", "stdin");
46
+ *
47
+ * @param raw - Raw string to parse (may be empty, truncated, or garbage).
48
+ * @param fallback - Value to return when parsing fails.
49
+ * @param hook - Hook name for error logging (optional; omit to skip logging).
50
+ * @param context - Context label for error logging (optional).
51
+ */
52
+ export function safeParse<T>(
53
+ raw: string,
54
+ fallback: T,
55
+ hook?: string,
56
+ context?: string,
57
+ ): T {
58
+ try {
59
+ return JSON.parse(raw) as T;
60
+ } catch (e) {
61
+ if (hook) noteHookError(hook, context ?? "JSON.parse", e);
62
+ return fallback;
63
+ }
64
+ }
65
+
66
+ export function noteHookError(hook: string, context: string, error: unknown): void {
67
+ const msg = error instanceof Error ? error.message : String(error);
68
+ try {
69
+ process.stderr.write(`[ashlr ${hook}] ${context}: ${msg}\n`);
70
+ } catch {
71
+ /* stderr may be closed in some hook harnesses — swallow */
72
+ }
73
+ try {
74
+ const p = errorsPath();
75
+ mkdirSync(dirname(p), { recursive: true });
76
+ const line = JSON.stringify({
77
+ ts: new Date().toISOString(),
78
+ hook,
79
+ context,
80
+ error: msg,
81
+ });
82
+ appendFileSync(p, line + "\n", "utf-8");
83
+ if (Math.random() < 0.01) trimIfOversized(p);
84
+ } catch {
85
+ /* persistence is best-effort */
86
+ }
87
+ }
@@ -0,0 +1,113 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * _hook-perf-emit.ts — SessionEnd helper: read hook-timings.jsonl,
4
+ * compute per-hook p50/p99, and emit one `hook_perf` telemetry event per hook.
5
+ *
6
+ * Called from session-end-consolidate.ts (fire-and-forget). Also exported
7
+ * for direct use in tests and future callers.
8
+ *
9
+ * Privacy: only hook names and latency percentiles are emitted — no file
10
+ * paths, no tool arguments, no content.
11
+ */
12
+
13
+ import { readHookTimings, computeAggregates } from "../scripts/hook-timings-report";
14
+ import { logHookPerfEvent, isTelemetryEnabled } from "../servers/_telemetry";
15
+
16
+ // ---------------------------------------------------------------------------
17
+ // p99 helper (computeAggregates only exposes p95; we need p99 for the spec)
18
+ // ---------------------------------------------------------------------------
19
+
20
+ function percentile(sorted: number[], p: number): number {
21
+ if (sorted.length === 0) return 0;
22
+ if (sorted.length === 1) return sorted[0]!;
23
+ const idx = (p / 100) * (sorted.length - 1);
24
+ const lo = Math.floor(idx);
25
+ const hi = Math.ceil(idx);
26
+ if (lo === hi) return sorted[lo]!;
27
+ const frac = idx - lo;
28
+ return Math.round(sorted[lo]! + frac * (sorted[hi]! - sorted[lo]!));
29
+ }
30
+
31
+ // ---------------------------------------------------------------------------
32
+ // Public API
33
+ // ---------------------------------------------------------------------------
34
+
35
+ export interface HookPerfSummary {
36
+ hook_name: string;
37
+ p50_ms: number;
38
+ p99_ms: number;
39
+ count: number;
40
+ }
41
+
42
+ /**
43
+ * Read hook-timings.jsonl from `timingsPath` (default: ~/.ashlr/hook-timings.jsonl),
44
+ * compute per-hook p50/p99 over the last `windowHours` hours, and return summaries.
45
+ */
46
+ export function computeHookPerfSummaries(opts: {
47
+ timingsPath?: string;
48
+ windowHours?: number;
49
+ } = {}): HookPerfSummary[] {
50
+ const { timingsPath, windowHours = 24 } = opts;
51
+ const records = readHookTimings(timingsPath);
52
+ if (records.length === 0) return [];
53
+
54
+ // Use computeAggregates for the p50 + grouping, then recompute p99
55
+ // from the raw records since the aggregate only exposes p95.
56
+ const aggregates = computeAggregates(records, windowHours);
57
+
58
+ // Build a map: hook → sorted durations (within the window)
59
+ const cutoff = Date.now() - windowHours * 3_600_000;
60
+ const byHook = new Map<string, number[]>();
61
+ for (const rec of records) {
62
+ const t = new Date(rec.ts).getTime();
63
+ if (isNaN(t) || t < cutoff) continue;
64
+ const arr = byHook.get(rec.hook) ?? [];
65
+ arr.push(rec.durationMs);
66
+ byHook.set(rec.hook, arr);
67
+ }
68
+
69
+ return aggregates.map((agg) => {
70
+ const durations = (byHook.get(agg.hook) ?? []).sort((a, b) => a - b);
71
+ return {
72
+ hook_name: agg.hook,
73
+ p50_ms: agg.p50,
74
+ p99_ms: percentile(durations, 99),
75
+ count: agg.calls,
76
+ };
77
+ });
78
+ }
79
+
80
+ /**
81
+ * Emit one `hook_perf` telemetry event per hook. No-op when telemetry is off.
82
+ * Returns the number of events emitted (0 when telemetry off or no records).
83
+ */
84
+ export function emitHookPerfEvents(opts: {
85
+ timingsPath?: string;
86
+ windowHours?: number;
87
+ homeDir?: string;
88
+ } = {}): number {
89
+ if (!isTelemetryEnabled(opts.homeDir)) return 0;
90
+ const summaries = computeHookPerfSummaries(opts);
91
+ for (const s of summaries) {
92
+ logHookPerfEvent({
93
+ hook_name: s.hook_name,
94
+ p50_ms: s.p50_ms,
95
+ p99_ms: s.p99_ms,
96
+ count: s.count,
97
+ }, opts.homeDir);
98
+ }
99
+ return summaries.length;
100
+ }
101
+
102
+ // ---------------------------------------------------------------------------
103
+ // CLI entry (called from session-end-consolidate.ts as fire-and-forget)
104
+ // ---------------------------------------------------------------------------
105
+
106
+ if (import.meta.main) {
107
+ try {
108
+ emitHookPerfEvents();
109
+ } catch {
110
+ // best-effort — never disturb session exit
111
+ }
112
+ process.exit(0);
113
+ }