vemora 0.1.0-alpha.15

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 (254) hide show
  1. package/README.md +851 -0
  2. package/dist/cli.d.ts +16 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +682 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/ask.d.ts +14 -0
  7. package/dist/commands/ask.d.ts.map +1 -0
  8. package/dist/commands/ask.js +137 -0
  9. package/dist/commands/ask.js.map +1 -0
  10. package/dist/commands/audit.d.ts +17 -0
  11. package/dist/commands/audit.d.ts.map +1 -0
  12. package/dist/commands/audit.js +398 -0
  13. package/dist/commands/audit.js.map +1 -0
  14. package/dist/commands/brief.d.ts +16 -0
  15. package/dist/commands/brief.d.ts.map +1 -0
  16. package/dist/commands/brief.js +84 -0
  17. package/dist/commands/brief.js.map +1 -0
  18. package/dist/commands/chat.d.ts +7 -0
  19. package/dist/commands/chat.d.ts.map +1 -0
  20. package/dist/commands/chat.js +155 -0
  21. package/dist/commands/chat.js.map +1 -0
  22. package/dist/commands/context.d.ts +63 -0
  23. package/dist/commands/context.d.ts.map +1 -0
  24. package/dist/commands/context.js +794 -0
  25. package/dist/commands/context.js.map +1 -0
  26. package/dist/commands/dead-code.d.ts +15 -0
  27. package/dist/commands/dead-code.d.ts.map +1 -0
  28. package/dist/commands/dead-code.js +206 -0
  29. package/dist/commands/dead-code.js.map +1 -0
  30. package/dist/commands/deps.d.ts +20 -0
  31. package/dist/commands/deps.d.ts.map +1 -0
  32. package/dist/commands/deps.js +138 -0
  33. package/dist/commands/deps.js.map +1 -0
  34. package/dist/commands/focus.d.ts +8 -0
  35. package/dist/commands/focus.d.ts.map +1 -0
  36. package/dist/commands/focus.js +310 -0
  37. package/dist/commands/focus.js.map +1 -0
  38. package/dist/commands/index.d.ts +10 -0
  39. package/dist/commands/index.d.ts.map +1 -0
  40. package/dist/commands/index.js +366 -0
  41. package/dist/commands/index.js.map +1 -0
  42. package/dist/commands/init-agent.d.ts +23 -0
  43. package/dist/commands/init-agent.d.ts.map +1 -0
  44. package/dist/commands/init-agent.js +384 -0
  45. package/dist/commands/init-agent.js.map +1 -0
  46. package/dist/commands/init.d.ts +2 -0
  47. package/dist/commands/init.d.ts.map +1 -0
  48. package/dist/commands/init.js +122 -0
  49. package/dist/commands/init.js.map +1 -0
  50. package/dist/commands/knowledge.d.ts +14 -0
  51. package/dist/commands/knowledge.d.ts.map +1 -0
  52. package/dist/commands/knowledge.js +115 -0
  53. package/dist/commands/knowledge.js.map +1 -0
  54. package/dist/commands/plan.d.ts +24 -0
  55. package/dist/commands/plan.d.ts.map +1 -0
  56. package/dist/commands/plan.js +867 -0
  57. package/dist/commands/plan.js.map +1 -0
  58. package/dist/commands/query.d.ts +39 -0
  59. package/dist/commands/query.d.ts.map +1 -0
  60. package/dist/commands/query.js +392 -0
  61. package/dist/commands/query.js.map +1 -0
  62. package/dist/commands/remember.d.ts +11 -0
  63. package/dist/commands/remember.d.ts.map +1 -0
  64. package/dist/commands/remember.js +267 -0
  65. package/dist/commands/remember.js.map +1 -0
  66. package/dist/commands/report.d.ts +10 -0
  67. package/dist/commands/report.d.ts.map +1 -0
  68. package/dist/commands/report.js +243 -0
  69. package/dist/commands/report.js.map +1 -0
  70. package/dist/commands/status.d.ts +2 -0
  71. package/dist/commands/status.d.ts.map +1 -0
  72. package/dist/commands/status.js +127 -0
  73. package/dist/commands/status.js.map +1 -0
  74. package/dist/commands/summarize.d.ts +14 -0
  75. package/dist/commands/summarize.d.ts.map +1 -0
  76. package/dist/commands/summarize.js +170 -0
  77. package/dist/commands/summarize.js.map +1 -0
  78. package/dist/commands/triage.d.ts +33 -0
  79. package/dist/commands/triage.d.ts.map +1 -0
  80. package/dist/commands/triage.js +419 -0
  81. package/dist/commands/triage.js.map +1 -0
  82. package/dist/commands/usages.d.ts +14 -0
  83. package/dist/commands/usages.d.ts.map +1 -0
  84. package/dist/commands/usages.js +236 -0
  85. package/dist/commands/usages.js.map +1 -0
  86. package/dist/core/config.d.ts +35 -0
  87. package/dist/core/config.d.ts.map +1 -0
  88. package/dist/core/config.js +159 -0
  89. package/dist/core/config.js.map +1 -0
  90. package/dist/core/types.d.ts +287 -0
  91. package/dist/core/types.d.ts.map +1 -0
  92. package/dist/core/types.js +4 -0
  93. package/dist/core/types.js.map +1 -0
  94. package/dist/embeddings/factory.d.ts +9 -0
  95. package/dist/embeddings/factory.d.ts.map +1 -0
  96. package/dist/embeddings/factory.js +26 -0
  97. package/dist/embeddings/factory.js.map +1 -0
  98. package/dist/embeddings/noop.d.ts +17 -0
  99. package/dist/embeddings/noop.d.ts.map +1 -0
  100. package/dist/embeddings/noop.js +22 -0
  101. package/dist/embeddings/noop.js.map +1 -0
  102. package/dist/embeddings/ollama.d.ts +11 -0
  103. package/dist/embeddings/ollama.d.ts.map +1 -0
  104. package/dist/embeddings/ollama.js +49 -0
  105. package/dist/embeddings/ollama.js.map +1 -0
  106. package/dist/embeddings/openai.d.ts +10 -0
  107. package/dist/embeddings/openai.d.ts.map +1 -0
  108. package/dist/embeddings/openai.js +67 -0
  109. package/dist/embeddings/openai.js.map +1 -0
  110. package/dist/embeddings/provider.d.ts +19 -0
  111. package/dist/embeddings/provider.d.ts.map +1 -0
  112. package/dist/embeddings/provider.js +3 -0
  113. package/dist/embeddings/provider.js.map +1 -0
  114. package/dist/indexer/callgraph.d.ts +16 -0
  115. package/dist/indexer/callgraph.d.ts.map +1 -0
  116. package/dist/indexer/callgraph.js +154 -0
  117. package/dist/indexer/callgraph.js.map +1 -0
  118. package/dist/indexer/chunkBySlidingWindow.d.ts +6 -0
  119. package/dist/indexer/chunkBySlidingWindow.d.ts.map +1 -0
  120. package/dist/indexer/chunkBySlidingWindow.js +30 -0
  121. package/dist/indexer/chunkBySlidingWindow.js.map +1 -0
  122. package/dist/indexer/chunkBySymbols.d.ts +7 -0
  123. package/dist/indexer/chunkBySymbols.d.ts.map +1 -0
  124. package/dist/indexer/chunkBySymbols.js +57 -0
  125. package/dist/indexer/chunkBySymbols.js.map +1 -0
  126. package/dist/indexer/chunker.d.ts +15 -0
  127. package/dist/indexer/chunker.d.ts.map +1 -0
  128. package/dist/indexer/chunker.js +26 -0
  129. package/dist/indexer/chunker.js.map +1 -0
  130. package/dist/indexer/classHeader.d.ts +7 -0
  131. package/dist/indexer/classHeader.d.ts.map +1 -0
  132. package/dist/indexer/classHeader.js +37 -0
  133. package/dist/indexer/classHeader.js.map +1 -0
  134. package/dist/indexer/deps.d.ts +66 -0
  135. package/dist/indexer/deps.d.ts.map +1 -0
  136. package/dist/indexer/deps.js +412 -0
  137. package/dist/indexer/deps.js.map +1 -0
  138. package/dist/indexer/hasher.d.ts +17 -0
  139. package/dist/indexer/hasher.d.ts.map +1 -0
  140. package/dist/indexer/hasher.js +38 -0
  141. package/dist/indexer/hasher.js.map +1 -0
  142. package/dist/indexer/parser.d.ts +18 -0
  143. package/dist/indexer/parser.d.ts.map +1 -0
  144. package/dist/indexer/parser.js +355 -0
  145. package/dist/indexer/parser.js.map +1 -0
  146. package/dist/indexer/scanner.d.ts +18 -0
  147. package/dist/indexer/scanner.d.ts.map +1 -0
  148. package/dist/indexer/scanner.js +37 -0
  149. package/dist/indexer/scanner.js.map +1 -0
  150. package/dist/indexer/strategy.d.ts +11 -0
  151. package/dist/indexer/strategy.d.ts.map +1 -0
  152. package/dist/indexer/strategy.js +15 -0
  153. package/dist/indexer/strategy.js.map +1 -0
  154. package/dist/indexer/tests.d.ts +15 -0
  155. package/dist/indexer/tests.d.ts.map +1 -0
  156. package/dist/indexer/tests.js +68 -0
  157. package/dist/indexer/tests.js.map +1 -0
  158. package/dist/indexer/todos.d.ts +9 -0
  159. package/dist/indexer/todos.d.ts.map +1 -0
  160. package/dist/indexer/todos.js +29 -0
  161. package/dist/indexer/todos.js.map +1 -0
  162. package/dist/llm/anthropic.d.ts +8 -0
  163. package/dist/llm/anthropic.d.ts.map +1 -0
  164. package/dist/llm/anthropic.js +76 -0
  165. package/dist/llm/anthropic.js.map +1 -0
  166. package/dist/llm/claude-code.d.ts +37 -0
  167. package/dist/llm/claude-code.d.ts.map +1 -0
  168. package/dist/llm/claude-code.js +97 -0
  169. package/dist/llm/claude-code.js.map +1 -0
  170. package/dist/llm/factory.d.ts +7 -0
  171. package/dist/llm/factory.d.ts.map +1 -0
  172. package/dist/llm/factory.js +47 -0
  173. package/dist/llm/factory.js.map +1 -0
  174. package/dist/llm/ollama.d.ts +8 -0
  175. package/dist/llm/ollama.d.ts.map +1 -0
  176. package/dist/llm/ollama.js +83 -0
  177. package/dist/llm/ollama.js.map +1 -0
  178. package/dist/llm/openai.d.ts +8 -0
  179. package/dist/llm/openai.d.ts.map +1 -0
  180. package/dist/llm/openai.js +68 -0
  181. package/dist/llm/openai.js.map +1 -0
  182. package/dist/llm/provider.d.ts +35 -0
  183. package/dist/llm/provider.d.ts.map +1 -0
  184. package/dist/llm/provider.js +3 -0
  185. package/dist/llm/provider.js.map +1 -0
  186. package/dist/search/bm25.d.ts +3 -0
  187. package/dist/search/bm25.d.ts.map +1 -0
  188. package/dist/search/bm25.js +104 -0
  189. package/dist/search/bm25.js.map +1 -0
  190. package/dist/search/formatter.d.ts +43 -0
  191. package/dist/search/formatter.d.ts.map +1 -0
  192. package/dist/search/formatter.js +208 -0
  193. package/dist/search/formatter.js.map +1 -0
  194. package/dist/search/hybrid.d.ts +10 -0
  195. package/dist/search/hybrid.d.ts.map +1 -0
  196. package/dist/search/hybrid.js +53 -0
  197. package/dist/search/hybrid.js.map +1 -0
  198. package/dist/search/merge.d.ts +33 -0
  199. package/dist/search/merge.d.ts.map +1 -0
  200. package/dist/search/merge.js +158 -0
  201. package/dist/search/merge.js.map +1 -0
  202. package/dist/search/mmr.d.ts +23 -0
  203. package/dist/search/mmr.d.ts.map +1 -0
  204. package/dist/search/mmr.js +95 -0
  205. package/dist/search/mmr.js.map +1 -0
  206. package/dist/search/rerank.d.ts +12 -0
  207. package/dist/search/rerank.d.ts.map +1 -0
  208. package/dist/search/rerank.js +113 -0
  209. package/dist/search/rerank.js.map +1 -0
  210. package/dist/search/signature.d.ts +42 -0
  211. package/dist/search/signature.d.ts.map +1 -0
  212. package/dist/search/signature.js +112 -0
  213. package/dist/search/signature.js.map +1 -0
  214. package/dist/search/vector.d.ts +41 -0
  215. package/dist/search/vector.d.ts.map +1 -0
  216. package/dist/search/vector.js +185 -0
  217. package/dist/search/vector.js.map +1 -0
  218. package/dist/storage/cache.d.ts +30 -0
  219. package/dist/storage/cache.d.ts.map +1 -0
  220. package/dist/storage/cache.js +160 -0
  221. package/dist/storage/cache.js.map +1 -0
  222. package/dist/storage/knowledge.d.ts +23 -0
  223. package/dist/storage/knowledge.d.ts.map +1 -0
  224. package/dist/storage/knowledge.js +81 -0
  225. package/dist/storage/knowledge.js.map +1 -0
  226. package/dist/storage/planSession.d.ts +39 -0
  227. package/dist/storage/planSession.d.ts.map +1 -0
  228. package/dist/storage/planSession.js +78 -0
  229. package/dist/storage/planSession.js.map +1 -0
  230. package/dist/storage/repository.d.ts +27 -0
  231. package/dist/storage/repository.d.ts.map +1 -0
  232. package/dist/storage/repository.js +95 -0
  233. package/dist/storage/repository.js.map +1 -0
  234. package/dist/storage/session.d.ts +38 -0
  235. package/dist/storage/session.d.ts.map +1 -0
  236. package/dist/storage/session.js +100 -0
  237. package/dist/storage/session.js.map +1 -0
  238. package/dist/storage/summaries.d.ts +19 -0
  239. package/dist/storage/summaries.d.ts.map +1 -0
  240. package/dist/storage/summaries.js +66 -0
  241. package/dist/storage/summaries.js.map +1 -0
  242. package/dist/storage/usage.d.ts +39 -0
  243. package/dist/storage/usage.d.ts.map +1 -0
  244. package/dist/storage/usage.js +55 -0
  245. package/dist/storage/usage.js.map +1 -0
  246. package/dist/utils/git.d.ts +20 -0
  247. package/dist/utils/git.d.ts.map +1 -0
  248. package/dist/utils/git.js +49 -0
  249. package/dist/utils/git.js.map +1 -0
  250. package/dist/utils/tokenizer.d.ts +32 -0
  251. package/dist/utils/tokenizer.d.ts.map +1 -0
  252. package/dist/utils/tokenizer.js +66 -0
  253. package/dist/utils/tokenizer.js.map +1 -0
  254. package/package.json +71 -0
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AnthropicProvider = void 0;
4
+ class AnthropicProvider {
5
+ name = "anthropic";
6
+ // biome-ignore lint/suspicious/noExplicitAny: @anthropic-ai/sdk is an optional peer dependency
7
+ client;
8
+ constructor(apiKey) {
9
+ let Anthropic;
10
+ try {
11
+ // biome-ignore lint/suspicious/noExplicitAny: optional peer dependency
12
+ Anthropic = require("@anthropic-ai/sdk").default ?? require("@anthropic-ai/sdk");
13
+ }
14
+ catch {
15
+ throw new Error('Package "@anthropic-ai/sdk" is not installed. Run: npm install @anthropic-ai/sdk');
16
+ }
17
+ this.client = new Anthropic({ apiKey });
18
+ }
19
+ async chat(messages, options = {}) {
20
+ const stream = options.stream || !!options.onToken;
21
+ const model = options.model || "claude-3-5-sonnet-20240620";
22
+ // Anthropic requires a separate system prompt from the messages array
23
+ const systemMessage = messages.find((m) => m.role === "system");
24
+ const userMessages = messages.filter((m) => m.role !== "system");
25
+ if (stream) {
26
+ const responseStream = await this.client.messages.create({
27
+ model,
28
+ system: systemMessage?.content,
29
+ messages: userMessages.map((m) => ({
30
+ role: m.role,
31
+ content: m.content,
32
+ })),
33
+ max_tokens: options.maxTokens || 4096,
34
+ temperature: options.temperature ?? 0.7,
35
+ stream: true,
36
+ });
37
+ let fullContent = "";
38
+ for await (const event of responseStream) {
39
+ if (event.type === "content_block_delta" &&
40
+ event.delta.type === "text_delta") {
41
+ const token = event.delta.text;
42
+ fullContent += token;
43
+ options.onToken?.(token);
44
+ }
45
+ }
46
+ return { content: fullContent };
47
+ }
48
+ const response = await this.client.messages.create({
49
+ model,
50
+ system: systemMessage?.content,
51
+ messages: userMessages.map((m) => ({
52
+ role: m.role,
53
+ content: m.content,
54
+ })),
55
+ max_tokens: options.maxTokens || 4096,
56
+ temperature: options.temperature ?? 0.7,
57
+ });
58
+ // Anthropic response content can be an array of blocks
59
+ const content = response.content
60
+ .filter((block) => block.type === "text")
61
+ .map((block) => block.text)
62
+ .join("\n");
63
+ return {
64
+ content,
65
+ usage: response.usage
66
+ ? {
67
+ promptTokens: response.usage.input_tokens,
68
+ completionTokens: response.usage.output_tokens,
69
+ totalTokens: response.usage.input_tokens + response.usage.output_tokens,
70
+ }
71
+ : undefined,
72
+ };
73
+ }
74
+ }
75
+ exports.AnthropicProvider = AnthropicProvider;
76
+ //# sourceMappingURL=anthropic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/llm/anthropic.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import type { ChatMessage, ChatOptions, LLMProvider, LLMResponse } from "./provider";
2
+ /**
3
+ * LLMProvider that delegates to the local `claude` CLI in non-interactive mode.
4
+ *
5
+ * Unlike API-based providers, ClaudeCodeProvider runs a subprocess and can
6
+ * grant the subprocess access to the project filesystem via its file tools
7
+ * (Read, Grep, Glob). This lets the planner explore the codebase autonomously
8
+ * rather than receiving pre-built context from vemora.
9
+ *
10
+ * Config example:
11
+ * ```json
12
+ * "planner": {
13
+ * "provider": "claude-code",
14
+ * "model": "claude-sonnet-4-6",
15
+ * "allowedTools": ["Read", "Grep", "Glob"],
16
+ * "maxBudgetUsd": 0.50
17
+ * }
18
+ * ```
19
+ *
20
+ * The `baseUrl` field is repurposed as the path to the `claude` binary
21
+ * (default: "claude", assumed to be on PATH).
22
+ */
23
+ export declare class ClaudeCodeProvider implements LLMProvider {
24
+ readonly name = "claude-code";
25
+ private readonly command;
26
+ private readonly model;
27
+ private readonly allowedTools;
28
+ private readonly maxBudgetUsd;
29
+ constructor(options?: {
30
+ command?: string;
31
+ model?: string;
32
+ allowedTools?: string[];
33
+ maxBudgetUsd?: number;
34
+ });
35
+ chat(messages: ChatMessage[], options?: ChatOptions): Promise<LLMResponse>;
36
+ }
37
+ //# sourceMappingURL=claude-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../src/llm/claude-code.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAIrF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,kBAAmB,YAAW,WAAW;IACpD,QAAQ,CAAC,IAAI,iBAAiB;IAE9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqB;IAC3C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAW;IACxC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,OAAO,GAAE;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,YAAY,CAAC,EAAE,MAAM,CAAC;KAClB;IAOA,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;CA2EjF"}
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ClaudeCodeProvider = void 0;
4
+ const child_process_1 = require("child_process");
5
+ // ─── Provider ─────────────────────────────────────────────────────────────────
6
+ /**
7
+ * LLMProvider that delegates to the local `claude` CLI in non-interactive mode.
8
+ *
9
+ * Unlike API-based providers, ClaudeCodeProvider runs a subprocess and can
10
+ * grant the subprocess access to the project filesystem via its file tools
11
+ * (Read, Grep, Glob). This lets the planner explore the codebase autonomously
12
+ * rather than receiving pre-built context from vemora.
13
+ *
14
+ * Config example:
15
+ * ```json
16
+ * "planner": {
17
+ * "provider": "claude-code",
18
+ * "model": "claude-sonnet-4-6",
19
+ * "allowedTools": ["Read", "Grep", "Glob"],
20
+ * "maxBudgetUsd": 0.50
21
+ * }
22
+ * ```
23
+ *
24
+ * The `baseUrl` field is repurposed as the path to the `claude` binary
25
+ * (default: "claude", assumed to be on PATH).
26
+ */
27
+ class ClaudeCodeProvider {
28
+ name = "claude-code";
29
+ command;
30
+ model;
31
+ allowedTools;
32
+ maxBudgetUsd;
33
+ constructor(options = {}) {
34
+ this.command = options.command ?? "claude";
35
+ this.model = options.model;
36
+ this.allowedTools = options.allowedTools ?? ["Read", "Grep", "Glob"];
37
+ this.maxBudgetUsd = options.maxBudgetUsd ?? 0.5;
38
+ }
39
+ async chat(messages, options) {
40
+ const projectRoot = options?.projectRoot ?? process.cwd();
41
+ // ── Separate system message from conversation ─────────────────────────────
42
+ const systemMsg = messages.find((m) => m.role === "system");
43
+ const otherMsgs = messages.filter((m) => m.role !== "system");
44
+ // Combine non-system messages into a single prompt string
45
+ const prompt = otherMsgs.length === 1
46
+ ? otherMsgs[0].content
47
+ : otherMsgs.map((m) => `[${m.role}]\n${m.content}`).join("\n\n");
48
+ // ── Build argument list ───────────────────────────────────────────────────
49
+ const args = [
50
+ "-p", prompt,
51
+ "--output-format", "text",
52
+ "--allowedTools", this.allowedTools.join(","),
53
+ "--max-budget-usd", String(this.maxBudgetUsd),
54
+ "--dangerously-skip-permissions", // non-interactive: no permission prompts
55
+ ];
56
+ if (this.model) {
57
+ args.push("--model", this.model);
58
+ }
59
+ if (systemMsg) {
60
+ args.push("--append-system-prompt", systemMsg.content);
61
+ }
62
+ // ── Spawn subprocess ──────────────────────────────────────────────────────
63
+ return new Promise((resolve, reject) => {
64
+ const proc = (0, child_process_1.spawn)(this.command, args, {
65
+ cwd: projectRoot,
66
+ stdio: ["ignore", "pipe", "pipe"],
67
+ });
68
+ let stdout = "";
69
+ let stderr = "";
70
+ proc.stdout.on("data", (chunk) => {
71
+ stdout += chunk.toString();
72
+ });
73
+ proc.stderr.on("data", (chunk) => {
74
+ stderr += chunk.toString();
75
+ });
76
+ proc.on("error", (err) => {
77
+ if (err.code === "ENOENT") {
78
+ reject(new Error(`claude CLI not found at "${this.command}". ` +
79
+ "Install it with: npm install -g @anthropic-ai/claude-code"));
80
+ }
81
+ else {
82
+ reject(err);
83
+ }
84
+ });
85
+ proc.on("close", (code) => {
86
+ if (code !== 0 && !stdout.trim()) {
87
+ reject(new Error(`claude exited with code ${code}.\nstderr: ${stderr.trim()}`));
88
+ return;
89
+ }
90
+ // --output-format text: stdout is the raw assistant response
91
+ resolve({ content: stdout.trim() });
92
+ });
93
+ });
94
+ }
95
+ }
96
+ exports.ClaudeCodeProvider = ClaudeCodeProvider;
97
+ //# sourceMappingURL=claude-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/llm/claude-code.ts"],"names":[],"mappings":";;;AAAA,iDAAsC;AAGtC,iFAAiF;AAEjF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAa,kBAAkB;IACpB,IAAI,GAAG,aAAa,CAAC;IAEb,OAAO,CAAS;IAChB,KAAK,CAAqB;IAC1B,YAAY,CAAW;IACvB,YAAY,CAAS;IAEtC,YAAY,UAKR,EAAE;QACJ,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAC;QAC3C,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACrE,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,GAAG,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,QAAuB,EAAE,OAAqB;QACvD,MAAM,WAAW,GAAG,OAAO,EAAE,WAAW,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAE1D,6EAA6E;QAC7E,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;QAC5D,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC;QAE9D,0DAA0D;QAC1D,MAAM,MAAM,GACV,SAAS,CAAC,MAAM,KAAK,CAAC;YACpB,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO;YACtB,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAErE,6EAA6E;QAC7E,MAAM,IAAI,GAAa;YACrB,IAAI,EAAE,MAAM;YACZ,iBAAiB,EAAE,MAAM;YACzB,gBAAgB,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC;YAC7C,kBAAkB,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC;YAC7C,gCAAgC,EAAE,yCAAyC;SAC5E,CAAC;QAEF,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QACnC,CAAC;QAED,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,CAAC,IAAI,CAAC,wBAAwB,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;QACzD,CAAC;QAED,6EAA6E;QAC7E,OAAO,IAAI,OAAO,CAAc,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAClD,MAAM,IAAI,GAAG,IAAA,qBAAK,EAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE;gBACrC,GAAG,EAAE,WAAW;gBAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;aAClC,CAAC,CAAC;YAEH,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,IAAI,MAAM,GAAG,EAAE,CAAC;YAEhB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;gBACvC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC7B,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;gBACvC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC7B,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACvB,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACrD,MAAM,CACJ,IAAI,KAAK,CACP,4BAA4B,IAAI,CAAC,OAAO,KAAK;wBAC7C,2DAA2D,CAC5D,CACF,CAAC;gBACJ,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,GAAG,CAAC,CAAC;gBACd,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gBACxB,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;oBACjC,MAAM,CACJ,IAAI,KAAK,CACP,2BAA2B,IAAI,cAAc,MAAM,CAAC,IAAI,EAAE,EAAE,CAC7D,CACF,CAAC;oBACF,OAAO;gBACT,CAAC;gBAED,6DAA6D;gBAC7D,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACtC,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AA/FD,gDA+FC"}
@@ -0,0 +1,7 @@
1
+ import type { SummarizationConfig } from "../core/types";
2
+ import type { LLMProvider } from "./provider";
3
+ /**
4
+ * Factory that instantiates the correct LLMProvider from config.
5
+ */
6
+ export declare function createLLMProvider(config: SummarizationConfig): LLMProvider;
7
+ //# sourceMappingURL=factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/llm/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAKzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,mBAAmB,GAAG,WAAW,CAwC1E"}
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createLLMProvider = createLLMProvider;
4
+ const anthropic_1 = require("./anthropic");
5
+ const claude_code_1 = require("./claude-code");
6
+ const ollama_1 = require("./ollama");
7
+ const openai_1 = require("./openai");
8
+ /**
9
+ * Factory that instantiates the correct LLMProvider from config.
10
+ */
11
+ function createLLMProvider(config) {
12
+ const apiKey = config.apiKey ??
13
+ (config.provider === "anthropic"
14
+ ? process.env.ANTHROPIC_API_KEY
15
+ : config.provider === "gemini"
16
+ ? (process.env.GEMINI_API_KEY ?? process.env.GOOGLE_API_KEY)
17
+ : process.env.OPENAI_API_KEY);
18
+ switch (config.provider) {
19
+ case "openai":
20
+ if (!apiKey)
21
+ throw new Error("OPENAI_API_KEY not found");
22
+ return new openai_1.OpenAIProvider(apiKey, config.baseUrl);
23
+ case "anthropic":
24
+ if (!apiKey)
25
+ throw new Error("ANTHROPIC_API_KEY not found");
26
+ return new anthropic_1.AnthropicProvider(apiKey);
27
+ case "gemini": {
28
+ if (!apiKey)
29
+ throw new Error("GEMINI_API_KEY (or GOOGLE_API_KEY) not found");
30
+ const baseUrl = config.baseUrl ??
31
+ "https://generativelanguage.googleapis.com/v1beta/openai/";
32
+ return new openai_1.OpenAIProvider(apiKey, baseUrl);
33
+ }
34
+ case "ollama":
35
+ return new ollama_1.OllamaProvider(config.baseUrl || "http://localhost:11434");
36
+ case "claude-code":
37
+ return new claude_code_1.ClaudeCodeProvider({
38
+ command: config.baseUrl || "claude", // baseUrl repurposed as binary path
39
+ model: config.model || undefined,
40
+ allowedTools: config.allowedTools,
41
+ maxBudgetUsd: config.maxBudgetUsd,
42
+ });
43
+ default:
44
+ throw new Error(`Unknown LLM provider: "${config.provider}"`);
45
+ }
46
+ }
47
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/llm/factory.ts"],"names":[],"mappings":";;AAUA,8CAwCC;AAjDD,2CAAgD;AAChD,+CAAmD;AACnD,qCAA0C;AAC1C,qCAA0C;AAG1C;;GAEG;AACH,SAAgB,iBAAiB,CAAC,MAA2B;IAC3D,MAAM,MAAM,GACV,MAAM,CAAC,MAAM;QACb,CAAC,MAAM,CAAC,QAAQ,KAAK,WAAW;YAC9B,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB;YAC/B,CAAC,CAAC,MAAM,CAAC,QAAQ,KAAK,QAAQ;gBAC5B,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;gBAC5D,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAEpC,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,KAAK,QAAQ;YACX,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;YACzD,OAAO,IAAI,uBAAc,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QAEpD,KAAK,WAAW;YACd,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;YAC5D,OAAO,IAAI,6BAAiB,CAAC,MAAM,CAAC,CAAC;QAEvC,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;YAC7E,MAAM,OAAO,GACX,MAAM,CAAC,OAAO;gBACd,0DAA0D,CAAC;YAC7D,OAAO,IAAI,uBAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC7C,CAAC;QAED,KAAK,QAAQ;YACX,OAAO,IAAI,uBAAc,CAAC,MAAM,CAAC,OAAO,IAAI,wBAAwB,CAAC,CAAC;QAExE,KAAK,aAAa;YAChB,OAAO,IAAI,gCAAkB,CAAC;gBAC5B,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,QAAQ,EAAE,oCAAoC;gBACzE,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,SAAS;gBAChC,YAAY,EAAE,MAAM,CAAC,YAAY;gBACjC,YAAY,EAAE,MAAM,CAAC,YAAY;aAClC,CAAC,CAAC;QAEL;YACE,MAAM,IAAI,KAAK,CAAC,0BAA0B,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC;IAClE,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ChatMessage, ChatOptions, LLMProvider, LLMResponse } from "./provider";
2
+ export declare class OllamaProvider implements LLMProvider {
3
+ readonly name = "ollama";
4
+ private baseUrl;
5
+ constructor(baseUrl?: string);
6
+ chat(messages: ChatMessage[], options?: ChatOptions): Promise<LLMResponse>;
7
+ }
8
+ //# sourceMappingURL=ollama.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama.d.ts","sourceRoot":"","sources":["../../src/llm/ollama.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,qBAAa,cAAe,YAAW,WAAW;IAChD,QAAQ,CAAC,IAAI,YAAY;IACzB,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,GAAE,MAAiC;IAIhD,IAAI,CACR,QAAQ,EAAE,WAAW,EAAE,EACvB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,WAAW,CAAC;CA6ExB"}
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OllamaProvider = void 0;
4
+ class OllamaProvider {
5
+ name = "ollama";
6
+ baseUrl;
7
+ constructor(baseUrl = "http://localhost:11434") {
8
+ this.baseUrl = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
9
+ }
10
+ async chat(messages, options = {}) {
11
+ const stream = options.stream || !!options.onToken;
12
+ const model = options.model;
13
+ const response = await fetch(`${this.baseUrl}/api/chat`, {
14
+ method: "POST",
15
+ headers: { "Content-Type": "application/json" },
16
+ body: JSON.stringify({
17
+ model,
18
+ messages: messages.map((m) => ({
19
+ role: m.role,
20
+ content: m.content,
21
+ })),
22
+ options: {
23
+ temperature: options.temperature ?? 0.7,
24
+ num_predict: options.maxTokens,
25
+ },
26
+ stream,
27
+ }),
28
+ });
29
+ if (!response.ok) {
30
+ const error = await response.text();
31
+ throw new Error(`Ollama API error: ${error}`);
32
+ }
33
+ if (stream) {
34
+ if (!response.body)
35
+ throw new Error("Ollama response body is empty");
36
+ const reader = response.body.getReader();
37
+ const decoder = new TextDecoder();
38
+ let fullContent = "";
39
+ try {
40
+ while (true) {
41
+ const { done, value } = await reader.read();
42
+ if (done)
43
+ break;
44
+ const chunk = decoder.decode(value, { stream: true });
45
+ // Ollama sends multiple JSON objects, one per line (NDJSON)
46
+ const lines = chunk.split("\n");
47
+ for (const line of lines) {
48
+ if (!line.trim())
49
+ continue;
50
+ try {
51
+ const data = JSON.parse(line);
52
+ if (data.message?.content) {
53
+ const token = data.message.content;
54
+ fullContent += token;
55
+ options.onToken?.(token);
56
+ }
57
+ }
58
+ catch (_e) {
59
+ // Partial JSON, wait for more data
60
+ }
61
+ }
62
+ }
63
+ }
64
+ finally {
65
+ reader.releaseLock();
66
+ }
67
+ return { content: fullContent };
68
+ }
69
+ const data = (await response.json());
70
+ return {
71
+ content: data.message?.content || "",
72
+ usage: data.prompt_eval_count
73
+ ? {
74
+ promptTokens: data.prompt_eval_count,
75
+ completionTokens: data.eval_count ?? 0,
76
+ totalTokens: data.prompt_eval_count + (data.eval_count ?? 0),
77
+ }
78
+ : undefined,
79
+ };
80
+ }
81
+ }
82
+ exports.OllamaProvider = OllamaProvider;
83
+ //# sourceMappingURL=ollama.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama.js","sourceRoot":"","sources":["../../src/llm/ollama.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { ChatMessage, ChatOptions, LLMProvider, LLMResponse } from "./provider";
2
+ export declare class OpenAIProvider implements LLMProvider {
3
+ readonly name = "openai";
4
+ private client;
5
+ constructor(apiKey: string, baseUrl?: string);
6
+ chat(messages: ChatMessage[], options?: ChatOptions): Promise<LLMResponse>;
7
+ }
8
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/llm/openai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,WAAW,EACX,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,qBAAa,cAAe,YAAW,WAAW;IAChD,QAAQ,CAAC,IAAI,YAAY;IAEzB,OAAO,CAAC,MAAM,CAAM;gBAER,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;IAgBtC,IAAI,CACR,QAAQ,EAAE,WAAW,EAAE,EACvB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,WAAW,CAAC;CAkDxB"}
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OpenAIProvider = void 0;
4
+ class OpenAIProvider {
5
+ name = "openai";
6
+ // biome-ignore lint/suspicious/noExplicitAny: openai is an optional peer dependency
7
+ client;
8
+ constructor(apiKey, baseUrl) {
9
+ let OpenAI;
10
+ try {
11
+ // biome-ignore lint/suspicious/noExplicitAny: optional peer dependency
12
+ OpenAI = require("openai").default ?? require("openai");
13
+ }
14
+ catch {
15
+ throw new Error('Package "openai" is not installed. Run: npm install openai');
16
+ }
17
+ this.client = new OpenAI({
18
+ apiKey,
19
+ ...(baseUrl ? { baseURL: baseUrl } : {}),
20
+ });
21
+ }
22
+ async chat(messages, options = {}) {
23
+ const stream = options.stream || !!options.onToken;
24
+ if (stream) {
25
+ const responseStream = await this.client.chat.completions.create({
26
+ model: options.model || "gpt-4o-mini",
27
+ messages: messages.map((m) => ({
28
+ role: m.role,
29
+ content: m.content,
30
+ })),
31
+ temperature: options.temperature ?? 0.7,
32
+ max_tokens: options.maxTokens,
33
+ stream: true,
34
+ });
35
+ let fullContent = "";
36
+ for await (const chunk of responseStream) {
37
+ const content = chunk.choices[0]?.delta?.content || "";
38
+ if (content) {
39
+ fullContent += content;
40
+ options.onToken?.(content);
41
+ }
42
+ }
43
+ return { content: fullContent };
44
+ }
45
+ const response = await this.client.chat.completions.create({
46
+ model: options.model || "gpt-4o-mini",
47
+ messages: messages.map((m) => ({
48
+ role: m.role,
49
+ content: m.content,
50
+ })),
51
+ temperature: options.temperature ?? 0.7,
52
+ max_tokens: options.maxTokens,
53
+ });
54
+ const content = response.choices[0]?.message?.content || "";
55
+ return {
56
+ content,
57
+ usage: response.usage
58
+ ? {
59
+ promptTokens: response.usage.prompt_tokens,
60
+ completionTokens: response.usage.completion_tokens,
61
+ totalTokens: response.usage.total_tokens,
62
+ }
63
+ : undefined,
64
+ };
65
+ }
66
+ }
67
+ exports.OpenAIProvider = OpenAIProvider;
68
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/llm/openai.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ export interface ChatMessage {
2
+ role: "system" | "user" | "assistant";
3
+ content: string;
4
+ }
5
+ export interface ChatOptions {
6
+ model?: string;
7
+ temperature?: number;
8
+ maxTokens?: number;
9
+ stream?: boolean;
10
+ onToken?: (token: string) => void;
11
+ /**
12
+ * Absolute path to the project root.
13
+ * Used by subprocess-based providers (e.g. claude-code) as the working
14
+ * directory and to grant file-tool access.
15
+ */
16
+ projectRoot?: string;
17
+ }
18
+ export interface LLMResponse {
19
+ content: string;
20
+ usage?: {
21
+ promptTokens: number;
22
+ completionTokens: number;
23
+ totalTokens: number;
24
+ };
25
+ }
26
+ export interface LLMProvider {
27
+ readonly name: string;
28
+ /**
29
+ * Sends a chat request to the LLM.
30
+ * If options.stream is true, it should ideally handle streaming
31
+ * (to be refined based on CLI requirements).
32
+ */
33
+ chat(messages: ChatMessage[], options?: ChatOptions): Promise<LLMResponse>;
34
+ }
35
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/llm/provider.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE;QACN,YAAY,EAAE,MAAM,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;QACzB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;;OAIG;IACH,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CAC5E"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/llm/provider.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import type { Chunk, SearchResult, SymbolIndex } from "../core/types";
2
+ export declare function computeBM25Scores(query: string, chunks: Chunk[], symbols: SymbolIndex, topK?: number): SearchResult[];
3
+ //# sourceMappingURL=bm25.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bm25.d.ts","sourceRoot":"","sources":["../../src/search/bm25.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AA2BtE,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,KAAK,EAAE,EACf,OAAO,EAAE,WAAW,EACpB,IAAI,SAAK,GACR,YAAY,EAAE,CAqGhB"}
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeBM25Scores = computeBM25Scores;
4
+ /**
5
+ * BM25 implementation for high-precision keyword search.
6
+ */
7
+ const K1 = 1.5;
8
+ const B = 0.75;
9
+ let bm25Cache = null;
10
+ function computeHash(chunks) {
11
+ if (chunks.length === 0)
12
+ return "";
13
+ const chunkIds = chunks.map((c) => c.id).sort();
14
+ return chunkIds.join("|");
15
+ }
16
+ function computeBM25Scores(query, chunks, symbols, topK = 10) {
17
+ if (!query)
18
+ return [];
19
+ // 1. Tokenize query
20
+ const queryTerms = query
21
+ .toLowerCase()
22
+ .split(/[\s\W]+/)
23
+ .filter((t) => t.length >= 2); // Slightly more inclusive than current TF search
24
+ if (queryTerms.length === 0)
25
+ return [];
26
+ const N = chunks.length;
27
+ if (N === 0)
28
+ return [];
29
+ const currentHash = computeHash(chunks);
30
+ // 2. Tokenize docs and compute stats (with CACHING)
31
+ if (!bm25Cache || bm25Cache.chunkIdsHash !== currentHash) {
32
+ // Cache miss: compute everything
33
+ const docTokens = [];
34
+ const tfMaps = [];
35
+ let totalLen = 0;
36
+ const dfMap = new Map();
37
+ for (const chunk of chunks) {
38
+ const tokens = (chunk.content ?? "").toLowerCase().split(/[\s\W]+/);
39
+ docTokens.push(tokens);
40
+ totalLen += tokens.length;
41
+ const tfMap = new Map();
42
+ for (const token of tokens) {
43
+ tfMap.set(token, (tfMap.get(token) || 0) + 1);
44
+ }
45
+ tfMaps.push(tfMap);
46
+ // Unique tokens for DF calculation
47
+ for (const token of tfMap.keys()) {
48
+ dfMap.set(token, (dfMap.get(token) || 0) + 1);
49
+ }
50
+ }
51
+ bm25Cache = {
52
+ chunkIdsHash: currentHash,
53
+ docTokens,
54
+ tfMaps,
55
+ dfMap,
56
+ avgdl: totalLen / N,
57
+ N,
58
+ };
59
+ }
60
+ const { docTokens, tfMaps, dfMap, avgdl } = bm25Cache;
61
+ // 3. Compute IDF for query terms
62
+ const idfMap = new Map();
63
+ for (const term of queryTerms) {
64
+ const df = dfMap.get(term) || 0;
65
+ // Standard BM25 IDF: ln((N - df + 0.5) / (df + 0.5) + 1)
66
+ const idf = Math.log((N - df + 0.5) / (df + 0.5) + 1);
67
+ idfMap.set(term, Math.max(0, idf)); // IDF can be negative if term is in > half docs
68
+ }
69
+ // 4. Compute BM25 scores
70
+ const results = chunks.map((chunk, i) => {
71
+ const tokens = docTokens[i];
72
+ const tfMap = tfMaps[i];
73
+ const dl = tokens.length;
74
+ let score = 0;
75
+ for (const term of queryTerms) {
76
+ const tf = tfMap.get(term) || 0;
77
+ const idf = idfMap.get(term) || 0;
78
+ // BM25 Formula: IDF * (tf * (k1 + 1)) / (tf + k1 * (1 - b + b * (dl / avgdl)))
79
+ const numerator = tf * (K1 + 1);
80
+ const denominator = tf + K1 * (1 - B + B * (dl / avgdl));
81
+ score += idf * (numerator / denominator);
82
+ }
83
+ // Bonus: exact symbol match
84
+ if (chunk.symbol) {
85
+ const symLower = chunk.symbol.toLowerCase();
86
+ if (queryTerms.some((t) => symLower.includes(t))) {
87
+ // Boost for keyword match in symbol name
88
+ score *= 1.5;
89
+ }
90
+ if (queryTerms.some((t) => symLower === t)) {
91
+ // Higher boost for exact identifier match
92
+ score *= 2.0;
93
+ }
94
+ }
95
+ const symbol = chunk.symbol ? symbols[chunk.symbol] : undefined;
96
+ return { chunk, score, symbol };
97
+ });
98
+ // 5. Sort and return
99
+ return results
100
+ .filter((r) => r.score > 0)
101
+ .sort((a, b) => b.score - a.score)
102
+ .slice(0, topK);
103
+ }
104
+ //# sourceMappingURL=bm25.js.map