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,447 @@
1
+ /**
2
+ * _manifest-v2.ts — Genome 2.0 manifest schema (additive, backward-compatible).
3
+ *
4
+ * v1 (core-efficiency) → v2 (this module) is purely ADDITIVE:
5
+ * - All v1 fields remain canonical and unchanged.
6
+ * - Section meta gains three optional freshness fields:
7
+ * lastUpdatedAt — ISO timestamp of last refresh (mirrors updatedAt for v1)
8
+ * sourceTrust — "static" | "commit" | "pr" | "issue" | "test"
9
+ * confidence — 0..1 float (heuristic, optional)
10
+ * - A new section type is introduced for commit-diff awareness:
11
+ * commit sections live at `commits/<sha>.json` (not markdown) and carry
12
+ * structured CommitSection metadata in addition to the SectionMeta entry.
13
+ * - schemaVersion is bumped to 2. v1 manifests auto-upgrade IN-MEMORY on load
14
+ * and persist v2 on the next write. v1 readers will still parse v2 because
15
+ * the only new top-level field is the optional `schemaVersion`; v1 keys
16
+ * (`version`, `project`, `sections`, etc.) remain untouched.
17
+ *
18
+ * This module deliberately does NOT modify `node_modules/@ashlr/core-efficiency`.
19
+ * It wraps the loader so existing call sites keep working with `loadManifest`
20
+ * from core-efficiency and only opt-in to v2 by going through
21
+ * `loadManifestV2` / `saveManifestV2` here.
22
+ */
23
+
24
+ import { existsSync } from "fs";
25
+ import { mkdir, readFile, rename, writeFile } from "fs/promises";
26
+ import { dirname, join } from "path";
27
+ import {
28
+ type GenomeManifest as GenomeManifestV1,
29
+ type SectionMeta as SectionMetaV1,
30
+ manifestPath,
31
+ } from "@ashlr/core-efficiency/genome";
32
+
33
+ // ---------------------------------------------------------------------------
34
+ // Types
35
+ // ---------------------------------------------------------------------------
36
+
37
+ export type SourceTrust = "static" | "commit" | "pr" | "issue" | "test" | "synthesis";
38
+
39
+ /** v2 SectionMeta — adds freshness metadata. All new fields are optional. */
40
+ export interface SectionMetaV2 extends SectionMetaV1 {
41
+ /** ISO timestamp of the most recent refresh. Mirrors updatedAt by default. */
42
+ lastUpdatedAt?: string;
43
+ /** Where this section's content was derived from. Defaults to "static". */
44
+ sourceTrust?: SourceTrust;
45
+ /** Heuristic 0..1 — higher = more trustworthy. Defaults unset. */
46
+ confidence?: number;
47
+ /**
48
+ * Marker so retrieval can distinguish section kinds.
49
+ *
50
+ * Q3 added "pr" + "issue" — cloud-sync'd genome deltas from GitHub
51
+ * webhooks. Older v2 manifests written before Q3 don't carry these and
52
+ * default to "static" via upgradeManifest().
53
+ */
54
+ kind?: "commit" | "static" | "discovery" | "pr" | "issue";
55
+ }
56
+
57
+ /**
58
+ * Commit section payload — stored at `.ashlrcode/genome/commits/<sha>.json`.
59
+ * The manifest also gets a SectionMetaV2 entry pointing at this file with
60
+ * `kind: "commit"` and `sourceTrust: "commit"`.
61
+ */
62
+ export interface CommitSection {
63
+ /** Full git SHA. */
64
+ sha: string;
65
+ /** Commit subject + body (raw, untruncated). */
66
+ message: string;
67
+ /** Author "Name <email>" line from `git show --pretty=fuller`. */
68
+ author: string;
69
+ /** ISO timestamp of the commit (author date). */
70
+ date: string;
71
+ /** Files changed in this commit (relative paths from repo root). */
72
+ filesChanged: string[];
73
+ /** Markdown body — typically a short summary + diff highlights. */
74
+ summary: string;
75
+ }
76
+
77
+ export interface GenomeManifestV2 extends Omit<GenomeManifestV1, "version"> {
78
+ /** v1 manifests have `version: 1`. v2 manifests carry both for compat. */
79
+ version: 1;
80
+ /** v2 schema marker. Absent on v1 manifests on disk. */
81
+ schemaVersion?: 2;
82
+ sections: SectionMetaV2[];
83
+ }
84
+
85
+ // ---------------------------------------------------------------------------
86
+ // Constants
87
+ // ---------------------------------------------------------------------------
88
+
89
+ /** Subdirectory under .ashlrcode/genome/ where commit sections live. */
90
+ export const COMMITS_SUBDIR = "commits";
91
+
92
+ /** Hard cap on commit sections kept on disk. Older ones are pruned. */
93
+ export const COMMIT_RETENTION_LIMIT = 50;
94
+
95
+ // ---------------------------------------------------------------------------
96
+ // Migration
97
+ // ---------------------------------------------------------------------------
98
+
99
+ /**
100
+ * Upgrade a v1 manifest to v2 in-memory.
101
+ * Idempotent — running on an already-v2 manifest is a no-op.
102
+ *
103
+ * Sets defaults for each section:
104
+ * - lastUpdatedAt ← updatedAt
105
+ * - sourceTrust ← "static"
106
+ * - kind ← "static"
107
+ *
108
+ * The original `updatedAt` field is preserved so v1 readers stay happy.
109
+ */
110
+ export function upgradeManifest(manifest: GenomeManifestV1 | GenomeManifestV2): GenomeManifestV2 {
111
+ const m = manifest as GenomeManifestV2;
112
+ if (m.schemaVersion === 2) {
113
+ // Already v2 — still backfill any missing per-section defaults so old v2
114
+ // manifests written before this defaulting existed pick up the fields.
115
+ for (const s of m.sections) {
116
+ if (!s.lastUpdatedAt) s.lastUpdatedAt = s.updatedAt;
117
+ if (!s.sourceTrust) s.sourceTrust = s.kind === "commit" ? "commit" : "static";
118
+ if (!s.kind) s.kind = "static";
119
+ }
120
+ return m;
121
+ }
122
+
123
+ // True v1 → v2 upgrade.
124
+ const upgraded: GenomeManifestV2 = {
125
+ ...(manifest as GenomeManifestV1),
126
+ schemaVersion: 2,
127
+ sections: (manifest.sections as SectionMetaV1[]).map((s) => ({
128
+ ...s,
129
+ lastUpdatedAt: (s as SectionMetaV2).lastUpdatedAt ?? s.updatedAt,
130
+ sourceTrust: (s as SectionMetaV2).sourceTrust ?? "static",
131
+ kind: (s as SectionMetaV2).kind ?? "static",
132
+ })),
133
+ };
134
+ return upgraded;
135
+ }
136
+
137
+ // ---------------------------------------------------------------------------
138
+ // Load / Save (v2-aware)
139
+ // ---------------------------------------------------------------------------
140
+
141
+ export async function loadManifestV2(cwd: string): Promise<GenomeManifestV2 | null> {
142
+ const p = manifestPath(cwd);
143
+ if (!existsSync(p)) return null;
144
+ try {
145
+ const raw = await readFile(p, "utf-8");
146
+ const parsed = JSON.parse(raw) as GenomeManifestV1 | GenomeManifestV2;
147
+ return upgradeManifest(parsed);
148
+ } catch {
149
+ // Corrupt / partial — treat as missing, same policy as v1 loader.
150
+ return null;
151
+ }
152
+ }
153
+
154
+ export async function saveManifestV2(cwd: string, manifest: GenomeManifestV2): Promise<void> {
155
+ const target = manifestPath(cwd);
156
+ const dir = dirname(target);
157
+ if (!existsSync(dir)) {
158
+ await mkdir(dir, { recursive: true });
159
+ }
160
+ manifest.updatedAt = new Date().toISOString();
161
+ if (!manifest.schemaVersion) manifest.schemaVersion = 2;
162
+ const tmp = target + ".tmp";
163
+ try {
164
+ await writeFile(tmp, JSON.stringify(manifest, null, 2), "utf-8");
165
+ await rename(tmp, target);
166
+ } catch (e) {
167
+ const { unlink } = await import("fs/promises");
168
+ await unlink(tmp).catch(() => {});
169
+ throw e;
170
+ }
171
+ }
172
+
173
+ // ---------------------------------------------------------------------------
174
+ // Commit-section file helpers
175
+ // ---------------------------------------------------------------------------
176
+
177
+ export function commitsDir(cwd: string): string {
178
+ return join(cwd, ".ashlrcode", "genome", COMMITS_SUBDIR);
179
+ }
180
+
181
+ export function commitSectionPath(cwd: string, sha: string): string {
182
+ // Relative path INSIDE the genome dir (matches SectionMetaV2.path convention).
183
+ return join(COMMITS_SUBDIR, `${sha}.json`);
184
+ }
185
+
186
+ export function commitSectionAbsPath(cwd: string, sha: string): string {
187
+ return join(commitsDir(cwd), `${sha}.json`);
188
+ }
189
+
190
+ /**
191
+ * Write a commit section JSON file (separate from the manifest update).
192
+ * Returns the relative path stored in the manifest's `sections[].path`.
193
+ */
194
+ export async function writeCommitSectionFile(
195
+ cwd: string,
196
+ payload: CommitSection,
197
+ ): Promise<string> {
198
+ const abs = commitSectionAbsPath(cwd, payload.sha);
199
+ const dir = dirname(abs);
200
+ if (!existsSync(dir)) {
201
+ await mkdir(dir, { recursive: true });
202
+ }
203
+ await writeFile(abs, JSON.stringify(payload, null, 2), "utf-8");
204
+ return commitSectionPath(cwd, payload.sha);
205
+ }
206
+
207
+ export async function readCommitSectionFile(
208
+ cwd: string,
209
+ sha: string,
210
+ ): Promise<CommitSection | null> {
211
+ const abs = commitSectionAbsPath(cwd, sha);
212
+ if (!existsSync(abs)) return null;
213
+ try {
214
+ const raw = await readFile(abs, "utf-8");
215
+ return JSON.parse(raw) as CommitSection;
216
+ } catch {
217
+ return null;
218
+ }
219
+ }
220
+
221
+ // ---------------------------------------------------------------------------
222
+ // Discovery sections (Q2 AI-Native Synthesis)
223
+ // ---------------------------------------------------------------------------
224
+
225
+ /** Subdirectory under .ashlrcode/genome/ where discovery sections live. */
226
+ export const DISCOVERIES_SUBDIR = "discoveries";
227
+
228
+ /** Hard cap on discovery sections kept on disk. Older ones are pruned. */
229
+ export const DISCOVERY_RETENTION_LIMIT = 30;
230
+
231
+ /** Evidence anchor for a discovery — points back at concrete code or files. */
232
+ export interface DiscoveryEvidence {
233
+ path: string;
234
+ lineRange?: [number, number];
235
+ }
236
+
237
+ /**
238
+ * Discovery section payload — stored at
239
+ * `.ashlrcode/genome/discoveries/<id>.json`. The manifest also gets a
240
+ * SectionMetaV2 entry pointing at this file with `kind: "discovery"` and
241
+ * `sourceTrust: "synthesis"`.
242
+ *
243
+ * Discoveries are AI-synthesized insights ("3 files use this util wrong",
244
+ * "auth refactor introduced a flaky test pattern"). Lower-confidence than
245
+ * commit sections (which are straight from git) but still actionable.
246
+ */
247
+ export interface DiscoverySection {
248
+ /** Stable ID — hash of summary + sourceCommits, used as filename. */
249
+ id: string;
250
+ /** 1-2 sentence insight written by the synthesizer. */
251
+ summary: string;
252
+ /** Anchors to concrete code — paths + optional line ranges. */
253
+ evidence: DiscoveryEvidence[];
254
+ /** SHAs of commit sections that inspired this discovery. */
255
+ sourceCommits: string[];
256
+ /** ISO timestamp of when the synthesizer produced this. */
257
+ synthesizedAt: string;
258
+ /** 0..1 confidence set by the synthesizer (LLM-self-reported, clamped). */
259
+ confidence: number;
260
+ }
261
+
262
+ export function discoveriesDir(cwd: string): string {
263
+ return join(cwd, ".ashlrcode", "genome", DISCOVERIES_SUBDIR);
264
+ }
265
+
266
+ export function discoverySectionPath(_cwd: string, id: string): string {
267
+ return join(DISCOVERIES_SUBDIR, `${id}.json`);
268
+ }
269
+
270
+ export function discoverySectionAbsPath(cwd: string, id: string): string {
271
+ return join(discoveriesDir(cwd), `${id}.json`);
272
+ }
273
+
274
+ /**
275
+ * Write a discovery section JSON file (separate from the manifest update).
276
+ * Returns the relative path stored in the manifest's `sections[].path`.
277
+ */
278
+ export async function writeDiscoverySectionFile(
279
+ cwd: string,
280
+ payload: DiscoverySection,
281
+ ): Promise<string> {
282
+ const abs = discoverySectionAbsPath(cwd, payload.id);
283
+ const dir = dirname(abs);
284
+ if (!existsSync(dir)) {
285
+ await mkdir(dir, { recursive: true });
286
+ }
287
+ await writeFile(abs, JSON.stringify(payload, null, 2), "utf-8");
288
+ return discoverySectionPath(cwd, payload.id);
289
+ }
290
+
291
+ export async function readDiscoverySectionFile(
292
+ cwd: string,
293
+ id: string,
294
+ ): Promise<DiscoverySection | null> {
295
+ const abs = discoverySectionAbsPath(cwd, id);
296
+ if (!existsSync(abs)) return null;
297
+ try {
298
+ const raw = await readFile(abs, "utf-8");
299
+ return JSON.parse(raw) as DiscoverySection;
300
+ } catch {
301
+ return null;
302
+ }
303
+ }
304
+
305
+ // ---------------------------------------------------------------------------
306
+ // PR sections (Q3 PR/Issue Retrieval)
307
+ // ---------------------------------------------------------------------------
308
+
309
+ /** Subdirectory under .ashlrcode/genome/sections/ where PR sections live. */
310
+ export const PRS_SUBDIR = "prs";
311
+
312
+ /** Hard cap on PR sections kept on disk. Older ones are pruned by mtime. */
313
+ export const PR_RETENTION_LIMIT = 100;
314
+
315
+ /**
316
+ * PR section payload — stored at `.ashlrcode/genome/sections/prs/<number>.json`.
317
+ * Populated from `pr_merged` deltas via genome-cloud-sync. The manifest carries
318
+ * a parallel SectionMetaV2 entry with `kind: "pr"` + `sourceTrust: "pr"`.
319
+ *
320
+ * Privacy: title + summary are already truncated server-side; no diffs.
321
+ */
322
+ export interface PrSection {
323
+ /** PR number as a string id (matches sourceSha in the cloud delta). */
324
+ id: string;
325
+ /** PR title (already truncated to 512 chars by the webhook handler). */
326
+ title: string;
327
+ /** ISO timestamp when the PR merged. May be empty for backfilled rows. */
328
+ mergedAt: string;
329
+ /** GitHub login of the PR author. May be empty. */
330
+ author: string;
331
+ /** Paths only — webhook never ships diff content. May be empty. */
332
+ filesChanged: string[];
333
+ /** 2-3 sentence body summary, already truncated to 1024 chars. */
334
+ summary: string;
335
+ /** Canonical https://github.com/<owner>/<repo>/pull/<n> URL. */
336
+ url: string;
337
+ }
338
+
339
+ export function prsDir(cwd: string): string {
340
+ return join(cwd, ".ashlrcode", "genome", "sections", PRS_SUBDIR);
341
+ }
342
+
343
+ export function prSectionPath(_cwd: string, id: string): string {
344
+ return join("sections", PRS_SUBDIR, `${id}.json`);
345
+ }
346
+
347
+ export function prSectionAbsPath(cwd: string, id: string): string {
348
+ return join(prsDir(cwd), `${id}.json`);
349
+ }
350
+
351
+ export async function writePrSectionFile(
352
+ cwd: string,
353
+ payload: PrSection,
354
+ ): Promise<string> {
355
+ const abs = prSectionAbsPath(cwd, payload.id);
356
+ const dir = dirname(abs);
357
+ if (!existsSync(dir)) {
358
+ await mkdir(dir, { recursive: true });
359
+ }
360
+ await writeFile(abs, JSON.stringify(payload, null, 2), "utf-8");
361
+ return prSectionPath(cwd, payload.id);
362
+ }
363
+
364
+ export async function readPrSectionFile(
365
+ cwd: string,
366
+ id: string,
367
+ ): Promise<PrSection | null> {
368
+ const abs = prSectionAbsPath(cwd, id);
369
+ if (!existsSync(abs)) return null;
370
+ try {
371
+ const raw = await readFile(abs, "utf-8");
372
+ return JSON.parse(raw) as PrSection;
373
+ } catch {
374
+ return null;
375
+ }
376
+ }
377
+
378
+ // ---------------------------------------------------------------------------
379
+ // Issue sections (Q3 PR/Issue Retrieval)
380
+ // ---------------------------------------------------------------------------
381
+
382
+ /** Subdirectory under .ashlrcode/genome/sections/ where Issue sections live. */
383
+ export const ISSUES_SUBDIR = "issues";
384
+
385
+ /** Hard cap on Issue sections kept on disk. Older ones are pruned by mtime. */
386
+ export const ISSUE_RETENTION_LIMIT = 100;
387
+
388
+ /**
389
+ * Issue section payload — stored at
390
+ * `.ashlrcode/genome/sections/issues/<number>.json`. Populated from
391
+ * `issue_closed` deltas via genome-cloud-sync.
392
+ */
393
+ export interface IssueSection {
394
+ /** Issue number as a string id. */
395
+ id: string;
396
+ /** Issue title (already truncated to 512 chars). */
397
+ title: string;
398
+ /** ISO timestamp when the issue was closed. May be empty. */
399
+ closedAt: string;
400
+ /** GitHub login of the issue author. May be empty. */
401
+ author: string;
402
+ /** Issue labels — currently empty (webhook does not yet ship labels). */
403
+ labels: string[];
404
+ /** Issue body summary, truncated to 1024 chars. */
405
+ summary: string;
406
+ /** Canonical https://github.com/<owner>/<repo>/issues/<n> URL. */
407
+ url: string;
408
+ }
409
+
410
+ export function issuesDir(cwd: string): string {
411
+ return join(cwd, ".ashlrcode", "genome", "sections", ISSUES_SUBDIR);
412
+ }
413
+
414
+ export function issueSectionPath(_cwd: string, id: string): string {
415
+ return join("sections", ISSUES_SUBDIR, `${id}.json`);
416
+ }
417
+
418
+ export function issueSectionAbsPath(cwd: string, id: string): string {
419
+ return join(issuesDir(cwd), `${id}.json`);
420
+ }
421
+
422
+ export async function writeIssueSectionFile(
423
+ cwd: string,
424
+ payload: IssueSection,
425
+ ): Promise<string> {
426
+ const abs = issueSectionAbsPath(cwd, payload.id);
427
+ const dir = dirname(abs);
428
+ if (!existsSync(dir)) {
429
+ await mkdir(dir, { recursive: true });
430
+ }
431
+ await writeFile(abs, JSON.stringify(payload, null, 2), "utf-8");
432
+ return issueSectionPath(cwd, payload.id);
433
+ }
434
+
435
+ export async function readIssueSectionFile(
436
+ cwd: string,
437
+ id: string,
438
+ ): Promise<IssueSection | null> {
439
+ const abs = issueSectionAbsPath(cwd, id);
440
+ if (!existsSync(abs)) return null;
441
+ try {
442
+ const raw = await readFile(abs, "utf-8");
443
+ return JSON.parse(raw) as IssueSection;
444
+ } catch {
445
+ return null;
446
+ }
447
+ }
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Multi-host MCP detection.
3
+ *
4
+ * The ashlr MCP server is consumable from any MCP-capable host (Claude Code,
5
+ * Cline, Claude Desktop, OpenAI Codex CLI, …). Most behavior is host-agnostic:
6
+ * - tool dispatch, snipCompact, genome retrieval, stats accounting all work
7
+ * regardless of who's calling.
8
+ * - PPID-derived session id (see `_stats.ts::ppidSessionId`) covers any host
9
+ * that doesn't forward `CLAUDE_SESSION_ID`.
10
+ * - `existsSync` guards on `~/.claude/` paths mean missing-CC-dirs are a
11
+ * no-op rather than a crash.
12
+ *
13
+ * But a few code paths are Claude-Code-specific (hook firing, status-line
14
+ * rendering, OAuth-token harvest from `~/.claude/.credentials.json`). The
15
+ * `ASHLR_MCP_HOST` env var declares which host launched us so those code
16
+ * paths can short-circuit cleanly when running under a non-CC host.
17
+ *
18
+ * Each host's MCP server config sets the env var:
19
+ *
20
+ * Claude Code (default, no change needed) → undefined or "claude-code"
21
+ * Cline (cline_mcp_settings.json) → "cline"
22
+ * Claude Desktop (claude_desktop_config.json) → "claude-desktop"
23
+ * Codex CLI (~/.codex/config.toml) → "codex-cli"
24
+ * Anything else → "generic"
25
+ *
26
+ * Backwards compat: when unset, we infer "claude-code" so existing installs
27
+ * keep their exact current behavior. The audit covered every gate; none of
28
+ * them change behavior when the env var is absent.
29
+ */
30
+
31
+ export type McpHost =
32
+ | "claude-code"
33
+ | "cline"
34
+ | "claude-desktop"
35
+ | "codex-cli"
36
+ | "generic";
37
+
38
+ const KNOWN_HOSTS: ReadonlySet<McpHost> = new Set([
39
+ "claude-code",
40
+ "cline",
41
+ "claude-desktop",
42
+ "codex-cli",
43
+ "generic",
44
+ ]);
45
+
46
+ /**
47
+ * Resolve which MCP host launched this process.
48
+ *
49
+ * Precedence:
50
+ * 1. `ASHLR_MCP_HOST` env var (explicit, set by each host's config snippet).
51
+ * 2. Presence of `CLAUDE_SESSION_ID` or `CLAUDE_PLUGIN_ROOT` → "claude-code"
52
+ * (covers the default Claude Code install path so users who don't set
53
+ * the env var still see the original behavior).
54
+ * 3. Fallback "generic" — safe default; disables CC-only side effects.
55
+ *
56
+ * Never throws; never reads files; never logs. Cheap to call repeatedly.
57
+ */
58
+ export function detectMcpHost(env: NodeJS.ProcessEnv = process.env): McpHost {
59
+ const explicit = env.ASHLR_MCP_HOST?.trim().toLowerCase();
60
+ if (explicit && KNOWN_HOSTS.has(explicit as McpHost)) {
61
+ return explicit as McpHost;
62
+ }
63
+ // Inference: any of these signals → Claude Code (preserves existing
64
+ // behavior for users who haven't set ASHLR_MCP_HOST).
65
+ if (
66
+ (env.CLAUDE_SESSION_ID && env.CLAUDE_SESSION_ID.trim().length > 0) ||
67
+ (env.CLAUDE_PLUGIN_ROOT && env.CLAUDE_PLUGIN_ROOT.trim().length > 0) ||
68
+ (env.CLAUDE_CODE_MODEL && env.CLAUDE_CODE_MODEL.trim().length > 0)
69
+ ) {
70
+ return "claude-code";
71
+ }
72
+ // Generic is the safe non-CC default: hooks/status-line code paths
73
+ // short-circuit; stats + genome + dispatch still work normally.
74
+ return "generic";
75
+ }
76
+
77
+ /** Convenience: are we running inside Claude Code (the default host)? */
78
+ export function isClaudeCodeHost(env: NodeJS.ProcessEnv = process.env): boolean {
79
+ return detectMcpHost(env) === "claude-code";
80
+ }
81
+
82
+ /**
83
+ * Convenience: should we skip Claude-Code-specific side effects?
84
+ * Returns true for every non-CC host. Used by:
85
+ * - status-line install nudges (other hosts have their own UI)
86
+ * - `~/.claude/settings.json` writes (other hosts use their own config)
87
+ * - hook-firing assumptions (only CC fires PreToolUse/SessionEnd hooks)
88
+ */
89
+ export function skipClaudeCodeSideEffects(
90
+ env: NodeJS.ProcessEnv = process.env,
91
+ ): boolean {
92
+ return detectMcpHost(env) !== "claude-code";
93
+ }