@nanonets/graft 0.13.0 → 0.16.0

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 (308) hide show
  1. package/README.md +26 -10
  2. package/dist/ai/crux.d.ts +14 -1
  3. package/dist/ai/crux.d.ts.map +1 -1
  4. package/dist/ai/crux.js +39 -51
  5. package/dist/ai/crux.js.map +1 -1
  6. package/dist/ai/failure.d.ts +13 -2
  7. package/dist/ai/failure.d.ts.map +1 -1
  8. package/dist/ai/failure.js +16 -4
  9. package/dist/ai/failure.js.map +1 -1
  10. package/dist/ai/llm/factory.d.ts +10 -1
  11. package/dist/ai/llm/factory.d.ts.map +1 -1
  12. package/dist/ai/llm/factory.js +16 -0
  13. package/dist/ai/llm/factory.js.map +1 -1
  14. package/dist/ai/llm/litellm.d.ts +34 -0
  15. package/dist/ai/llm/litellm.d.ts.map +1 -0
  16. package/dist/ai/llm/litellm.js +45 -0
  17. package/dist/ai/llm/litellm.js.map +1 -0
  18. package/dist/ai/llm/openai.d.ts.map +1 -1
  19. package/dist/ai/llm/openai.js +66 -7
  20. package/dist/ai/llm/openai.js.map +1 -1
  21. package/dist/ai/llm/orcarouter.d.ts +34 -0
  22. package/dist/ai/llm/orcarouter.d.ts.map +1 -0
  23. package/dist/ai/llm/orcarouter.js +45 -0
  24. package/dist/ai/llm/orcarouter.js.map +1 -0
  25. package/dist/ai/llm/recover-tool.d.ts +19 -0
  26. package/dist/ai/llm/recover-tool.d.ts.map +1 -0
  27. package/dist/ai/llm/recover-tool.js +109 -0
  28. package/dist/ai/llm/recover-tool.js.map +1 -0
  29. package/dist/ai/providers.d.ts.map +1 -1
  30. package/dist/ai/providers.js +15 -3
  31. package/dist/ai/providers.js.map +1 -1
  32. package/dist/ai/synthesize.d.ts.map +1 -1
  33. package/dist/ai/synthesize.js +19 -5
  34. package/dist/ai/synthesize.js.map +1 -1
  35. package/dist/app/checkout.d.ts +28 -0
  36. package/dist/app/checkout.d.ts.map +1 -0
  37. package/dist/app/checkout.js +100 -0
  38. package/dist/app/checkout.js.map +1 -0
  39. package/dist/app/events.d.ts +37 -0
  40. package/dist/app/events.d.ts.map +1 -0
  41. package/dist/app/events.js +59 -0
  42. package/dist/app/events.js.map +1 -0
  43. package/dist/app/identity.d.ts +54 -0
  44. package/dist/app/identity.d.ts.map +1 -0
  45. package/dist/app/identity.js +96 -0
  46. package/dist/app/identity.js.map +1 -0
  47. package/dist/app/main.d.ts +2 -0
  48. package/dist/app/main.d.ts.map +1 -0
  49. package/dist/app/main.js +56 -0
  50. package/dist/app/main.js.map +1 -0
  51. package/dist/app/pages.d.ts +39 -0
  52. package/dist/app/pages.d.ts.map +1 -0
  53. package/dist/app/pages.js +86 -0
  54. package/dist/app/pages.js.map +1 -0
  55. package/dist/app/queue.d.ts +40 -0
  56. package/dist/app/queue.d.ts.map +1 -0
  57. package/dist/app/queue.js +68 -0
  58. package/dist/app/queue.js.map +1 -0
  59. package/dist/app/review.d.ts +23 -0
  60. package/dist/app/review.d.ts.map +1 -0
  61. package/dist/app/review.js +139 -0
  62. package/dist/app/review.js.map +1 -0
  63. package/dist/app/server.d.ts +40 -0
  64. package/dist/app/server.d.ts.map +1 -0
  65. package/dist/app/server.js +117 -0
  66. package/dist/app/server.js.map +1 -0
  67. package/dist/ask/ask.d.ts +35 -0
  68. package/dist/ask/ask.d.ts.map +1 -1
  69. package/dist/ask/ask.js +427 -63
  70. package/dist/ask/ask.js.map +1 -1
  71. package/dist/ask/file-rank.d.ts +72 -0
  72. package/dist/ask/file-rank.d.ts.map +1 -0
  73. package/dist/ask/file-rank.js +160 -0
  74. package/dist/ask/file-rank.js.map +1 -0
  75. package/dist/ask/file-selection.d.ts +4 -0
  76. package/dist/ask/file-selection.d.ts.map +1 -1
  77. package/dist/ask/file-selection.js +25 -0
  78. package/dist/ask/file-selection.js.map +1 -1
  79. package/dist/ask/fuse.d.ts +16 -0
  80. package/dist/ask/fuse.d.ts.map +1 -1
  81. package/dist/ask/fuse.js +21 -4
  82. package/dist/ask/fuse.js.map +1 -1
  83. package/dist/ask/graphrank.d.ts +18 -0
  84. package/dist/ask/graphrank.d.ts.map +1 -1
  85. package/dist/ask/graphrank.js +65 -19
  86. package/dist/ask/graphrank.js.map +1 -1
  87. package/dist/blast/blast-cli.d.ts +5 -0
  88. package/dist/blast/blast-cli.d.ts.map +1 -1
  89. package/dist/blast/blast-cli.js +21 -30
  90. package/dist/blast/blast-cli.js.map +1 -1
  91. package/dist/blast/blast.d.ts +9 -0
  92. package/dist/blast/blast.d.ts.map +1 -1
  93. package/dist/blast/blast.js.map +1 -1
  94. package/dist/blast/name.d.ts +13 -0
  95. package/dist/blast/name.d.ts.map +1 -1
  96. package/dist/blast/name.js +36 -0
  97. package/dist/blast/name.js.map +1 -1
  98. package/dist/blast/owners.d.ts +85 -0
  99. package/dist/blast/owners.d.ts.map +1 -0
  100. package/dist/blast/owners.js +272 -0
  101. package/dist/blast/owners.js.map +1 -0
  102. package/dist/blast/render.d.ts.map +1 -1
  103. package/dist/blast/render.js +105 -0
  104. package/dist/blast/render.js.map +1 -1
  105. package/dist/blast/viz.d.ts.map +1 -1
  106. package/dist/blast/viz.js +10 -0
  107. package/dist/blast/viz.js.map +1 -1
  108. package/dist/claude/format.js +1 -1
  109. package/dist/claude/format.js.map +1 -1
  110. package/dist/claude/hooks.d.ts.map +1 -1
  111. package/dist/claude/hooks.js +132 -22
  112. package/dist/claude/hooks.js.map +1 -1
  113. package/dist/claude/init.d.ts +1 -0
  114. package/dist/claude/init.d.ts.map +1 -1
  115. package/dist/claude/init.js +1 -1
  116. package/dist/claude/init.js.map +1 -1
  117. package/dist/claude/session-metrics.d.ts +63 -0
  118. package/dist/claude/session-metrics.d.ts.map +1 -0
  119. package/dist/claude/session-metrics.js +181 -0
  120. package/dist/claude/session-metrics.js.map +1 -0
  121. package/dist/claude/settings-merge.d.ts +18 -1
  122. package/dist/claude/settings-merge.d.ts.map +1 -1
  123. package/dist/claude/settings-merge.js +70 -27
  124. package/dist/claude/settings-merge.js.map +1 -1
  125. package/dist/claude/state.d.ts +25 -0
  126. package/dist/claude/state.d.ts.map +1 -1
  127. package/dist/claude/state.js +14 -1
  128. package/dist/claude/state.js.map +1 -1
  129. package/dist/claude/statusline.d.ts +5 -3
  130. package/dist/claude/statusline.d.ts.map +1 -1
  131. package/dist/claude/statusline.js +6 -4
  132. package/dist/claude/statusline.js.map +1 -1
  133. package/dist/claude/tally.d.ts +23 -0
  134. package/dist/claude/tally.d.ts.map +1 -0
  135. package/dist/claude/tally.js +138 -0
  136. package/dist/claude/tally.js.map +1 -0
  137. package/dist/cli.js +145 -4
  138. package/dist/cli.js.map +1 -1
  139. package/dist/context/build.d.ts +11 -0
  140. package/dist/context/build.d.ts.map +1 -1
  141. package/dist/context/build.js +49 -9
  142. package/dist/context/build.js.map +1 -1
  143. package/dist/context/check.d.ts.map +1 -1
  144. package/dist/context/check.js +5 -12
  145. package/dist/context/check.js.map +1 -1
  146. package/dist/context/node-file.d.ts +2 -1
  147. package/dist/context/node-file.d.ts.map +1 -1
  148. package/dist/context/node-file.js +70 -3
  149. package/dist/context/node-file.js.map +1 -1
  150. package/dist/context/savings.d.ts +8 -0
  151. package/dist/context/savings.d.ts.map +1 -1
  152. package/dist/context/savings.js +14 -0
  153. package/dist/context/savings.js.map +1 -1
  154. package/dist/engine.d.ts +4 -0
  155. package/dist/engine.d.ts.map +1 -1
  156. package/dist/engine.js +2 -0
  157. package/dist/engine.js.map +1 -1
  158. package/dist/graph/bindings.d.ts +6 -5
  159. package/dist/graph/bindings.d.ts.map +1 -1
  160. package/dist/graph/bindings.js +117 -5
  161. package/dist/graph/bindings.js.map +1 -1
  162. package/dist/graph/build.d.ts +4 -0
  163. package/dist/graph/build.d.ts.map +1 -1
  164. package/dist/graph/build.js +7 -4
  165. package/dist/graph/build.js.map +1 -1
  166. package/dist/graph/cards.d.ts +4 -3
  167. package/dist/graph/cards.d.ts.map +1 -1
  168. package/dist/graph/cards.js +34 -6
  169. package/dist/graph/cards.js.map +1 -1
  170. package/dist/graph/check.d.ts.map +1 -1
  171. package/dist/graph/check.js +36 -6
  172. package/dist/graph/check.js.map +1 -1
  173. package/dist/graph/enrich.d.ts +4 -4
  174. package/dist/graph/enrich.d.ts.map +1 -1
  175. package/dist/graph/enrich.js +32 -6
  176. package/dist/graph/enrich.js.map +1 -1
  177. package/dist/graph/extract.d.ts +9 -2
  178. package/dist/graph/extract.d.ts.map +1 -1
  179. package/dist/graph/extract.js +356 -12
  180. package/dist/graph/extract.js.map +1 -1
  181. package/dist/graph/fingerprint.d.ts +6 -1
  182. package/dist/graph/fingerprint.d.ts.map +1 -1
  183. package/dist/graph/fingerprint.js +7 -3
  184. package/dist/graph/fingerprint.js.map +1 -1
  185. package/dist/graph/generic.d.ts +10 -0
  186. package/dist/graph/generic.d.ts.map +1 -1
  187. package/dist/graph/generic.js +20 -3
  188. package/dist/graph/generic.js.map +1 -1
  189. package/dist/graph/invariants.d.ts +3 -2
  190. package/dist/graph/invariants.d.ts.map +1 -1
  191. package/dist/graph/invariants.js +6 -3
  192. package/dist/graph/invariants.js.map +1 -1
  193. package/dist/graph/refresh.d.ts.map +1 -1
  194. package/dist/graph/refresh.js +6 -2
  195. package/dist/graph/refresh.js.map +1 -1
  196. package/dist/graph/resolve.d.ts +1 -1
  197. package/dist/graph/resolve.d.ts.map +1 -1
  198. package/dist/graph/resolve.js +106 -5
  199. package/dist/graph/resolve.js.map +1 -1
  200. package/dist/graph/scopes.d.ts.map +1 -1
  201. package/dist/graph/scopes.js +2 -1
  202. package/dist/graph/scopes.js.map +1 -1
  203. package/dist/graph/source-files.d.ts +7 -2
  204. package/dist/graph/source-files.d.ts.map +1 -1
  205. package/dist/graph/source-files.js +19 -6
  206. package/dist/graph/source-files.js.map +1 -1
  207. package/dist/graph/workspace-cli.d.ts +2 -0
  208. package/dist/graph/workspace-cli.d.ts.map +1 -1
  209. package/dist/graph/workspace-cli.js +3 -0
  210. package/dist/graph/workspace-cli.js.map +1 -1
  211. package/dist/graph/workspace.d.ts +2 -0
  212. package/dist/graph/workspace.d.ts.map +1 -1
  213. package/dist/graph/workspace.js +173 -6
  214. package/dist/graph/workspace.js.map +1 -1
  215. package/dist/hosts/antigravity.d.ts +2 -2
  216. package/dist/hosts/antigravity.d.ts.map +1 -1
  217. package/dist/hosts/codex-hooks.d.ts +2 -6
  218. package/dist/hosts/codex-hooks.d.ts.map +1 -1
  219. package/dist/hosts/codex-hooks.js +7 -30
  220. package/dist/hosts/codex-hooks.js.map +1 -1
  221. package/dist/hosts/config-write.d.ts +36 -0
  222. package/dist/hosts/config-write.d.ts.map +1 -0
  223. package/dist/hosts/config-write.js +63 -0
  224. package/dist/hosts/config-write.js.map +1 -0
  225. package/dist/hosts/cursor-hooks.d.ts +18 -0
  226. package/dist/hosts/cursor-hooks.d.ts.map +1 -0
  227. package/dist/hosts/cursor-hooks.js +100 -0
  228. package/dist/hosts/cursor-hooks.js.map +1 -0
  229. package/dist/hosts/init.d.ts +2 -2
  230. package/dist/hosts/init.d.ts.map +1 -1
  231. package/dist/hosts/init.js +8 -2
  232. package/dist/hosts/init.js.map +1 -1
  233. package/dist/hosts/mcp-config.d.ts +15 -5
  234. package/dist/hosts/mcp-config.d.ts.map +1 -1
  235. package/dist/hosts/mcp-config.js +51 -15
  236. package/dist/hosts/mcp-config.js.map +1 -1
  237. package/dist/hosts/plan.d.ts.map +1 -1
  238. package/dist/hosts/plan.js +2 -0
  239. package/dist/hosts/plan.js.map +1 -1
  240. package/dist/hosts/retract.d.ts +47 -0
  241. package/dist/hosts/retract.d.ts.map +1 -0
  242. package/dist/hosts/retract.js +473 -0
  243. package/dist/hosts/retract.js.map +1 -0
  244. package/dist/index.d.ts +2 -0
  245. package/dist/index.d.ts.map +1 -1
  246. package/dist/index.js +2 -0
  247. package/dist/index.js.map +1 -1
  248. package/dist/ingest/fs.d.ts +39 -5
  249. package/dist/ingest/fs.d.ts.map +1 -1
  250. package/dist/ingest/fs.js +104 -11
  251. package/dist/ingest/fs.js.map +1 -1
  252. package/dist/mcp/tool-names.d.ts +20 -0
  253. package/dist/mcp/tool-names.d.ts.map +1 -0
  254. package/dist/mcp/tool-names.js +36 -0
  255. package/dist/mcp/tool-names.js.map +1 -0
  256. package/dist/mcp/tools.d.ts +11 -2
  257. package/dist/mcp/tools.d.ts.map +1 -1
  258. package/dist/mcp/tools.js +9 -21
  259. package/dist/mcp/tools.js.map +1 -1
  260. package/dist/telemetry/contract.d.ts.map +1 -1
  261. package/dist/telemetry/contract.js +17 -3
  262. package/dist/telemetry/contract.js.map +1 -1
  263. package/dist/telemetry/flush.d.ts.map +1 -1
  264. package/dist/telemetry/flush.js +1 -0
  265. package/dist/telemetry/flush.js.map +1 -1
  266. package/dist/telemetry/identity.d.ts +7 -0
  267. package/dist/telemetry/identity.d.ts.map +1 -1
  268. package/dist/telemetry/identity.js.map +1 -1
  269. package/dist/telemetry/index.d.ts +2 -2
  270. package/dist/telemetry/index.d.ts.map +1 -1
  271. package/dist/telemetry/index.js +2 -2
  272. package/dist/telemetry/index.js.map +1 -1
  273. package/dist/telemetry/sessions.d.ts +19 -2
  274. package/dist/telemetry/sessions.d.ts.map +1 -1
  275. package/dist/telemetry/sessions.js +57 -34
  276. package/dist/telemetry/sessions.js.map +1 -1
  277. package/dist/telemetry/track.d.ts +22 -3
  278. package/dist/telemetry/track.d.ts.map +1 -1
  279. package/dist/telemetry/track.js +34 -5
  280. package/dist/telemetry/track.js.map +1 -1
  281. package/dist/upkeep-run.js +1 -1
  282. package/dist/upkeep-run.js.map +1 -1
  283. package/dist/upkeep.d.ts +7 -4
  284. package/dist/upkeep.d.ts.map +1 -1
  285. package/dist/upkeep.js +2 -1
  286. package/dist/upkeep.js.map +1 -1
  287. package/dist/util/state.d.ts +12 -2
  288. package/dist/util/state.d.ts.map +1 -1
  289. package/dist/util/state.js +4 -0
  290. package/dist/util/state.js.map +1 -1
  291. package/dist/viewer/app.js +2 -1
  292. package/dist/viewer/style.css +14 -0
  293. package/dist/viz/assemble.d.ts +17 -0
  294. package/dist/viz/assemble.d.ts.map +1 -1
  295. package/dist/viz/assemble.js.map +1 -1
  296. package/package.json +12 -4
  297. package/scripts/graph-quality.mjs +3 -3
  298. package/scripts/postinstall.mjs +42 -3
  299. package/scripts/run-tests.mjs +14 -0
  300. package/scripts/tally-audit.mjs +140 -0
  301. package/dist/ai/llm/claude-cli.d.ts +0 -60
  302. package/dist/ai/llm/claude-cli.d.ts.map +0 -1
  303. package/dist/ai/llm/claude-cli.js +0 -417
  304. package/dist/ai/llm/claude-cli.js.map +0 -1
  305. package/dist/util/num.d.ts +0 -3
  306. package/dist/util/num.d.ts.map +0 -1
  307. package/dist/util/num.js +0 -20
  308. package/dist/util/num.js.map +0 -1
