@nanonets/graft 0.15.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 (157) hide show
  1. package/README.md +10 -5
  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 +31 -1
  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 +6 -1
  11. package/dist/ai/llm/factory.d.ts.map +1 -1
  12. package/dist/ai/llm/factory.js +8 -0
  13. package/dist/ai/llm/factory.js.map +1 -1
  14. package/dist/ai/llm/orcarouter.d.ts +34 -0
  15. package/dist/ai/llm/orcarouter.d.ts.map +1 -0
  16. package/dist/ai/llm/orcarouter.js +45 -0
  17. package/dist/ai/llm/orcarouter.js.map +1 -0
  18. package/dist/ai/providers.d.ts.map +1 -1
  19. package/dist/ai/providers.js +13 -3
  20. package/dist/ai/providers.js.map +1 -1
  21. package/dist/app/review.d.ts.map +1 -1
  22. package/dist/app/review.js +10 -0
  23. package/dist/app/review.js.map +1 -1
  24. package/dist/blast/blast-cli.d.ts.map +1 -1
  25. package/dist/blast/blast-cli.js +6 -30
  26. package/dist/blast/blast-cli.js.map +1 -1
  27. package/dist/blast/name.d.ts +13 -0
  28. package/dist/blast/name.d.ts.map +1 -1
  29. package/dist/blast/name.js +36 -0
  30. package/dist/blast/name.js.map +1 -1
  31. package/dist/claude/hooks.d.ts.map +1 -1
  32. package/dist/claude/hooks.js +93 -23
  33. package/dist/claude/hooks.js.map +1 -1
  34. package/dist/claude/init.d.ts +1 -0
  35. package/dist/claude/init.d.ts.map +1 -1
  36. package/dist/claude/init.js +1 -1
  37. package/dist/claude/init.js.map +1 -1
  38. package/dist/claude/session-metrics.d.ts +63 -0
  39. package/dist/claude/session-metrics.d.ts.map +1 -0
  40. package/dist/claude/session-metrics.js +181 -0
  41. package/dist/claude/session-metrics.js.map +1 -0
  42. package/dist/claude/settings-merge.d.ts +7 -1
  43. package/dist/claude/settings-merge.d.ts.map +1 -1
  44. package/dist/claude/settings-merge.js +47 -18
  45. package/dist/claude/settings-merge.js.map +1 -1
  46. package/dist/claude/state.d.ts +12 -0
  47. package/dist/claude/state.d.ts.map +1 -1
  48. package/dist/claude/state.js +14 -1
  49. package/dist/claude/state.js.map +1 -1
  50. package/dist/cli.js +29 -3
  51. package/dist/cli.js.map +1 -1
  52. package/dist/context/build.d.ts +11 -0
  53. package/dist/context/build.d.ts.map +1 -1
  54. package/dist/context/build.js +27 -6
  55. package/dist/context/build.js.map +1 -1
  56. package/dist/context/check.d.ts.map +1 -1
  57. package/dist/context/check.js +5 -13
  58. package/dist/context/check.js.map +1 -1
  59. package/dist/context/node-file.d.ts +1 -1
  60. package/dist/context/node-file.d.ts.map +1 -1
  61. package/dist/context/node-file.js +38 -6
  62. package/dist/context/node-file.js.map +1 -1
  63. package/dist/context/savings.d.ts +8 -0
  64. package/dist/context/savings.d.ts.map +1 -1
  65. package/dist/context/savings.js +14 -0
  66. package/dist/context/savings.js.map +1 -1
  67. package/dist/engine.d.ts +2 -0
  68. package/dist/engine.d.ts.map +1 -1
  69. package/dist/engine.js +1 -0
  70. package/dist/engine.js.map +1 -1
  71. package/dist/graph/cards.d.ts +4 -3
  72. package/dist/graph/cards.d.ts.map +1 -1
  73. package/dist/graph/cards.js +34 -6
  74. package/dist/graph/cards.js.map +1 -1
  75. package/dist/graph/enrich.d.ts +4 -4
  76. package/dist/graph/enrich.d.ts.map +1 -1
  77. package/dist/graph/enrich.js +32 -6
  78. package/dist/graph/enrich.js.map +1 -1
  79. package/dist/graph/generic.d.ts +10 -0
  80. package/dist/graph/generic.d.ts.map +1 -1
  81. package/dist/graph/generic.js +20 -2
  82. package/dist/graph/generic.js.map +1 -1
  83. package/dist/graph/workspace.d.ts +2 -0
  84. package/dist/graph/workspace.d.ts.map +1 -1
  85. package/dist/graph/workspace.js +173 -6
  86. package/dist/graph/workspace.js.map +1 -1
  87. package/dist/hosts/antigravity.d.ts +2 -2
  88. package/dist/hosts/antigravity.d.ts.map +1 -1
  89. package/dist/hosts/codex-hooks.d.ts +2 -6
  90. package/dist/hosts/codex-hooks.d.ts.map +1 -1
  91. package/dist/hosts/codex-hooks.js +7 -30
  92. package/dist/hosts/codex-hooks.js.map +1 -1
  93. package/dist/hosts/config-write.d.ts +36 -0
  94. package/dist/hosts/config-write.d.ts.map +1 -0
  95. package/dist/hosts/config-write.js +63 -0
  96. package/dist/hosts/config-write.js.map +1 -0
  97. package/dist/hosts/cursor-hooks.d.ts +18 -0
  98. package/dist/hosts/cursor-hooks.d.ts.map +1 -0
  99. package/dist/hosts/cursor-hooks.js +100 -0
  100. package/dist/hosts/cursor-hooks.js.map +1 -0
  101. package/dist/hosts/init.d.ts +2 -2
  102. package/dist/hosts/init.d.ts.map +1 -1
  103. package/dist/hosts/init.js +8 -2
  104. package/dist/hosts/init.js.map +1 -1
  105. package/dist/hosts/mcp-config.d.ts +3 -5
  106. package/dist/hosts/mcp-config.d.ts.map +1 -1
  107. package/dist/hosts/mcp-config.js +5 -10
  108. package/dist/hosts/mcp-config.js.map +1 -1
  109. package/dist/hosts/plan.d.ts.map +1 -1
  110. package/dist/hosts/plan.js +2 -0
  111. package/dist/hosts/plan.js.map +1 -1
  112. package/dist/index.d.ts +2 -0
  113. package/dist/index.d.ts.map +1 -1
  114. package/dist/index.js +2 -0
  115. package/dist/index.js.map +1 -1
  116. package/dist/ingest/fs.d.ts +20 -0
  117. package/dist/ingest/fs.d.ts.map +1 -1
  118. package/dist/ingest/fs.js +76 -3
  119. package/dist/ingest/fs.js.map +1 -1
  120. package/dist/mcp/tool-names.d.ts +20 -0
  121. package/dist/mcp/tool-names.d.ts.map +1 -0
  122. package/dist/mcp/tool-names.js +36 -0
  123. package/dist/mcp/tool-names.js.map +1 -0
  124. package/dist/mcp/tools.d.ts +11 -2
  125. package/dist/mcp/tools.d.ts.map +1 -1
  126. package/dist/mcp/tools.js +9 -21
  127. package/dist/mcp/tools.js.map +1 -1
  128. package/dist/telemetry/contract.d.ts.map +1 -1
  129. package/dist/telemetry/contract.js +10 -1
  130. package/dist/telemetry/contract.js.map +1 -1
  131. package/dist/telemetry/flush.d.ts.map +1 -1
  132. package/dist/telemetry/flush.js +1 -0
  133. package/dist/telemetry/flush.js.map +1 -1
  134. package/dist/telemetry/identity.d.ts +7 -0
  135. package/dist/telemetry/identity.d.ts.map +1 -1
  136. package/dist/telemetry/identity.js.map +1 -1
  137. package/dist/telemetry/index.d.ts +2 -2
  138. package/dist/telemetry/index.d.ts.map +1 -1
  139. package/dist/telemetry/index.js +2 -2
  140. package/dist/telemetry/index.js.map +1 -1
  141. package/dist/telemetry/sessions.d.ts +19 -2
  142. package/dist/telemetry/sessions.d.ts.map +1 -1
  143. package/dist/telemetry/sessions.js +57 -40
  144. package/dist/telemetry/sessions.js.map +1 -1
  145. package/dist/telemetry/track.d.ts +22 -3
  146. package/dist/telemetry/track.d.ts.map +1 -1
  147. package/dist/telemetry/track.js +34 -5
  148. package/dist/telemetry/track.js.map +1 -1
  149. package/dist/upkeep-run.js +1 -1
  150. package/dist/upkeep-run.js.map +1 -1
  151. package/dist/upkeep.d.ts +7 -4
  152. package/dist/upkeep.d.ts.map +1 -1
  153. package/dist/upkeep.js +2 -1
  154. package/dist/upkeep.js.map +1 -1
  155. package/package.json +2 -2
  156. package/scripts/postinstall.mjs +42 -3
  157. package/scripts/run-tests.mjs +14 -0
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>
@@ -240,7 +243,7 @@ _Summary, sources, links, and notes ship today in markdown nodes. The crux ships
240
243
  ## What runs where
