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,150 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * One-shot installer that wires the ashlr status-line script into the user's
4
+ * Claude Code settings.
5
+ *
6
+ * Strategy for safe merging:
7
+ * 1. Read ~/.claude/settings.json if it exists; parse it as JSON. If the file
8
+ * is corrupt, abort loudly — we will not overwrite a file we can't parse.
9
+ * 2. Take a timestamped backup (settings.json.bak-<epoch>) before writing.
10
+ * 3. Shallow-merge: set settings.statusLine = { type: "command", command: "..." }
11
+ * only if statusLine is missing OR already points at our script. We never
12
+ * clobber a custom statusLine the user has configured for something else.
13
+ * 4. Ensure settings.ashlr defaults exist (statusLine + sub-toggles), again
14
+ * only filling in keys that aren't already set.
15
+ * 5. Write back with 2-space indent, preserving every other top-level key.
16
+ *
17
+ * Idempotent: re-running is a no-op aside from refreshing the absolute path
18
+ * to the script (in case the plugin moved).
19
+ */
20
+
21
+ import { existsSync, readFileSync, writeFileSync, copyFileSync, mkdirSync } from "fs";
22
+ import { homedir } from "os";
23
+ import { dirname, join, resolve } from "path";
24
+ import { c, sym, box, isColorEnabled, prefix } from "./ui.ts";
25
+
26
+ interface StatusLineCmd {
27
+ type: "command";
28
+ command: string;
29
+ padding?: number;
30
+ }
31
+
32
+ interface ClaudeSettings {
33
+ statusLine?: StatusLineCmd | unknown;
34
+ ashlr?: Record<string, unknown>;
35
+ [k: string]: unknown;
36
+ }
37
+
38
+ const SCRIPT_PATH = resolve(import.meta.dir, "savings-status-line.ts");
39
+ const SETTINGS_PATH = join(homedir(), ".claude", "settings.json");
40
+ const COMMAND = `bun run ${SCRIPT_PATH}`;
41
+
42
+ function isOurStatusLine(sl: unknown): sl is StatusLineCmd {
43
+ if (!sl || typeof sl !== "object") return false;
44
+ const cmd = (sl as { command?: unknown }).command;
45
+ return typeof cmd === "string" && cmd.includes("savings-status-line");
46
+ }
47
+
48
+ function main(): void {
49
+ let settings: ClaudeSettings = {};
50
+ let existed = false;
51
+
52
+ if (existsSync(SETTINGS_PATH)) {
53
+ existed = true;
54
+ const raw = readFileSync(SETTINGS_PATH, "utf-8");
55
+ try {
56
+ settings = JSON.parse(raw) as ClaudeSettings;
57
+ } catch (err) {
58
+ const msg = (err as Error).message;
59
+ const head = isColorEnabled()
60
+ ? `${c.red(sym.cross)} ${c.bold("refusing to touch")} ${c.cyan(SETTINGS_PATH)}`
61
+ : `refusing to touch ${SETTINGS_PATH}`;
62
+ console.error(`${head}: not valid JSON (${msg})`);
63
+ process.exit(1);
64
+ }
65
+ // Backup before any write.
66
+ const backup = `${SETTINGS_PATH}.bak-${Date.now()}`;
67
+ copyFileSync(SETTINGS_PATH, backup);
68
+ } else {
69
+ mkdirSync(dirname(SETTINGS_PATH), { recursive: true });
70
+ }
71
+
72
+ const actions: string[] = [];
73
+
74
+ // 1. statusLine command
75
+ const currentSl = settings.statusLine;
76
+ if (!currentSl) {
77
+ settings.statusLine = { type: "command", command: COMMAND, padding: 0 };
78
+ actions.push("added statusLine command");
79
+ } else if (isOurStatusLine(currentSl)) {
80
+ if ((currentSl as StatusLineCmd).command !== COMMAND) {
81
+ (settings.statusLine as StatusLineCmd).command = COMMAND;
82
+ actions.push("refreshed statusLine command path");
83
+ } else {
84
+ actions.push("statusLine already installed (no change)");
85
+ }
86
+ } else {
87
+ const warnHead = isColorEnabled()
88
+ ? `${c.yellow(sym.warn)} ${c.bold("warning:")}`
89
+ : "warning:";
90
+ console.warn(
91
+ `${warnHead} an existing statusLine is configured and points elsewhere; leaving it alone.`,
92
+ );
93
+ const cmd = isColorEnabled() ? c.cyan(COMMAND) : COMMAND;
94
+ console.warn(` to use ashlr instead, set statusLine.command to: ${cmd}`);
95
+ }
96
+
97
+ // 2. ashlr defaults
98
+ const ashlr = (settings.ashlr ??= {}) as Record<string, unknown>;
99
+ const defaults: Record<string, boolean> = {
100
+ statusLine: true,
101
+ statusLineSession: true,
102
+ statusLineLifetime: true,
103
+ statusLineTips: true,
104
+ };
105
+ let addedDefaults = 0;
106
+ for (const [k, v] of Object.entries(defaults)) {
107
+ if (!(k in ashlr)) {
108
+ ashlr[k] = v;
109
+ addedDefaults++;
110
+ }
111
+ }
112
+ if (addedDefaults > 0) actions.push(`seeded ${addedDefaults} ashlr default toggle(s)`);
113
+
114
+ writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2) + "\n", "utf-8");
115
+
116
+ const verb = existed ? "updated" : "created";
117
+ const verbColored = isColorEnabled() ? c.brightGreen(c.bold(verb)) : verb;
118
+ const pathColored = isColorEnabled() ? c.cyan(SETTINGS_PATH) : SETTINGS_PATH;
119
+ console.log(`${prefix.ok(`${verbColored} ${pathColored}`)}`);
120
+ for (const a of actions) {
121
+ const dotGlyph = isColorEnabled() ? c.magenta(sym.bullet) : "-";
122
+ console.log(` ${dotGlyph} ${a}`);
123
+ }
124
+ const scriptLabel = isColorEnabled() ? c.dim("status-line script:") : "status-line script:";
125
+ const scriptColored = isColorEnabled() ? c.cyan(SCRIPT_PATH) : SCRIPT_PATH;
126
+ console.log(`${scriptLabel} ${scriptColored}`);
127
+
128
+ // On a TTY, include a small summary box so the install feels complete.
129
+ if (isColorEnabled()) {
130
+ const body = [
131
+ `${prefix.ok("status line wired")}`,
132
+ ` reload Claude Code to see it`,
133
+ ` toggle anytime via ${c.cyan("/ashlr-settings")}`,
134
+ ].join("\n");
135
+ console.log("");
136
+ console.log(box(body, { title: "ashlr status line", color: c.green }));
137
+ }
138
+ }
139
+
140
+ if (import.meta.main) {
141
+ try {
142
+ main();
143
+ } catch (err) {
144
+ const head = isColorEnabled()
145
+ ? `${c.red(sym.cross)} ${c.bold("install-status-line failed:")}`
146
+ : "install-status-line failed:";
147
+ console.error(`${head} ${(err as Error).message}`);
148
+ process.exit(1);
149
+ }
150
+ }
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env bash
2
+ # ashlr-plugin MCP server entrypoint (LEGACY — Unix-only ports).
3
+ #
4
+ # NOTE: Claude Code itself no longer uses this script. As of v1.15 the
5
+ # canonical entrypoint is `scripts/bootstrap.mjs`, which hands off to
6
+ # `scripts/mcp-entrypoint.ts`. Both run on Windows without Git Bash.
7
+ #
8
+ # This `.sh` is retained ONLY for the Unix-only `ports/` distributions
9
+ # (Cursor, Goose — see `ports/cursor/mcp.json` and `ports/README.md`).
10
+ # If you are on Windows and something invoked this file, that is a bug:
11
+ # your plugin config should point at `scripts/bootstrap.mjs` instead.
12
+ #
13
+ # Wraps every MCP server launch with idempotent self-healing:
14
+ # 1. cd to the plugin root
15
+ # 2. if node_modules is missing, run `bun install` (once; subsequent launches skip)
16
+ # 3. opportunistically drop stale sibling versioned cache dirs (best-effort)
17
+ # 4. exec `bun run <server.ts>` with any passed args
18
+ #
19
+ # Usage (ports distributions only):
20
+ # "command": "bash",
21
+ # "args": ["${ASHLR_PLUGIN_ROOT}/scripts/mcp-entrypoint.sh", "servers/foo-server.ts"]
22
+ #
23
+ # All output is suppressed to stdout (since stdio is the MCP protocol channel).
24
+ # Logs go to stderr, which Claude Code surfaces in its transcript.
25
+
26
+ # Hard guard: if somehow invoked on Windows, redirect the caller to the
27
+ # bun/node-native entrypoint. MSYS/MINGW/CYGWIN all set OSTYPE accordingly.
28
+ case "${OSTYPE:-}" in
29
+ msys*|cygwin*|win32*)
30
+ echo "[ashlr] mcp-entrypoint.sh is Unix-only." >&2
31
+ echo "[ashlr] On Windows, point your MCP config at scripts/bootstrap.mjs instead:" >&2
32
+ echo "[ashlr] node \"\${CLAUDE_PLUGIN_ROOT}/scripts/bootstrap.mjs\" servers/<server>.ts" >&2
33
+ exit 1
34
+ ;;
35
+ esac
36
+
37
+ set -e
38
+
39
+ # Resolve plugin root from the entrypoint's own path (never trust cwd).
40
+ PLUGIN_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
41
+ cd "$PLUGIN_ROOT"
42
+
43
+ # 1. Self-install deps if missing. Idempotent.
44
+ if [ ! -d "node_modules/@modelcontextprotocol/sdk" ]; then
45
+ echo "[ashlr] first-run: installing dependencies in $PLUGIN_ROOT" >&2
46
+ if ! bun install --silent >&2 2>&1; then
47
+ echo "[ashlr] bun install failed. Ensure bun is on PATH and network is available." >&2
48
+ echo "[ashlr] Manual fix: cd \"$PLUGIN_ROOT\" && bun install" >&2
49
+ exit 1
50
+ fi
51
+ fi
52
+
53
+ # 2. Opportunistically drop stale sibling version caches. Safe: strict semver
54
+ # guard + skip current dir. Non-version dirs (latest, dev-branch) survive.
55
+ CURRENT_VERSION="$(basename "$PLUGIN_ROOT")"
56
+ PARENT="$(dirname "$PLUGIN_ROOT")"
57
+ if [[ "$CURRENT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [ -d "$PARENT" ] && [[ "$PARENT" == */plugins/cache/* ]]; then
58
+ for sib in "$PARENT"/*/; do
59
+ sib="${sib%/}"
60
+ name="$(basename "$sib")"
61
+ if [[ "$name" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [ "$name" != "$CURRENT_VERSION" ]; then
62
+ rm -rf "$sib" 2>/dev/null && echo "[ashlr] removed stale cache: $name" >&2 || true
63
+ fi
64
+ done
65
+ fi
66
+
67
+ # 3. Forward Claude Code's session id so MCP servers can attribute savings to
68
+ # the correct per-session bucket in ~/.ashlr/stats.json. Without this, the
69
+ # status line's "session +N" number gets clobbered across concurrent
70
+ # terminals. We export both the canonical name and a mirror so any tool in
71
+ # the subprocess tree can read it.
72
+ if [ -n "${CLAUDE_SESSION_ID:-}" ]; then
73
+ export CLAUDE_SESSION_ID
74
+ export ASHLR_SESSION_ID="$CLAUDE_SESSION_ID"
75
+ fi
76
+
77
+ # 4. Exec the requested server script with any remaining args.
78
+ exec bun run "$@"
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * Bun-native MCP server entrypoint. Replaces `scripts/mcp-entrypoint.sh`
4
+ * so the plugin works on Windows without Git Bash.
5
+ *
6
+ * Responsibilities (in order):
7
+ * 1. Resolve PLUGIN_ROOT from __dirname (never trust cwd).
8
+ * 2. Self-install deps if the MCP SDK cannot be resolved from the plugin.
9
+ * 3. Opportunistically drop stale sibling versioned cache dirs.
10
+ * 4. Forward CLAUDE_SESSION_ID so savings bucket to the right session.
11
+ * 5. Spawn `bun run <server.ts>` as a child and forward stdio 1:1 so the
12
+ * MCP protocol continues to own stdin/stdout/stderr.
13
+ *
14
+ * Why not `await import()` the server directly? Bun would share the import
15
+ * cache with this bootstrapping module, which subtly breaks servers that
16
+ * assume they own `process.argv` or call `process.exit`. A dedicated child
17
+ * keeps the MCP process cleanly isolated.
18
+ *
19
+ * Usage (in .claude-plugin/plugin.json mcpServers entries):
20
+ * "command": "bun",
21
+ * "args": ["run", "${CLAUDE_PLUGIN_ROOT}/scripts/mcp-entrypoint.ts", "servers/_router.ts"]
22
+ */
23
+
24
+ import { existsSync, readdirSync, rmSync, statSync } from "node:fs";
25
+ import { basename, dirname, resolve } from "node:path";
26
+ import { fileURLToPath } from "node:url";
27
+
28
+ const __filename = fileURLToPath(import.meta.url);
29
+ const PLUGIN_ROOT = resolve(dirname(__filename), "..");
30
+ process.chdir(PLUGIN_ROOT);
31
+
32
+ // 1. Self-install deps if missing. Idempotent — `bun install` is a no-op once
33
+ // node_modules is populated.
34
+ // npm may hoist dependencies into an ancestor node_modules directory. Resolve
35
+ // the exact SDK modules used by the router, from this plugin's location, rather
36
+ // than treating the absence of a nested directory as a missing dependency.
37
+ // Resolution does not execute third-party code or consult a caller-selected cwd.
38
+ let sdkReady = false;
39
+ try {
40
+ for (const specifier of [
41
+ "@modelcontextprotocol/sdk/server/index.js",
42
+ "@modelcontextprotocol/sdk/server/stdio.js",
43
+ "@modelcontextprotocol/sdk/types.js",
44
+ ]) {
45
+ Bun.resolveSync(specifier, PLUGIN_ROOT);
46
+ }
47
+ sdkReady = true;
48
+ } catch {
49
+ // Preserve the existing first-run recovery for genuinely missing SDK modules.
50
+ }
51
+ if (!sdkReady) {
52
+ console.error(`[ashlr] first-run: installing dependencies in ${PLUGIN_ROOT}`);
53
+ const result = Bun.spawnSync(["bun", "install", "--silent"], {
54
+ cwd: PLUGIN_ROOT,
55
+ stdio: ["ignore", "inherit", "inherit"],
56
+ });
57
+ if (!result.success) {
58
+ console.error(`[ashlr] bun install failed. Ensure bun is on PATH and network is available.`);
59
+ console.error(`[ashlr] Manual fix: cd "${PLUGIN_ROOT}" && bun install`);
60
+ process.exit(1);
61
+ }
62
+ }
63
+
64
+ // 2. Opportunistically drop stale sibling version caches. Safe: strict semver
65
+ // guard + skip current dir. Non-version dirs (latest, dev-branch) survive.
66
+ // Handles both Unix and Windows path separators for the "plugins/cache"
67
+ // marker so it fires correctly inside %USERPROFILE%\.claude\plugins\cache\.
68
+ const currentVersion = basename(PLUGIN_ROOT);
69
+ const parent = dirname(PLUGIN_ROOT);
70
+ const SEMVER = /^\d+\.\d+\.\d+$/;
71
+ const inCacheDir =
72
+ parent.includes(`${resolve("/").slice(0, 1)}plugins${resolve("/").slice(0, 1)}cache`) ||
73
+ parent.includes("/plugins/cache/") ||
74
+ parent.includes("\\plugins\\cache\\");
75
+ if (SEMVER.test(currentVersion) && existsSync(parent) && inCacheDir) {
76
+ try {
77
+ for (const sib of readdirSync(parent)) {
78
+ if (!SEMVER.test(sib) || sib === currentVersion) continue;
79
+ const sibPath = resolve(parent, sib);
80
+ try {
81
+ if (statSync(sibPath).isDirectory()) {
82
+ rmSync(sibPath, { recursive: true, force: true });
83
+ console.error(`[ashlr] removed stale cache: ${sib}`);
84
+ }
85
+ } catch {
86
+ // Best-effort — if a rm fails (permissions, busy files on Windows),
87
+ // skip it. The cache still works; just keeps a bit of extra disk.
88
+ }
89
+ }
90
+ } catch {
91
+ // readdirSync of the parent failed — not fatal; proceed.
92
+ }
93
+ }
94
+
95
+ // 3. Forward Claude Code's session id so MCP servers attribute savings to the
96
+ // correct per-session bucket in ~/.ashlr/stats.json. Without this, the
97
+ // status-line "session +N" number gets clobbered across concurrent
98
+ // terminals. Mirror under ASHLR_SESSION_ID for subprocesses to read.
99
+ if (process.env["CLAUDE_SESSION_ID"]) {
100
+ process.env["ASHLR_SESSION_ID"] = process.env["CLAUDE_SESSION_ID"];
101
+ }
102
+
103
+ // 4. Exec the requested server script. Any remaining argv are passed through
104
+ // to `bun run <script> [...args]`, preserving compatibility with the bash
105
+ // entrypoint's `exec bun run "$@"` behavior.
106
+ const args = process.argv.slice(2);
107
+ if (args.length === 0) {
108
+ console.error(`[ashlr] usage: mcp-entrypoint.ts <server.ts> [...args]`);
109
+ process.exit(1);
110
+ }
111
+
112
+ const child = Bun.spawn(["bun", "run", ...args], {
113
+ cwd: PLUGIN_ROOT,
114
+ stdio: ["inherit", "inherit", "inherit"],
115
+ env: process.env,
116
+ });
117
+
118
+ // Propagate SIGINT/SIGTERM so a plugin reload or shutdown cleans up cleanly.
119
+ for (const signal of ["SIGINT", "SIGTERM"] as const) {
120
+ process.on(signal, () => {
121
+ try {
122
+ child.kill(signal);
123
+ } catch {
124
+ // Child may already be gone; ignore.
125
+ }
126
+ });
127
+ }
128
+
129
+ const exitCode = await child.exited;
130
+ process.exit(exitCode);
@@ -0,0 +1,152 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * mdx-angle-bracket-lint.ts — flag unbacked `<placeholder>` tokens in body
4
+ * prose of `commands/*.md` and `site/content/docs/skills/*.mdx`.
5
+ *
6
+ * Why: Fumadocs' MDX parser interprets bare angle-bracket tokens
7
+ * (e.g. `<task>`, `<amount>`, `<level>`) as JSX tags. The Vercel docs build
8
+ * fails when these appear in prose. The convention is to wrap them in inline
9
+ * backticks so MDX renders them as literal `<task>` text.
10
+ *
11
+ * Strategy:
12
+ * - Read every target file
13
+ * - Skip code fences (``` ... ```), inline-code spans (`...`), HTML comments
14
+ * - Skip frontmatter (--- ... ---) and YAML inside fences
15
+ * - For remaining content, flag any `<word-or-placeholder>` not preceded by
16
+ * a real-tag whitelist (e.g. `<br>`, `<details>`, `<summary>`, `<a ...>`,
17
+ * `<img ...>`, etc.)
18
+ *
19
+ * Usage:
20
+ * bun run scripts/mdx-angle-bracket-lint.ts # lint all targets, exit non-zero on fail
21
+ * bun run scripts/mdx-angle-bracket-lint.ts <file>... # lint specific files
22
+ * bun run scripts/mdx-angle-bracket-lint.ts --quiet # exit code only, no per-file output
23
+ */
24
+
25
+ import { readFileSync, readdirSync, statSync } from "fs";
26
+ import { join, resolve } from "path";
27
+
28
+ const KNOWN_HTML_TAGS = new Set([
29
+ "a", "abbr", "address", "article", "aside", "audio", "b", "blockquote", "br",
30
+ "button", "canvas", "caption", "code", "col", "colgroup", "data", "datalist",
31
+ "dd", "del", "details", "dfn", "dialog", "div", "dl", "dt", "em", "embed",
32
+ "fieldset", "figcaption", "figure", "footer", "form", "h1", "h2", "h3", "h4",
33
+ "h5", "h6", "head", "header", "hr", "html", "i", "iframe", "img", "input",
34
+ "ins", "kbd", "label", "legend", "li", "main", "mark", "menu", "meta",
35
+ "meter", "nav", "noscript", "object", "ol", "optgroup", "option", "output",
36
+ "p", "param", "picture", "pre", "progress", "q", "rp", "rt", "ruby", "s",
37
+ "samp", "script", "section", "select", "small", "source", "span", "strong",
38
+ "style", "sub", "summary", "sup", "svg", "table", "tbody", "td", "template",
39
+ "textarea", "tfoot", "th", "thead", "time", "title", "tr", "track", "u",
40
+ "ul", "var", "video", "wbr",
41
+ // Closing tags appear as </tag>; allow common patterns
42
+ "br/", "hr/",
43
+ ]);
44
+
45
+ interface LintError {
46
+ file: string;
47
+ line: number;
48
+ col: number;
49
+ match: string;
50
+ }
51
+
52
+ /** Strip code fences and inline-code spans from a line array, in-place. */
53
+ export function stripFences(content: string): string {
54
+ // Remove fenced code blocks first.
55
+ let out = content.replace(/```[\s\S]*?```/g, (m) => m.replace(/[^\n]/g, " "));
56
+ // Remove inline code spans `...`
57
+ out = out.replace(/`[^`\n]+`/g, (m) => m.replace(/[^\n]/g, " "));
58
+ // Remove HTML comments
59
+ out = out.replace(/<!--[\s\S]*?-->/g, (m) => m.replace(/[^\n]/g, " "));
60
+ // Strip YAML frontmatter at top of file (--- through ---)
61
+ out = out.replace(/^---\n[\s\S]*?\n---\n/, (m) => m.replace(/[^\n]/g, " "));
62
+ return out;
63
+ }
64
+
65
+ /** Lint a single file's content. Returns array of errors (empty == ok). */
66
+ export function lintContent(file: string, content: string): LintError[] {
67
+ const stripped = stripFences(content);
68
+ const errors: LintError[] = [];
69
+ const lines = stripped.split("\n");
70
+ // Match `<word>` and `<word>...</word>` opening, but NOT real HTML/JSX tags
71
+ // (those have attributes or are in known list).
72
+ // We're conservative: any `<NAME>` where NAME is lowercase letters or has
73
+ // hyphens but no `=`, no `/`, no spaces, and not in the known tag set.
74
+ const TOKEN_RE = /<([a-z][a-z0-9_-]*)>/gi;
75
+
76
+ for (let i = 0; i < lines.length; i++) {
77
+ const line = lines[i]!;
78
+ let m: RegExpExecArray | null;
79
+ TOKEN_RE.lastIndex = 0;
80
+ while ((m = TOKEN_RE.exec(line)) !== null) {
81
+ const tag = m[1]!.toLowerCase();
82
+ if (KNOWN_HTML_TAGS.has(tag)) continue;
83
+ errors.push({ file, line: i + 1, col: m.index + 1, match: m[0] });
84
+ }
85
+ }
86
+ return errors;
87
+ }
88
+
89
+ function listMdAndMdx(dir: string): string[] {
90
+ const out: string[] = [];
91
+ if (!statSafe(dir)) return out;
92
+ const stack: string[] = [dir];
93
+ while (stack.length > 0) {
94
+ const cur = stack.pop()!;
95
+ for (const entry of readdirSync(cur, { withFileTypes: true })) {
96
+ const full = join(cur, entry.name);
97
+ if (entry.isDirectory()) stack.push(full);
98
+ else if (entry.isFile() && (full.endsWith(".md") || full.endsWith(".mdx"))) out.push(full);
99
+ }
100
+ }
101
+ return out;
102
+ }
103
+
104
+ function statSafe(p: string): boolean {
105
+ try { return statSync(p).isDirectory(); } catch { return false; }
106
+ }
107
+
108
+ async function main(): Promise<void> {
109
+ const args = process.argv.slice(2);
110
+ const quiet = args.includes("--quiet");
111
+ const explicit = args.filter((a) => !a.startsWith("--"));
112
+
113
+ const cwd = process.cwd();
114
+ const targets: string[] = [];
115
+ if (explicit.length > 0) {
116
+ for (const t of explicit) targets.push(resolve(cwd, t));
117
+ } else {
118
+ targets.push(...listMdAndMdx(join(cwd, "commands")));
119
+ targets.push(...listMdAndMdx(join(cwd, "site", "content", "docs", "skills")));
120
+ }
121
+
122
+ let totalErrors = 0;
123
+ const seenFiles = new Set<string>();
124
+ for (const file of targets) {
125
+ if (seenFiles.has(file)) continue;
126
+ seenFiles.add(file);
127
+ let content: string;
128
+ try { content = readFileSync(file, "utf-8"); } catch { continue; }
129
+ const errors = lintContent(file, content);
130
+ if (errors.length === 0) continue;
131
+ totalErrors += errors.length;
132
+ if (!quiet) {
133
+ for (const e of errors) {
134
+ process.stderr.write(`${e.file}:${e.line}:${e.col} unwrapped angle-bracket token: ${e.match}\n`);
135
+ }
136
+ }
137
+ }
138
+
139
+ if (totalErrors === 0) {
140
+ if (!quiet) process.stdout.write(`mdx-lint: ok (${seenFiles.size} files scanned)\n`);
141
+ process.exit(0);
142
+ }
143
+ if (!quiet) {
144
+ process.stderr.write(`\nmdx-lint: ${totalErrors} unwrapped angle-bracket token(s) across ${seenFiles.size} files.\n`);
145
+ process.stderr.write(`Fix: wrap them in backticks (e.g. \`<level>\`) so MDX renders them as literal text.\n`);
146
+ }
147
+ process.exit(1);
148
+ }
149
+
150
+ if (import.meta.main) {
151
+ void main();
152
+ }
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * measure-cold-start — time how long the ashlr-router takes from process
4
+ * launch to a valid `initialize` response over stdio.
5
+ *
6
+ * Usage:
7
+ * bun run scripts/measure-cold-start.ts # single run, prints ms
8
+ * bun run scripts/measure-cold-start.ts --runs 5 # average of N runs
9
+ * bun run scripts/measure-cold-start.ts --assert # exit 1 if p95 >= 100ms
10
+ *
11
+ * The measurement starts at spawn() and ends when the first valid JSON line
12
+ * appears on stdout (the initialize response). This captures the full
13
+ * cold-start path: Bun startup + module evaluation + handler registration +
14
+ * MCP stdio handshake.
15
+ */
16
+
17
+ import { spawn } from "bun";
18
+ import { resolve } from "path";
19
+
20
+ const ROUTER = resolve(import.meta.dir, "..", "servers", "_router.ts");
21
+
22
+ const INIT_REQUEST =
23
+ JSON.stringify({
24
+ jsonrpc: "2.0",
25
+ id: 1,
26
+ method: "initialize",
27
+ params: {
28
+ protocolVersion: "2024-11-05",
29
+ capabilities: {},
30
+ clientInfo: { name: "cold-start-measure", version: "1" },
31
+ },
32
+ }) + "\n";
33
+
34
+ /** Measure one cold-start. Returns elapsed milliseconds. */
35
+ async function measureOnce(): Promise<number> {
36
+ const t0 = performance.now();
37
+
38
+ const proc = spawn({
39
+ cmd: ["bun", "run", ROUTER],
40
+ cwd: resolve(import.meta.dir, ".."),
41
+ stdin: "pipe",
42
+ stdout: "pipe",
43
+ stderr: "pipe",
44
+ env: {
45
+ ...process.env,
46
+ ASHLR_STATS_SYNC: "1",
47
+ ASHLR_SESSION_LOG: "0",
48
+ },
49
+ });
50
+
51
+ proc.stdin.write(INIT_REQUEST);
52
+ await proc.stdin.end();
53
+
54
+ // Read lines until we get the initialize response.
55
+ const reader = proc.stdout.getReader();
56
+ let buf = "";
57
+ let elapsed = -1;
58
+
59
+ outer: while (true) {
60
+ const { done, value } = await reader.read();
61
+ if (done) break;
62
+ buf += new TextDecoder().decode(value);
63
+ const lines = buf.split("\n");
64
+ buf = lines.pop() ?? "";
65
+ for (const line of lines) {
66
+ if (!line.trim()) continue;
67
+ try {
68
+ const msg = JSON.parse(line);
69
+ if (msg?.result?.serverInfo?.name === "ashlr-router") {
70
+ elapsed = performance.now() - t0;
71
+ break outer;
72
+ }
73
+ } catch {
74
+ // not JSON yet — keep reading
75
+ }
76
+ }
77
+ }
78
+
79
+ reader.cancel();
80
+ await proc.exited;
81
+
82
+ if (elapsed < 0) throw new Error("Router did not emit an initialize response");
83
+ return elapsed;
84
+ }
85
+
86
+ // ---------------------------------------------------------------------------
87
+ // CLI
88
+ // ---------------------------------------------------------------------------
89
+
90
+ const args = process.argv.slice(2);
91
+ const runsArg = args.indexOf("--runs");
92
+ const runs = runsArg >= 0 ? parseInt(args[runsArg + 1] ?? "5", 10) : 1;
93
+ const shouldAssert = args.includes("--assert");
94
+ const TARGET_MS = 100;
95
+
96
+ const samples: number[] = [];
97
+ for (let i = 0; i < runs; i++) {
98
+ const ms = await measureOnce();
99
+ samples.push(ms);
100
+ process.stdout.write(` run ${i + 1}/${runs}: ${ms.toFixed(1)}ms\n`);
101
+ }
102
+
103
+ samples.sort((a, b) => a - b);
104
+ const avg = samples.reduce((s, v) => s + v, 0) / samples.length;
105
+ const p50 = samples[Math.floor(samples.length * 0.5)]!;
106
+ const p95 = samples[Math.floor(samples.length * 0.95)]!;
107
+ const max = samples[samples.length - 1]!;
108
+
109
+ process.stdout.write(
110
+ `\nashlr-router cold-start (${runs} run${runs === 1 ? "" : "s"})\n` +
111
+ ` avg ${avg.toFixed(1)}ms\n` +
112
+ ` p50 ${p50.toFixed(1)}ms\n` +
113
+ ` p95 ${p95.toFixed(1)}ms\n` +
114
+ ` max ${max.toFixed(1)}ms\n` +
115
+ ` target: < ${TARGET_MS}ms\n`,
116
+ );
117
+
118
+ if (shouldAssert) {
119
+ if (p95 >= TARGET_MS) {
120
+ process.stderr.write(
121
+ `[measure-cold-start] FAIL: p95=${p95.toFixed(1)}ms >= ${TARGET_MS}ms target\n`,
122
+ );
123
+ process.exit(1);
124
+ }
125
+ process.stdout.write(`[measure-cold-start] PASS: p95=${p95.toFixed(1)}ms < ${TARGET_MS}ms\n`);
126
+ }