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,381 @@
1
+ /**
2
+ * _pro.ts — Pro token validation with 24h cache and 7-day offline grace.
3
+ *
4
+ * The token stored in ~/.ashlr/pro-token is a permanent API token (not a JWT)
5
+ * issued by POST /auth/verify on the server. Validation is done by calling
6
+ * GET /user/me with the Bearer token — the server returns { userId, email,
7
+ * tier, githubLogin, hasGitHub }. "Pro" status means tier === "pro" || "team".
8
+ *
9
+ * Cache semantics:
10
+ * - Validated result is written to ~/.ashlr/pro-token-cache.json.
11
+ * - Cache < 24h old → used directly, no network call.
12
+ * - Cache 24h–7d old → used immediately (offline grace), background refresh
13
+ * triggered via setImmediate.
14
+ * - Cache > 7d old → treated as expired; forces synchronous re-validation.
15
+ * - 401 from server → renames token to pro-token.invalid, returns invalid.
16
+ * - Network error → falls back to cached result if < 7 days old.
17
+ */
18
+
19
+ import { existsSync, renameSync, statSync } from "fs";
20
+ import { readFile, writeFile, mkdir } from "fs/promises";
21
+ import { homedir } from "os";
22
+ import { join, dirname } from "path";
23
+
24
+ // ---------------------------------------------------------------------------
25
+ // Constants
26
+ // ---------------------------------------------------------------------------
27
+
28
+ const CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24h
29
+ const OFFLINE_GRACE_MS = 7 * 24 * 60 * 60 * 1000; // 7d
30
+
31
+ const API_URL = process.env["ASHLR_API_URL"] ?? "https://api.ashlr.ai";
32
+
33
+ /**
34
+ * Offline / air-gapped escape hatch.
35
+ *
36
+ * Setting `ASHLR_PRO_ASSUME=true` (case-insensitive) forces `isProSync()`
37
+ * to return true regardless of cache state or the 7-day staleness gate.
38
+ * Use when you cannot reach api.ashlr.ai for an extended period (planes,
39
+ * air-gapped networks, conference Wi-Fi from hell) and need Pro features
40
+ * to keep working.
41
+ *
42
+ * Truthy values: any non-empty value other than "0", "false", "no", or
43
+ * "off" (case-insensitive after trim). Unset / empty → disabled.
44
+ */
45
+ export function isProAssumeEnabled(env: NodeJS.ProcessEnv = process.env): boolean {
46
+ const raw = env["ASHLR_PRO_ASSUME"];
47
+ if (raw == null) return false;
48
+ const v = String(raw).trim().toLowerCase();
49
+ if (v === "" || v === "0" || v === "false" || v === "no" || v === "off") return false;
50
+ return true;
51
+ }
52
+
53
+ // ---------------------------------------------------------------------------
54
+ // Paths
55
+ // ---------------------------------------------------------------------------
56
+
57
+ function ashlrDir(homeOverride?: string): string {
58
+ return join(homeOverride ?? process.env.HOME ?? homedir(), ".ashlr");
59
+ }
60
+
61
+ export function proTokenPath(homeOverride?: string): string {
62
+ return join(ashlrDir(homeOverride), "pro-token");
63
+ }
64
+
65
+ export function proTokenCachePath(homeOverride?: string): string {
66
+ return join(ashlrDir(homeOverride), "pro-token-cache.json");
67
+ }
68
+
69
+ // ---------------------------------------------------------------------------
70
+ // Cache types
71
+ // ---------------------------------------------------------------------------
72
+
73
+ export interface ProTokenCache {
74
+ valid: boolean;
75
+ plan: string | null;
76
+ trialEndsAt: string | null;
77
+ validatedAt: string; // ISO
78
+ }
79
+
80
+ export interface ProValidationResult {
81
+ valid: boolean;
82
+ plan: string | null;
83
+ trialEndsAt: string | null;
84
+ validatedAt: string | null;
85
+ reason?: "no-token" | "expired-or-revoked" | "network-error" | "cached";
86
+ }
87
+
88
+ // ---------------------------------------------------------------------------
89
+ // Cache I/O
90
+ // ---------------------------------------------------------------------------
91
+
92
+ async function readCache(homeOverride?: string): Promise<ProTokenCache | null> {
93
+ const p = proTokenCachePath(homeOverride);
94
+ try {
95
+ const raw = await readFile(p, "utf-8");
96
+ const parsed = JSON.parse(raw) as ProTokenCache;
97
+ if (
98
+ typeof parsed.valid === "boolean" &&
99
+ typeof parsed.validatedAt === "string"
100
+ ) {
101
+ return parsed;
102
+ }
103
+ return null;
104
+ } catch {
105
+ return null;
106
+ }
107
+ }
108
+
109
+ async function writeCache(cache: ProTokenCache, homeOverride?: string): Promise<void> {
110
+ const p = proTokenCachePath(homeOverride);
111
+ try {
112
+ await mkdir(dirname(p), { recursive: true });
113
+ await writeFile(p, JSON.stringify(cache, null, 2), { encoding: "utf-8", mode: 0o600 });
114
+ } catch {
115
+ // best-effort — never block the hot path
116
+ }
117
+ }
118
+
119
+ // ---------------------------------------------------------------------------
120
+ // Token file I/O
121
+ // ---------------------------------------------------------------------------
122
+
123
+ function readTokenSync(homeOverride?: string): string | null {
124
+ const p = proTokenPath(homeOverride);
125
+ try {
126
+ const s = statSync(p);
127
+ if (!s.isFile() || s.size === 0) return null;
128
+ const { readFileSync } = require("fs") as typeof import("fs");
129
+ return readFileSync(p, "utf-8").trim() || null;
130
+ } catch {
131
+ return null;
132
+ }
133
+ }
134
+
135
+ function invalidateToken(homeOverride?: string): void {
136
+ const p = proTokenPath(homeOverride);
137
+ const dest = p + ".invalid";
138
+ try {
139
+ renameSync(p, dest);
140
+ } catch {
141
+ // best-effort
142
+ }
143
+ }
144
+
145
+ // ---------------------------------------------------------------------------
146
+ // Network validation
147
+ // ---------------------------------------------------------------------------
148
+
149
+ interface UserMeResponse {
150
+ userId?: string;
151
+ email?: string;
152
+ tier?: string;
153
+ githubLogin?: string | null;
154
+ hasGitHub?: boolean;
155
+ }
156
+
157
+ type FetchLike = (input: Parameters<typeof fetch>[0], init?: Parameters<typeof fetch>[1]) => Promise<Response>;
158
+
159
+ /**
160
+ * Calls GET /user/me with the given token.
161
+ * Returns null on network error (caller should fall back to cache).
162
+ * Returns { tier } on success, or throws with status 401 when revoked.
163
+ */
164
+ async function fetchUserMe(
165
+ token: string,
166
+ fetchImpl: FetchLike = globalThis.fetch,
167
+ timeoutMs = 5000,
168
+ ): Promise<{ tier: string; trialEndsAt: string | null } | null> {
169
+ const ctrl = new AbortController();
170
+ const timer = setTimeout(() => ctrl.abort(), timeoutMs);
171
+
172
+ try {
173
+ const res = await fetchImpl(`${API_URL}/user/me`, {
174
+ method: "GET",
175
+ headers: {
176
+ Authorization: `Bearer ${token}`,
177
+ "Content-Type": "application/json",
178
+ },
179
+ signal: ctrl.signal,
180
+ });
181
+
182
+ if (res.status === 401) {
183
+ throw Object.assign(new Error("401"), { status: 401 });
184
+ }
185
+
186
+ if (!res.ok) {
187
+ // 5xx or unexpected — treat as network error (fallback to cache)
188
+ return null;
189
+ }
190
+
191
+ let body: UserMeResponse;
192
+ try {
193
+ body = (await res.json()) as UserMeResponse;
194
+ } catch {
195
+ return null;
196
+ }
197
+
198
+ return {
199
+ tier: body.tier ?? "free",
200
+ // trialEndsAt is always null: the server's GET /user/me response does not
201
+ // include a trial_end field (the DB user row has no trial_end column and
202
+ // Stripe trial_end is not fetched on this path). No UI in the plugin
203
+ // displays this value today, so null is correct and safe — it is NOT a
204
+ // countdown timer that could mislead users. Wire it when the server adds
205
+ // the field (requires a Stripe subscription lookup + DB migration).
206
+ trialEndsAt: null,
207
+ };
208
+ } catch (err: unknown) {
209
+ if (err instanceof Error && "status" in err && (err as { status: number }).status === 401) {
210
+ throw err; // propagate 401
211
+ }
212
+ // Timeout or network error → caller falls back
213
+ return null;
214
+ } finally {
215
+ clearTimeout(timer);
216
+ }
217
+ }
218
+
219
+ // ---------------------------------------------------------------------------
220
+ // Background refresh
221
+ // ---------------------------------------------------------------------------
222
+
223
+ function spawnBackgroundRefresh(homeOverride?: string): void {
224
+ setImmediate(async () => {
225
+ try {
226
+ const token = readTokenSync(homeOverride);
227
+ if (!token) return;
228
+ const result = await fetchUserMe(token);
229
+ if (!result) return;
230
+ const isPro = result.tier === "pro" || result.tier === "team";
231
+ await writeCache(
232
+ {
233
+ valid: isPro,
234
+ plan: result.tier,
235
+ trialEndsAt: result.trialEndsAt,
236
+ validatedAt: new Date().toISOString(),
237
+ },
238
+ homeOverride,
239
+ );
240
+ } catch {
241
+ // background refresh — never throw
242
+ }
243
+ });
244
+ }
245
+
246
+ // ---------------------------------------------------------------------------
247
+ // Public API
248
+ // ---------------------------------------------------------------------------
249
+
250
+ /**
251
+ * Validate the Pro token in ~/.ashlr/pro-token.
252
+ *
253
+ * @param opts.homeOverride Override home dir (for testing).
254
+ * @param opts.fetchImpl Override fetch (for testing).
255
+ * @param opts.nowMs Override Date.now() (for testing).
256
+ */
257
+ export async function validateProToken(opts: {
258
+ homeOverride?: string;
259
+ fetchImpl?: FetchLike;
260
+ nowMs?: number;
261
+ } = {}): Promise<ProValidationResult> {
262
+ const { homeOverride, fetchImpl = globalThis.fetch, nowMs = Date.now() } = opts;
263
+
264
+ // 1. Check token file
265
+ const token = readTokenSync(homeOverride);
266
+ if (!token) {
267
+ return { valid: false, plan: null, trialEndsAt: null, validatedAt: null, reason: "no-token" };
268
+ }
269
+
270
+ // 2. Read cache
271
+ const cached = await readCache(homeOverride);
272
+ const cacheAge = cached ? nowMs - new Date(cached.validatedAt).getTime() : Infinity;
273
+
274
+ // 3. Cache < 24h → use directly
275
+ if (cached && cacheAge < CACHE_TTL_MS) {
276
+ return {
277
+ valid: cached.valid,
278
+ plan: cached.plan,
279
+ trialEndsAt: cached.trialEndsAt,
280
+ validatedAt: cached.validatedAt,
281
+ reason: "cached",
282
+ };
283
+ }
284
+
285
+ // 4. Cache is stale (24h–7d) → return cached value, refresh in background
286
+ if (cached && cacheAge < OFFLINE_GRACE_MS) {
287
+ spawnBackgroundRefresh(homeOverride);
288
+ return {
289
+ valid: cached.valid,
290
+ plan: cached.plan,
291
+ trialEndsAt: cached.trialEndsAt,
292
+ validatedAt: cached.validatedAt,
293
+ reason: "cached",
294
+ };
295
+ }
296
+
297
+ // 5. No usable cache → do a synchronous network call
298
+ try {
299
+ const result = await fetchUserMe(token, fetchImpl);
300
+
301
+ if (result === null) {
302
+ // Network error — if we have a stale cache (> 7d), still use it
303
+ if (cached) {
304
+ return {
305
+ valid: cached.valid,
306
+ plan: cached.plan,
307
+ trialEndsAt: cached.trialEndsAt,
308
+ validatedAt: cached.validatedAt,
309
+ reason: "network-error",
310
+ };
311
+ }
312
+ return { valid: false, plan: null, trialEndsAt: null, validatedAt: null, reason: "network-error" };
313
+ }
314
+
315
+ const isPro = result.tier === "pro" || result.tier === "team";
316
+ const newCache: ProTokenCache = {
317
+ valid: isPro,
318
+ plan: result.tier,
319
+ trialEndsAt: result.trialEndsAt,
320
+ validatedAt: new Date(nowMs).toISOString(),
321
+ };
322
+ await writeCache(newCache, homeOverride);
323
+
324
+ return {
325
+ valid: isPro,
326
+ plan: result.tier,
327
+ trialEndsAt: result.trialEndsAt,
328
+ validatedAt: newCache.validatedAt,
329
+ };
330
+ } catch (err: unknown) {
331
+ // 401 → revoke token
332
+ if (err instanceof Error && "status" in err && (err as { status: number }).status === 401) {
333
+ invalidateToken(homeOverride);
334
+ return {
335
+ valid: false,
336
+ plan: null,
337
+ trialEndsAt: null,
338
+ validatedAt: null,
339
+ reason: "expired-or-revoked",
340
+ };
341
+ }
342
+
343
+ // Unexpected error → fallback to stale cache
344
+ if (cached) {
345
+ return {
346
+ valid: cached.valid,
347
+ plan: cached.plan,
348
+ trialEndsAt: cached.trialEndsAt,
349
+ validatedAt: cached.validatedAt,
350
+ reason: "network-error",
351
+ };
352
+ }
353
+ return { valid: false, plan: null, trialEndsAt: null, validatedAt: null, reason: "network-error" };
354
+ }
355
+ }
356
+
357
+ /**
358
+ * Synchronous best-effort Pro check — reads only the cache file.
359
+ * Returns false when no cache or cache is expired beyond 7d.
360
+ * Suitable for hot paths where we cannot await.
361
+ */
362
+ export function isProSync(homeOverride?: string): boolean {
363
+ // Offline / air-gapped escape hatch — set ASHLR_PRO_ASSUME=true to bypass
364
+ // the 7-day cache-staleness gate (and the cache existence check).
365
+ if (isProAssumeEnabled()) return true;
366
+
367
+ const cached = (() => {
368
+ const p = proTokenCachePath(homeOverride);
369
+ try {
370
+ const { readFileSync } = require("fs") as typeof import("fs");
371
+ const raw = readFileSync(p, "utf-8");
372
+ return JSON.parse(raw) as ProTokenCache;
373
+ } catch {
374
+ return null;
375
+ }
376
+ })();
377
+
378
+ if (!cached) return false;
379
+ const age = Date.now() - new Date(cached.validatedAt).getTime();
380
+ return cached.valid && age < OFFLINE_GRACE_MS;
381
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * _read-cache — per-process content cache for ashlr__read.
3
+ *
4
+ * Keyed by absolute path; the cached result is only reused when the file's
5
+ * mtimeMs matches — any write (ours via ashlr__edit, or external) invalidates.
6
+ * Lives for the MCP server lifetime, which aligns with a single Claude Code
7
+ * session.
8
+ *
9
+ * Module-level singleton. All consumers (read-server, edit-server) import
10
+ * the same instance.
11
+ */
12
+
13
+ export interface ReadCacheEntry {
14
+ mtimeMs: number;
15
+ /** The exact string we would have returned on a miss. */
16
+ result: string;
17
+ /** Bytes of the original file when cached — for correct savings math on reuse. */
18
+ sourceBytes: number;
19
+ }
20
+
21
+ const readCache: Map<string, ReadCacheEntry> = new Map();
22
+
23
+ /** Return the cached entry for `abs`, or undefined if absent. */
24
+ export function getCached(abs: string): ReadCacheEntry | undefined {
25
+ return readCache.get(abs);
26
+ }
27
+
28
+ /** Store a cache entry for `abs`. */
29
+ export function setCached(abs: string, entry: ReadCacheEntry): void {
30
+ readCache.set(abs, entry);
31
+ }
32
+
33
+ /**
34
+ * Invalidate the cache entry for `abs` so the next read fetches fresh
35
+ * content. Called by edit-server immediately after a successful write.
36
+ *
37
+ * Sets mtimeMs to -1 (guaranteed mismatch against any real stat) rather than
38
+ * deleting so that a concurrent read that already looked up the entry will
39
+ * still see a miss when it compares mtimes.
40
+ */
41
+ export function invalidateCached(abs: string): void {
42
+ const hit = readCache.get(abs);
43
+ if (hit) readCache.set(abs, { ...hit, mtimeMs: -1 });
44
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * _router-handlers — side-effect aggregator.
3
+ *
4
+ * Importing this file registers all migrated tool handlers into the shared
5
+ * registry (_tool-base.ts). The router imports this once on startup; each
6
+ * per-server handlers module is a no-op if imported again (registerTool is
7
+ * idempotent — last write wins).
8
+ *
9
+ * Add one import per server as it completes Track A migration.
10
+ */
11
+
12
+ import "./glob-server-handlers";
13
+ import "./tree-server-handlers";
14
+ import "./ls-server-handlers";
15
+ import "./diff-server-handlers";
16
+ import "./webfetch-server-handlers";
17
+ // Track B (v1.21): efficiency-server decomposed into 5 per-tool servers.
18
+ // The old composite efficiency-server-handlers is retired; each new
19
+ // handler module side-effect-registers its tool below.
20
+ import "./read-server-handlers";
21
+ import "./grep-server-handlers";
22
+ import "./edit-server-handlers";
23
+ import "./flush-server-handlers";
24
+ import "./savings-server-handlers";
25
+ import "./orient-server-handlers";
26
+ import "./http-server-handlers";
27
+ import "./logs-server-handlers";
28
+ import "./sql-server-handlers";
29
+ import "./multi-edit-server-handlers";
30
+ import "./diff-semantic-server-handlers";
31
+ import "./github-server-handlers";
32
+ import "./genome-server-handlers";
33
+ import "./ask-server-handlers";
34
+ import "./bash-server-handlers";
35
+ import "./edit-structural-server-handlers";
36
+ import "./test-server-handlers";
37
+ import "./rename-file-server-handlers";
38
+ import "./search-replace-regex-server-handlers";
39
+ // v1.22 Track B
40
+ import "./websearch-server-handlers";
41
+ import "./task-server-handlers";
42
+ // v1.22 Track C
43
+ import "./notebook-edit-server-handlers";
44
+ import "./write-server-handlers";
45
+ // v1.34 Track 3 — flag-gated; no-op when ASHLR_PIPE_ENABLE != "1"
46
+ import "./pipe-server-handlers";
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * ashlr-router — single long-lived MCP process hosting all 40 ashlr__* tools.
4
+ *
5
+ * One process replaces the old N-process architecture where each tool spawned
6
+ * its own child. Shared resources (SQLite embedding cache, summarizer pool,
7
+ * genome LRU) are initialized once and reused across every tool call.
8
+ *
9
+ * Architecture:
10
+ * - `_router-handlers.ts` imports every handler module as a side-effect,
11
+ * which registers all tools into the shared registry in `_tool-base.ts`.
12
+ * - `runStandalone()` boots a single MCP stdio server that dispatches
13
+ * `tools/list` and `tools/call` via the registry.
14
+ * - Per-handler crash isolation: one handler throwing does NOT kill the
15
+ * process — the dispatch boundary in `_tool-base.ts::runStandalone` wraps
16
+ * each call in try/catch and returns `isError: true` with a crash-dump.
17
+ * - `ASHLR_ROUTER_DISABLE=1` short-circuits and exits cleanly so legacy
18
+ * per-server plugin.json entries can take over if needed.
19
+ *
20
+ * Legacy entrypoints (efficiency-server.ts, grep-server.ts, …) keep their
21
+ * `if (import.meta.main)` guards intact so they still work for direct
22
+ * invocation and for smoke tests.
23
+ */
24
+
25
+ import { listTools, runStandalone } from "./_tool-base";
26
+ import { detectMcpHost } from "./_mcp-host";
27
+ import "./_router-handlers";
28
+
29
+ // ---------------------------------------------------------------------------
30
+ // Entry point
31
+ // ---------------------------------------------------------------------------
32
+
33
+ async function main(): Promise<void> {
34
+ if (process.env.ASHLR_ROUTER_DISABLE === "1") {
35
+ process.stderr.write(
36
+ "[ashlr-router] ASHLR_ROUTER_DISABLE=1 set; exiting so per-server entries run instead.\n",
37
+ );
38
+ process.exit(0);
39
+ }
40
+
41
+ const toolCount = listTools().length;
42
+ const host = detectMcpHost();
43
+ process.stderr.write(
44
+ `[ashlr-router] starting · ${toolCount} tools registered · version=${process.env.ASHLR_VERSION ?? "dev"} · host=${host}\n`,
45
+ );
46
+
47
+ await runStandalone("ashlr-router", process.env.ASHLR_VERSION ?? "dev");
48
+ }
49
+
50
+ if (import.meta.main) {
51
+ main().catch((err) => {
52
+ process.stderr.write(`[ashlr-router] fatal: ${err instanceof Error ? err.stack ?? err.message : String(err)}\n`);
53
+ process.exit(1);
54
+ });
55
+ }
@@ -0,0 +1,173 @@
1
+ /**
2
+ * _run-with-timeout.ts — async subprocess wrapper with process-group cleanup.
3
+ *
4
+ * Mirrors the bash-server.ts `runRaw` pattern (spawn + on('close') + accumulator
5
+ * buffers + signal handling) but generalises it into a reusable utility for the
6
+ * server hot-paths that previously called spawnSync.
7
+ *
8
+ * Key behaviours:
9
+ * - POSIX: `detached: true` creates a process group; on timeout we SIGKILL
10
+ * the whole group (`-pid`) so grandchild processes don't leak.
11
+ * - Windows: `taskkill /T /F /PID` cascades through the process tree.
12
+ * - SIGTERM first, 250 ms grace, then SIGKILL.
13
+ * - Never throws on subprocess error — returns `exitCode: -1` with the error
14
+ * surfaced in `stderr`.
15
+ * - Stdout and stderr are each capped at 10 MB to prevent OOM on runaway
16
+ * output; excess bytes are silently dropped (the cap notice appears in
17
+ * stderr so callers can detect truncation).
18
+ */
19
+
20
+ import { spawn } from "child_process";
21
+
22
+ /** Maximum bytes buffered per stream before we stop accumulating. */
23
+ const STREAM_CAP = 10 * 1024 * 1024; // 10 MB
24
+
25
+ export interface RunWithTimeoutOptions {
26
+ command: string;
27
+ args: string[];
28
+ cwd?: string;
29
+ env?: Record<string, string>;
30
+ timeoutMs: number;
31
+ /** Optional stdin to feed the child process (UTF-8 string). */
32
+ input?: string;
33
+ }
34
+
35
+ export interface RunWithTimeoutResult {
36
+ stdout: string;
37
+ stderr: string;
38
+ /** Process exit code, or -1 on spawn error. */
39
+ exitCode: number;
40
+ timedOut: boolean;
41
+ }
42
+
43
+ /**
44
+ * Spawn `command args` and collect stdout/stderr, killing the process (group)
45
+ * after `timeoutMs` milliseconds. Returns a resolved Promise — never rejects.
46
+ */
47
+ export function runWithTimeout(opts: RunWithTimeoutOptions): Promise<RunWithTimeoutResult> {
48
+ return new Promise((resolveP) => {
49
+ const isWin = process.platform === "win32";
50
+
51
+ const child = spawn(opts.command, opts.args, {
52
+ cwd: opts.cwd,
53
+ env: opts.env ?? (process.env as Record<string, string>),
54
+ stdio: opts.input !== undefined ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"],
55
+ // POSIX: own process group so timeout can kill the whole tree.
56
+ // Windows: detached:true spawns a new console window, so we skip it.
57
+ detached: !isWin,
58
+ });
59
+
60
+ let stdout = "";
61
+ let stderr = "";
62
+ let stdoutCapped = false;
63
+ let stderrCapped = false;
64
+ let timedOut = false;
65
+
66
+ child.stdout?.on("data", (b: Buffer) => {
67
+ if (stdout.length >= STREAM_CAP) {
68
+ if (!stdoutCapped) {
69
+ stdoutCapped = true;
70
+ stderr += `\n[_run-with-timeout: stdout capped at ${STREAM_CAP} bytes]\n`;
71
+ }
72
+ return;
73
+ }
74
+ const remaining = STREAM_CAP - stdout.length;
75
+ if (b.length <= remaining) {
76
+ stdout += b.toString("utf-8");
77
+ } else {
78
+ // Truncate the chunk so total stays at exactly STREAM_CAP.
79
+ stdout += b.subarray(0, remaining).toString("utf-8");
80
+ if (!stdoutCapped) {
81
+ stdoutCapped = true;
82
+ stderr += `\n[_run-with-timeout: stdout capped at ${STREAM_CAP} bytes]\n`;
83
+ }
84
+ }
85
+ });
86
+
87
+ child.stderr?.on("data", (b: Buffer) => {
88
+ if (stderr.length >= STREAM_CAP) {
89
+ if (!stderrCapped) {
90
+ stderrCapped = true;
91
+ stderr += `\n[_run-with-timeout: stderr capped at ${STREAM_CAP} bytes]\n`;
92
+ }
93
+ return;
94
+ }
95
+ const remaining = STREAM_CAP - stderr.length;
96
+ if (b.length <= remaining) {
97
+ stderr += b.toString("utf-8");
98
+ } else {
99
+ stderr += b.subarray(0, remaining).toString("utf-8");
100
+ if (!stderrCapped) {
101
+ stderrCapped = true;
102
+ stderr += `\n[_run-with-timeout: stderr capped at ${STREAM_CAP} bytes]\n`;
103
+ }
104
+ }
105
+ });
106
+
107
+ // Write stdin if provided, then close it.
108
+ if (opts.input !== undefined && child.stdin) {
109
+ try {
110
+ child.stdin.write(opts.input, "utf-8");
111
+ child.stdin.end();
112
+ } catch {
113
+ // stdin may already be closed if the child died immediately.
114
+ }
115
+ }
116
+
117
+ /** Kill the process tree and set timedOut flag. */
118
+ function killTree(): void {
119
+ timedOut = true;
120
+ if (isWin) {
121
+ // taskkill /T cascades through child processes on Windows.
122
+ if (child.pid != null) {
123
+ spawn("taskkill", ["/T", "/F", "/PID", String(child.pid)], {
124
+ stdio: "ignore",
125
+ }).on("error", () => {
126
+ // Ignore — process may already be gone.
127
+ });
128
+ } else {
129
+ try { child.kill("SIGKILL"); } catch { /* already dead */ }
130
+ }
131
+ } else if (child.pid != null) {
132
+ // SIGTERM first; escalate to SIGKILL after 250 ms grace period.
133
+ try {
134
+ process.kill(-child.pid, "SIGTERM");
135
+ } catch {
136
+ try { child.kill("SIGTERM"); } catch { /* already dead */ }
137
+ }
138
+ setTimeout(() => {
139
+ try {
140
+ // Negative pid => send to the whole process group.
141
+ process.kill(-child.pid!, "SIGKILL");
142
+ } catch {
143
+ try { child.kill("SIGKILL"); } catch { /* already dead */ }
144
+ }
145
+ }, 250);
146
+ } else {
147
+ try { child.kill("SIGKILL"); } catch { /* already dead */ }
148
+ }
149
+ }
150
+
151
+ const timer = setTimeout(killTree, opts.timeoutMs);
152
+
153
+ child.on("close", (code) => {
154
+ clearTimeout(timer);
155
+ resolveP({
156
+ stdout,
157
+ stderr,
158
+ exitCode: code ?? (timedOut ? -1 : -1),
159
+ timedOut,
160
+ });
161
+ });
162
+
163
+ child.on("error", (err) => {
164
+ clearTimeout(timer);
165
+ resolveP({
166
+ stdout,
167
+ stderr: stderr + `\n[spawn error: ${err.message}]`,
168
+ exitCode: -1,
169
+ timedOut,
170
+ });
171
+ });
172
+ });
173
+ }