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,86 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * migrate-stats-to-sqlite.ts — one-shot move from ~/.ashlr/stats.json to
4
+ * ~/.ashlr/stats.db. Fired from the SessionStart hook once when the db
5
+ * is absent and the legacy JSON is present. Idempotent: no-ops if the
6
+ * db already exists, or if there is no JSON to migrate.
7
+ *
8
+ * Post-migration, the legacy JSON is renamed to stats.json.migrated-<epoch>
9
+ * rather than deleted — keeps a manual-recovery path for users.
10
+ *
11
+ * Never throws. Stats writes must never block the plugin.
12
+ */
13
+
14
+ import { existsSync, renameSync, statSync } from "fs";
15
+ import { dbPath as sqliteDbPath, importStatsFile } from "../servers/_stats-sqlite";
16
+ import { readStats as readJsonStats, statsPath as jsonStatsPath } from "../servers/_stats";
17
+
18
+ export interface MigrationResult {
19
+ migrated: boolean;
20
+ reason?:
21
+ | "db-already-exists"
22
+ | "no-legacy-json"
23
+ | "empty-legacy-json"
24
+ | "migrated-ok"
25
+ | "migration-error";
26
+ sessions?: number;
27
+ lifetimeCalls?: number;
28
+ }
29
+
30
+ export async function migrateStatsIfNeeded(): Promise<MigrationResult> {
31
+ try {
32
+ // 1. DB already present → nothing to do.
33
+ const dbP = sqliteDbPath();
34
+ if (existsSync(dbP) && statSync(dbP).size > 0) {
35
+ return { migrated: false, reason: "db-already-exists" };
36
+ }
37
+
38
+ // 2. No legacy JSON → fresh install, let the sqlite backend auto-seed.
39
+ const jsonP = jsonStatsPath();
40
+ if (!existsSync(jsonP)) {
41
+ return { migrated: false, reason: "no-legacy-json" };
42
+ }
43
+
44
+ // 3. Legacy present: load via the JSON backend so we get the same
45
+ // schema-v1→v2 migration the production path applies.
46
+ const stats = await readJsonStats();
47
+
48
+ // Nothing to move? Still rename the JSON out of the way so we don't
49
+ // re-check on every SessionStart from now on.
50
+ const hasAnything =
51
+ stats.lifetime.calls > 0 ||
52
+ Object.keys(stats.sessions).length > 0 ||
53
+ Object.keys(stats.lifetime.byTool).length > 0;
54
+
55
+ importStatsFile(stats);
56
+
57
+ try {
58
+ renameSync(jsonP, `${jsonP}.migrated-${Date.now()}`);
59
+ } catch {
60
+ // Rename failure is cosmetic — the db is the source of truth now.
61
+ }
62
+
63
+ return {
64
+ migrated: true,
65
+ reason: hasAnything ? "migrated-ok" : "empty-legacy-json",
66
+ sessions: Object.keys(stats.sessions).length,
67
+ lifetimeCalls: stats.lifetime.calls,
68
+ };
69
+ } catch {
70
+ return { migrated: false, reason: "migration-error" };
71
+ }
72
+ }
73
+
74
+ if (import.meta.main) {
75
+ migrateStatsIfNeeded().then((r) => {
76
+ // One compact stderr line — drives the SessionStart hook's diagnostic log.
77
+ if (r.migrated) {
78
+ process.stderr.write(
79
+ `[ashlr] stats migrated to SQLite (${r.sessions} session(s), ${r.lifetimeCalls} lifetime calls)\n`,
80
+ );
81
+ } else if (r.reason !== "db-already-exists" && r.reason !== "no-legacy-json") {
82
+ process.stderr.write(`[ashlr] stats migration: ${r.reason ?? "no-op"}\n`);
83
+ }
84
+ process.exit(0);
85
+ });
86
+ }
@@ -0,0 +1,498 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * ashlr ollama-setup — diagnose + guided install of Ollama for `--summarize`.
4
+ *
5
+ * Flow:
6
+ * 1. Check Ollama is on PATH and that the daemon is reachable.
7
+ * 2. List installed models via /api/tags.
8
+ * 3. If no recommended (fast, summarization-quality) model is present,
9
+ * either auto-install the top pick (when --yes / ASHLR_OLLAMA_AUTO=1)
10
+ * or print the exact pull command for the user.
11
+ * 4. Smoke-test the chosen model with a 1-sentence prompt under 30 s.
12
+ * 5. Warn if the user only has 20B+ parameter models — those time out.
13
+ *
14
+ * Zero external dependencies. ANSI colors inline so this script stays
15
+ * independent from scripts/ui.ts (owned by a sibling feature).
16
+ *
17
+ * Exit codes:
18
+ * 0 everything works (installed + running + fast model ready + smoke-test passed)
19
+ * 1 actionable user-facing problem (not installed / not running / pull needed / smoke-test failed)
20
+ * 2 internal error (unexpected exception)
21
+ */
22
+ /* eslint-disable no-console */
23
+
24
+ import { spawn } from "bun";
25
+
26
+ // ---------------------------------------------------------------------------
27
+ // Colored output (zero deps, respects NO_COLOR / FORCE_COLOR / !isTTY)
28
+ // ---------------------------------------------------------------------------
29
+
30
+ function colorEnabled(): boolean {
31
+ if (process.env.NO_COLOR) return false;
32
+ if (process.env.FORCE_COLOR) return true;
33
+ return typeof process.stdout?.isTTY === "boolean" ? process.stdout.isTTY : false;
34
+ }
35
+
36
+ const ESC = "\u001b[";
37
+ function wrap(open: string, close: string, s: string): string {
38
+ return colorEnabled() ? `${ESC}${open}m${s}${ESC}${close}m` : s;
39
+ }
40
+ const c = {
41
+ red: (s: string): string => wrap("31", "39", s),
42
+ green: (s: string): string => wrap("32", "39", s),
43
+ yellow: (s: string): string => wrap("33", "39", s),
44
+ cyan: (s: string): string => wrap("36", "39", s),
45
+ magenta: (s: string): string => wrap("35", "39", s),
46
+ dim: (s: string): string => wrap("2", "22", s),
47
+ bold: (s: string): string => wrap("1", "22", s),
48
+ };
49
+
50
+ // ✓ / ✗ / ⚠ / ℹ glyphs; ASCII fallback when colors are off (safer in pipes).
51
+ function glyph(kind: "ok" | "fail" | "warn" | "info"): string {
52
+ const unicode = { ok: "✓", fail: "✗", warn: "⚠", info: "ℹ" };
53
+ const ascii = { ok: "[ok]", fail: "[x]", warn: "[!]", info: "[i]" };
54
+ const g = colorEnabled() ? unicode[kind] : ascii[kind];
55
+ if (!colorEnabled()) return g;
56
+ const color = { ok: c.green, fail: c.red, warn: c.yellow, info: c.cyan }[kind];
57
+ return color(g);
58
+ }
59
+
60
+ function printOk(msg: string): void {
61
+ console.log(`${glyph("ok")} ${msg}`);
62
+ }
63
+ function printFail(msg: string): void {
64
+ console.log(`${glyph("fail")} ${msg}`);
65
+ }
66
+ function printWarn(msg: string): void {
67
+ console.log(`${glyph("warn")} ${msg}`);
68
+ }
69
+ function printInfo(msg: string): void {
70
+ console.log(`${glyph("info")} ${msg}`);
71
+ }
72
+ function printFix(cmd: string): void {
73
+ const label = colorEnabled() ? c.yellow("fix:") : "fix:";
74
+ const body = colorEnabled() ? c.dim(cmd) : cmd;
75
+ console.log(` ${label} ${body}`);
76
+ }
77
+
78
+ // ---------------------------------------------------------------------------
79
+ // Types + constants
80
+ // ---------------------------------------------------------------------------
81
+
82
+ export const OLLAMA_BASE_URL = "http://localhost:11434";
83
+ const TAGS_TIMEOUT_MS = 3000;
84
+ const SMOKE_TIMEOUT_MS = 30000;
85
+
86
+ export interface RecommendedModel {
87
+ name: string;
88
+ sizeGB: number;
89
+ note: string;
90
+ }
91
+
92
+ /**
93
+ * Recommended models in preference order — fast AND good enough for
94
+ * 2–3 sentence summarization on CPU / small GPUs.
95
+ */
96
+ export const RECOMMENDED_MODELS: RecommendedModel[] = [
97
+ { name: "llama3.2:3b", sizeGB: 2.0, note: "recommended default — fastest, good quality" },
98
+ { name: "llama3.2:1b", sizeGB: 1.3, note: "tiny, acceptable fallback" },
99
+ { name: "qwen2.5:3b", sizeGB: 2.0, note: "alternative" },
100
+ { name: "phi3.5:3.8b", sizeGB: 2.2, note: "alternative" },
101
+ ];
102
+
103
+ /** Roughly parse Ollama's "llama3.2:3b" style tag into a parameter count in B. */
104
+ export function estimateParamsB(modelName: string): number | null {
105
+ // e.g. "llama3.2:3b", "gemma4:26b", "qwen2.5:3b-instruct", "phi3.5:3.8b"
106
+ const m = modelName.match(/:([0-9]+(?:\.[0-9]+)?)b/i);
107
+ if (!m) return null;
108
+ const n = parseFloat(m[1]);
109
+ return Number.isFinite(n) ? n : null;
110
+ }
111
+
112
+ /** True if the model is ≥20B parameters and so likely too slow for summarization. */
113
+ export function isSlowModel(modelName: string): boolean {
114
+ const p = estimateParamsB(modelName);
115
+ return p !== null && p >= 20;
116
+ }
117
+
118
+ // ---------------------------------------------------------------------------
119
+ // Platform detection
120
+ // ---------------------------------------------------------------------------
121
+
122
+ function installInstructions(): string[] {
123
+ const plat = process.platform;
124
+ if (plat === "darwin") {
125
+ return [
126
+ "macOS — install via Homebrew:",
127
+ " brew install ollama",
128
+ " or download the app from:",
129
+ " https://ollama.com/download",
130
+ ];
131
+ }
132
+ if (plat === "linux") {
133
+ return [
134
+ "Linux — one-line install:",
135
+ " curl -fsSL https://ollama.com/install.sh | sh",
136
+ ];
137
+ }
138
+ return [
139
+ "Download Ollama for your platform:",
140
+ " https://ollama.com/download",
141
+ ];
142
+ }
143
+
144
+ function startInstructions(): string[] {
145
+ const plat = process.platform;
146
+ if (plat === "darwin") {
147
+ return [
148
+ "Start the Ollama daemon:",
149
+ " ollama serve # run in a separate terminal",
150
+ " or, if installed via Homebrew:",
151
+ " brew services start ollama",
152
+ ];
153
+ }
154
+ return [
155
+ "Start the Ollama daemon:",
156
+ " ollama serve # run in a separate terminal",
157
+ " or (systemd):",
158
+ " systemctl --user start ollama",
159
+ ];
160
+ }
161
+
162
+ // ---------------------------------------------------------------------------
163
+ // Ollama probes
164
+ // ---------------------------------------------------------------------------
165
+
166
+ /** True if `ollama` is on PATH. */
167
+ export async function hasOllamaOnPath(): Promise<boolean> {
168
+ try {
169
+ const proc = spawn({
170
+ cmd: ["which", "ollama"],
171
+ stdout: "pipe",
172
+ stderr: "pipe",
173
+ });
174
+ const out = (await new Response(proc.stdout).text()).trim();
175
+ await proc.exited;
176
+ return out.length > 0 && proc.exitCode === 0;
177
+ } catch {
178
+ return false;
179
+ }
180
+ }
181
+
182
+ export interface OllamaModelInfo {
183
+ name: string;
184
+ sizeBytes?: number;
185
+ }
186
+
187
+ export interface TagsResult {
188
+ running: boolean;
189
+ models: OllamaModelInfo[];
190
+ error?: string;
191
+ }
192
+
193
+ /** Fetch /api/tags. Returns `running: false` if the daemon is unreachable. */
194
+ export async function fetchTags(
195
+ baseUrl = OLLAMA_BASE_URL,
196
+ timeoutMs = TAGS_TIMEOUT_MS,
197
+ fetchImpl: typeof fetch = fetch,
198
+ ): Promise<TagsResult> {
199
+ const ctrl = new AbortController();
200
+ const t = setTimeout(() => ctrl.abort(), timeoutMs);
201
+ try {
202
+ const res = await fetchImpl(`${baseUrl}/api/tags`, { signal: ctrl.signal });
203
+ if (!res.ok) return { running: false, models: [], error: `HTTP ${res.status}` };
204
+ const j = (await res.json()) as { models?: Array<{ name: string; size?: number }> };
205
+ const models = (j.models ?? []).map((m) => ({ name: m.name, sizeBytes: m.size }));
206
+ return { running: true, models };
207
+ } catch (err) {
208
+ return { running: false, models: [], error: err instanceof Error ? err.message : String(err) };
209
+ } finally {
210
+ clearTimeout(t);
211
+ }
212
+ }
213
+
214
+ /** Run `ollama pull <model>` and stream stdout/stderr through. */
215
+ async function pullModel(model: string): Promise<boolean> {
216
+ printInfo(`pulling ${c.bold(model)} — this may take a few minutes...`);
217
+ try {
218
+ const proc = spawn({
219
+ cmd: ["ollama", "pull", model],
220
+ stdout: "inherit",
221
+ stderr: "inherit",
222
+ });
223
+ await proc.exited;
224
+ return proc.exitCode === 0;
225
+ } catch (err) {
226
+ printFail(`failed to start ollama pull: ${err instanceof Error ? err.message : String(err)}`);
227
+ return false;
228
+ }
229
+ }
230
+
231
+ export interface SmokeTestResult {
232
+ ok: boolean;
233
+ durationMs: number;
234
+ error?: string;
235
+ sampleResponse?: string;
236
+ }
237
+
238
+ /**
239
+ * Send a 1-sentence prompt to the model and verify it responds in <30s.
240
+ * Uses /api/chat with stream:false for simplicity.
241
+ */
242
+ export async function smokeTest(
243
+ model: string,
244
+ baseUrl = OLLAMA_BASE_URL,
245
+ timeoutMs = SMOKE_TIMEOUT_MS,
246
+ fetchImpl: typeof fetch = fetch,
247
+ ): Promise<SmokeTestResult> {
248
+ const ctrl = new AbortController();
249
+ const t = setTimeout(() => ctrl.abort(), timeoutMs);
250
+ const start = Date.now();
251
+ try {
252
+ const res = await fetchImpl(`${baseUrl}/api/chat`, {
253
+ method: "POST",
254
+ headers: { "Content-Type": "application/json" },
255
+ body: JSON.stringify({
256
+ model,
257
+ messages: [
258
+ {
259
+ role: "user",
260
+ content: "Reply with exactly one short sentence: 'Ollama is working.'",
261
+ },
262
+ ],
263
+ stream: false,
264
+ options: { num_predict: 40, temperature: 0 },
265
+ }),
266
+ signal: ctrl.signal,
267
+ });
268
+ const durationMs = Date.now() - start;
269
+ if (!res.ok) {
270
+ return { ok: false, durationMs, error: `HTTP ${res.status}` };
271
+ }
272
+ const j = (await res.json()) as { message?: { content?: string } };
273
+ const content = j.message?.content?.trim() ?? "";
274
+ if (!content) {
275
+ return { ok: false, durationMs, error: "empty response" };
276
+ }
277
+ return { ok: true, durationMs, sampleResponse: content };
278
+ } catch (err) {
279
+ const durationMs = Date.now() - start;
280
+ const msg = err instanceof Error ? err.message : String(err);
281
+ const error = ctrl.signal.aborted ? `timed out after ${timeoutMs}ms` : msg;
282
+ return { ok: false, durationMs, error };
283
+ } finally {
284
+ clearTimeout(t);
285
+ }
286
+ }
287
+
288
+ // ---------------------------------------------------------------------------
289
+ // Policy helpers
290
+ // ---------------------------------------------------------------------------
291
+
292
+ /** Pick the first recommended model that's available locally, or null. */
293
+ export function pickRecommendedAvailable(
294
+ installed: OllamaModelInfo[],
295
+ recs: RecommendedModel[] = RECOMMENDED_MODELS,
296
+ ): string | null {
297
+ const set = new Set(installed.map((m) => m.name));
298
+ for (const r of recs) {
299
+ if (set.has(r.name)) return r.name;
300
+ }
301
+ return null;
302
+ }
303
+
304
+ /** True if every installed model has ≥20B params. */
305
+ export function hasOnlySlowModels(installed: OllamaModelInfo[]): boolean {
306
+ if (installed.length === 0) return false;
307
+ return installed.every((m) => isSlowModel(m.name));
308
+ }
309
+
310
+ export interface CliArgs {
311
+ yes: boolean;
312
+ help: boolean;
313
+ }
314
+
315
+ export function parseArgs(argv: string[]): CliArgs {
316
+ const out: CliArgs = {
317
+ yes: process.env.ASHLR_OLLAMA_AUTO === "1",
318
+ help: false,
319
+ };
320
+ for (const a of argv) {
321
+ if (a === "--yes" || a === "-y") out.yes = true;
322
+ else if (a === "--help" || a === "-h") out.help = true;
323
+ }
324
+ return out;
325
+ }
326
+
327
+ function printHelp(): void {
328
+ console.log(
329
+ `ashlr ollama-setup — diagnose Ollama for the --summarize flag\n\n` +
330
+ `Usage: bun run scripts/ollama-setup.ts [--yes]\n\n` +
331
+ `Options:\n` +
332
+ ` --yes, -y Auto-pull the recommended model (llama3.2:3b, ~2 GB)\n` +
333
+ ` without prompting. Same effect as ASHLR_OLLAMA_AUTO=1.\n` +
334
+ ` --help, -h Show this message.\n\n` +
335
+ `Exit codes:\n` +
336
+ ` 0 Ollama installed, running, recommended model present, smoke-test passed\n` +
337
+ ` 1 actionable problem (not installed / not running / no model / smoke-test failed)\n` +
338
+ ` 2 internal error`,
339
+ );
340
+ }
341
+
342
+ // ---------------------------------------------------------------------------
343
+ // Main
344
+ // ---------------------------------------------------------------------------
345
+
346
+ export async function run(args: CliArgs): Promise<number> {
347
+ const header = "ashlr ollama-setup";
348
+ console.log(colorEnabled() ? c.bold(c.magenta(header)) : header);
349
+ console.log("");
350
+
351
+ // --- 1. Is ollama on PATH? -----------------------------------------------
352
+ const onPath = await hasOllamaOnPath();
353
+
354
+ // --- 2. Is daemon reachable? ---------------------------------------------
355
+ // Do this regardless of PATH — Ollama.app on macOS binds 127.0.0.1:11434
356
+ // even when the CLI isn't on $PATH, so the daemon probe is the real test.
357
+ const tags = await fetchTags();
358
+
359
+ if (!onPath && !tags.running) {
360
+ printFail("Ollama is not installed (not on PATH and daemon unreachable)");
361
+ console.log("");
362
+ for (const l of installInstructions()) console.log(` ${l}`);
363
+ console.log("");
364
+ printInfo("after installing, re-run: /ashlr-ollama-setup");
365
+ return 1;
366
+ }
367
+
368
+ if (!tags.running) {
369
+ printOk("Ollama CLI found on PATH");
370
+ printFail(
371
+ `Ollama daemon not reachable at ${OLLAMA_BASE_URL}${tags.error ? ` (${tags.error})` : ""}`,
372
+ );
373
+ console.log("");
374
+ for (const l of startInstructions()) console.log(` ${l}`);
375
+ console.log("");
376
+ printInfo("after starting the daemon, re-run: /ashlr-ollama-setup");
377
+ return 1;
378
+ }
379
+
380
+ printOk("Ollama is installed and running");
381
+
382
+ // --- 3. List installed models --------------------------------------------
383
+ const installed = tags.models;
384
+ if (installed.length === 0) {
385
+ printWarn("no models installed");
386
+ } else {
387
+ const names = installed.map((m) => m.name).join(", ");
388
+ printOk(`${installed.length} model${installed.length === 1 ? "" : "s"} installed: ${c.dim(names)}`);
389
+ }
390
+
391
+ // --- 4. Is a recommended model present? ----------------------------------
392
+ const chosen = pickRecommendedAvailable(installed);
393
+
394
+ // If we have nothing recommended, offer/auto-install the top pick.
395
+ let modelForSmokeTest: string | null = chosen;
396
+ if (!chosen) {
397
+ const topPick = RECOMMENDED_MODELS[0];
398
+ printWarn(`no fast recommended model installed (${topPick.name} is the recommended default)`);
399
+ console.log("");
400
+ console.log(` ${c.bold("recommended models")} (pick one):`);
401
+ for (const r of RECOMMENDED_MODELS) {
402
+ const sizeStr = `~${r.sizeGB} GB`;
403
+ console.log(` ${c.cyan(r.name.padEnd(16))} ${c.dim(sizeStr.padEnd(10))} ${c.dim(r.note)}`);
404
+ }
405
+ console.log("");
406
+
407
+ if (args.yes) {
408
+ printInfo(`--yes / ASHLR_OLLAMA_AUTO=1 set — auto-pulling ${topPick.name} (~${topPick.sizeGB} GB)`);
409
+ const ok = await pullModel(topPick.name);
410
+ if (!ok) {
411
+ printFail(`ollama pull ${topPick.name} failed`);
412
+ printFix(`ollama pull ${topPick.name}`);
413
+ return 1;
414
+ }
415
+ printOk(`pulled ${topPick.name}`);
416
+ modelForSmokeTest = topPick.name;
417
+ } else {
418
+ printInfo("to install the recommended model, run:");
419
+ printFix(`ollama pull ${topPick.name}`);
420
+ console.log("");
421
+ printInfo("or re-run with --yes to install automatically:");
422
+ printFix("bun run scripts/ollama-setup.ts --yes");
423
+ // Warn about slow-only models before exiting so the user sees it now.
424
+ if (hasOnlySlowModels(installed)) {
425
+ console.log("");
426
+ printWarn(
427
+ `your installed models are all ≥20B params (${installed.map((m) => m.name).join(", ")}) — ` +
428
+ `expect --summarize to time out. Adding a 3B model strongly recommended.`,
429
+ );
430
+ }
431
+ return 1;
432
+ }
433
+ } else {
434
+ printOk(`recommended model available: ${c.bold(chosen)}`);
435
+ }
436
+
437
+ // --- 5. Warn about slow-only installs ------------------------------------
438
+ // Even when we have a recommended model, if the user also has giant ones it's
439
+ // worth noting — genome-init's auto-picker prefers the recommended, but users
440
+ // doing manual `ollama run <big>` will feel the pain.
441
+ const slowOnly = hasOnlySlowModels(installed) && !chosen;
442
+ if (slowOnly) {
443
+ printWarn(
444
+ `every installed model is ≥20B params — summarization will likely time out. ` +
445
+ `Install a small model: ollama pull ${RECOMMENDED_MODELS[0].name}`,
446
+ );
447
+ }
448
+
449
+ // --- 6. Smoke test -------------------------------------------------------
450
+ if (!modelForSmokeTest) {
451
+ // Shouldn't happen given above branches, but guard.
452
+ printFail("no model available for smoke test");
453
+ return 1;
454
+ }
455
+ printInfo(`smoke-testing ${c.bold(modelForSmokeTest)} (30 s timeout)...`);
456
+ const smoke = await smokeTest(modelForSmokeTest);
457
+ if (!smoke.ok) {
458
+ printFail(`smoke test failed: ${smoke.error ?? "unknown error"} (${smoke.durationMs} ms)`);
459
+ if (isSlowModel(modelForSmokeTest)) {
460
+ printFix(`ollama pull ${RECOMMENDED_MODELS[0].name} # ${modelForSmokeTest} is too large for fast summaries`);
461
+ } else {
462
+ printFix(`ollama run ${modelForSmokeTest} # try interactively to see the error`);
463
+ }
464
+ return 1;
465
+ }
466
+ const secs = (smoke.durationMs / 1000).toFixed(1);
467
+ printOk(`smoke test passed in ${secs}s`);
468
+ if (smoke.sampleResponse) {
469
+ const preview = smoke.sampleResponse.length > 120
470
+ ? smoke.sampleResponse.slice(0, 117) + "..."
471
+ : smoke.sampleResponse;
472
+ console.log(` ${c.dim("→")} ${c.dim(preview)}`);
473
+ }
474
+
475
+ // --- Done ---------------------------------------------------------------
476
+ console.log("");
477
+ const ok = colorEnabled() ? c.bold(c.green("ready")) : "ready";
478
+ console.log(`${ok} — /ashlr-genome-init --summarize will use ${c.bold(modelForSmokeTest)}`);
479
+ return 0;
480
+ }
481
+
482
+ async function main(): Promise<number> {
483
+ const args = parseArgs(process.argv.slice(2));
484
+ if (args.help) {
485
+ printHelp();
486
+ return 0;
487
+ }
488
+ try {
489
+ return await run(args);
490
+ } catch (err) {
491
+ printFail(`internal error: ${err instanceof Error ? err.message : String(err)}`);
492
+ return 2;
493
+ }
494
+ }
495
+
496
+ if (import.meta.main) {
497
+ main().then((code) => process.exit(code));
498
+ }