241
244
 
242
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.
243
- - **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.)
244
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.
245
248
 
246
249
  See [`.env.example`](.env.example) for the full list of settings (model, base URL, graph directory).
@@ -271,6 +274,7 @@ With no TTY to prompt on — CI, a Dockerfile, a piped shell — `init` writes *
271
274
  | `--list-agents` | print the known agent ids and exit |
272
275
  | `--no-mcp` | skip MCP server registration |
273
276
  | `--no-hooks` | skip hook installation |
277
+ | `--no-statusline` | skip writing Claude Code `statusLine` (same as `GRAFT_NO_STATUSLINE=1`) |
274
278
  | `--no-global` | skip writes outside this repo (the `~/.codex/` entries below) |
275
279
 
276
280
  #### Writes outside the repo
@@ -324,7 +328,7 @@ Where a CLI agent supports user-level `hooks.json`, `init` also installs Graft's
324
328
  <br/><sub>edit a file → blast radius appears inline → graph auto-resyncs → confirmed in <code>graft viz</code></sub>
325
329
  </p>
326
330
 
327
- `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.
328
332
 
329
333
  ---
330
334
 
@@ -382,6 +386,7 @@ graft init --dry-run # list every file it would touch, then exit
382
386
  graft init --agents cursor kiro # wire only these agents, no prompt (ids: agents, cursor, gemini, grok, copilot, kiro, windsurf, adal, claude)
383
387
  graft init --yes # no prompt; wire every detected agent
384
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)
385
390
  graft init --no-build # wire the files only; don't build the graph
386
391
  graft init --all-agents # wire every known agent, detected or not
387
392
  graft init --list-agents # list known agent ids and exit
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;AAEhD,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;AA+FD,+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,4 +1,30 @@
1
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
+ }
2
28
  const SYSTEM_PROMPT = `You explain code definitions for a code graph that helps engineers navigate a codebase.