package/README.md CHANGED
@@ -4,6 +4,8 @@
4
4
 
5
5
  ### Turbocharge Claude Code, Cursor, Codex, Gemini & every coding agent: faster, cheaper, with contextual understanding specific to your codebase.
6
6
 
7
+ <a href="https://trendshift.io/repositories/92209?utm_source=trendshift-badge&utm_medium=badge&utm_campaign=badge-trendshift-92209" target="_blank" rel="noopener noreferrer"><img src="https://trendshift.io/api/badge/trendshift/repositories/92209/daily?language=TypeScript" alt="trailhq/Graft | Trendshift" width="250" height="55"/></a>
8
+
7
9
  <p>
8
10
  <a href="https://github.com/NanoNets/Graft"><img src="https://img.shields.io/github/stars/NanoNets/Graft?style=for-the-badge&logo=github&logoColor=white&label=Star%20on%20GitHub&color=FFC83D" /></a>
9
11
  <a href="https://graft.nanonets.ai"><img src="https://img.shields.io/badge/website-graft.nanonets.ai-546FFF?style=for-the-badge" /></a>
@@ -15,6 +17,7 @@
15
17
  <img src="https://img.shields.io/badge/License-MIT-20C997?style=for-the-badge" />
16
18
  <a href="TELEMETRY.md"><img src="https://img.shields.io/badge/telemetry-anonymous%2C%20opt--out-546FFF?style=for-the-badge" /></a>
