@nanonets/graft 0.23.0 → 0.24.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 (287) hide show
  1. package/README.md +4 -4
  2. package/dist/ai/crux.d.ts +31 -3
  3. package/dist/ai/crux.d.ts.map +1 -1
  4. package/dist/ai/crux.js +88 -10
  5. package/dist/ai/crux.js.map +1 -1
  6. package/dist/ai/llm/openai.d.ts +101 -0
  7. package/dist/ai/llm/openai.d.ts.map +1 -1
  8. package/dist/ai/llm/openai.js +396 -6
  9. package/dist/ai/llm/openai.js.map +1 -1
  10. package/dist/ai/llm/recover-tool.d.ts +2 -0
  11. package/dist/ai/llm/recover-tool.d.ts.map +1 -1
  12. package/dist/ai/llm/recover-tool.js +1 -1
  13. package/dist/ai/llm/recover-tool.js.map +1 -1
  14. package/dist/ai/synthesize.d.ts.map +1 -1
  15. package/dist/ai/synthesize.js +100 -1
  16. package/dist/ai/synthesize.js.map +1 -1
  17. package/dist/claude/format.d.ts +21 -0
  18. package/dist/claude/format.d.ts.map +1 -1
  19. package/dist/claude/format.js +46 -1
  20. package/dist/claude/format.js.map +1 -1
  21. package/dist/claude/hooks.d.ts +5 -9
  22. package/dist/claude/hooks.d.ts.map +1 -1
  23. package/dist/claude/hooks.js +71 -58
  24. package/dist/claude/hooks.js.map +1 -1
  25. package/dist/claude/init.js +3 -3
  26. package/dist/claude/init.js.map +1 -1
  27. package/dist/claude/note-signals.d.ts +28 -0
  28. package/dist/claude/note-signals.d.ts.map +1 -0
  29. package/dist/claude/note-signals.js +325 -0
  30. package/dist/claude/note-signals.js.map +1 -0
  31. package/dist/claude/shim-template.d.ts.map +1 -1
  32. package/dist/claude/shim-template.js +17 -6
  33. package/dist/claude/shim-template.js.map +1 -1
  34. package/dist/claude/skill-template.d.ts.map +1 -1
  35. package/dist/claude/skill-template.js +49 -18
  36. package/dist/claude/skill-template.js.map +1 -1
  37. package/dist/claude/state.d.ts +4 -3
  38. package/dist/claude/state.d.ts.map +1 -1
  39. package/dist/claude/state.js.map +1 -1
  40. package/dist/claude/sync-run.js +1 -1
  41. package/dist/claude/sync-run.js.map +1 -1
  42. package/dist/cli-picker.d.ts +12 -5
  43. package/dist/cli-picker.d.ts.map +1 -1
  44. package/dist/cli-picker.js +24 -8
  45. package/dist/cli-picker.js.map +1 -1
  46. package/dist/cli.d.ts +2 -0
  47. package/dist/cli.d.ts.map +1 -1
  48. package/dist/cli.js +149 -43
  49. package/dist/cli.js.map +1 -1
  50. package/dist/context/batches.d.ts +29 -0
  51. package/dist/context/batches.d.ts.map +1 -0
  52. package/dist/context/batches.js +130 -0
  53. package/dist/context/batches.js.map +1 -0
  54. package/dist/context/build.d.ts +7 -2
  55. package/dist/context/build.d.ts.map +1 -1
  56. package/dist/context/build.js +84 -50
  57. package/dist/context/build.js.map +1 -1
  58. package/dist/context/node-file.d.ts.map +1 -1
  59. package/dist/context/node-file.js +41 -4
  60. package/dist/context/node-file.js.map +1 -1
  61. package/dist/engine.d.ts +2 -0
  62. package/dist/engine.d.ts.map +1 -1
  63. package/dist/engine.js +1 -0
  64. package/dist/engine.js.map +1 -1
  65. package/dist/graph/cards.d.ts.map +1 -1
  66. package/dist/graph/cards.js +9 -4
  67. package/dist/graph/cards.js.map +1 -1
  68. package/dist/graph/enrich.d.ts.map +1 -1
  69. package/dist/graph/enrich.js +8 -3
  70. package/dist/graph/enrich.js.map +1 -1
  71. package/dist/graph/generic.d.ts.map +1 -1
  72. package/dist/graph/generic.js +207 -6
  73. package/dist/graph/generic.js.map +1 -1
  74. package/dist/graph/lsp/client.d.ts +18 -0
  75. package/dist/graph/lsp/client.d.ts.map +1 -1
  76. package/dist/graph/lsp/client.js +40 -2
  77. package/dist/graph/lsp/client.js.map +1 -1
  78. package/dist/graph/lsp/enrich.d.ts.map +1 -1
  79. package/dist/graph/lsp/enrich.js +9 -1
  80. package/dist/graph/lsp/enrich.js.map +1 -1
  81. package/dist/graph/lsp/registry.d.ts +7 -0
  82. package/dist/graph/lsp/registry.d.ts.map +1 -1
  83. package/dist/graph/lsp/registry.js +27 -2
  84. package/dist/graph/lsp/registry.js.map +1 -1
  85. package/dist/graph/queries/gleam.scm +51 -0
  86. package/dist/graph/resolve.d.ts.map +1 -1
  87. package/dist/graph/resolve.js +65 -3
  88. package/dist/graph/resolve.js.map +1 -1
  89. package/dist/graph/workspace-cli.d.ts +2 -0
  90. package/dist/graph/workspace-cli.d.ts.map +1 -1
  91. package/dist/graph/workspace-cli.js +1 -1
  92. package/dist/graph/workspace-cli.js.map +1 -1
  93. package/dist/init-guard.d.ts +11 -0
  94. package/dist/init-guard.d.ts.map +1 -0
  95. package/dist/init-guard.js +21 -0
  96. package/dist/init-guard.js.map +1 -0
  97. package/dist/mcp/tools.d.ts.map +1 -1
  98. package/dist/mcp/tools.js +2 -1
  99. package/dist/mcp/tools.js.map +1 -1
  100. package/dist/notes/branches.d.ts +7 -1
  101. package/dist/notes/branches.d.ts.map +1 -1
  102. package/dist/notes/branches.js +31 -3
  103. package/dist/notes/branches.js.map +1 -1
  104. package/dist/notes/cold-start.d.ts +12 -2
  105. package/dist/notes/cold-start.d.ts.map +1 -1
  106. package/dist/notes/cold-start.js +46 -5
  107. package/dist/notes/cold-start.js.map +1 -1
  108. package/dist/notes/credit.d.ts +37 -0
  109. package/dist/notes/credit.d.ts.map +1 -0
  110. package/dist/notes/credit.js +78 -0
  111. package/dist/notes/credit.js.map +1 -0
  112. package/dist/notes/find-notes.d.ts +17 -0
  113. package/dist/notes/find-notes.d.ts.map +1 -0
  114. package/dist/notes/find-notes.js +48 -0
  115. package/dist/notes/find-notes.js.map +1 -0
  116. package/dist/notes/flatten.d.ts +31 -0
  117. package/dist/notes/flatten.d.ts.map +1 -0
  118. package/dist/notes/flatten.js +73 -0
  119. package/dist/notes/flatten.js.map +1 -0
  120. package/dist/notes/git-facts.d.ts +7 -1
  121. package/dist/notes/git-facts.d.ts.map +1 -1
  122. package/dist/notes/git-facts.js +12 -2
  123. package/dist/notes/git-facts.js.map +1 -1
  124. package/dist/notes/home.d.ts +24 -6
  125. package/dist/notes/home.d.ts.map +1 -1
  126. package/dist/notes/home.js +82 -15
  127. package/dist/notes/home.js.map +1 -1
  128. package/dist/notes/learning-fields.d.ts +102 -0
  129. package/dist/notes/learning-fields.d.ts.map +1 -0
  130. package/dist/notes/learning-fields.js +214 -0
  131. package/dist/notes/learning-fields.js.map +1 -0
  132. package/dist/notes/memory-notes.d.ts +71 -0
  133. package/dist/notes/memory-notes.d.ts.map +1 -0
  134. package/dist/notes/memory-notes.js +239 -0
  135. package/dist/notes/memory-notes.js.map +1 -0
  136. package/dist/notes/note-gate.d.ts +42 -0
  137. package/dist/notes/note-gate.d.ts.map +1 -0
  138. package/dist/notes/note-gate.js +181 -0
  139. package/dist/notes/note-gate.js.map +1 -0
  140. package/dist/notes/notes.d.ts +29 -77
  141. package/dist/notes/notes.d.ts.map +1 -1
  142. package/dist/notes/notes.js +69 -228
  143. package/dist/notes/notes.js.map +1 -1
  144. package/dist/notes/pr-reviews.d.ts +35 -7
  145. package/dist/notes/pr-reviews.d.ts.map +1 -1
  146. package/dist/notes/pr-reviews.js +156 -46
  147. package/dist/notes/pr-reviews.js.map +1 -1
  148. package/dist/notes/secrets.d.ts +28 -0
  149. package/dist/notes/secrets.d.ts.map +1 -0
  150. package/dist/notes/secrets.js +362 -0
  151. package/dist/notes/secrets.js.map +1 -0
  152. package/dist/notes/session-cost.d.ts +2 -0
  153. package/dist/notes/session-cost.d.ts.map +1 -1
  154. package/dist/notes/session-cost.js +8 -3
  155. package/dist/notes/session-cost.js.map +1 -1
  156. package/dist/notes/targets.d.ts +37 -0
  157. package/dist/notes/targets.d.ts.map +1 -0
  158. package/dist/notes/targets.js +108 -0
  159. package/dist/notes/targets.js.map +1 -0
  160. package/dist/notes/team-check.d.ts +22 -0
  161. package/dist/notes/team-check.d.ts.map +1 -0
  162. package/dist/notes/team-check.js +130 -0
  163. package/dist/notes/team-check.js.map +1 -0
  164. package/dist/notes/trail-home.d.ts +3 -0
  165. package/dist/notes/trail-home.d.ts.map +1 -0
  166. package/dist/notes/trail-home.js +12 -0
  167. package/dist/notes/trail-home.js.map +1 -0
  168. package/dist/search/grep-cli.d.ts +5 -2
  169. package/dist/search/grep-cli.d.ts.map +1 -1
  170. package/dist/search/grep-cli.js +11 -4
  171. package/dist/search/grep-cli.js.map +1 -1
  172. package/dist/search/ignored-code.d.ts +9 -0
  173. package/dist/search/ignored-code.d.ts.map +1 -0
  174. package/dist/search/ignored-code.js +73 -0
  175. package/dist/search/ignored-code.js.map +1 -0
  176. package/dist/skills/answers-prompt.d.ts +13 -0
  177. package/dist/skills/answers-prompt.d.ts.map +1 -0
  178. package/dist/skills/answers-prompt.js +83 -0
  179. package/dist/skills/answers-prompt.js.map +1 -0
  180. package/dist/skills/never-save.d.ts +5 -0
  181. package/dist/skills/never-save.d.ts.map +1 -0
  182. package/dist/skills/never-save.js +158 -0
  183. package/dist/skills/never-save.js.map +1 -0
  184. package/dist/skills/params.d.ts +39 -0
  185. package/dist/skills/params.d.ts.map +1 -0
  186. package/dist/skills/params.js +275 -0
  187. package/dist/skills/params.js.map +1 -0
  188. package/dist/skills/ran-less.d.ts +5 -0
  189. package/dist/skills/ran-less.d.ts.map +1 -0
  190. package/dist/skills/ran-less.js +51 -0
  191. package/dist/skills/ran-less.js.map +1 -0
  192. package/dist/skills/risk-delta.d.ts +32 -0
  193. package/dist/skills/risk-delta.d.ts.map +1 -0
  194. package/dist/skills/risk-delta.js +56 -0
  195. package/dist/skills/risk-delta.js.map +1 -0
  196. package/dist/skills/risk.d.ts +73 -0
  197. package/dist/skills/risk.d.ts.map +1 -0
  198. package/dist/skills/risk.js +396 -0
  199. package/dist/skills/risk.js.map +1 -0
  200. package/dist/skills/types.d.ts +422 -0
  201. package/dist/skills/types.d.ts.map +1 -0
  202. package/dist/skills/types.js +2 -0
  203. package/dist/skills/types.js.map +1 -0
  204. package/dist/telemetry/contract.d.ts.map +1 -1
  205. package/dist/telemetry/contract.js +8 -6
  206. package/dist/telemetry/contract.js.map +1 -1
  207. package/dist/telemetry/notice.d.ts.map +1 -1
  208. package/dist/telemetry/notice.js +3 -1
  209. package/dist/telemetry/notice.js.map +1 -1
  210. package/dist/trace/check-reads.d.ts +36 -0
  211. package/dist/trace/check-reads.d.ts.map +1 -0
  212. package/dist/trace/check-reads.js +57 -0
  213. package/dist/trace/check-reads.js.map +1 -0
  214. package/dist/trace/host.d.ts +40 -0
  215. package/dist/trace/host.d.ts.map +1 -0
  216. package/dist/trace/host.js +84 -0
  217. package/dist/trace/host.js.map +1 -0
  218. package/dist/trace/redact.d.ts +8 -0
  219. package/dist/trace/redact.d.ts.map +1 -0
  220. package/dist/trace/redact.js +63 -0
  221. package/dist/trace/redact.js.map +1 -0
  222. package/dist/trace/seen-cache.d.ts +9 -0
  223. package/dist/trace/seen-cache.d.ts.map +1 -0
  224. package/dist/trace/seen-cache.js +46 -0
  225. package/dist/trace/seen-cache.js.map +1 -0
  226. package/dist/trace/shell-scan.d.ts +52 -0
  227. package/dist/trace/shell-scan.d.ts.map +1 -0
  228. package/dist/trace/shell-scan.js +318 -0
  229. package/dist/trace/shell-scan.js.map +1 -0
  230. package/dist/trace/shell-words.d.ts +91 -0
  231. package/dist/trace/shell-words.d.ts.map +1 -0
  232. package/dist/trace/shell-words.js +558 -0
  233. package/dist/trace/shell-words.js.map +1 -0
  234. package/dist/trace/shell.d.ts +91 -0
  235. package/dist/trace/shell.d.ts.map +1 -0
  236. package/dist/trace/shell.js +435 -0
  237. package/dist/trace/shell.js.map +1 -0
  238. package/dist/trace/state.d.ts +27 -0
  239. package/dist/trace/state.d.ts.map +1 -0
  240. package/dist/trace/state.js +98 -0
  241. package/dist/trace/state.js.map +1 -0
  242. package/dist/trace/tamper-code.d.ts +9 -0
  243. package/dist/trace/tamper-code.d.ts.map +1 -0
  244. package/dist/trace/tamper-code.js +174 -0
  245. package/dist/trace/tamper-code.js.map +1 -0
  246. package/dist/trace/tamper-git.d.ts +12 -0
  247. package/dist/trace/tamper-git.d.ts.map +1 -0
  248. package/dist/trace/tamper-git.js +77 -0
  249. package/dist/trace/tamper-git.js.map +1 -0
  250. package/dist/trace/types.d.ts +477 -0
  251. package/dist/trace/types.d.ts.map +1 -0
  252. package/dist/trace/types.js +12 -0
  253. package/dist/trace/types.js.map +1 -0
  254. package/dist/trace/walls-glob.d.ts +11 -0
  255. package/dist/trace/walls-glob.d.ts.map +1 -0
  256. package/dist/trace/walls-glob.js +264 -0
  257. package/dist/trace/walls-glob.js.map +1 -0
  258. package/dist/trace/walls-quoted.d.ts +25 -0
  259. package/dist/trace/walls-quoted.d.ts.map +1 -0
  260. package/dist/trace/walls-quoted.js +81 -0
  261. package/dist/trace/walls-quoted.js.map +1 -0
  262. package/dist/upkeep.d.ts +1 -1
  263. package/dist/upkeep.d.ts.map +1 -1
  264. package/dist/upkeep.js +4 -1
  265. package/dist/upkeep.js.map +1 -1
  266. package/dist/util/actions-folder.d.ts +2 -0
  267. package/dist/util/actions-folder.d.ts.map +1 -0
  268. package/dist/util/actions-folder.js +9 -0
  269. package/dist/util/actions-folder.js.map +1 -0
  270. package/dist/util/front-matter.d.ts +31 -4
  271. package/dist/util/front-matter.d.ts.map +1 -1
  272. package/dist/util/front-matter.js +95 -3
  273. package/dist/util/front-matter.js.map +1 -1
  274. package/dist/util/private-file.d.ts +14 -0
  275. package/dist/util/private-file.d.ts.map +1 -0
  276. package/dist/util/private-file.js +82 -0
  277. package/dist/util/private-file.js.map +1 -0
  278. package/dist/util/private-fs.d.ts +25 -0
  279. package/dist/util/private-fs.d.ts.map +1 -0
  280. package/dist/util/private-fs.js +253 -0
  281. package/dist/util/private-fs.js.map +1 -0
  282. package/dist/util/state.d.ts.map +1 -1
  283. package/dist/util/state.js +3 -0
  284. package/dist/util/state.js.map +1 -1
  285. package/dist/viewer/app.js +2 -2
  286. package/package.json +5 -5
  287. package/scripts/run-tests.mjs +14 -2
