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,137 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * context-db-migrate — CLI utility for managing the ashlr context database.
4
+ *
5
+ * Usage:
6
+ * bun run scripts/context-db-migrate.ts [command]
7
+ *
8
+ * Commands:
9
+ * migrate Run migrations on ~/.ashlr/context.db (default)
10
+ * version Print current schema version
11
+ * status Print schema version + row counts
12
+ *
13
+ * Environment:
14
+ * ASHLR_CONTEXT_DB_HOME Override home directory (for testing)
15
+ * ASHLR_CONTEXT_DB_DISABLE=1 No-op mode (migration prints a notice and exits)
16
+ */
17
+
18
+ import { Database } from "bun:sqlite";
19
+ import { existsSync, mkdirSync } from "fs";
20
+ import { homedir } from "os";
21
+ import { join } from "path";
22
+ import { openContextDb, getSchemaVersion, SCHEMA_VERSION } from "../servers/_embedding-cache";
23
+
24
+ function getDbPath(home?: string): string {
25
+ const dir = join(home ?? homedir(), ".ashlr");
26
+ return join(dir, "context.db");
27
+ }
28
+
29
+ function printUsage(): void {
30
+ console.log(`
31
+ context-db-migrate — ashlr context database migration CLI
32
+
33
+ Usage:
34
+ bun run scripts/context-db-migrate.ts [command]
35
+
36
+ Commands:
37
+ migrate Apply pending schema migrations (default)
38
+ version Print current schema version stored in db
39
+ status Print schema version + row counts + db path
40
+
41
+ Environment:
42
+ ASHLR_CONTEXT_DB_HOME Override home directory (for testing)
43
+ ASHLR_CONTEXT_DB_DISABLE=1 No-op mode — prints notice and exits
44
+ `.trim());
45
+ }
46
+
47
+ async function cmdMigrate(): Promise<void> {
48
+ if (process.env.ASHLR_CONTEXT_DB_DISABLE === "1") {
49
+ console.log("[context-db-migrate] ASHLR_CONTEXT_DB_DISABLE=1 — skipping migration (no-op mode).");
50
+ process.exit(0);
51
+ }
52
+
53
+ const home = process.env.ASHLR_CONTEXT_DB_HOME;
54
+ const db = openContextDb(home);
55
+
56
+ console.log(`[context-db-migrate] Migration complete. Target schema version: ${SCHEMA_VERSION}`);
57
+ db.close();
58
+ }
59
+
60
+ async function cmdVersion(): Promise<void> {
61
+ if (process.env.ASHLR_CONTEXT_DB_DISABLE === "1") {
62
+ console.log("Schema version: N/A (ASHLR_CONTEXT_DB_DISABLE=1)");
63
+ return;
64
+ }
65
+
66
+ const home = process.env.ASHLR_CONTEXT_DB_HOME;
67
+ const dbPath = getDbPath(home);
68
+
69
+ if (!existsSync(dbPath)) {
70
+ console.log(`Schema version: 0 (db not yet created at ${dbPath})`);
71
+ return;
72
+ }
73
+
74
+ const rawDb = new Database(dbPath, { readonly: true });
75
+ const version = getSchemaVersion(rawDb);
76
+ rawDb.close();
77
+ console.log(`Schema version: ${version} (target: ${SCHEMA_VERSION})`);
78
+ }
79
+
80
+ async function cmdStatus(): Promise<void> {
81
+ if (process.env.ASHLR_CONTEXT_DB_DISABLE === "1") {
82
+ console.log("Status: disabled (ASHLR_CONTEXT_DB_DISABLE=1)");
83
+ return;
84
+ }
85
+
86
+ const home = process.env.ASHLR_CONTEXT_DB_HOME;
87
+ const dbPath = getDbPath(home);
88
+
89
+ if (!existsSync(dbPath)) {
90
+ console.log(`Context db not yet created.\nExpected path: ${dbPath}`);
91
+ return;
92
+ }
93
+
94
+ const db = openContextDb(home);
95
+ const s = db.stats();
96
+ db.close();
97
+
98
+ const rawDb = new Database(dbPath, { readonly: true });
99
+ const version = getSchemaVersion(rawDb);
100
+ rawDb.close();
101
+
102
+ const sizeMb = (s.dbBytes / (1024 * 1024)).toFixed(2);
103
+ console.log(`Context DB Status
104
+ Path: ${dbPath}
105
+ Schema version: ${version} (target: ${SCHEMA_VERSION})
106
+ Total embeddings: ${s.totalEmbeddings}
107
+ Projects tracked: ${s.projects}
108
+ DB size: ${sizeMb} MB
109
+ Hit rate (last 1000): ${(s.hitRateLast1000 * 100).toFixed(1)}%`);
110
+ }
111
+
112
+ // ---------------------------------------------------------------------------
113
+ // Entry point
114
+ // ---------------------------------------------------------------------------
115
+
116
+ const cmd = process.argv[2] ?? "migrate";
117
+
118
+ switch (cmd) {
119
+ case "migrate":
120
+ await cmdMigrate();
121
+ break;
122
+ case "version":
123
+ await cmdVersion();
124
+ break;
125
+ case "status":
126
+ await cmdStatus();
127
+ break;
128
+ case "--help":
129
+ case "-h":
130
+ case "help":
131
+ printUsage();
132
+ break;
133
+ default:
134
+ console.error(`Unknown command: ${cmd}`);
135
+ printUsage();
136
+ process.exit(1);
137
+ }
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * context-status.ts — Pretty-print embedding cache stats.
4
+ *
5
+ * Called by the /ashlr-context-status slash command.
6
+ *
7
+ * Output format:
8
+ *
9
+ * ashlr context-db
10
+ * embeddings: 42
11
+ * projects: 3
12
+ * db size: 0.12 MB
13
+ * hit rate: 73.0% (last 1000 retrievals)
14
+ * embedder: bm25 (dim=256) | remote: http://localhost:11434/api/embeddings
15
+ *
16
+ * Respects ASHLR_CONTEXT_DB_DISABLE=1.
17
+ */
18
+
19
+ import { openContextDb } from "../servers/_embedding-cache";
20
+ import { EMBED_DIM } from "../servers/_embedding-model";
21
+
22
+ if (process.env.ASHLR_CONTEXT_DB_DISABLE === "1") {
23
+ console.log("ashlr context-db: disabled (ASHLR_CONTEXT_DB_DISABLE=1)");
24
+ process.exit(0);
25
+ }
26
+
27
+ const db = openContextDb();
28
+ const s = db.stats();
29
+ db.close();
30
+
31
+ const mbSize = (s.dbBytes / (1024 * 1024)).toFixed(2);
32
+ const hitPct = (s.hitRateLast1000 * 100).toFixed(1);
33
+
34
+ const embedderLine = process.env.ASHLR_EMBED_URL
35
+ ? `bm25 (dim=${EMBED_DIM}) + remote: ${process.env.ASHLR_EMBED_URL}`
36
+ : `bm25 (dim=${EMBED_DIM})`;
37
+
38
+ console.log(`ashlr context-db`);
39
+ console.log(` embeddings: ${s.totalEmbeddings}`);
40
+ console.log(` projects: ${s.projects}`);
41
+ console.log(` db size: ${mbSize} MB`);
42
+ console.log(` hit rate: ${hitPct}% (last 1000 retrievals)`);
43
+ console.log(` embedder: ${embedderLine}`);
@@ -0,0 +1,255 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * demo-run.ts — 30-second scripted showcase of ashlr token savings.
4
+ *
5
+ * Usage:
6
+ * bun run scripts/demo-run.ts [--cwd <dir>]
7
+ *
8
+ * Behavior:
9
+ * 1. Finds a largish source file (>2KB) in the target directory.
10
+ * 2. Reads it via snipCompact (same path as ashlr__read) — reports bytes.
11
+ * 3. Greps for a common pattern — reports bytes.
12
+ * 4. Shows totals + projected lifetime savings from ~/.ashlr/stats.json.
13
+ *
14
+ * Contract:
15
+ * - Exits 0 always.
16
+ * - Never writes files.
17
+ * - Output <= 30 lines, plain text, width <= 80.
18
+ * - Safe to run repeatedly.
19
+ */
20
+
21
+ import { existsSync, readdirSync, readFileSync, statSync } from "fs";
22
+ import { homedir } from "os";
23
+ import { join, extname, relative } from "path";
24
+ import { spawnSync } from "child_process";
25
+
26
+ import { snipCompact, type Message } from "@ashlr/core-efficiency";
27
+
28
+ // ---------------------------------------------------------------------------
29
+ // Helpers
30
+ // ---------------------------------------------------------------------------
31
+
32
+ function print(s: string): void {
33
+ process.stdout.write(s + "\n");
34
+ }
35
+
36
+ function fmtBytes(n: number): string {
37
+ if (n < 1024) return `${n} B`;
38
+ if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
39
+ return `${(n / (1024 * 1024)).toFixed(1)} MB`;
40
+ }
41
+
42
+ function pct(saved: number, original: number): string {
43
+ if (original <= 0) return "0%";
44
+ return `${Math.round((saved / original) * 100)}%`;
45
+ }
46
+
47
+ /** Walk directory up to maxDepth, collect files matching predicate. */
48
+ function walkFiles(
49
+ dir: string,
50
+ pred: (p: string) => boolean,
51
+ maxDepth = 3,
52
+ ): string[] {
53
+ const results: string[] = [];
54
+ function walk(d: string, depth: number): void {
55
+ if (depth > maxDepth) return;
56
+ let entries: string[];
57
+ try {
58
+ entries = readdirSync(d);
59
+ } catch {
60
+ return;
61
+ }
62
+ for (const name of entries) {
63
+ if (name.startsWith(".") || name === "node_modules") continue;
64
+ const full = join(d, name);
65
+ let st;
66
+ try {
67
+ st = statSync(full);
68
+ } catch {
69
+ continue;
70
+ }
71
+ if (st.isDirectory()) {
72
+ walk(full, depth + 1);
73
+ } else if (pred(full)) {
74
+ results.push(full);
75
+ }
76
+ }
77
+ }
78
+ walk(dir, 0);
79
+ return results;
80
+ }
81
+
82
+ const SOURCE_EXTS = new Set([
83
+ ".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs", ".java",
84
+ ".rb", ".c", ".cpp", ".h", ".cs", ".swift", ".kt",
85
+ ]);
86
+
87
+ /** Find the largest source file > 2KB, up to 500KB. */
88
+ function findDemoFile(cwd: string): string | null {
89
+ const candidates = walkFiles(cwd, (p) => SOURCE_EXTS.has(extname(p)));
90
+ const sized = candidates
91
+ .map((p) => ({ p, size: statSync(p).size }))
92
+ .filter(({ size }) => size > 2048 && size < 500 * 1024)
93
+ .sort((a, b) => b.size - a.size);
94
+ return sized[0]?.p ?? null;
95
+ }
96
+
97
+ /** Apply snipCompact exactly as ashlr__read does (without summarization). */
98
+ function compactRead(content: string): string {
99
+ const msgs: Message[] = [
100
+ {
101
+ role: "user",
102
+ content: [{ type: "tool_result", tool_use_id: "demo-read", content }],
103
+ },
104
+ ];
105
+ const compact = snipCompact(msgs);
106
+ const block = (compact[0]!.content as { type: string; content: string }[])[0]!;
107
+ return (block as { content: string }).content;
108
+ }
109
+
110
+ /** Run ripgrep and return raw output bytes + truncated text. */
111
+ function runGrep(pattern: string, cwd: string): { rawBytes: number; outBytes: number } {
112
+ // Resolve rg binary (mirrors efficiency-server logic).
113
+ const rgBin =
114
+ (typeof (globalThis as { Bun?: { which(b: string): string | null } }).Bun !== "undefined"
115
+ ? (globalThis as { Bun: { which(b: string): string | null } }).Bun.which("rg")
116
+ : null) ??
117
+ ["/opt/homebrew/bin/rg", "/usr/local/bin/rg", "/usr/bin/rg"].find((p) => {
118
+ try { require("fs").accessSync(p); return true; } catch { return false; }
119
+ }) ??
120
+ "rg";
121
+
122
+ const res = spawnSync(rgBin, ["--json", "-n", "--", pattern, cwd], {
123
+ encoding: "utf-8",
124
+ timeout: 8_000,
125
+ });
126
+ const raw = res.stdout ?? "";
127
+ const truncated =
128
+ raw.length > 4000 ? raw.slice(0, 2000) + "\n\n[...truncated...]\n\n" + raw.slice(-1000) : raw;
129
+ return { rawBytes: raw.length, outBytes: truncated.length };
130
+ }
131
+
132
+ /** Read lifetime stats for projection. */
133
+ function readLifetimeStats(): { calls: number; tokensSaved: number } {
134
+ // Prefer $HOME when explicitly set so tests (and container/shell overrides)
135
+ // work uniformly on Windows, where `homedir()` reads USERPROFILE instead.
136
+ const home = process.env.HOME ?? homedir();
137
+ const p = join(home, ".ashlr", "stats.json");
138
+ if (!existsSync(p)) return { calls: 0, tokensSaved: 0 };
139
+ try {
140
+ const data = JSON.parse(readFileSync(p, "utf-8")) as {
141
+ lifetime?: { calls?: number; tokensSaved?: number };
142
+ };
143
+ return {
144
+ calls: data.lifetime?.calls ?? 0,
145
+ tokensSaved: data.lifetime?.tokensSaved ?? 0,
146
+ };
147
+ } catch {
148
+ return { calls: 0, tokensSaved: 0 };
149
+ }
150
+ }
151
+
152
+ // ---------------------------------------------------------------------------
153
+ // Main
154
+ // ---------------------------------------------------------------------------
155
+
156
+ function main(): void {
157
+ // Parse --cwd arg
158
+ const args = process.argv.slice(2);
159
+ let cwd = process.cwd();
160
+ const cwdIdx = args.indexOf("--cwd");
161
+ if (cwdIdx !== -1 && args[cwdIdx + 1]) {
162
+ cwd = args[cwdIdx + 1]!;
163
+ }
164
+
165
+ const lines: string[] = [];
166
+
167
+ lines.push("ashlr 30-second demo");
168
+ lines.push("=".repeat(40));
169
+ lines.push(`project: ${cwd}`);
170
+ lines.push("");
171
+
172
+ // Step 1: find a source file
173
+ const demoFile = findDemoFile(cwd);
174
+ if (!demoFile) {
175
+ lines.push("no suitable source file found (need >2KB source file)");
176
+ lines.push("tip: run from a project directory with source code.");
177
+ lines.forEach(print);
178
+ process.exit(0);
179
+ }
180
+
181
+ const relPath = relative(cwd, demoFile);
182
+ const rawContent = readFileSync(demoFile, "utf-8");
183
+ const rawBytes = Buffer.byteLength(rawContent, "utf-8");
184
+
185
+ // Step 2: ashlr__read (snipCompact)
186
+ const compacted = compactRead(rawContent);
187
+ const compactBytes = Buffer.byteLength(compacted, "utf-8");
188
+ const readSaved = Math.max(0, rawBytes - compactBytes);
189
+ const readTokSaved = Math.ceil(readSaved / 4);
190
+
191
+ lines.push(`[1] ashlr__read ${relPath}`);
192
+ lines.push(` original : ${fmtBytes(rawBytes)}`);
193
+ lines.push(` compacted: ${fmtBytes(compactBytes)} (${pct(readSaved, rawBytes)} smaller)`);
194
+ lines.push(` tokens saved: ~${readTokSaved.toLocaleString()}`);
195
+ lines.push("");
196
+
197
+ // Step 3: ashlr__grep
198
+ const pattern = "import|function";
199
+ const { rawBytes: grepRaw, outBytes: grepOut } = runGrep(pattern, cwd);
200
+ const grepSaved = Math.max(0, grepRaw - grepOut);
201
+ const grepTokSaved = Math.ceil(grepSaved / 4);
202
+
203
+ lines.push(`[2] ashlr__grep pattern: "${pattern}"`);
204
+ if (grepRaw === 0) {
205
+ lines.push(` ripgrep not available — skipping grep demo`);
206
+ } else {
207
+ lines.push(` raw rg output : ${fmtBytes(grepRaw)}`);
208
+ lines.push(` truncated to : ${fmtBytes(grepOut)} (${pct(grepSaved, grepRaw)} smaller)`);
209
+ lines.push(` tokens saved: ~${grepTokSaved.toLocaleString()}`);
210
+ }
211
+ lines.push("");
212
+
213
+ // Step 4: totals + projection
214
+ const demoTokSaved = readTokSaved + grepTokSaved;
215
+ const lifetime = readLifetimeStats();
216
+ const lifetimeTokSaved = lifetime.tokensSaved + demoTokSaved;
217
+
218
+ // Rough projection: extrapolate from lifetime average calls-per-day
219
+ // Assume ~5 working days/week, 50 weeks/year = 250 days.
220
+ const COST_PER_M_TOK = 3.0; // sonnet-4.5 input
221
+ const lifetimeCost = (lifetimeTokSaved * COST_PER_M_TOK) / 1_000_000;
222
+
223
+ lines.push(`[3] totals`);
224
+ lines.push(` this demo saved: ~${demoTokSaved.toLocaleString()} tokens`);
225
+ lines.push(
226
+ ` lifetime total : ~${lifetimeTokSaved.toLocaleString()} tokens` +
227
+ ` (≈ $${lifetimeCost.toFixed(2)})`,
228
+ );
229
+
230
+ if (lifetime.calls >= 10) {
231
+ // Enough data to project: average tok/call, assume 50 calls/day typical session.
232
+ const avgTokPerCall = lifetime.tokensSaved / lifetime.calls;
233
+ const projectedAnnualTok = avgTokPerCall * 50 * 250;
234
+ const projectedAnnualCost = (projectedAnnualTok * COST_PER_M_TOK) / 1_000_000;
235
+ lines.push(
236
+ ` projected annual: ~${Math.round(projectedAnnualTok / 1000)}K tokens` +
237
+ ` ≈ $${projectedAnnualCost.toFixed(0)}/yr`,
238
+ );
239
+ }
240
+
241
+ lines.push("");
242
+ lines.push("install: https://plugin.ashlr.ai");
243
+
244
+ // Trim to 30 lines
245
+ const out = lines.slice(0, 30);
246
+ out.forEach(print);
247
+ }
248
+
249
+ try {
250
+ main();
251
+ } catch (err) {
252
+ const msg = err instanceof Error ? err.message : String(err);
253
+ process.stdout.write(`demo-run error: ${msg}\n`);
254
+ }
255
+ process.exit(0);
@@ -0,0 +1,140 @@
1
+ #!/usr/bin/env bash
2
+ # deploy-smoke.sh — post-deploy smoke test for ashlr production endpoints.
3
+ #
4
+ # Usage:
5
+ # ASHLR_TOKEN=<api_token> ./scripts/deploy-smoke.sh
6
+ #
7
+ # Required env:
8
+ # ASHLR_TOKEN — a valid provisioned API token (from `bun run issue-token`)
9
+ #
10
+ # Optional env:
11
+ # SITE_URL — override site base (default: https://plugin.ashlr.ai)
12
+ # API_URL — override API base (default: https://api.ashlr.ai)
13
+ #
14
+ # Exit codes:
15
+ # 0 — all checks passed
16
+ # 1 — one or more checks failed
17
+
18
+ set -euo pipefail
19
+
20
+ SITE_URL="${SITE_URL:-https://plugin.ashlr.ai}"
21
+ API_URL="${API_URL:-https://api.ashlr.ai}"
22
+ TOKEN="${ASHLR_TOKEN:-}"
23
+
24
+ RED='\033[0;31m'
25
+ GRN='\033[0;32m'
26
+ YLW='\033[0;33m'
27
+ RST='\033[0m'
28
+
29
+ PASS=0
30
+ FAIL=0
31
+
32
+ pass() { echo -e "${GRN}PASS${RST} $1"; PASS=$((PASS + 1)); }
33
+ fail() { echo -e "${RED}FAIL${RST} $1"; FAIL=$((FAIL + 1)); }
34
+ info() { echo -e "${YLW}----${RST} $1"; }
35
+
36
+ # ---------------------------------------------------------------------------
37
+ # 1. Site health
38
+ # ---------------------------------------------------------------------------
39
+ info "Checking site health: ${SITE_URL}"
40
+
41
+ STATUS=$(curl -sf -o /dev/null -w "%{http_code}" "${SITE_URL}" || echo "000")
42
+ if [ "$STATUS" = "200" ]; then
43
+ pass "GET ${SITE_URL} → 200"
44
+ else
45
+ fail "GET ${SITE_URL} → ${STATUS} (expected 200)"
46
+ fi
47
+
48
+ # robots.txt
49
+ STATUS=$(curl -sf -o /dev/null -w "%{http_code}" "${SITE_URL}/robots.txt" || echo "000")
50
+ if [ "$STATUS" = "200" ]; then
51
+ pass "GET ${SITE_URL}/robots.txt → 200"
52
+ else
53
+ fail "GET ${SITE_URL}/robots.txt → ${STATUS}"
54
+ fi
55
+
56
+ # sitemap.xml
57
+ STATUS=$(curl -sf -o /dev/null -w "%{http_code}" "${SITE_URL}/sitemap.xml" || echo "000")
58
+ if [ "$STATUS" = "200" ]; then
59
+ pass "GET ${SITE_URL}/sitemap.xml → 200"
60
+ else
61
+ fail "GET ${SITE_URL}/sitemap.xml → ${STATUS}"
62
+ fi
63
+
64
+ # ---------------------------------------------------------------------------
65
+ # 2. API health
66
+ # ---------------------------------------------------------------------------
67
+ info "Checking API health: ${API_URL}"
68
+
69
+ HEALTH=$(curl -sf "${API_URL}/" || echo "{}")
70
+ OK=$(echo "$HEALTH" | grep -o '"ok":true' || echo "")
71
+ if [ -n "$OK" ]; then
72
+ pass "GET ${API_URL}/ → {ok: true}"
73
+ else
74
+ fail "GET ${API_URL}/ → unexpected body: ${HEALTH}"
75
+ fi
76
+
77
+ # ---------------------------------------------------------------------------
78
+ # 3. Badge endpoint (no auth — public)
79
+ # ---------------------------------------------------------------------------
80
+ info "Checking badge endpoint"
81
+
82
+ if [ -z "$TOKEN" ]; then
83
+ info "ASHLR_TOKEN not set — skipping authenticated badge + stats checks"
84
+ else
85
+ # Upload a minimal stats payload to create a user record
86
+ SYNC_STATUS=$(curl -sf -o /dev/null -w "%{http_code}" \
87
+ -X POST "${API_URL}/stats/sync" \
88
+ -H "Authorization: Bearer ${TOKEN}" \
89
+ -H "Content-Type: application/json" \
90
+ -d '{"stats":{"lifetime":{"calls":42,"tokensSaved":99000,"byTool":{},"byDay":{}}}}' \
91
+ || echo "000")
92
+
93
+ if [ "$SYNC_STATUS" = "200" ]; then
94
+ pass "POST ${API_URL}/stats/sync → 200"
95
+ else
96
+ fail "POST ${API_URL}/stats/sync → ${SYNC_STATUS} (expected 200)"
97
+ fi
98
+
99
+ # Derive userId from token (first 8 chars as a smoke proxy — real impl uses DB lookup)
100
+ # Instead, hit the aggregate endpoint to get the userId
101
+ AGG=$(curl -sf \
102
+ -H "Authorization: Bearer ${TOKEN}" \
103
+ "${API_URL}/stats/aggregate" || echo "{}")
104
+ USER_ID=$(echo "$AGG" | grep -o '"user_id":"[^"]*"' | cut -d'"' -f4 || echo "")
105
+
106
+ if [ -n "$USER_ID" ]; then
107
+ pass "GET ${API_URL}/stats/aggregate → user_id present"
108
+
109
+ # Badge SVG
110
+ BADGE=$(curl -sf "${API_URL}/u/${USER_ID}/badge.svg" || echo "")
111
+ if echo "$BADGE" | grep -q "<svg"; then
112
+ pass "GET ${API_URL}/u/${USER_ID}/badge.svg → SVG content"
113
+ else
114
+ fail "GET ${API_URL}/u/${USER_ID}/badge.svg → missing <svg element"
115
+ fi
116
+
117
+ # Check badge has token metric text
118
+ if echo "$BADGE" | grep -qi "saved\|tokens\|calls"; then
119
+ pass "Badge SVG contains expected metric text"
120
+ else
121
+ fail "Badge SVG missing metric text"
122
+ fi
123
+ else
124
+ fail "GET ${API_URL}/stats/aggregate → user_id missing in response: ${AGG}"
125
+ fi
126
+ fi
127
+
128
+ # ---------------------------------------------------------------------------
129
+ # Summary
130
+ # ---------------------------------------------------------------------------
131
+ echo ""
132
+ echo -e "Results: ${GRN}${PASS} passed${RST} ${RED}${FAIL} failed${RST}"
133
+
134
+ if [ "$FAIL" -gt 0 ]; then
135
+ echo -e "${RED}Smoke test FAILED${RST}"
136
+ exit 1
137
+ else
138
+ echo -e "${GRN}Smoke test PASSED${RST}"
139
+ exit 0
140
+ fi