17
19
  <a href="https://scorecard.dev/viewer/?uri=github.com/NanoNets/Graft"><img src="https://img.shields.io/ossf-scorecard/github.com/NanoNets/Graft?style=for-the-badge&label=openssf%20scorecard" /></a>
20
+ <a href="https://github.com/apps/trailhq-graft"><img src="https://img.shields.io/badge/PR%20reviews-install%20GitHub%20App-546FFF?style=for-the-badge&logo=github&logoColor=white" /></a>
18
21
  </p>
19
22
 
20
23
  ### Up to **4× cheaper** and **3× faster**, with better or no loss of correctness.
@@ -26,10 +29,10 @@
26
29
  | Time savings | Baseline | **+60%** |
27
30
  | Correctness | 54% | **66% (+12 pts)** |
28
31
 
29
- <sub>Efficiency is a 162-run controlled benchmark (same agent, same file tools, only the context differs). Correctness is **SWE-bench Verified**, graded by the official harness — graft resolved 66% of instances tested against Cold Claude Code's 54%. [Efficiency method ↓](#benchmark) · [SWE-bench ↓](#swe-bench-verified) · [Per-repo numbers ↓](#tested-on-your-popular-repos)</sub>
30
-
31
32
  </div>
32
33
 
34
+ <p align="center"><b>Reviewing pull requests?</b> <a href="https://github.com/apps/trailhq-graft">Add the graft GitHub App</a> to get an automatic blast-radius review on every PR.</p>
35
+
33
36
  <p align="center">
34
37
  <img src="assets/graft-comparison-demo.gif" alt="Side-by-side comparison of a coding agent working with and without graft" width="820"/>
35
38
  </p>
@@ -107,7 +110,7 @@ Graft builds that understanding **once** and writes it into your repo as a folde
107
110
  - **A real graph you can read.** No embeddings, no similarity search, no index to keep warm. The graph is a set of linked files your agent opens, greps, and follows, exactly the way it reads any other file in the repo.
108
111
  - **A local cache, not a committed artifact.** `graft build` writes `graft/` and adds it to `.gitignore` — it's a regenerable local cache, like `node_modules`. What you commit is the small wiring `graft init` drops in (`.claude/`, `AGENTS.md`, the MCP config); each teammate runs `graft build` to generate their own graph. No database, no server, no setup.
109
112
  - **Always fresh, automatically.** Every query rebuilds the graph against the working tree first — structural, `$0`, ~3ms when nothing moved — so `ask`/`grep`/`callers`/`skeleton`/`map` describe the code as it is right now, including uncommitted edits. `graft check` is a local freshness signal; there's no stale index to babysit.
110
- - **Your provider, your key, your model.** Summaries are written by any provider you choose — OpenAI, Anthropic (native), OpenRouter, Fireworks, Groq, a LiteLLM proxy, or a local model — under your own key. The structural code graph (`graft build`, `graft check`) is deterministic tree-sitter and never calls a model at all.
113
+ - **Your provider, your key, your model.** Summaries are written by any provider you choose — OpenAI, Anthropic (native), OpenRouter, Fireworks, Groq, OrcaRouter, a LiteLLM proxy, or a local model — under your own key. The structural code graph (`graft build`, `graft check`) is deterministic tree-sitter and never calls a model at all.
111
114
 