package/README.md CHANGED
@@ -146,7 +146,7 @@ Without a map, your coding agent starts every task blind. It greps a term, opens
146
146
 
147
147
  The graft map builds that understanding once, and keeps it current:
148
148
 
149
- - **Every file, function and caller.** Parsed with tree-sitter into a graph of symbols and who calls what. Deterministic, no model, no network, 23 languages.
149
+ - **Every file, function and caller.** Parsed with tree-sitter into a graph of symbols and who calls what. Deterministic, no model, no network, 24 languages.
150
150
  - **The right code with every prompt.** In Claude Code, hooks add the matching files and functions to each prompt, and show what depends on a file right after your agent edits it (the "blast radius"). Cursor, Codex and other agents get the same map through MCP tools and their instruction files.
151
151
  - **Always fresh.** Every query checks the working tree first (a few tens of milliseconds when nothing moved) and rebuilds only what changed, so answers describe the code as it is right now, uncommitted edits included.
152
152
  - **Plain files you can read.** Linked markdown nodes your agent opens and greps like any other file. No embeddings, no index to keep warm.
@@ -489,7 +489,7 @@ compiler-grade layer, all `$0` and deterministic (no model, no key):
489
489
  - **Broad**: symbols (functions, classes, methods, types, …) plus name-resolved