3
29
 
4
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.
@@ -83,10 +109,12 @@ function argsFromResponse(res) {
83
109
  /** Crux summarizer backed by any {@link ChatModel} via forced tool calling. */
84
110
  export class ChatCruxSummarizer {
85
111
  model;
112
+ lastMiss = null;
86
113
  constructor(model) {
87
114
  this.model = model;
88
115
  }
89
116
  async describeFile(input) {
117
+ this.lastMiss = null;
90
118
  if (input.nodes.length === 0)
91
119
  return [];
92
120
  const res = await this.model.create({
@@ -105,7 +133,9 @@ export class ChatCruxSummarizer {
105
133
  { role: "user", content: userContent(input) },
106
134
  ],
107
135
  });
108
- return parseResults(argsFromResponse(res));
136
+ const parsed = parseResults(argsFromResponse(res));
137
+ this.lastMiss = classifyCruxMiss(res, parsed);
138
+ return parsed;
109
139
  }
110
140
  }
111
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"}
@@ -8,9 +8,14 @@
8
8
  * `litellm` is a convenience over `openai`: same wire format, but pointed at a
9
9
  * LiteLLM proxy by default and paired with `/v1/models` auto-discovery
10
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.
11
16
  */
12
17
  import type { ChatModel } from "./types.js";
13
- export type ProviderKind = "openai" | "anthropic" | "litellm";
18
+ export type ProviderKind = "openai" | "anthropic" | "litellm" | "orcarouter";
14
19
  export interface ChatModelConfig {
15
20
  provider: ProviderKind;
16
21
  apiKey: string;
@@ -1 +1 @@
1
- {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../../src/ai/llm/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAK5C,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,WAAW,GAAG,SAAS,CAAC;AAE9D,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,CAuB/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,6 +1,7 @@
1
1
  import { OpenAIChatModel } from "./openai.js";
2
2
  import { AnthropicChatModel } from "./anthropic.js";
3
3
  import { LiteLLMChatModel } from "./litellm.js";
4
+ import { OrcaRouterChatModel } from "./orcarouter.js";
4
5
  export function createChatModel(cfg) {
5
6
  switch (cfg.provider) {
6
7
  case "anthropic":
@@ -19,6 +20,13 @@ export function createChatModel(cfg) {
19
20
  baseUrl: cfg.baseUrl,
20
21
  headers: cfg.headers,
21
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
+ });
22
30
  default: {
23
31
  const _exhaustive = cfg.provider;
24
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":"AAYA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAahD,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,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
+ * OrcaRouter transport. The OrcaRouter gateway speaks the OpenAI-compatible
3
+ * wire format, so this reuses the OpenAI adapter's request/response translation
4
+ * and simply points it at the gateway. The value over a bare `openai` provider +
5
+ * `baseUrl` is a first-class, self-describing provider: a sensible default
6
+ * gateway address and `/v1/models` auto-discovery (see {@link listOrcaRouterModels}),
7
+ * so callers can enumerate whatever upstream models the gateway routes to —
8
+ * reaching 150+ models from OpenAI, Anthropic, Google, DeepSeek, Qwen, and more
9
+ * through one endpoint without a per-vendor code path.
10
+ */
11
+ import OpenAI from "openai";
12
+ import { OpenAIChatModel, type OpenAIChatModelOptions } from "./openai.js";
13
+ /** Public endpoint of the OrcaRouter AI gateway. */
14
+ export declare const DEFAULT_ORCAROUTER_BASE_URL = "https://api.orcarouter.ai/v1";
15
+ export type OrcaRouterChatModelOptions = OpenAIChatModelOptions;
16
+ /**
17
+ * ChatModel backed by the OrcaRouter gateway. Inherits every translation detail
18
+ * from {@link OpenAIChatModel} (the gateway is OpenAI-compatible) and only
19
+ * changes the defaults: the gateway base URL and an `orcarouter:<model>` label.
20
+ */
21
+ export declare class OrcaRouterChatModel extends OpenAIChatModel {
22
+ constructor(opts: OrcaRouterChatModelOptions);
23
+ }
24
+ /**
25
+ * Auto-discover the models the OrcaRouter gateway can route to via `GET
26
+ * /v1/models`. Returns the model ids so a caller can present/validate them
27
+ * instead of hardcoding a model string. A stub `client` may be injected for tests.
28
+ */
29
+ export declare function listOrcaRouterModels(opts: {
30
+ apiKey: string;
31
+ baseUrl?: string;
32
+ client?: OpenAI;
33
+ }): Promise<string[]>;
34
+ //# sourceMappingURL=orcarouter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orcarouter.d.ts","sourceRoot":"","sources":["../../../src/ai/llm/orcarouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAG3E,oDAAoD;AACpD,eAAO,MAAM,2BAA2B,iCAAiC,CAAC;AAE1E,MAAM,MAAM,0BAA0B,GAAG,sBAAsB,CAAC;AAEhE;;;;GAIG;AACH,qBAAa,mBAAoB,SAAQ,eAAe;gBAC1C,IAAI,EAAE,0BAA0B;CAO7C;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAC/C,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
+ * OrcaRouter transport. The OrcaRouter gateway speaks the OpenAI-compatible
3
+ * wire format, so this reuses the OpenAI adapter's request/response translation
4
+ * and simply points it at the gateway. The value over a bare `openai` provider +
5
+ * `baseUrl` is a first-class, self-describing provider: a sensible default
6
+ * gateway address and `/v1/models` auto-discovery (see {@link listOrcaRouterModels}),
7
+ * so callers can enumerate whatever upstream models the gateway routes to —
8
+ * reaching 150+ models from OpenAI, Anthropic, Google, DeepSeek, Qwen, and more
9
+ * through one 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
+ /** Public endpoint of the OrcaRouter AI gateway. */
15
+ export const DEFAULT_ORCAROUTER_BASE_URL = "https://api.orcarouter.ai/v1";
16
+ /**
17
+ * ChatModel backed by the OrcaRouter gateway. Inherits every translation detail
18
+ * from {@link OpenAIChatModel} (the gateway is OpenAI-compatible) and only
19
+ * changes the defaults: the gateway base URL and an `orcarouter:<model>` label.
20
+ */
21
+ export class OrcaRouterChatModel extends OpenAIChatModel {
22
+ constructor(opts) {
23
+ super({
24
+ ...opts,
25
+ baseUrl: opts.baseUrl ?? DEFAULT_ORCAROUTER_BASE_URL,
26
+ label: opts.label ?? `orcarouter:${opts.model}`,
27
+ });
28
+ }
29
+ }
30
+ /**
31
+ * Auto-discover the models the OrcaRouter gateway can route to via `GET
32
+ * /v1/models`. Returns the model ids so a caller can present/validate them
33
+ * instead of hardcoding a model string. A stub `client` may be injected for tests.
34
+ */
35
+ export async function listOrcaRouterModels(opts) {
36
+ const client = opts.client ??
37
+ new OpenAI({
38
+ apiKey: opts.apiKey,
39
+ baseURL: opts.baseUrl ?? DEFAULT_ORCAROUTER_BASE_URL,
40
+ maxRetries: transportRetries(),
41
+ });
42
+ const res = await client.models.list();
43
+ return res.data.map((m) => m.id);
44
+ }
45
+ //# sourceMappingURL=orcarouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"orcarouter.js","sourceRoot":"","sources":["../../../src/ai/llm/orcarouter.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,oDAAoD;AACpD,MAAM,CAAC,MAAM,2BAA2B,GAAG,8BAA8B,CAAC;AAI1E;;;;GAIG;AACH,MAAM,OAAO,mBAAoB,SAAQ,eAAe;IACtD,YAAY,IAAgC;QAC1C,KAAK,CAAC;YACJ,GAAG,IAAI;YACP,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,2BAA2B;YACpD,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,cAAc,IAAI,CAAC,KAAK,EAAE;SAChD,CAAC,CAAC;IACL,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,IAI1C;IACC,MAAM,MAAM,GACV,IAAI,CAAC,MAAM;QACX,IAAI,MAAM,CAAC;YACT,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,2BAA2B;YACpD,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":"providers.d.ts","sourceRoot":"","sources":["../../src/ai/providers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD;;;;;;;;;GASG;AACH,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,wFAAwF;IACxF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,oEAAoE;IACpE,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,gCAAgC;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,oCAAoC;IACpC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,8DAA8D;AAC9D,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,wEAAwE;IACxE,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAID,kCAAkC;AAClC,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAKvD,CAAC;AAEF,eAAO,MAAM,QAAQ;uBACG,YAAY;;CAE1B,CAAC;AAEX,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,MAAM,GAAE,YAAiB,GAAG,cAAc,CAmCvE"}
1
+ {"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../src/ai/providers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD;;;;;;;;;GASG;AACH,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,wFAAwF;IACxF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,oEAAoE;IACpE,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,gCAAgC;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,oCAAoC;IACpC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,8DAA8D;AAC9D,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,wEAAwE;IACxE,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAKD,kCAAkC;AAClC,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAOvD,CAAC;AAEF,eAAO,MAAM,QAAQ;uBACG,YAAY;;CAE1B,CAAC;AAEX,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,MAAM,GAAE,YAAiB,GAAG,cAAc,CAyCvE"}
@@ -1,10 +1,13 @@
1
1
  const OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
2
+ const ORCAROUTER_BASE_URL = "https://api.orcarouter.ai/v1";
2
3
  /** Per-provider default model. */
3
4
  export const DEFAULT_MODELS = {
4
5
  openai: "openai/gpt-4o-mini",
5
6
  anthropic: "claude-sonnet-5",
6
7
  // Provider-prefixed so the LiteLLM proxy routes it; override with GRAFT_MODEL.
7
8
  litellm: "openai/gpt-4o-mini",
9
+ // Provider-prefixed so the OrcaRouter gateway routes it; override with GRAFT_MODEL.
10
+ orcarouter: "openai/gpt-4o-mini",
8
11
  };
9
12
  export const DEFAULTS = {
10
13
  provider: "openai",
@@ -16,14 +19,21 @@ export function resolveConfig(config = {}) {
16
19
  const provider = config.provider ?? env.GRAFT_PROVIDER ?? DEFAULTS.provider;
17
20
  const explicitKey = config.apiKey ?? env.GRAFT_API_KEY;
18
21
  const legacyKey = env.OPENROUTER_API_KEY;
19
- const apiKey = explicitKey ?? legacyKey;
22
+ const apiKey = explicitKey ?? legacyKey ?? env.ORCAROUTER_API_KEY;
20
23
  const usedLegacyEnv = !explicitKey && !!legacyKey;
21
- const model = config.model ?? env.GRAFT_MODEL ?? env.GRAFT_OPENROUTER_MODEL ?? DEFAULT_MODELS[provider];
22
- let baseUrl = config.baseUrl ?? env.GRAFT_BASE_URL ?? env.OPENROUTER_BASE_URL;
24
+ const model = config.model ??
25
+ env.GRAFT_MODEL ??
26
+ env.GRAFT_OPENROUTER_MODEL ??
27
+ env.ORCAROUTER_MODEL ??
28
+ DEFAULT_MODELS[provider];
29
+ let baseUrl = config.baseUrl ?? env.GRAFT_BASE_URL ?? env.OPENROUTER_BASE_URL ?? env.ORCAROUTER_BASE_URL;
23
30
  // Back-compat: an existing setup with only OPENROUTER_API_KEY keeps hitting
24
31
  // OpenRouter without any config change.
25
32
  if (!baseUrl && provider === "openai" && usedLegacyEnv)
26
33
  baseUrl = OPENROUTER_BASE_URL;
34
+ // The orcarouter provider points at the gateway unless a base URL is given.
35
+ if (!baseUrl && provider === "orcarouter")
36
+ baseUrl = ORCAROUTER_BASE_URL;
27
37
  const headers = provider === "openai" && baseUrl?.includes("openrouter.ai")
28
38
  ? { "X-Title": "graft" }
29
39
  : undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/ai/providers.ts"],"names":[],"mappings":"AAwDA,MAAM,mBAAmB,GAAG,8BAA8B,CAAC;AAE3D,kCAAkC;AAClC,MAAM,CAAC,MAAM,cAAc,GAAiC;IAC1D,MAAM,EAAE,oBAAoB;IAC5B,SAAS,EAAE,iBAAiB;IAC5B,+EAA+E;IAC/E,OAAO,EAAE,oBAAoB;CAC9B,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,QAAQ,EAAE,QAAwB;IAClC,KAAK,EAAE,cAAc,CAAC,MAAM;CACpB,CAAC;AAEX,iEAAiE;AACjE,MAAM,UAAU,aAAa,CAAC,SAAuB,EAAE;IACrD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACxB,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAK,GAAG,CAAC,cAA2C,IAAI,QAAQ,CAAC,QAAQ,CAAC;IAE1G,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,aAAa,CAAC;IACvD,MAAM,SAAS,GAAG,GAAG,CAAC,kBAAkB,CAAC;IACzC,MAAM,MAAM,GAAG,WAAW,IAAI,SAAS,CAAC;IACxC,MAAM,aAAa,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC,SAAS,CAAC;IAElD,MAAM,KAAK,GACT,MAAM,CAAC,KAAK,IAAI,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,sBAAsB,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAC;IAE5F,IAAI,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,mBAAmB,CAAC;IAC9E,4EAA4E;IAC5E,wCAAwC;IACxC,IAAI,CAAC,OAAO,IAAI,QAAQ,KAAK,QAAQ,IAAI,aAAa;QAAE,OAAO,GAAG,mBAAmB,CAAC;IAEtF,MAAM,OAAO,GACX,QAAQ,KAAK,QAAQ,IAAI,OAAO,EAAE,QAAQ,CAAC,eAAe,CAAC;QACzD,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE;QACxB,CAAC,CAAC,SAAS,CAAC;IAEhB,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS;QAC9C,QAAQ;QACR,MAAM;QACN,KAAK;QACL,OAAO;QACP,OAAO;QACP,aAAa;QACb,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,cAAc,EAAE,MAAM,CAAC,cAAc;KACtC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/ai/providers.ts"],"names":[],"mappings":"AAwDA,MAAM,mBAAmB,GAAG,8BAA8B,CAAC;AAC3D,MAAM,mBAAmB,GAAG,8BAA8B,CAAC;AAE3D,kCAAkC;AAClC,MAAM,CAAC,MAAM,cAAc,GAAiC;IAC1D,MAAM,EAAE,oBAAoB;IAC5B,SAAS,EAAE,iBAAiB;IAC5B,+EAA+E;IAC/E,OAAO,EAAE,oBAAoB;IAC7B,oFAAoF;IACpF,UAAU,EAAE,oBAAoB;CACjC,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,QAAQ,EAAE,QAAwB;IAClC,KAAK,EAAE,cAAc,CAAC,MAAM;CACpB,CAAC;AAEX,iEAAiE;AACjE,MAAM,UAAU,aAAa,CAAC,SAAuB,EAAE;IACrD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACxB,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAK,GAAG,CAAC,cAA2C,IAAI,QAAQ,CAAC,QAAQ,CAAC;IAE1G,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,aAAa,CAAC;IACvD,MAAM,SAAS,GAAG,GAAG,CAAC,kBAAkB,CAAC;IACzC,MAAM,MAAM,GAAG,WAAW,IAAI,SAAS,IAAI,GAAG,CAAC,kBAAkB,CAAC;IAClE,MAAM,aAAa,GAAG,CAAC,WAAW,IAAI,CAAC,CAAC,SAAS,CAAC;IAElD,MAAM,KAAK,GACT,MAAM,CAAC,KAAK;QACZ,GAAG,CAAC,WAAW;QACf,GAAG,CAAC,sBAAsB;QAC1B,GAAG,CAAC,gBAAgB;QACpB,cAAc,CAAC,QAAQ,CAAC,CAAC;IAE3B,IAAI,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,GAAG,CAAC,cAAc,IAAI,GAAG,CAAC,mBAAmB,IAAI,GAAG,CAAC,mBAAmB,CAAC;IACzG,4EAA4E;IAC5E,wCAAwC;IACxC,IAAI,CAAC,OAAO,IAAI,QAAQ,KAAK,QAAQ,IAAI,aAAa;QAAE,OAAO,GAAG,mBAAmB,CAAC;IACtF,4EAA4E;IAC5E,IAAI,CAAC,OAAO,IAAI,QAAQ,KAAK,YAAY;QAAE,OAAO,GAAG,mBAAmB,CAAC;IAEzE,MAAM,OAAO,GACX,QAAQ,KAAK,QAAQ,IAAI,OAAO,EAAE,QAAQ,CAAC,eAAe,CAAC;QACzD,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE;QACxB,CAAC,CAAC,SAAS,CAAC;IAEhB,OAAO;QACL,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS;QAC9C,QAAQ;QACR,MAAM;QACN,KAAK;QACL,OAAO;QACP,OAAO;QACP,aAAa;QACb,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,cAAc,EAAE,MAAM,CAAC,cAAc;KACtC,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/app/review.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE3C,iFAAiF;AACjF,eAAO,MAAM,MAAM,gCAAgC,CAAC;AAIpD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;qBAEiB;IACjB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACnE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAuC/F"}
1
+ {"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../src/app/review.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAE3C,iFAAiF;AACjF,eAAO,MAAM,MAAM,gCAAgC,CAAC;AAIpD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,KAAK,EAAE,KAAK,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;qBAEiB;IACjB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACnE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,YAAY,CAAC,CAmD/F"}
@@ -33,6 +33,16 @@ export async function reviewPullRequest(job, deps) {
33
33
  if (!diff)
34
34
  throw new Error(`no diff against ${job.baseRef}`);
35
35
  const report = blastRadiusIn(graph, contextDir, diff.files, diff.basis, DEPTH);
36
+ // Same two passes `graft blast --name` runs, in the same order: a reviewer's
37
+ // reason cites area labels, and naming is what gives an area its final one.
38
+ // Both are best-effort — without GRAFT_API_KEY the areas keep their symbol
39
+ // names and the comment still goes out.
40
+ const { nameReport } = await import("../blast/name.js");
41
+ const { note } = await nameReport(graph, report, contextDir);
42
+ if (note)
43
+ log(`${job.owner}/${job.repo}#${job.number}: ${note}`);
44
+ const { attachOwners, diffAuthors } = await import("../blast/owners.js");
45
+ attachOwners(checkout.dir, report, { exclude: diffAuthors(checkout.dir, checkout.base) });
36
46
  // NOTE: once #180 lands, pass `{ root: checkout.dir }` so the collapsed list
37
47
  // quotes the reaching line here too. It is additive, and the App works without it.
38
48
  let body = `${MARKER}\n${markdownReport(report)}`;
@@ -1 +1 @@
1
- {"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/app/review.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,mBAAmB,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAI5D,iFAAiF;AACjF,MAAM,CAAC,MAAM,MAAM,GAAG,6BAA6B,CAAC;AAEpD,MAAM,KAAK,GAAG,CAAC,CAAC;AAqBhB,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,GAAc,EAAE,IAAgB;IACtE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACnC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAE5H,IAAI,CAAC;QACH,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,MAAM,YAAY,CAAC,CAAC;QACxD,MAAM,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAE/B,MAAM,UAAU,GAAG,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC/C,MAAM,KAAK,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAEvD,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC;QACvD,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAE7D,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC/E,6EAA6E;QAC7E,mFAAmF;QACnF,IAAI,IAAI,GAAG,GAAG,MAAM,KAAK,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC;QAElD,IAAI,SAAS,GAAkB,IAAI,CAAC;QACpC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACrE,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YACxD,IAAI,SAAS,EAAE,CAAC;gBACd,IAAI,IAAI,wCAAwC,SAAS,iFAAiF,CAAC;YAC7I,CAAC;QACH,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAC/D,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE,CAAC;IAChG,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,6EAA6E;QAC7E,yBAAyB;QACzB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IACnF,CAAC;YAAS,CAAC;QACT,QAAQ,CAAC,OAAO,EAAE,CAAC;IACrB,CAAC;AACH,CAAC;AAED,oFAAoF;AACpF,KAAK,UAAU,UAAU,CACvB,MAAwC,EACxC,UAAkB,EAClB,IAAY,EACZ,GAAc;IAEd,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,kBAAkB,CAAC,CAAC;IACvD,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IACnD,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IACtE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;IAC3C,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;IAE3C,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,aAAa,CAAC,CAAC,CAAC;IACvD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,SAAS,CAAC;YACpB,UAAU;YACV,SAAS,EAAE,aAAa,CAAC,IAAI,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAChE,MAAM,EAAE,GAAG;YACX,QAAQ,EAAE,GAAG,CAAC,IAAI;YAClB,QAAQ,EAAE,OAAO,GAAG,CAAC,MAAM,EAAE;YAC7B,YAAY,EAAE,aAAa,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC;YAC7C,2EAA2E;YAC3E,0BAA0B;YAC1B,IAAI,EAAE,CAAC,SAAS,CAAC;SAClB,CAAC,CAAC;QACH,OAAO,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,aAAa,CAAC,GAAc,EAAE,IAAY,EAAE,KAAa,EAAE,IAAgB;IACxF,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,wBAAwB,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACtE,MAAM,IAAI,GAAG,GAAG,GAAG,UAAU,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,IAAI,WAAW,GAAG,CAAC,MAAM,WAAW,CAAC;IACnF,MAAM,OAAO,GAAG;QACd,aAAa,EAAE,SAAS,KAAK,EAAE;QAC/B,MAAM,EAAE,6BAA6B;QACrC,cAAc,EAAE,kBAAkB;QAClC,YAAY,EAAE,WAAW;KAC1B,CAAC;IAEF,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9D,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,GAAG,UAAU,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,IAAI,oBAAoB,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE;QAClH,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;QACnC,OAAO;QACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC;KAC/B,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,CAAC,MAAM,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACpF,OAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,CAA2B,CAAC,QAAQ,IAAI,IAAI,CAAC;AACtE,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,OAA+B,EAAE,SAAgB;IACxF,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,sBAAsB,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QAC9E,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAyC,CAAC;QACnF,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3D,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG;YAAE,OAAO,IAAI,CAAC;IACtC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/app/review.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"blast-cli.d.ts","sourceRoot":"","sources":["../../src/blast/blast-cli.ts"],"names":[],"mappings":"AAeA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;AAEnE,MAAM,WAAW,eAAe;IAC9B,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;oFACgF;IAChF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;6DAEyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;iFAC6E;IAC7E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAuBD,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA6DvF;AAsCD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAY9C"}
1
+ {"version":3,"file":"blast-cli.d.ts","sourceRoot":"","sources":["../../src/blast/blast-cli.ts"],"names":[],"mappings":"AAeA,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;AAEnE,MAAM,WAAW,eAAe;IAC9B,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;oFACgF;IAChF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;6DAEyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;iFAC6E;IAC7E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mFAAmF;IACnF,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAuBD,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA6DvF;AAcD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAY9C"}
@@ -93,38 +93,14 @@ export async function runBlastCommand(dir, opts) {
93
93
  /**
94
94
  * Name the clusters left on their symbol backstop, then report what it cost.
95
95
  *
96
- * Everything here is best-effort by construction: no key, a spent quota or a
97
- * refused call leaves the backstop labels in place and the command still exits 0,
98
- * because a PR check must not fail over a cosmetic layer.
96
+ * The work lives in `name.ts` so the GitHub App runs the identical pass; all
97
+ * this adds is the `--name:` prefix a CLI note wants.
99
98
  */
100
99
  async function nameClusters(graph, report, contextDir) {
101
- const { applyNames, ChatNamer } = await import("./name.js");
102
- const { resolveConfig } = await import("../ai/providers.js");
103
- const cfg = resolveConfig({ contextDir });
104
- let namer;
105
- if (cfg.chatModel) {
106
- namer = new ChatNamer(cfg.chatModel);
107
- }
108
- else if (cfg.apiKey) {
109
- const { createChatModel } = await import("../ai/llm/factory.js");
110
- namer = new ChatNamer(createChatModel({
111
- provider: cfg.provider, apiKey: cfg.apiKey, model: cfg.model,
112
- baseUrl: cfg.baseUrl, headers: cfg.headers,
113
- }));
114
- }
115
- const stats = await applyNames(graph, report, { namer, contextDir });
116
- if (!namer) {
117
- console.error("• --name: no API key (GRAFT_API_KEY), so areas keep their symbol names");
118
- return;
119
- }
120
- if (stats.error)
121
- console.error(`• --name: naming failed (${stats.error}) — areas keep their symbol names`);
122
- else if (stats.named + stats.cached + stats.declined > 0) {
123
- const bits = [`${stats.named} named`, `${stats.cached} cached`];
124
- if (stats.declined > 0)
125
- bits.push(`${stats.declined} left as symbols (mixed)`);
126
- console.error(`• --name: ${bits.join(", ")}`);
127
- }
100
+ const { nameReport } = await import("./name.js");
101
+ const { note } = await nameReport(graph, report, contextDir);
102
+ if (note)
103
+ console.error(`• --name: ${note}`);
128
104
  }
129
105
  /**
130
106
  * What to call the repository in the appbar.