112
115
  <p align="center">
113
116
  <picture>
@@ -193,13 +196,15 @@ compiler-grade layer — all `$0` and deterministic (no model, no key):
193
196
  - **Full-fidelity** — hand-written extractors with scope-aware, cross-file call
194
197
  and import resolution:
195
198
  **TypeScript / JavaScript** (incl. JSX & TSX), **Python**, **Go**, **Java**,
196
- **R** (`.R`/`.r` — plain functions, S3/S4/R6 classes and methods, roxygen
197
- `@export`, `library()`/`source()` imports).
199
+ **Kotlin**, **PHP**, **Swift** (classes, structs, enums, actors, protocols;
200
+ extension members attach to the extended type), **R** (`.R`/`.r` — plain
201
+ functions, S3/S4/R6 classes and methods, roxygen `@export`,
202
+ `library()`/`source()` imports).
198
203
 
199
204
  - **Broad** — symbols (functions, classes, methods, types, …) plus name-resolved
200
205
  call edges via a generic tree-sitter extractor, one grammar per language:
201
- **Rust, C, C++, C#, Ruby, PHP, Kotlin, Scala, Swift, Elixir, Solidity,
202
- OCaml, Zig, Dart, Clojure, Lua**.
206
+ **Rust, C, C++, C#, Ruby, Scala, Elixir, Solidity,
207
+ OCaml, Zig, Dart, Clojure, Nix, Lua**.
203
208
 
204
209
  - **Compiler-grade edges (opt-in)** — `graft build --lsp` adds precise