490
490
  call edges via a generic tree-sitter extractor, one grammar per language:
491
491
  **Rust, C, C++, C#, Ruby, Scala, Elixir, Solidity,
492
- Dart, Clojure, Nix, Lua**, and **OCaml, Zig** (symbols only for now, no call edges).
492
+ Dart, Clojure, Nix, Lua, Gleam**, and **OCaml, Zig** (symbols only for now, no call edges).
493
493
 
494
494
  - **Compiler-grade edges (opt-in)**: `trail build --lsp` adds precise
495
495
  `lsp_resolved` call edges (member calls the static pass can't type) when a
@@ -498,7 +498,7 @@ compiler-grade layer, all `$0` and deterministic (no model, no key):
498
498
  **gopls** (Go), **pyright** (Python), **typescript-language-server** (TS/JS).
499
499
  It's best-effort: with no server installed the graph is unchanged.
500
500
 
501
- Twenty-three languages, plus Vue single-file components. A file whose language isn't listed is skipped, not
501
+ Twenty-four languages, plus Vue single-file components. A file whose language isn't listed is skipped, not
502
502
  indexed. Adding a broad-tier language is a small contribution; see
503
503
  [CREDITS.md](CREDITS.md) for the folks who added the current set.
504
504
 
@@ -531,7 +531,7 @@ _Summary, sources, links, and your text ship today in markdown nodes. The crux s
531
531
  - **On your machine, no key, no network:** the structural code graph. `trail build` (wiring graph + per-file cards), `trail build --check`, `trail ask`, learnings and `trail check` are deterministic. They never call a model.
532
532
  - **Through your provider key:** the LLM-written parts. `trail build --deep` adds the concept nodes (file summaries + node synthesis) and the per-symbol summaries and cruxes. The graft map 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.)
