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,58 @@
1
+ /**
2
+ * sql-server-handlers — registers ashlr__sql on the shared registry.
3
+ */
4
+
5
+ import { registerTool, type ToolCallContext, type ToolResult } from "./_tool-base";
6
+ import { ashlrSql, type SqlArgs } from "./sql-server";
7
+
8
+ registerTool({
9
+ name: "ashlr__sql",
10
+ description:
11
+ "Run SQL against SQLite or Postgres and get a compact, token-dense text " +
12
+ "result. Replaces the typical 3-4 Bash calls (psql / sqlite3 + parse " +
13
+ "stdout) with one tool call. Supports SELECT, DDL, DML, EXPLAIN, and a " +
14
+ "schema-introspection mode.",
15
+ inputSchema: {
16
+ type: "object",
17
+ properties: {
18
+ query: {
19
+ type: "string",
20
+ description: "SQL to run (SELECT, EXPLAIN, DDL, DML — all allowed). Required unless schema:true.",
21
+ },
22
+ connection: {
23
+ type: "string",
24
+ description:
25
+ "Connection URL (postgres://…) or SQLite path. If omitted, reads $DATABASE_URL, then looks for *.db / *.sqlite files in cwd.",
26
+ },
27
+ explain: {
28
+ type: "boolean",
29
+ description: "Wrap in EXPLAIN ANALYZE (postgres) / EXPLAIN QUERY PLAN (sqlite). Default false.",
30
+ },
31
+ limit: {
32
+ type: "number",
33
+ description: "Max rows to return in the compact output (default 20). Total row count is always reported.",
34
+ },
35
+ schema: {
36
+ type: "boolean",
37
+ description: "Skip the query and instead list tables, columns, and row counts. Cheaper than many \\d / SHOW TABLES round-trips.",
38
+ },
39
+ bypassSummary: {
40
+ type: "boolean",
41
+ description: "Skip LLM summarization of long output",
42
+ },
43
+ },
44
+ },
45
+ handler: async (args: Record<string, unknown>, _ctx: ToolCallContext): Promise<ToolResult> => {
46
+ try {
47
+ const text = await ashlrSql((args ?? {}) as SqlArgs);
48
+ return { content: [{ type: "text", text }] };
49
+ } catch (err) {
50
+ const message = err instanceof Error ? err.message : String(err);
51
+ const firstLine = message.split("\n")[0]!.slice(0, 400);
52
+ return {
53
+ content: [{ type: "text", text: `ashlr__sql error: ${firstLine}` }],
54
+ isError: true,
55
+ };
56
+ }
57
+ },
58
+ });
@@ -0,0 +1,505 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * ashlr-sql MCP server.
4
+ *
5
+ * Exposes a single tool, `ashlr__sql`, that runs SQL against SQLite or
6
+ * Postgres and returns a compact, token-dense text result. Designed to
7
+ * collapse the typical "shell out to psql / sqlite3 + reparse stdout" loop
8
+ * into one tool call.
9
+ *
10
+ * Drivers:
11
+ * - SQLite: bun:sqlite (built-in)
12
+ * - Postgres: porsager/postgres
13
+ * - MySQL/mssql: explicitly unsupported in v0.2 — clear error.
14
+ */
15
+
16
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
17
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
18
+ import {
19
+ CallToolRequestSchema,
20
+ ListToolsRequestSchema,
21
+ } from "@modelcontextprotocol/sdk/types.js";
22
+ import { Database } from "bun:sqlite";
23
+ import { existsSync, readdirSync, statSync } from "fs";
24
+ import { isAbsolute, join, resolve } from "path";
25
+ import { summarizeIfLarge, PROMPTS, confidenceBadge, confidenceTier } from "./_summarize";
26
+ import { recordSaving as recordSavingCore } from "./_stats";
27
+ import { logEvent } from "./_events";
28
+
29
+ async function recordSaving(rawChars: number, compactChars: number): Promise<void> {
30
+ await recordSavingCore(rawChars, compactChars, "ashlr__sql");
31
+ }
32
+
33
+ // ---------------------------------------------------------------------------
34
+ // Connection auto-detection
35
+ // ---------------------------------------------------------------------------
36
+
37
+ type Kind = "sqlite" | "postgres" | "mysql" | "mssql" | "unknown";
38
+
39
+ interface Conn {
40
+ kind: Kind;
41
+ /** Original spec (URL or path) — never logged verbatim if it has a password. */
42
+ raw: string;
43
+ /** Header-safe label with the password redacted. */
44
+ display: string;
45
+ }
46
+
47
+ function classify(spec: string): Conn {
48
+ const s = spec.trim();
49
+ if (/^postgres(ql)?:\/\//i.test(s)) return { kind: "postgres", raw: s, display: redactUrl(s) };
50
+ if (/^mysql:\/\//i.test(s)) return { kind: "mysql", raw: s, display: redactUrl(s) };
51
+ if (/^(mssql|sqlserver):\/\//i.test(s)) return { kind: "mssql", raw: s, display: redactUrl(s) };
52
+ if (/^sqlite:\/\//i.test(s)) {
53
+ const path = s.replace(/^sqlite:\/\//i, "");
54
+ return { kind: "sqlite", raw: path, display: `sqlite://${path}` };
55
+ }
56
+ // Treat as a filesystem path (relative or absolute, ":memory:" too).
57
+ return { kind: "sqlite", raw: s, display: `sqlite://${s}` };
58
+ }
59
+
60
+ function redactUrl(url: string): string {
61
+ // Replace the password component (between `:` and `@` after the scheme) with `***`.
62
+ return url.replace(/^([a-z]+:\/\/[^:/@]+):[^@/]*@/i, "$1:***@");
63
+ }
64
+
65
+ function autoDetectConnection(cwd: string): Conn | null {
66
+ const env = process.env.DATABASE_URL;
67
+ if (env && env.length > 0) return classify(env);
68
+
69
+ // Look for *.db / *.sqlite / *.sqlite3 in cwd (non-recursive — explicit > magic).
70
+ try {
71
+ const entries = readdirSync(cwd).filter((f) => /\.(db|sqlite3?|s3db)$/i.test(f));
72
+ if (entries.length > 0) {
73
+ // If there's exactly one, take it. If multiple, prefer one named like the
74
+ // dir; otherwise pick the most-recently-modified — deterministic on a
75
+ // given filesystem and matches what a human would do.
76
+ let pick = entries[0]!;
77
+ if (entries.length > 1) {
78
+ const sorted = entries
79
+ .map((f) => ({ f, m: statSync(join(cwd, f)).mtimeMs }))
80
+ .sort((a, b) => b.m - a.m);
81
+ pick = sorted[0]!.f;
82
+ }
83
+ return classify(join(cwd, pick));
84
+ }
85
+ } catch {
86
+ // unreadable cwd — fall through
87
+ }
88
+ return null;
89
+ }
90
+
91
+ // ---------------------------------------------------------------------------
92
+ // Compact output formatter
93
+ // ---------------------------------------------------------------------------
94
+
95
+ interface QueryResult {
96
+ cols: string[];
97
+ rows: unknown[][];
98
+ totalRows: number;
99
+ }
100
+
101
+ function fmtCell(v: unknown): string {
102
+ if (v === null || v === undefined) return "NULL";
103
+ if (v instanceof Date) return v.toISOString();
104
+ if (typeof v === "string") return v;
105
+ if (typeof v === "object") {
106
+ try {
107
+ return JSON.stringify(v);
108
+ } catch {
109
+ return String(v);
110
+ }
111
+ }
112
+ return String(v);
113
+ }
114
+
115
+ function renderTable(cols: string[], rows: unknown[][]): string {
116
+ if (cols.length === 0) return "";
117
+ const widths = cols.map((c, i) => {
118
+ let w = c.length;
119
+ for (const r of rows) {
120
+ const cell = fmtCell(r[i]);
121
+ if (cell.length > w) w = cell.length;
122
+ }
123
+ return Math.min(w, 60); // cap column width for readability
124
+ });
125
+ const pad = (s: string, w: number) => (s.length > w ? s.slice(0, w - 1) + "…" : s.padEnd(w));
126
+ const header = " " + cols.map((c, i) => pad(c, widths[i]!)).join(" | ");
127
+ const sep = " " + widths.map((w) => "─".repeat(w)).join("─┼─");
128
+ const body = rows
129
+ .map((r) => " " + cols.map((_, i) => pad(fmtCell(r[i]), widths[i]!)).join(" | "))
130
+ .join("\n");
131
+ return [header, sep, body].join("\n");
132
+ }
133
+
134
+ function csvBaselineBytes(cols: string[], rows: unknown[][]): number {
135
+ // Realistic CSV baseline: header + each row joined by commas + newlines.
136
+ let bytes = cols.join(",").length + 1;
137
+ for (const r of rows) {
138
+ let line = 0;
139
+ for (let i = 0; i < cols.length; i++) {
140
+ const cell = fmtCell(r[i]);
141
+ // Quote if contains comma/quote/newline (csv standard adds 2 chars + escapes).
142
+ if (/[,"\n]/.test(cell)) line += cell.length + 2 + (cell.match(/"/g)?.length ?? 0);
143
+ else line += cell.length;
144
+ if (i < cols.length - 1) line += 1;
145
+ }
146
+ bytes += line + 1;
147
+ }
148
+ return bytes;
149
+ }
150
+
151
+ function formatResult(
152
+ conn: Conn,
153
+ result: QueryResult,
154
+ elapsedSec: number,
155
+ limit: number,
156
+ ): { text: string; baselineBytes: number } {
157
+ const { cols, rows, totalRows } = result;
158
+ const shown = rows.slice(0, limit);
159
+ const elided = totalRows - shown.length;
160
+
161
+ const header = `${conn.display} · ${elapsedSec.toFixed(3)}s · ${totalRows} row${totalRows === 1 ? "" : "s"} × ${cols.length} col${cols.length === 1 ? "" : "s"}`;
162
+ const body = cols.length === 0 ? " (no columns)" : renderTable(cols, shown);
163
+ const footer =
164
+ elided > 0
165
+ ? ` [${totalRows} rows total · ${elided} elided; set limit:N to see more]`
166
+ : totalRows === 0
167
+ ? " (no rows)"
168
+ : "";
169
+
170
+ const text = [header, "", body, footer].filter(Boolean).join("\n");
171
+ // Baseline = full result set as CSV (the "naive dump" the agent would otherwise pull).
172
+ const baselineBytes = csvBaselineBytes(cols, rows);
173
+ return { text, baselineBytes };
174
+ }
175
+
176
+ // ---------------------------------------------------------------------------
177
+ // SQLite driver
178
+ // ---------------------------------------------------------------------------
179
+
180
+ function runSqlite(spec: string, query: string, opts: { explain?: boolean; schema?: boolean }): {
181
+ result: QueryResult;
182
+ elapsedSec: number;
183
+ } {
184
+ // Normalize relative paths; ":memory:" passes through unchanged.
185
+ const path = spec === ":memory:" || isAbsolute(spec) ? spec : resolve(spec);
186
+ // create:true so DDL on a fresh path works; readwrite is the default behavior we want.
187
+ const db = new Database(path, { create: true, readwrite: true });
188
+ try {
189
+ if (opts.schema) {
190
+ const tables = db
191
+ .prepare(
192
+ "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%' ORDER BY name",
193
+ )
194
+ .all() as { name: string }[];
195
+ const cols = ["table", "columns", "rows"];
196
+ const rows: unknown[][] = [];
197
+ for (const t of tables) {
198
+ const info = db.prepare(`PRAGMA table_info("${t.name.replace(/"/g, '""')}")`).all() as {
199
+ name: string;
200
+ type: string;
201
+ }[];
202
+ const colDesc = info.map((c) => `${c.name}:${c.type || "ANY"}`).join(", ");
203
+ const count = (
204
+ db.prepare(`SELECT COUNT(*) AS c FROM "${t.name.replace(/"/g, '""')}"`).get() as {
205
+ c: number;
206
+ }
207
+ ).c;
208
+ rows.push([t.name, colDesc, count]);
209
+ }
210
+ return { result: { cols, rows, totalRows: rows.length }, elapsedSec: 0 };
211
+ }
212
+
213
+ const sql = opts.explain ? `EXPLAIN QUERY PLAN ${query}` : query;
214
+ const t0 = performance.now();
215
+
216
+ // Classify by leading keyword: row-returning vs side-effect. EXPLAIN QUERY
217
+ // PLAN always returns rows. Multiple statements (separated by `;`) are
218
+ // routed through .run() via db.run() so all are executed.
219
+ const head = query.replace(/^\s*(\/\*[\s\S]*?\*\/|--[^\n]*\n)*\s*/, "").slice(0, 16).toUpperCase();
220
+ const returnsRows =
221
+ opts.explain ||
222
+ head.startsWith("SELECT") ||
223
+ head.startsWith("WITH") ||
224
+ head.startsWith("VALUES") ||
225
+ head.startsWith("PRAGMA") ||
226
+ head.startsWith("EXPLAIN");
227
+
228
+ let cols: string[] = [];
229
+ let rows: unknown[][] = [];
230
+
231
+ if (returnsRows) {
232
+ const stmt = db.prepare(sql);
233
+ const out = stmt.all() as Record<string, unknown>[];
234
+ if (out.length > 0) {
235
+ cols = Object.keys(out[0]!);
236
+ rows = out.map((r) => cols.map((c) => r[c]));
237
+ } else {
238
+ const cnames = (stmt as unknown as { columnNames?: string[] }).columnNames;
239
+ if (cnames) cols = cnames;
240
+ }
241
+ } else {
242
+ // db.run handles multi-statement scripts; .changes reflects the last stmt.
243
+ const info = db.run(sql);
244
+ cols = ["changes", "lastInsertRowid"];
245
+ rows = [[info.changes, Number(info.lastInsertRowid)]];
246
+ }
247
+ const elapsedSec = (performance.now() - t0) / 1000;
248
+ return { result: { cols, rows, totalRows: rows.length }, elapsedSec };
249
+ } finally {
250
+ db.close();
251
+ }
252
+ }
253
+
254
+ // ---------------------------------------------------------------------------
255
+ // Postgres driver
256
+ // ---------------------------------------------------------------------------
257
+
258
+ async function runPostgres(
259
+ spec: string,
260
+ query: string,
261
+ opts: { explain?: boolean; schema?: boolean },
262
+ ): Promise<{ result: QueryResult; elapsedSec: number }> {
263
+ // Lazy-import so the module load doesn't fail if the dep is missing in some
264
+ // installs; the explicit message is friendlier than a cryptic resolve error.
265
+ let postgres: (url: string, opts?: Record<string, unknown>) => any;
266
+ try {
267
+ const mod = await import("postgres");
268
+ postgres = (mod as unknown as { default: typeof postgres }).default ?? (mod as unknown as typeof postgres);
269
+ } catch {
270
+ throw new Error(
271
+ "Postgres driver not installed. Run `bun add postgres` in the plugin directory.",
272
+ );
273
+ }
274
+
275
+ const sql = postgres(spec, {
276
+ connect_timeout: 10,
277
+ idle_timeout: 5,
278
+ max: 1,
279
+ prepare: false, // safer for ad-hoc queries
280
+ onnotice: () => {},
281
+ });
282
+
283
+ try {
284
+ if (opts.schema) {
285
+ const tables = (await sql.unsafe(
286
+ `SELECT table_schema, table_name
287
+ FROM information_schema.tables
288
+ WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
289
+ AND table_type = 'BASE TABLE'
290
+ ORDER BY table_schema, table_name`,
291
+ )) as { table_schema: string; table_name: string }[];
292
+ const cols = ["table", "columns", "rows"];
293
+ const rows: unknown[][] = [];
294
+ for (const t of tables) {
295
+ const info = (await sql.unsafe(
296
+ `SELECT column_name, data_type
297
+ FROM information_schema.columns
298
+ WHERE table_schema = $1 AND table_name = $2
299
+ ORDER BY ordinal_position`,
300
+ [t.table_schema, t.table_name],
301
+ )) as { column_name: string; data_type: string }[];
302
+ const colDesc = info.map((c) => `${c.column_name}:${c.data_type}`).join(", ");
303
+ let count: number | string = "?";
304
+ try {
305
+ const r = (await sql.unsafe(
306
+ `SELECT COUNT(*)::bigint AS c FROM "${t.table_schema}"."${t.table_name}"`,
307
+ )) as { c: string }[];
308
+ count = Number(r[0]!.c);
309
+ } catch {
310
+ /* permission denied or similar — leave as "?" */
311
+ }
312
+ const label = t.table_schema === "public" ? t.table_name : `${t.table_schema}.${t.table_name}`;
313
+ rows.push([label, colDesc, count]);
314
+ }
315
+ return { result: { cols, rows, totalRows: rows.length }, elapsedSec: 0 };
316
+ }
317
+
318
+ const text = opts.explain ? `EXPLAIN ANALYZE ${query}` : query;
319
+ const t0 = performance.now();
320
+ // 60s query timeout via a Promise.race — postgres.js doesn't natively expose
321
+ // a per-query timeout that aborts cleanly without statement_timeout, which
322
+ // requires a session round-trip. Race + end() is the pragmatic move.
323
+ const queryPromise = sql.unsafe(text);
324
+ const result = (await Promise.race([
325
+ queryPromise,
326
+ new Promise((_, reject) =>
327
+ setTimeout(() => reject(new Error("Query timeout (60s)")), 60_000),
328
+ ),
329
+ ])) as Record<string, unknown>[];
330
+ const elapsedSec = (performance.now() - t0) / 1000;
331
+
332
+ let cols: string[] = [];
333
+ let rows: unknown[][] = [];
334
+ if (Array.isArray(result) && result.length > 0) {
335
+ cols = Object.keys(result[0]!);
336
+ rows = result.map((r) => cols.map((c) => r[c]));
337
+ } else if (Array.isArray(result)) {
338
+ // Try to grab column descriptors from the result object (postgres.js attaches them).
339
+ const desc = (result as unknown as { columns?: { name: string }[] }).columns;
340
+ if (desc) cols = desc.map((c) => c.name);
341
+ }
342
+ return { result: { cols, rows, totalRows: rows.length }, elapsedSec };
343
+ } finally {
344
+ await sql.end({ timeout: 1 });
345
+ }
346
+ }
347
+
348
+ // ---------------------------------------------------------------------------
349
+ // Tool entry point
350
+ // ---------------------------------------------------------------------------
351
+
352
+ export interface SqlArgs {
353
+ query?: string;
354
+ connection?: string;
355
+ explain?: boolean;
356
+ limit?: number;
357
+ schema?: boolean;
358
+ bypassSummary?: boolean;
359
+ }
360
+
361
+ export async function ashlrSql(input: SqlArgs): Promise<string> {
362
+ const limit = typeof input.limit === "number" && input.limit > 0 ? Math.floor(input.limit) : 20;
363
+ const explain = input.explain === true;
364
+ const schema = input.schema === true;
365
+ const query = (input.query ?? "").trim();
366
+
367
+ if (!schema && query.length === 0) {
368
+ throw new Error("ashlr__sql: 'query' is required (or set schema:true to introspect).");
369
+ }
370
+
371
+ // Resolve connection.
372
+ const conn = input.connection
373
+ ? classify(input.connection)
374
+ : autoDetectConnection(process.cwd());
375
+ if (!conn) {
376
+ throw new Error(
377
+ "No connection found. Pass `connection` (postgres://… or path/to/file.db), or set $DATABASE_URL, or run from a directory containing a *.db / *.sqlite file.",
378
+ );
379
+ }
380
+
381
+ if (conn.kind === "mysql" || conn.kind === "mssql") {
382
+ throw new Error(
383
+ `${conn.kind} is not supported in ashlr v0.2. Track support at https://github.com/ashlrai/ashlr-plugin/issues`,
384
+ );
385
+ }
386
+ if (conn.kind === "unknown") {
387
+ throw new Error(`Unrecognized connection: ${conn.display}`);
388
+ }
389
+
390
+ let runOut: { result: QueryResult; elapsedSec: number };
391
+ if (conn.kind === "sqlite") {
392
+ runOut = runSqlite(conn.raw, query, { explain, schema });
393
+ } else {
394
+ runOut = await runPostgres(conn.raw, query, { explain, schema });
395
+ }
396
+
397
+ // EXPLAIN: emit the plan as a single text block per row, no table chrome.
398
+ if (explain) {
399
+ const lines = runOut.result.rows.map((r) => r.map(fmtCell).join(" ")).join("\n");
400
+ const header = `${conn.display} · ${runOut.elapsedSec.toFixed(3)}s · EXPLAIN`;
401
+ const text = `${header}\n\n${lines || "(empty plan)"}`;
402
+ await recordSaving(csvBaselineBytes(runOut.result.cols, runOut.result.rows), text.length);
403
+ return text;
404
+ }
405
+
406
+ const { text, baselineBytes } = formatResult(conn, runOut.result, runOut.elapsedSec, limit);
407
+
408
+ // LLM summarization — only for large result sets that exceed 16KB rendered.
409
+ // EXPLAIN and schema modes are already structured and bail out before here.
410
+ let finalText = text;
411
+ if (
412
+ runOut.result.rows.length > 100 &&
413
+ Buffer.byteLength(finalText, "utf-8") > 16_384 &&
414
+ !input.bypassSummary
415
+ ) {
416
+ const s = await summarizeIfLarge(finalText, {
417
+ toolName: "ashlr__sql",
418
+ systemPrompt: PROMPTS.sql,
419
+ bypass: false,
420
+ });
421
+ finalText = s.text;
422
+ }
423
+
424
+ await recordSaving(baselineBytes, finalText.length);
425
+
426
+ const sqlBadgeOpts = {
427
+ toolName: "ashlr__sql",
428
+ rawBytes: baselineBytes,
429
+ outputBytes: finalText.length,
430
+ };
431
+ if (confidenceTier(sqlBadgeOpts) === "low") {
432
+ await logEvent("tool_low_confidence_shipped", { tool: "ashlr__sql", reason: "low-confidence" });
433
+ }
434
+ return finalText + confidenceBadge(sqlBadgeOpts);
435
+ }
436
+
437
+ // ---------------------------------------------------------------------------
438
+ // MCP server wiring
439
+ // ---------------------------------------------------------------------------
440
+
441
+ const server = new Server(
442
+ { name: "ashlr-sql", version: "0.2.0" },
443
+ { capabilities: { tools: {} } },
444
+ );
445
+
446
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
447
+ tools: [
448
+ {
449
+ name: "ashlr__sql",
450
+ description:
451
+ "Run SQL against SQLite or Postgres and get a compact, token-dense text result. Replaces the typical 3-4 Bash calls (psql / sqlite3 + parse stdout) with one tool call. Supports SELECT, DDL, DML, EXPLAIN, and a schema-introspection mode.",
452
+ inputSchema: {
453
+ type: "object",
454
+ properties: {
455
+ query: {
456
+ type: "string",
457
+ description: "SQL to run (SELECT, EXPLAIN, DDL, DML — all allowed). Required unless schema:true.",
458
+ },
459
+ connection: {
460
+ type: "string",
461
+ description:
462
+ "Connection URL (postgres://…) or SQLite path. If omitted, reads $DATABASE_URL, then looks for *.db / *.sqlite files in cwd.",
463
+ },
464
+ explain: {
465
+ type: "boolean",
466
+ description: "Wrap in EXPLAIN ANALYZE (postgres) / EXPLAIN QUERY PLAN (sqlite). Default false.",
467
+ },
468
+ limit: {
469
+ type: "number",
470
+ description: "Max rows to return in the compact output (default 20). Total row count is always reported.",
471
+ },
472
+ schema: {
473
+ type: "boolean",
474
+ description: "Skip the query and instead list tables, columns, and row counts. Cheaper than many \\d / SHOW TABLES round-trips.",
475
+ },
476
+ bypassSummary: {
477
+ type: "boolean",
478
+ description: "Skip LLM summarization of long output",
479
+ },
480
+ },
481
+ },
482
+ },
483
+ ],
484
+ }));
485
+
486
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
487
+ const { name, arguments: args } = req.params;
488
+ try {
489
+ if (name === "ashlr__sql") {
490
+ const text = await ashlrSql((args ?? {}) as SqlArgs);
491
+ return { content: [{ type: "text", text }] };
492
+ }
493
+ return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
494
+ } catch (err) {
495
+ // Short, clean error — never the driver's full stack.
496
+ const message = err instanceof Error ? err.message : String(err);
497
+ const firstLine = message.split("\n")[0]!.slice(0, 400);
498
+ return { content: [{ type: "text", text: `ashlr__sql error: ${firstLine}` }], isError: true };
499
+ }
500
+ });
501
+
502
+ if (import.meta.main) {
503
+ const transport = new StdioServerTransport();
504
+ await server.connect(transport);
505
+ }