205
210
  `lsp_resolved` call edges (member calls the static pass can't type) when a
@@ -207,7 +212,7 @@ compiler-grade layer — all `$0` and deterministic (no model, no key):
207
212
  **gopls** (Go), **pyright** (Python), **typescript-language-server** (TS/JS).
208
213
  It's best-effort — with no server installed the graph is unchanged.
209
214
 
210
- Twenty-two languages in total. A file whose language isn't listed is skipped, not
215
+ Twenty-three languages in total. A file whose language isn't listed is skipped, not
211
216
  indexed. Adding a broad-tier language is a small contribution — see
212
217
  [CREDITS.md](CREDITS.md) for the folks who added the current set.
213
218
 
@@ -238,7 +243,7 @@ _Summary, sources, links, and notes ship today in markdown nodes. The crux ships
238
243
  ## What runs where
239
244
 
240
245
  - **On your machine, no key, no network:** the structural code graph. `graft build` (wiring graph + per-file cards), `graft check`, and `graft ask` are deterministic tree-sitter — they never call a model.
241
- - **Through your provider key:** the LLM-written parts — `graft build --deep` adds the concept nodes (file summaries + node synthesis) and the per-symbol summaries and cruxes. graft is vendor-neutral: set `GRAFT_PROVIDER` (`openai` for any OpenAI-compatible endpoint, or `anthropic` for the native API), your `GRAFT_API_KEY`, `GRAFT_MODEL`, and — for the `openai` wire format — `GRAFT_BASE_URL` to point at OpenRouter, Fireworks, Groq, a LiteLLM proxy, a local server, or OpenAI itself. Or pass `--provider/--model/--api-key/--base-url` on the command line. (`OPENROUTER_API_KEY` still works as a deprecated fallback.)
246
+ - **Through your provider key:** the LLM-written parts — `graft build --deep` adds the concept nodes (file summaries + node synthesis) and the per-symbol summaries and cruxes. graft is vendor-neutral: set `GRAFT_PROVIDER` (`openai` for any OpenAI-compatible endpoint, `anthropic` for the native API, or `litellm` / `orcarouter` for a gateway that speaks the OpenAI-compatible format), your `GRAFT_API_KEY`, `GRAFT_MODEL`, and — for the `openai` wire format — `GRAFT_BASE_URL` to point at OpenRouter, Fireworks, Groq, a LiteLLM proxy, a local server, or OpenAI itself. Or pass `--provider/--model/--api-key/--base-url` on the command line. (`OPENROUTER_API_KEY` still works as a deprecated fallback, and `ORCAROUTER_API_KEY` as a second one.)
242
247
  - **Anonymous usage stats** — the only network calls are the LLM requests you configured, a daily npm version check, and one batched usage ping. The ping carries buckets and fixed labels only: never your code, file paths, repo name, symbols, queries, or error messages. [`TELEMETRY.md`](TELEMETRY.md) is the complete list and `graft telemetry debug` prints exactly what your machine would send. Turn it off with `graft telemetry disable`, `DO_NOT_TRACK=1`, or by unchecking the box in `graft init`; it is off in CI and in any build from source.
243
248
 
244
249
  See [`.env.example`](.env.example) for the full list of settings (model, base URL, graph directory).
@@ -269,6 +274,7 @@ With no TTY to prompt on — CI, a Dockerfile, a piped shell — `init` writes *
269
274
  | `--list-agents` | print the known agent ids and exit |
270
275
  | `--no-mcp` | skip MCP server registration |
271
276
  | `--no-hooks` | skip hook installation |
277
+ | `--no-statusline` | skip writing Claude Code `statusLine` (same as `GRAFT_NO_STATUSLINE=1`) |
272
278
  | `--no-global` | skip writes outside this repo (the `~/.codex/` entries below) |
273
279
 
274
280
  #### Writes outside the repo
@@ -322,7 +328,7 @@ Where a CLI agent supports user-level `hooks.json`, `init` also installs Graft's
322
328
  <br/><sub>edit a file → blast radius appears inline → graph auto-resyncs → confirmed in <code>graft viz</code></sub>
323
329
  </p>
324
330
 
325
- `graft init` is idempotent and never clobbers your existing `.claude/settings.json` — it merges its blocks and leaves the rest alone. Want the LLM summaries too? Run `graft build --deep` (with a key) whenever you like; auto-sync will never do it for you.
331
+ `graft init` is idempotent and never clobbers your existing `.claude/settings.json` — it merges its blocks and leaves the rest alone. A `statusLine` that is not Graft's (anything whose command does not name `graft-statusline.cjs`) is left untouched; re-running `init` will refresh Graft's own helper command if it is already installed. Pass `--no-statusline` (or `GRAFT_NO_STATUSLINE=1`) to skip installing one at all — a project-level `statusLine` would otherwise hide a custom one in `~/.claude/settings.json`. Want the LLM summaries too? Run `graft build --deep` (with a key) whenever you like; auto-sync will never do it for you.
326
332
 
327
333
  ---
328
334
 
@@ -335,6 +341,8 @@ graft build --extensions .ts .py # only include these code extensions
335
341
  graft build --no-reuse # re-parse every file instead of replaying unchanged ones from cache
336
342
  graft build --follow-submodules # include initialized submodules; persist the choice for builds + MCP refresh
337
343
  graft build --no-follow-submodules # exclude submodules again and persist that choice (the default)
344
+ graft build --follow-nested-repos # include nested git clones the index doesn't track; persist the choice
345
+ graft build --no-follow-nested-repos # exclude nested clones again and persist that choice (the default)
338
346
 
339
347
  graft ask "<task>" [dir] # query the graph — ranked nodes + exact file:line (no LLM, no key)
340
348
  graft ask "<task>" --json # machine-readable result
@@ -358,6 +366,7 @@ graft blast --base origin/main # diff against the merge base with HEAD —
358
366
  graft blast --format markdown # a PR comment: the areas a change can reach, per-symbol detail collapsed under it
359
367
  graft blast --base origin/main --name # name those areas with one cached LLM call, instead of a full --deep build
360
368
  graft blast --export-viz site/ # also write the interactive page for this radius (what a PR comment links to)
369
+ graft blast --no-owners # skip "who to tag" — by default git history names the people behind each area
361
370
  graft blast --depth all --format json # the full transitive closure, machine-readable
362
371
 
363
372
  graft check [dir] # fail (exit 1) if graft/ has drifted from the code (never auto-refreshes — it's the drift report)
@@ -377,10 +386,16 @@ graft init --dry-run # list every file it would touch, then exit
377
386
  graft init --agents cursor kiro # wire only these agents, no prompt (ids: agents, cursor, gemini, grok, copilot, kiro, windsurf, adal, claude)
378
387
  graft init --yes # no prompt; wire every detected agent
379
388
  graft init --no-global # skip writes outside this repo (~/.codex/ config + hooks)
389
+ graft init --no-statusline # skip Claude Code statusLine (same as GRAFT_NO_STATUSLINE=1)
380
390
  graft init --no-build # wire the files only; don't build the graph
381
391
  graft init --all-agents # wire every known agent, detected or not
382
392
  graft init --list-agents # list known agent ids and exit
383
393
 
394
+ graft uninstall [dir] # remove every file and config entry graft wrote here (the inverse of init)
395
+ graft uninstall -y # actually remove (without -y it prints what it would remove and exits)
396
+ graft uninstall --keep-cache # wiring only; leave graft/ and the .gitignore entry
397
+ graft uninstall --no-global # leave out-of-repo files alone (~/.codex, ~/.gemini)
398
+
384
399
  graft version # print the installed + latest published npm version
385
400
  graft upgrade # npm install -g the latest published version
386
401
  # a new version is announced automatically (checked once a day);
@@ -447,6 +462,7 @@ Graft supports these layouts:
447
462
  is saved in `.graft/config.json`, so later no-flag builds and MCP automatic
448
463
  refreshes behave the same way. Run `graft build --no-follow-submodules` to
449
464
  restore and persist the default boundary.
465
+ - **A git repo with other repos cloned inside it** (no gitlink, no index entry) — the shape multi-repo manifest tools like `west`, `repo`, `gclient` and `tsrc` check dependencies out into, and the shape you get by cloning an upstream into the tree to patch it locally. `--follow-submodules` cannot reach these: they have no `160000` index entry to follow. Run `graft build --follow-nested-repos` to fold them into one graph, prefixing child paths (for example, `external/parser/src/index.ts`) while honoring each clone's own Git ignore rules. A clone at a git-ignored path stays absent, since Git never reports it. The choice is saved in `.graft/config.json` and is independent of `--follow-submodules` — neither flag implies the other. Run `graft build --no-follow-nested-repos` to restore and persist the default boundary. Prefer this over the multi-repo split below when the nested repos import from each other and you want those edges in one graph; prefer the split when you want each repo scored and refreshed on its own.
450
466
  - **A folder of separate git repos** (no `.git` at the top) — `graft build`
451
467
  auto-splits: each child gets its own (git-ignored) `graft/`, and the parent
452
468
  gets a `graft/workspace.json` index. Queries from the parent federate across
package/dist/ai/crux.d.ts CHANGED
@@ -14,7 +14,7 @@
14
14
  * sees each symbol's neighbours, which sharpens the summaries. Line numbers are
15
15
  * consumed once, at write time, to slice the crux text verbatim from source.
16
16
  */
17
- import type { ChatModel } from "./llm/types.js";
17
+ import type { ChatModel, ChatResponse } from "./llm/types.js";
18
18
  import type { Kind } from "../graph/types.js";
19
19
  /** One definition we want described, located by its line span within the file. */
20
20
  export interface NodeRef {
@@ -37,10 +37,23 @@ export interface NodeCrux {
37
37
  }
38
38
  export interface CruxSummarizer {
39
39
  describeFile(input: FileCruxInput): Promise<NodeCrux[]>;
40
+ /** Set by {@link ChatCruxSummarizer} after each call; optional on fakes. */
41
+ lastMiss?: CruxMiss | null;
40
42
  }
43
+ /** Why a crux call produced no usable summaries (#235). */
44
+ export type CruxMissKind = "empty-toolCalls" | "unparseable" | "truncated" | "empty-parsed";
45
+ export interface CruxMiss {
46
+ kind: CruxMissKind;
47
+ finishReason: string | null;
48
+ }
49
+ /** Classify an empty/unusable crux reply. `null` means at least one usable summary. */
50
+ export declare function classifyCruxMiss(res: ChatResponse, parsed: NodeCrux[]): CruxMiss | null;
51
+ /** Per-file error text: miss class + the provider's finish_reason (#235). */
52
+ export declare function formatCruxMiss(kind: CruxMissKind, finishReason: string | null): string;
41
53
  /** Crux summarizer backed by any {@link ChatModel} via forced tool calling. */
42
54
  export declare class ChatCruxSummarizer implements CruxSummarizer {
43
55
  private model;
56
+ lastMiss: CruxMiss | null;
44
57
  constructor(model: ChatModel);
45
58
  describeFile(input: FileCruxInput): Promise<NodeCrux[]>;
46
59
  }
@@ -1 +1 @@
1
- {"version":3,"file":"crux.d.ts","sourceRoot":"","sources":["../../src/ai/crux.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAE9C,kFAAkF;AAClF,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;CACzD;AAqID,+EAA+E;AAC/E,qBAAa,kBAAmB,YAAW,cAAc;IAC3C,OAAO,CAAC,KAAK;gBAAL,KAAK,EAAE,SAAS;IAE9B,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;CAoB9D"}
1
+ {"version":3,"file":"crux.d.ts","sourceRoot":"","sources":["../../src/ai/crux.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAE9C,kFAAkF;AAClF,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IACxD,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC5B;AAED,2DAA2D;AAC3D,MAAM,MAAM,YAAY,GAAG,iBAAiB,GAAG,aAAa,GAAG,WAAW,GAAG,cAAc,CAAC;AAE5F,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAQD,uFAAuF;AACvF,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,QAAQ,GAAG,IAAI,CASvF;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAGtF;AA+FD,+EAA+E;AAC/E,qBAAa,kBAAmB,YAAW,cAAc;IAG3C,OAAO,CAAC,KAAK;IAFzB,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAQ;gBAEb,KAAK,EAAE,SAAS;IAE9B,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;CAuB9D"}
package/dist/ai/crux.js CHANGED
@@ -1,3 +1,30 @@
1
+ import { recoverToolArgsFromContent, warnToolChoiceIgnored } from "./llm/recover-tool.js";
2
+ function isTruncatedStop(reason) {
3
+ if (!reason)
4
+ return false;
5
+ const r = reason.toLowerCase();
6
+ return r === "length" || r === "max_tokens";
7
+ }
8
+ /** Classify an empty/unusable crux reply. `null` means at least one usable summary. */
9
+ export function classifyCruxMiss(res, parsed) {
10
+ const finishReason = res.stopReason;
11
+ if (parsed.some((p) => p.summary.trim()))
12
+ return null;
13
+ if (isTruncatedStop(finishReason))
14
+ return { kind: "truncated", finishReason };
15
+ if (parsed.length > 0)
16
+ return { kind: "empty-parsed", finishReason };
17
+ const emptyTools = res.toolCalls.length === 0;
18
+ const emptyText = !res.text?.trim();
19
+ if (emptyTools && emptyText)
20
+ return { kind: "empty-toolCalls", finishReason };
21
+ return { kind: "unparseable", finishReason };
22
+ }
23
+ /** Per-file error text: miss class + the provider's finish_reason (#235). */
24
+ export function formatCruxMiss(kind, finishReason) {
25
+ const fr = finishReason == null || finishReason === "" ? "null" : finishReason;
26
+ return `model returned no usable symbol summaries [${kind}, finish_reason=${fr}]`;
27
+ }
1
28
  const SYSTEM_PROMPT = `You explain code definitions for a code graph that helps engineers navigate a codebase.
2
29
 
3
30
  You are given ONE source file with 1-based line numbers, and a list of TARGET definitions in it. Describe EVERY target via the record_symbols tool.
@@ -71,64 +98,23 @@ function argsFromResponse(res) {
71
98
  if (call?.args && typeof call.args === "object" && !Array.isArray(call.args)) {
72
99
  return call.args;
73
100
  }
74
- return recoverArgsFromContent(res.text);
75
- }
76
- function recoverArgsFromContent(text) {
77
- const raw = text?.trim();
78
- if (!raw)
79
- return undefined;
80
- const stripped = raw.replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/i, "").trim();
81
- const asSymbols = (value) => {
82
- if (!value || typeof value !== "object")
83
- return undefined;
84
- if (Array.isArray(value)) {
85
- for (const item of value) {
86
- if (!item || typeof item !== "object")
87
- continue;
88
- const rec = item;
89
- const name = typeof rec.name === "string" ? rec.name : "";
90
- // Accept the crux tool, or a generic emit_json wrapper some gateways use.
91
- if (name && name !== RECORD_TOOL && name !== "emit_json")
92
- continue;
93
- const params = rec.parameters ?? rec.arguments ?? rec.args;
94
- const hit = asSymbols(params);
95
- if (hit)
96
- return hit;
97
- }
98
- return undefined;
99
- }
100
- const obj = value;
101
- if (Array.isArray(obj.symbols))
102
- return obj;
103
- return undefined;
104
- };
105
- try {
106
- const hit = asSymbols(JSON.parse(stripped));
107
- if (hit)
108
- return hit;
109
- }
110
- catch {
111
- /* try bracket slice below */
112
- }
113
- const start = stripped.indexOf("{");
114
- const end = stripped.lastIndexOf("}");
115
- if (start >= 0 && end > start) {
116
- try {
117
- return asSymbols(JSON.parse(stripped.slice(start, end + 1)));
118
- }
119
- catch {
120
- return undefined;
121
- }
122
- }
123
- return undefined;
101
+ const recovered = recoverToolArgsFromContent(res.text, {
102
+ toolNames: [RECORD_TOOL, "emit_json"],
103
+ payloadKey: "symbols",
104
+ });
105
+ if (!recovered)
106
+ warnToolChoiceIgnored("crux", res.text?.trim() ? "unparsed" : "empty");
107
+ return recovered;
124
108
  }
125
109
  /** Crux summarizer backed by any {@link ChatModel} via forced tool calling. */
126
110
  export class ChatCruxSummarizer {
127
111
  model;
112
+ lastMiss = null;
128
113
  constructor(model) {
129
114
  this.model = model;
130
115
  }
131
116
  async describeFile(input) {
117
+ this.lastMiss = null;
132
118
  if (input.nodes.length === 0)
133
119
  return [];
134
120
  const res = await this.model.create({
@@ -147,7 +133,9 @@ export class ChatCruxSummarizer {
147
133
  { role: "user", content: userContent(input) },
148
134
  ],
149
135
  });
150
- return parseResults(argsFromResponse(res));
136
+ const parsed = parseResults(argsFromResponse(res));
137
+ this.lastMiss = classifyCruxMiss(res, parsed);
138
+ return parsed;
151
139
  }
152
140
  }
153
141
  //# sourceMappingURL=crux.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"crux.js","sourceRoot":"","sources":["../../src/ai/crux.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"crux.js","sourceRoot":"","sources":["../../src/ai/crux.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,11 @@
10
10
  *
11
11
  * One gate, shared by both passes, so they agree on what "the provider stopped
12
12
  * working" means and a caller can report it once.
13
+ *
14
+ * Content-quality misses (empty/unusable crux, #235) still count as failed files
15
+ * so they are not cached as success (#177), but they do not increment the
16
+ * consecutive-failure cutoff — the provider is answering, just not usefully for
17
+ * those files. Quota/auth stay immediately terminal (#127).
13
18
  */
14
19
  /** Consecutive failures that end a pass. One flaky file is normal; five in a row is
15
20
  * a provider that is not going to start working, and each further call is spend
@@ -39,8 +44,14 @@ export declare class LlmFailureGate {
39
44
  private consecutive;
40
45
  /** True once the pass should stop issuing calls. */
41
46
  get stopped(): boolean;
42
- /** Record a failed unit; sets {@link fatal} when this failure is the last straw. */
43
- record(message: string): void;
47
+ /**
48
+ * Record a failed unit; sets {@link fatal} when this failure is the last straw.
49
+ * Pass `{ quality: true }` for a content-quality miss (#235): counted, not fatal,
50
+ * unless the message is quota/auth (those still stop immediately).
51
+ */
52
+ record(message: string, opts?: {
53
+ quality?: boolean;
54
+ }): void;
44
55
  /** Record a success — a failure run only counts while it is unbroken. */
45
56
  succeeded(): void;
46
57
  /** Record a unit that was not attempted because the pass had stopped. */
@@ -1 +1 @@
1
- {"version":3,"file":"failure.d.ts","sourceRoot":"","sources":["../../src/ai/failure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;iCAEiC;AACjC,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAS7D;AAED;;;;;;GAMG;AACH,qBAAa,cAAc;IACzB,uCAAuC;IACvC,MAAM,SAAK;IACX,mEAAmE;IACnE,OAAO,SAAK;IACZ,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,WAAW,CAAK;IAExB,oDAAoD;IACpD,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,oFAAoF;IACpF,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAW7B,yEAAyE;IACzE,SAAS,IAAI,IAAI;IAIjB,yEAAyE;IACzE,IAAI,IAAI,IAAI;CAGb"}
1
+ {"version":3,"file":"failure.d.ts","sourceRoot":"","sources":["../../src/ai/failure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;iCAEiC;AACjC,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAS7D;AAED;;;;;;GAMG;AACH,qBAAa,cAAc;IACzB,uCAAuC;IACvC,MAAM,SAAK;IACX,mEAAmE;IACnE,OAAO,SAAK;IACZ,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,WAAW,CAAK;IAExB,oDAAoD;IACpD,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;;OAIG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI;IAc3D,yEAAyE;IACzE,SAAS,IAAI,IAAI;IAIjB,yEAAyE;IACzE,IAAI,IAAI,IAAI;CAGb"}
@@ -10,6 +10,11 @@
10
10
  *
11
11
  * One gate, shared by both passes, so they agree on what "the provider stopped
12
12
  * working" means and a caller can report it once.
13
+ *
14
+ * Content-quality misses (empty/unusable crux, #235) still count as failed files
15
+ * so they are not cached as success (#177), but they do not increment the
16
+ * consecutive-failure cutoff — the provider is answering, just not usefully for
17
+ * those files. Quota/auth stay immediately terminal (#127).
13
18
  */
14
19
  /** Consecutive failures that end a pass. One flaky file is normal; five in a row is
15
20
  * a provider that is not going to start working, and each further call is spend
@@ -50,15 +55,22 @@ export class LlmFailureGate {
50
55
  get stopped() {
51
56
  return this.fatal !== undefined;
52
57
  }
53
- /** Record a failed unit; sets {@link fatal} when this failure is the last straw. */
54
- record(message) {
58
+ /**
59
+ * Record a failed unit; sets {@link fatal} when this failure is the last straw.
60
+ * Pass `{ quality: true }` for a content-quality miss (#235): counted, not fatal,
61
+ * unless the message is quota/auth (those still stop immediately).
62
+ */
63
+ record(message, opts) {
55
64
  this.failed++;
56
- this.consecutive++;
57
65
  const terminal = terminalReason(message);
58
66
  if (terminal) {
59
67
  this.fatal = `${terminal} — stopped after ${this.failed} failed file(s). First error: ${message}`;
68
+ return;
60
69
  }
61
- else if (this.consecutive >= MAX_CONSECUTIVE_FAILURES) {
70
+ if (opts?.quality)
71
+ return;
72
+ this.consecutive++;
73
+ if (this.consecutive >= MAX_CONSECUTIVE_FAILURES) {
62
74
  this.fatal = `${this.consecutive} files in a row failed, so the pass stopped rather than keep calling. Last error: ${message}`;
63
75
  }
64
76
  }
@@ -1 +1 @@
1
- {"version":3,"file":"failure.js","sourceRoot":"","sources":["../../src/ai/failure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;iCAEiC;AACjC,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAE1C;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,MAAM,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAChC,IAAI,gFAAgF,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7F,OAAO,iEAAiE,CAAC;IAC3E,CAAC;IACD,IAAI,6EAA6E,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1F,OAAO,mCAAmC,CAAC;IAC7C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,cAAc;IACzB,uCAAuC;IACvC,MAAM,GAAG,CAAC,CAAC;IACX,mEAAmE;IACnE,OAAO,GAAG,CAAC,CAAC;IACZ,yCAAyC;IACzC,KAAK,CAAU;IACP,WAAW,GAAG,CAAC,CAAC;IAExB,oDAAoD;IACpD,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC;IAClC,CAAC;IAED,oFAAoF;IACpF,MAAM,CAAC,OAAe;QACpB,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,KAAK,GAAG,GAAG,QAAQ,oBAAoB,IAAI,CAAC,MAAM,iCAAiC,OAAO,EAAE,CAAC;QACpG,CAAC;aAAM,IAAI,IAAI,CAAC,WAAW,IAAI,wBAAwB,EAAE,CAAC;YACxD,IAAI,CAAC,KAAK,GAAG,GAAG,IAAI,CAAC,WAAW,qFAAqF,OAAO,EAAE,CAAC;QACjI,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,SAAS;QACP,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;IACvB,CAAC;IAED,yEAAyE;IACzE,IAAI;QACF,IAAI,CAAC,OAAO,EAAE,CAAC;IACjB,CAAC;CACF"}
1
+ {"version":3,"file":"failure.js","sourceRoot":"","sources":["../../src/ai/failure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;iCAEiC;AACjC,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAE1C;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,MAAM,CAAC,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAChC,IAAI,gFAAgF,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7F,OAAO,iEAAiE,CAAC;IAC3E,CAAC;IACD,IAAI,6EAA6E,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1F,OAAO,mCAAmC,CAAC;IAC7C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,cAAc;IACzB,uCAAuC;IACvC,MAAM,GAAG,CAAC,CAAC;IACX,mEAAmE;IACnE,OAAO,GAAG,CAAC,CAAC;IACZ,yCAAyC;IACzC,KAAK,CAAU;IACP,WAAW,GAAG,CAAC,CAAC;IAExB,oDAAoD;IACpD,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC;IAClC,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,OAAe,EAAE,IAA4B;QAClD,IAAI,CAAC,MAAM,EAAE,CAAC;QACd,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC,KAAK,GAAG,GAAG,QAAQ,oBAAoB,IAAI,CAAC,MAAM,iCAAiC,OAAO,EAAE,CAAC;YAClG,OAAO;QACT,CAAC;QACD,IAAI,IAAI,EAAE,OAAO;YAAE,OAAO;QAC1B,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,IAAI,CAAC,WAAW,IAAI,wBAAwB,EAAE,CAAC;YACjD,IAAI,CAAC,KAAK,GAAG,GAAG,IAAI,CAAC,WAAW,qFAAqF,OAAO,EAAE,CAAC;QACjI,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,SAAS;QACP,IAAI,CAAC,WAAW,GAAG,CAAC,CAAC;IACvB,CAAC;IAED,yEAAyE;IACzE,IAAI;QACF,IAAI,CAAC,OAAO,EAAE,CAAC;IACjB,CAAC;CACF"}
@@ -4,9 +4,18 @@
4
4
  * `baseUrl` at OpenRouter, Fireworks, a LiteLLM proxy, Groq, a local server, …),
5
5
  * `anthropic` speaks the native Messages API. Adding a vendor is a base URL, not
6
6
  * a code change; adding a wire format is one new adapter here.
7
+ *
8
+ * `litellm` is a convenience over `openai`: same wire format, but pointed at a
9
+ * LiteLLM proxy by default and paired with `/v1/models` auto-discovery
10
+ * (see litellm.ts), so one endpoint reaches 100+ providers.
11
+ *
12
+ * `orcarouter` is the same kind of convenience over `openai`, pointed at the
13
+ * OrcaRouter AI gateway by default (see orcarouter.ts) so its users get the
14
+ * gateway's routing, failover, and guardrails behind a named provider instead
15
+ * of a bare custom base URL.
7
16
  */
8
17
  import type { ChatModel } from "./types.js";
9
- export type ProviderKind = "openai" | "anthropic";
18
+ export type ProviderKind = "openai" | "anthropic" | "litellm" | "orcarouter";
10
19
  export interface ChatModelConfig {
11
20
  provider: ProviderKind;
12
21
  apiKey: string;
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/ai/llm/factory.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAI5C,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,WAAW,CAAC;AAElD,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yFAAyF;IACzF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,SAAS,CAgB/D"}
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/ai/llm/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAM5C,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,GAAG,YAAY,CAAC;AAE7E,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yFAAyF;IACzF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,SAAS,CA8B/D"}
@@ -1,5 +1,7 @@
1
1
  import { OpenAIChatModel } from "./openai.js";
2
2
  import { AnthropicChatModel } from "./anthropic.js";
3
+ import { LiteLLMChatModel } from "./litellm.js";
4
+ import { OrcaRouterChatModel } from "./orcarouter.js";
3
5
  export function createChatModel(cfg) {
4
6
  switch (cfg.provider) {
5
7
  case "anthropic":
@@ -11,6 +13,20 @@ export function createChatModel(cfg) {
11
13
  baseUrl: cfg.baseUrl,
12
14
  headers: cfg.headers,
13
15
  });
16
+ case "litellm":
17
+ return new LiteLLMChatModel({
18
+ apiKey: cfg.apiKey,
19
+ model: cfg.model,
20
+ baseUrl: cfg.baseUrl,
21
+ headers: cfg.headers,
22
+ });
23
+ case "orcarouter":
24
+ return new OrcaRouterChatModel({
25
+ apiKey: cfg.apiKey,
26
+ model: cfg.model,
27
+ baseUrl: cfg.baseUrl,
28
+ headers: cfg.headers,
29
+ });
14
30
  default: {
15
31
  const _exhaustive = cfg.provider;
16
32
  throw new Error(`unknown provider: ${String(_exhaustive)}`);
@@ -1 +1 @@
1
- {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../src/ai/llm/factory.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAapD,MAAM,UAAU,eAAe,CAAC,GAAoB;IAClD,QAAQ,GAAG,CAAC,QAAQ,EAAE,CAAC;QACrB,KAAK,WAAW;YACd,OAAO,IAAI,kBAAkB,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAChG,KAAK,QAAQ;YACX,OAAO,IAAI,eAAe,CAAC;gBACzB,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,OAAO,EAAE,GAAG,CAAC,OAAO;aACrB,CAAC,CAAC;QACL,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,WAAW,GAAU,GAAG,CAAC,QAAQ,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,qBAAqB,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../../src/ai/llm/factory.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAatD,MAAM,UAAU,eAAe,CAAC,GAAoB;IAClD,QAAQ,GAAG,CAAC,QAAQ,EAAE,CAAC;QACrB,KAAK,WAAW;YACd,OAAO,IAAI,kBAAkB,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAChG,KAAK,QAAQ;YACX,OAAO,IAAI,eAAe,CAAC;gBACzB,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,OAAO,EAAE,GAAG,CAAC,OAAO;aACrB,CAAC,CAAC;QACL,KAAK,SAAS;YACZ,OAAO,IAAI,gBAAgB,CAAC;gBAC1B,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,OAAO,EAAE,GAAG,CAAC,OAAO;aACrB,CAAC,CAAC;QACL,KAAK,YAAY;YACf,OAAO,IAAI,mBAAmB,CAAC;gBAC7B,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,KAAK,EAAE,GAAG,CAAC,KAAK;gBAChB,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,OAAO,EAAE,GAAG,CAAC,OAAO;aACrB,CAAC,CAAC;QACL,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,WAAW,GAAU,GAAG,CAAC,QAAQ,CAAC;YACxC,MAAM,IAAI,KAAK,CAAC,qBAAqB,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * LiteLLM transport. A LiteLLM proxy speaks the OpenAI-compatible wire format,
3
+ * so this reuses the OpenAI adapter's request/response translation and simply
4
+ * points it at the proxy. The value over a bare `openai` provider + `baseUrl`
5
+ * is a first-class, self-describing provider: a sensible default proxy address
6
+ * and `/v1/models` auto-discovery (see {@link listLiteLLMModels}), so callers
7
+ * can enumerate whatever models the proxy is configured to serve — reaching
8
+ * 100+ providers (OpenAI, Anthropic, Gemini, Bedrock, Vertex, …) through one
9
+ * endpoint without a per-vendor code path.
10
+ */
11
+ import OpenAI from "openai";
12
+ import { OpenAIChatModel, type OpenAIChatModelOptions } from "./openai.js";
13
+ /** Conventional local address of a self-hosted LiteLLM proxy. */
14
+ export declare const DEFAULT_LITELLM_BASE_URL = "http://localhost:4000";
15
+ export type LiteLLMChatModelOptions = OpenAIChatModelOptions;
16
+ /**
17
+ * ChatModel backed by a LiteLLM proxy. Inherits every translation detail from
18
+ * {@link OpenAIChatModel} (the proxy is OpenAI-compatible) and only changes the
19
+ * defaults: the proxy base URL and a `litellm:<model>` label.
20
+ */
21
+ export declare class LiteLLMChatModel extends OpenAIChatModel {
22
+ constructor(opts: LiteLLMChatModelOptions);
23
+ }
24
+ /**
25
+ * Auto-discover the models a LiteLLM proxy is serving via `GET /v1/models`.
26
+ * Returns the model ids so a caller can present/validate them instead of
27
+ * hardcoding a model string. A stub `client` may be injected for tests.
28
+ */
29
+ export declare function listLiteLLMModels(opts: {
30
+ apiKey: string;
31
+ baseUrl?: string;
32
+ client?: OpenAI;
33
+ }): Promise<string[]>;
34
+ //# sourceMappingURL=litellm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"litellm.d.ts","sourceRoot":"","sources":["../../../src/ai/llm/litellm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAG3E,iEAAiE;AACjE,eAAO,MAAM,wBAAwB,0BAA0B,CAAC;AAEhE,MAAM,MAAM,uBAAuB,GAAG,sBAAsB,CAAC;AAE7D;;;;GAIG;AACH,qBAAa,gBAAiB,SAAQ,eAAe;gBACvC,IAAI,EAAE,uBAAuB;CAO1C;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAUpB"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * LiteLLM transport. A LiteLLM proxy speaks the OpenAI-compatible wire format,
3
+ * so this reuses the OpenAI adapter's request/response translation and simply
4
+ * points it at the proxy. The value over a bare `openai` provider + `baseUrl`
5
+ * is a first-class, self-describing provider: a sensible default proxy address
6
+ * and `/v1/models` auto-discovery (see {@link listLiteLLMModels}), so callers
7
+ * can enumerate whatever models the proxy is configured to serve — reaching
8
+ * 100+ providers (OpenAI, Anthropic, Gemini, Bedrock, Vertex, …) through one
9
+ * endpoint without a per-vendor code path.
10
+ */
11
+ import OpenAI from "openai";
12
+ import { OpenAIChatModel } from "./openai.js";
13
+ import { transportRetries } from "./types.js";
14
+ /** Conventional local address of a self-hosted LiteLLM proxy. */
15
+ export const DEFAULT_LITELLM_BASE_URL = "http://localhost:4000";
16
+ /**
17
+ * ChatModel backed by a LiteLLM proxy. Inherits every translation detail from
18
+ * {@link OpenAIChatModel} (the proxy is OpenAI-compatible) and only changes the
19
+ * defaults: the proxy base URL and a `litellm:<model>` label.
20
+ */
21
+ export class LiteLLMChatModel extends OpenAIChatModel {
22
+ constructor(opts) {
23
+ super({
24
+ ...opts,
25
+ baseUrl: opts.baseUrl ?? DEFAULT_LITELLM_BASE_URL,
26
+ label: opts.label ?? `litellm:${opts.model}`,
27
+ });
28
+ }
29
+ }
30
+ /**
31
+ * Auto-discover the models a LiteLLM proxy is serving via `GET /v1/models`.
32
+ * Returns the model ids so a caller can present/validate them instead of
33
+ * hardcoding a model string. A stub `client` may be injected for tests.
34
+ */
35
+ export async function listLiteLLMModels(opts) {
36
+ const client = opts.client ??
37
+ new OpenAI({
38
+ apiKey: opts.apiKey,
39
+ baseURL: opts.baseUrl ?? DEFAULT_LITELLM_BASE_URL,
40
+ maxRetries: transportRetries(),
41
+ });
42
+ const res = await client.models.list();
43
+ return res.data.map((m) => m.id);
44
+ }
45
+ //# sourceMappingURL=litellm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"litellm.js","sourceRoot":"","sources":["../../../src/ai/llm/litellm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,eAAe,EAA+B,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,iEAAiE;AACjE,MAAM,CAAC,MAAM,wBAAwB,GAAG,uBAAuB,CAAC;AAIhE;;;;GAIG;AACH,MAAM,OAAO,gBAAiB,SAAQ,eAAe;IACnD,YAAY,IAA6B;QACvC,KAAK,CAAC;YACJ,GAAG,IAAI;YACP,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,wBAAwB;YACjD,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,WAAW,IAAI,CAAC,KAAK,EAAE;SAC7C,CAAC,CAAC;IACL,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAIvC;IACC,MAAM,MAAM,GACV,IAAI,CAAC,MAAM;QACX,IAAI,MAAM,CAAC;YACT,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,wBAAwB;YACjD,UAAU,EAAE,gBAAgB,EAAE;SAC/B,CAAC,CAAC;IACL,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IACvC,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AACnC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/ai/llm/openai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAsC,MAAM,YAAY,CAAC;AAM3G,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA0DD,qBAAa,eAAgB,YAAW,SAAS;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;gBAEV,IAAI,EAAE,sBAAsB;IAalC,MAAM,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA2BrD;;;;;;;;;OASG;YACW,oBAAoB;IAWlC,OAAO,CAAC,YAAY;CA6CrB"}
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/ai/llm/openai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAsC,MAAM,YAAY,CAAC;AAM3G,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAuGD,qBAAa,eAAgB,YAAW,SAAS;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;gBAEV,IAAI,EAAE,sBAAsB;IAalC,MAAM,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA2BrD;;;;;;;;;OASG;YACW,oBAAoB;IAkClC,OAAO,CAAC,YAAY;CA6CrB"}