533
533
  - **Through Trail, only if you connect a workspace:** the learnings in the repos you picked, and the searches and checks that used them. See [What stays on your machine](#what-stays-on-your-machine).
534
- - **Anonymous usage stats:** 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, learnings or error messages. [`TELEMETRY.md`](TELEMETRY.md) is the complete list and `trail telemetry debug` prints exactly what your machine would send. Turn it off with `trail telemetry disable`, `DO_NOT_TRACK=1`, or by unchecking the box in `trail init`; it is off in CI and in any build from source.
534
+ - **Anonymous usage stats:** 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, learnings or error messages. [`TELEMETRY.md`](TELEMETRY.md) is the complete list and `trail telemetry debug` prints exactly what your machine would send. `DO_NOT_TRACK=1` disables both network calls; `trail telemetry disable` or unchecking the box in `trail init` disables only the usage ping. The ping is off in CI and in any build from source.
535
535
 
536
536
  Settings keep their `GRAFT_` names. See [`.env.example`](.env.example) for the full list (model, base URL, graph directory).
537
537
 
package/dist/ai/crux.d.ts CHANGED
@@ -41,15 +41,43 @@ export interface CruxSummarizer {
41
41
  lastMiss?: CruxMiss | null;
42
42
  }
43
43
  /** Why a crux call produced no usable summaries (#235). */
44
- export type CruxMissKind = "empty-toolCalls" | "unparseable" | "truncated" | "empty-parsed";
44
+ export type CruxMissKind = "empty-toolCalls" | "unparseable" | "truncated" | "empty-parsed" | "id-mismatch";
45
45
  export interface CruxMiss {
46
46
  kind: CruxMissKind;
47
47
  finishReason: string | null;
48
+ /** `id-mismatch` only: how many entries came back, and the first one's raw id. */
49
+ returned?: number;
50
+ firstId?: string;
48
51
  }
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;
52
+ /**
53
+ * Classify an empty/unusable crux reply. `null` means at least one usable summary.
54
+ * With `requested`, a summary only counts when its id is one we asked for: enrich
55
+ * looks results up by node id, so a summary under any other id is never applied.
56
+ */
57
+ export declare function classifyCruxMiss(res: ChatResponse, parsed: NodeCrux[], requested?: readonly string[]): CruxMiss | null;
51
58
  /** Per-file error text: miss class + the provider's finish_reason (#235). */
52
59
  export declare function formatCruxMiss(kind: CruxMissKind, finishReason: string | null): string;
60
+ /**
61
+ * The model's text for an `id-mismatch`, kept apart from {@link formatCruxMiss}:
62
+ * the failure gate matches words like "quota" in the error message, and a
63
+ * returned id can carry any source text, so it must never reach the gate.
64
+ */
65
+ export declare function formatCruxMissDetail(miss: CruxMiss | null | undefined): string;
66
+ /**
67
+ * Map an id the model returned onto one of the ids we asked for, or null.
68
+ *
69
+ * Models echo decorated target rows instead of the bare id (#259, #298, #486).
70
+ * Rather than cut the string at a guessed delimiter, every rule compares against
71
+ * the requested ids, so the result is always an id we asked for — never a
72
+ * fragment of a hallucinated one — and no rule assumes which characters an id
73
+ * may contain. In order:
74
+ * 1. exact match;
75
+ * 2. a requested id followed by ` | ` (the row echoed from the id onwards);
76
+ * 3. the same two with a leading `id=` removed;
77
+ * 4. a row ending in ` | id=<requested id>` (the current layout echoed whole).
78
+ * When several requested ids qualify, the longest wins.
79
+ */
80
+ export declare function resolveTargetId(raw: string, requested: readonly string[]): string | null;
53
81
  /** Crux summarizer backed by any {@link ChatModel} via forced tool calling. */
54
82
  export declare class ChatCruxSummarizer implements CruxSummarizer {
55
83
  private model;
@@ -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,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"}
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,GACpB,iBAAiB,GACjB,aAAa,GACb,WAAW,GACX,cAAc,GACd,aAAa,CAAC;AAElB,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAQD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,YAAY,EACjB,MAAM,EAAE,QAAQ,EAAE,EAClB,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,GAC5B,QAAQ,GAAG,IAAI,CAcjB;AAED,6EAA6E;AAC7E,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAMtF;AAKD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAO9E;AAwED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAYxF;AA2CD,+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;CAwB9D"}
package/dist/ai/crux.js CHANGED
@@ -5,13 +5,22 @@ function isTruncatedStop(reason) {
5
5
  const r = reason.toLowerCase();
6
6
  return r === "length" || r === "max_tokens";
7
7
  }
8
- /** Classify an empty/unusable crux reply. `null` means at least one usable summary. */
9
- export function classifyCruxMiss(res, parsed) {
8
+ /**
9
+ * Classify an empty/unusable crux reply. `null` means at least one usable summary.
10
+ * With `requested`, a summary only counts when its id is one we asked for: enrich
11
+ * looks results up by node id, so a summary under any other id is never applied.
12
+ */
13
+ export function classifyCruxMiss(res, parsed, requested) {
10
14
  const finishReason = res.stopReason;
11
- if (parsed.some((p) => p.summary.trim()))
15
+ const wanted = requested ? new Set(requested) : undefined;
16
+ const matched = wanted ? parsed.filter((p) => wanted.has(p.id)) : parsed;
17
+ if (matched.some((p) => p.summary.trim()))
12
18
  return null;
13
19
  if (isTruncatedStop(finishReason))
14
20
  return { kind: "truncated", finishReason };
21
+ if (parsed.length > 0 && matched.length === 0) {
22
+ return { kind: "id-mismatch", finishReason, returned: parsed.length, firstId: parsed[0].id };
23
+ }
15
24
  if (parsed.length > 0)
16
25
  return { kind: "empty-parsed", finishReason };
17
26
  const emptyTools = res.toolCalls.length === 0;
@@ -23,8 +32,26 @@ export function classifyCruxMiss(res, parsed) {
23
32
  /** Per-file error text: miss class + the provider's finish_reason (#235). */
24
33
  export function formatCruxMiss(kind, finishReason) {
25
34
  const fr = finishReason == null || finishReason === "" ? "null" : finishReason;
35
+ if (kind === "id-mismatch") {
36
+ return `model returned summaries but no id matched a requested target [${kind}, finish_reason=${fr}]`;
37
+ }
26
38
  return `model returned no usable symbol summaries [${kind}, finish_reason=${fr}]`;
27
39
  }
40
+ /** Longest echoed id shown in an error; a whole echoed row can carry a long signature. */
41
+ const MAX_SHOWN_ID_CHARS = 200;
42
+ /**
43
+ * The model's text for an `id-mismatch`, kept apart from {@link formatCruxMiss}:
44
+ * the failure gate matches words like "quota" in the error message, and a
45
+ * returned id can carry any source text, so it must never reach the gate.
46
+ */
47
+ export function formatCruxMissDetail(miss) {
48
+ if (miss?.kind !== "id-mismatch" || miss.firstId === undefined)
49
+ return "";
50
+ const id = miss.firstId.length > MAX_SHOWN_ID_CHARS
51
+ ? `${miss.firstId.slice(0, MAX_SHOWN_ID_CHARS)}…`
52
+ : miss.firstId;
53
+ return `first of ${miss.returned ?? 1} returned id(s): ${JSON.stringify(id)}`;
54
+ }
28
55
  const SYSTEM_PROMPT = `You explain code definitions for a code graph that helps engineers navigate a codebase.
29
56
 
30
57
  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.
@@ -63,16 +90,66 @@ function numberLines(source) {
63
90
  .map((line, i) => `${i + 1}\t${line}`)
64
91
  .join("\n");
65
92
  }
93
+ /**
94
+ * `id=` is the LAST field of a target line, so the id ends where the line does.
95
+ * With the id first nothing terminated it, and models asked for the id
96
+ * "verbatim" copied the whole row — `a.cs#Level | variable | lines L58-L58 | sig`
97
+ * — into `id` (#259). {@link resolveTargetId} still repairs echoes of either layout.
98
+ */
66
99
  function userContent(input) {
67
100
  const targets = input.nodes
68
- .map((n) => `- id=${n.id} | ${n.kind} | lines L${n.startLine}-L${n.endLine}` +
69
- (n.signature ? ` | ${n.signature}` : ""))
101
+ .map((n) => `- ${n.kind} | lines L${n.startLine}-L${n.endLine}` +
102
+ (n.signature ? ` | ${n.signature}` : "") +
103
+ ` | id=${n.id}`)
70
104
  .join("\n");
71
105
  const n = input.nodes.length;
72
106
  return `FILE: ${input.path}\n\n${numberLines(input.source)}\n\nTARGETS (${n} — return all ${n}, one entry per id):\n${targets}`;
73
107
  }
74
- /** Normalize the tool's parsed argument object into a {@link NodeCrux} list. */
75
- function parseResults(obj) {
108
+ /** The longest requested id `test` accepts, or null. */
109
+ function longestMatch(requested, test) {
110
+ let best = null;
111
+ for (const id of requested)
112
+ if (test(id) && (best === null || id.length > best.length))
113
+ best = id;
114
+ return best;
115
+ }
116
+ /**
117
+ * Map an id the model returned onto one of the ids we asked for, or null.
118
+ *
119
+ * Models echo decorated target rows instead of the bare id (#259, #298, #486).
120
+ * Rather than cut the string at a guessed delimiter, every rule compares against
121
+ * the requested ids, so the result is always an id we asked for — never a
122
+ * fragment of a hallucinated one — and no rule assumes which characters an id
123
+ * may contain. In order:
124
+ * 1. exact match;
125
+ * 2. a requested id followed by ` | ` (the row echoed from the id onwards);
126
+ * 3. the same two with a leading `id=` removed;
127
+ * 4. a row ending in ` | id=<requested id>` (the current layout echoed whole).
128
+ * When several requested ids qualify, the longest wins.
129
+ */
130
+ export function resolveTargetId(raw, requested) {
131
+ const id = raw.trim();
132
+ if (requested.includes(id))
133
+ return id;
134
+ const echoed = longestMatch(requested, (r) => id.startsWith(`${r} | `));
135
+ if (echoed)
136
+ return echoed;
137
+ if (id.startsWith("id=")) {
138
+ const bare = id.slice(3).trim();
139
+ if (requested.includes(bare))
140
+ return bare;
141
+ const bareEchoed = longestMatch(requested, (r) => bare.startsWith(`${r} | `));
142
+ if (bareEchoed)
143
+ return bareEchoed;
144
+ }
145
+ return longestMatch(requested, (r) => id.endsWith(` | id=${r}`));
146
+ }
147
+ /**
148
+ * Normalize the tool's parsed argument object into a {@link NodeCrux} list. Ids
149
+ * are resolved against `requested`; one that matches nothing keeps its raw text
150
+ * so {@link classifyCruxMiss} can report what the model actually sent.
151
+ */
152
+ function parseResults(obj, requested) {
76
153
  if (!obj || !Array.isArray(obj.symbols))
77
154
  return [];
78
155
  const num = (v) => (typeof v === "number" && Number.isFinite(v) ? Math.trunc(v) : 0);
@@ -80,7 +157,7 @@ function parseResults(obj) {
80
157
  .map((s) => s)
81
158
  .filter((s) => typeof s.id === "string")
82
159
  .map((s) => ({
83
- id: s.id,
160
+ id: resolveTargetId(s.id, requested) ?? s.id,
84
161
  summary: typeof s.summary === "string" ? s.summary.trim() : "",
85
162
  crux_start: num(s.crux_start),
86
163
  crux_end: num(s.crux_end),
@@ -133,8 +210,9 @@ export class ChatCruxSummarizer {
133
210
  { role: "user", content: userContent(input) },
134
211
  ],
135
212
  });
136
- const parsed = parseResults(argsFromResponse(res));
137
- this.lastMiss = classifyCruxMiss(res, parsed);
213
+ const requested = input.nodes.map((n) => n.id);
214
+ const parsed = parseResults(argsFromResponse(res), requested);
215
+ this.lastMiss = classifyCruxMiss(res, parsed, requested);
138
216
  return parsed;
139
217
  }
140
218
  }
@@ -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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"}
@@ -8,6 +8,16 @@
8
8
  * is forwarded, cache breakpoints become `cache_control` content parts (which
9
9
  * OpenRouter forwards to Anthropic), and cached tokens are subtracted out of the
10
10
  * input count so {@link Usage.input} is uncached-only.
11
+ *
12
+ * Past that, everything here is tolerance rather than preference. An
13
+ * OpenAI-compatible endpoint is a gateway whose own upstream calls can fail
14
+ * while the HTTP status stays 200, and whose support for a forced `tool_choice`
15
+ * — the one structured-output mechanism graft can rely on across providers —
16
+ * ranges from exact to none. Each way that goes wrong gets its own narrow
17
+ * recovery: {@link ProviderResponseError} for a 200 that is not a completion,
18
+ * and a bounded rung ladder in {@link OpenAIChatModel.structured} for a
19
+ * structured reply the endpoint answers some other way. None of it changes the
20
+ * bytes on the wire for an endpoint that behaves.
11
21
  */
12
22
  import OpenAI from "openai";
13
23
  import type { ChatModel, ChatRequest, ChatResponse } from "./types.js";
@@ -21,13 +31,96 @@ export interface OpenAIChatModelOptions {
21
31
  headers?: Record<string, string>;
22
32
  /** Inject a pre-built client (tests pass a stub; production omits it). */
23
33
  client?: OpenAI;
34
+ /** Wait between retries of a 200-that-is-an-error (tests pass a no-op). */
35
+ sleep?: (ms: number) => Promise<void>;
36
+ }
37
+ /**
38
+ * A 200 that is not a completion.
39
+ *
40
+ * A proxy in front of a model can answer HTTP 200 with
41
+ * `{"error": {...}}` and no `choices` when the upstream call fails, because the
42
+ * failure belongs to a server the proxy itself did not talk to. The SDK's retry
43
+ * policy only ever sees the status, so it returns that body as a success, and
44
+ * the first `choices[0]` used to turn it into a TypeError naming nothing a user
45
+ * could act on. Retryable by construction — the request was never served — and
46
+ * carrying the provider's own message and code so the failure that does reach
47
+ * the caller says what the endpoint said.
48
+ */
49
+ export declare class ProviderResponseError extends Error {
50
+ /** The provider's own error code, when the body carried one. */
51
+ readonly code?: string | number | undefined;
52
+ /** The status the provider actually sent. 200: that is the whole surprise. */
53
+ readonly status = 200;
54
+ /** Always true — the same request can succeed on a later attempt. */
55
+ readonly retryable = true;
56
+ constructor(message: string,
57
+ /** The provider's own error code, when the body carried one. */
58
+ code?: string | number | undefined);
24
59
  }
25
60
  export declare class OpenAIChatModel implements ChatModel {
26
61
  readonly label: string;
27
62
  private client;
28
63
  private model;
64
+ private sleep;
65
+ /** Key into {@link forcedToolChoiceIgnored}: one entry per endpoint + model. */
66
+ private choiceKey;
67
+ private forcedIgnored;
29
68
  constructor(opts: OpenAIChatModelOptions);
30
69
  create(req: ChatRequest): Promise<ChatResponse>;
70
+ /**
71
+ * A structured reply, however the endpoint is willing to produce one.
72
+ *
73
+ * A forced `tool_choice` is the only structured-output mechanism graft can
74
+ * rely on across providers, and it is the least portable corner of the
75
+ * OpenAI-compatible spec: an endpoint can reject the object form (handled one
76
+ * layer down), answer 200 with an error object, or quietly answer in prose.
77
+ * So walk a bounded ladder — the object form, then `"required"`, then
78
+ * `"auto"` with the tool named in the prompt — and take the payload from
79
+ * `content` if that is where it landed. `"required"` only stands in for the
80
+ * object form when one tool was offered, the same rule the 400 fallback
81
+ * applies: with several tools it would let the model pick freely rather than
82
+ * honour the caller's choice.
83
+ *
84
+ * An endpoint that honours the forced form never sees rung two — the first
85
+ * attempt answers the question and the ladder ends.
86
+ *
87
+ * An errored body is a weaker signal than a served-but-wrong reply, since it
88
+ * may belong to an upstream that a retry would reach, so it never downgrades
89
+ * on its own: it is counted instead. A call where every forced-family rung
90
+ * failed that way and the final "auto" rung then answered is a rescue, and
91
+ * the second rescue with no successful forced call in between is the
92
+ * endpoint's pattern, not its upstream's — that, and only that, switches
93
+ * later calls straight to "auto".
94
+ */
95
+ private structured;
96
+ /** One rung: the forced object form, its equivalent string form, or "auto" plus a prompt. */
97
+ private attempt;
98
+ /** Did the reply carry the payload the caller forced a tool for? */
99
+ private delivered;
100
+ /**
101
+ * One more rescued call for this endpoint + model. When the count reaches
102
+ * the threshold with no successful forced call in between, the endpoint is
103
+ * marked the same way a served-but-wrong reply marks it.
104
+ */
105
+ private noteForcedRescue;
106
+ /**
107
+ * Remember, for this process, that the endpoint did not answer a forced
108
+ * `tool_choice` with a tool call, so later requests go straight to the rung
109
+ * that works. Logged once per endpoint + model — the set is shared by every
110
+ * instance, so a second adapter for the same endpoint never repeats it: it
111
+ * changes the bytes on the wire, which is exactly what someone reading a
112
+ * failing build needs told.
113
+ */
114
+ private rememberForcedIgnored;
115
+ /**
116
+ * One completion, with the transport's retry policy extended to a 200 that
117
+ * carried an error instead of one. The SDK retries 429, 5xx and connection
118
+ * failures but never a successful status, and that body is the endpoint
119
+ * reporting a failed upstream call — the same judgement, so the same
120
+ * `GRAFT_LLM_RETRIES` budget and backoff apply, and the typed error is what
121
+ * reaches the caller once that budget is spent.
122
+ */
123
+ private complete;
31
124
  /**
32
125
  * Wraps `chat.completions.create` with a narrow, safe fallback: if the
33
126
  * server rejects an object-form `tool_choice` and exactly one tool was
@@ -39,6 +132,14 @@ export declare class OpenAIChatModel implements ChatModel {
39
132
  * automatically.
40
133
  */
41
134
  private createChatCompletion;
135
+ /**
136
+ * Normalize provider message content to the plain text representation
137
+ * expected by the rest of Graft. Some OpenAI-compatible providers
138
+ * (observed with GLM-5.3 hosted on Mistral's platform) return content as
139
+ * structured content parts, e.g. `[{ type: "text", text: "..." }]`,
140
+ * instead of a plain string — this path in Graft assumed the latter.
141
+ */
142
+ private static contentToText;
42
143
  private fromResponse;
43
144
  }
44
145
  //# sourceMappingURL=openai.d.ts.map
@@ -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;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"}
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/ai/llm/openai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAsC,MAAM,YAAY,CAAC;AAsD3G,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;IAChB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAuGD;;;;;;;;;;;GAWG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAO5C,gEAAgE;IAChE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM;IAPjC,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,OAAO;IACtB,qEAAqE;IACrE,QAAQ,CAAC,SAAS,QAAQ;gBAExB,OAAO,EAAE,MAAM;IACf,gEAAgE;IACvD,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,YAAA;CAKlC;AAiGD,qBAAa,eAAgB,YAAW,SAAS;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,KAAK,CAAgC;IAC7C,gFAAgF;IAChF,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,aAAa,CAAU;gBAEnB,IAAI,EAAE,sBAAsB;IAgBlC,MAAM,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA6BrD;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;YACW,UAAU;IA2CxB,6FAA6F;IAC7F,OAAO,CAAC,OAAO;IAMf,oEAAoE;IACpE,OAAO,CAAC,SAAS;IAKjB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAOxB;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB;IAS7B;;;;;;;OAOG;YACW,QAAQ;IAgBtB;;;;;;;;;OASG;YACW,oBAAoB;IAkClC;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;IAe5B,OAAO,CAAC,YAAY;CAgDrB"}