ownkey 1.3.0 → 1.4.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 (68) hide show
  1. package/README.md +53 -1
  2. package/dist/ai/anthropic.d.ts +2 -3
  3. package/dist/ai/anthropic.d.ts.map +1 -1
  4. package/dist/ai/anthropic.js +5 -15
  5. package/dist/ai/anthropic.js.map +1 -1
  6. package/dist/ai/gemini.d.ts +3 -3
  7. package/dist/ai/gemini.d.ts.map +1 -1
  8. package/dist/ai/gemini.js +9 -20
  9. package/dist/ai/gemini.js.map +1 -1
  10. package/dist/ai/ollama.d.ts +7 -3
  11. package/dist/ai/ollama.d.ts.map +1 -1
  12. package/dist/ai/ollama.js +27 -17
  13. package/dist/ai/ollama.js.map +1 -1
  14. package/dist/ai/openai.d.ts +2 -3
  15. package/dist/ai/openai.d.ts.map +1 -1
  16. package/dist/ai/openai.js +7 -15
  17. package/dist/ai/openai.js.map +1 -1
  18. package/dist/ai/provider.d.ts +17 -8
  19. package/dist/ai/provider.d.ts.map +1 -1
  20. package/dist/ai/provider.js +16 -0
  21. package/dist/ai/provider.js.map +1 -1
  22. package/dist/bench/cases.d.ts +5 -0
  23. package/dist/bench/cases.d.ts.map +1 -1
  24. package/dist/bench/cases.js +47 -0
  25. package/dist/bench/cases.js.map +1 -1
  26. package/dist/commands/bench.d.ts +2 -1
  27. package/dist/commands/bench.d.ts.map +1 -1
  28. package/dist/commands/bench.js +13 -5
  29. package/dist/commands/bench.js.map +1 -1
  30. package/dist/commands/review.d.ts.map +1 -1
  31. package/dist/commands/review.js +25 -3
  32. package/dist/commands/review.js.map +1 -1
  33. package/dist/core/review/agent.d.ts +58 -0
  34. package/dist/core/review/agent.d.ts.map +1 -0
  35. package/dist/core/review/agent.js +225 -0
  36. package/dist/core/review/agent.js.map +1 -0
  37. package/dist/core/review/report.d.ts +2 -2
  38. package/dist/core/review/report.d.ts.map +1 -1
  39. package/dist/core/review/report.js +4 -2
  40. package/dist/core/review/report.js.map +1 -1
  41. package/dist/core/review/run.d.ts +11 -2
  42. package/dist/core/review/run.d.ts.map +1 -1
  43. package/dist/core/review/run.js +12 -4
  44. package/dist/core/review/run.js.map +1 -1
  45. package/dist/types/index.d.ts +2 -0
  46. package/dist/types/index.d.ts.map +1 -1
  47. package/dist/types/index.js.map +1 -1
  48. package/dist/ui/App.d.ts +11 -3
  49. package/dist/ui/App.d.ts.map +1 -1
  50. package/dist/ui/App.js +20 -6
  51. package/dist/ui/App.js.map +1 -1
  52. package/dist/ui/Keeper.d.ts +18 -0
  53. package/dist/ui/Keeper.d.ts.map +1 -0
  54. package/dist/ui/Keeper.js +45 -0
  55. package/dist/ui/Keeper.js.map +1 -0
  56. package/dist/ui/keeper-term.d.ts +33 -0
  57. package/dist/ui/keeper-term.d.ts.map +1 -0
  58. package/dist/ui/keeper-term.js +104 -0
  59. package/dist/ui/keeper-term.js.map +1 -0
  60. package/dist/ui/keeper.d.ts +60 -0
  61. package/dist/ui/keeper.d.ts.map +1 -0
  62. package/dist/ui/keeper.js +167 -0
  63. package/dist/ui/keeper.js.map +1 -0
  64. package/dist/ui/session.d.ts +3 -0
  65. package/dist/ui/session.d.ts.map +1 -1
  66. package/dist/ui/session.js +32 -7
  67. package/dist/ui/session.js.map +1 -1
  68. package/package.json +1 -1
package/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ <p align="center"><img src="assets/keeper.svg" alt="Keeper, the OwnKey mascot: a living orange key with one inspecting eye, holding a magnifying glass" width="132"></p>
2
+
1
3
  <h1 align="center">OwnKey</h1>
2
4
 
3
5
  <h3 align="center">The local-first AI code reviewer that runs on your own keys.</h3>
@@ -102,6 +104,24 @@ ownkey undo --list # recent applies
102
104
 
103
105
  For a whole-project audit of any folder, git or not, use `ownkey suggest .`
104
106
 
107
+ ## How a review works
108
+
109
+ OwnKey sends the model your changed files and the diff, then lets it investigate before it answers, much like a teammate who opens a few files before leaving a comment. With read-only tools, it can:
110
+
111
+ - read any file in the repository, with line numbers
112
+ - search the codebase with a regular expression
113
+ - list a folder
114
+
115
+ Each step is printed as it happens:
116
+
117
+ ```text
118
+ Investigating the repository before reporting...
119
+ ↳ search /findOrder\(/
120
+ ↳ read src/orders.ts
121
+ ```
122
+
123
+ That's how it catches bugs that only show up across files, such as a lookup that can return `undefined`, a value in cents compared against dollars, or an async loader used without `await`. It also stays quiet about code that is already guarded elsewhere. Files ignored by `.gitignore` or `.ownkeyignore` are never readable. Use `--max-steps <n>` to cap the investigation (default 6 rounds), or `--quick` for the old single-pass review.
124
+
105
125
  ## Interactive session
106
126
 
107
127
  Run `ownkey` with no arguments in any project folder and it opens a session for that folder. The header shows the repository, branch, how many files changed, and which model is reviewing. Then type any command without the `ownkey` prefix:
@@ -115,6 +135,24 @@ Run `ownkey` with no arguments in any project folder and it opens a session for
115
135
 
116
136
  Tab completes commands and their flags, the arrow keys walk your history (kept in `~/.ownkey/history`), `help` lists every command, and Ctrl+D leaves. Commands run exactly as they do from the shell, including interactive prompts like the `config` wizard. Ctrl+C stops the running command without closing the session.
117
137
 
138
+ ### Keeper
139
+
140
+ Keeper, the key with one inspecting eye, keeps you company in the terminal and shows what OwnKey is doing:
141
+
142
+ ```text
143
+ ╭─────╮ !
144
+ │ ◎ │ Found 3 issues
145
+ ╰──┬──╯ 1 high or critical
146
+ ├┐
147
+ ╵
148
+ ```
149
+
150
+ - While a review investigates, Keeper's eye darts between files on a live status line that counts its lookups.
151
+ - When a review finishes, Keeper is alarmed if it found issues, smiles if everything is clear, and shows an × if something went wrong. Back at the session prompt, it keeps that look until your next command.
152
+ - Keeper resizes with your terminal: a full figure from 72 columns, a compact one from 44, a one-line `( ◉ )━┳┳╸` below that, and nothing on very narrow screens. Words never wrap into it, and it redraws when you resize the window.
153
+
154
+ Keeper only moves on an interactive terminal. In CI, pipes, and `--format json|sarif|markdown` output it never appears, so logs and reports stay clean. Set `OWNKEY_REDUCED_MOTION=1` to keep Keeper still, or `OWNKEY_NO_MASCOT=1` to hide it.
155
+
118
156
  Outside an interactive terminal (pipes, scripts, CI), or with `OWNKEY_NO_UI=1` set, a bare `ownkey` prints help as before. Every subcommand behaves the same with or without the session.
119
157
 
120
158
  ## Commands
@@ -231,7 +269,20 @@ ownkey bench --model claude-opus-5-5 # compare another model on the sam
231
269
  ownkey bench --format markdown --output bench.md
232
270
  ```
233
271
 
234
- It reports **recall** (planted bugs reported within 3 lines of the defect with a matching type), **precision** (matching findings over all findings at medium or above), and how many controls stayed clean. Low and info findings never count against a model. Bench runs in temporary directories and stores nothing, but it does send every case to your provider, so a full run costs about 15 small review calls.
272
+ It reports **recall** (planted bugs reported within 3 lines of the defect with a matching type), **precision** (matching findings over all findings at medium or above), and how many controls stayed clean. Low and info findings never count against a model. Bench runs in temporary directories and stores nothing, but it does send every case to your provider. A full run is 19 cases: one call each with `--quick`, a few each in agentic mode.
273
+
274
+ ### Results
275
+
276
+ One run of all 19 cases (15 bugs, 4 controls) on Ollama Cloud, 2026-10-24, OwnKey 1.4.0:
277
+
278
+ | Model | Mode | Recall | Precision | Controls with false alarms |
279
+ |---|---|---|---|---|
280
+ | `gpt-oss:120b` | agentic | 15/15 | 0.60 | 2 of 4 |
281
+ | `gpt-oss:120b` | quick | 14/15 | 0.44 | 4 of 4 |
282
+ | `gemma4:31b` | agentic | 14/15 | 0.88 | 1 of 4 |
283
+ | `gemma4:31b` | quick | 15/15 | 0.76 | 4 of 4 |
284
+
285
+ Both models catch nearly every planted bug either way. Investigating first mostly cuts noise: on correct changes, the agentic reviewer flagged half or fewer of the controls, against all four in a single pass. A single run on 19 small cases is a smoke test, not a leaderboard, so run `ownkey bench` on your own model before you rely on it.
235
286
 
236
287
  ## Providers
237
288
 
@@ -241,6 +292,7 @@ It reports **recall** (planted bugs reported within 3 lines of the defect with a
241
292
  | Anthropic | `--provider anthropic --api-key <key>` | `claude-sonnet-5-5` |
242
293
  | Google Gemini | `--provider gemini --api-key <key>` | `gemini-3.8-flash` |
243
294
  | Ollama | `--provider ollama [--endpoint http://host:11434]` | `qwen2.5-coder:latest` |
295
+ | Ollama Cloud | `--provider ollama --endpoint https://ollama.com --model gpt-oss:120b`, with `OLLAMA_API_KEY` set | Set with `--model` |
244
296
  | OpenAI-compatible | `--provider openai --endpoint <base-url> --api-key <key>` | Set with `--model` |
245
297
 
246
298
  Defaults are mid-tier models chosen for review quality per dollar. Override with `--model`, for example `gpt-6-astra` or `claude-opus-5-5` for the deepest review. OwnKey sends each model the request shape it expects, including reasoning-era OpenAI models and Claude's adaptive thinking.
@@ -1,5 +1,4 @@
1
- import { AIProvider } from './provider.js';
2
- import type { CodeContext, Suggestion } from '../types/index.js';
1
+ import { AIProvider, type ChatMessage } from './provider.js';
3
2
  /**
4
3
  * Anthropic Claude AI Provider
5
4
  * Supports all Claude models: Opus, Sonnet, and Haiku variants
@@ -11,7 +10,7 @@ export declare class AnthropicProvider extends AIProvider {
11
10
  constructor(apiKey?: string, model?: string);
12
11
  getDefaultModel(): string;
13
12
  testConnection(): Promise<boolean>;
14
- analyze(context: CodeContext): AsyncGenerator<Suggestion>;
13
+ chat(system: string, messages: ChatMessage[]): Promise<string>;
15
14
  /**
16
15
  * Get available Claude models
17
16
  * Note: Anthropic doesn't provide a models API endpoint
@@ -1 +1 @@
1
- {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/ai/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIjE;;;;GAIG;AACH,qBAAa,iBAAkB,SAAQ,UAAU;IAC7C,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,UAAU,CAAgB;gBAEtB,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAI3C,eAAe,IAAI,MAAM;IAInB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAkCjC,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,UAAU,CAAC;IAwDhE;;;;OAIG;WACU,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAUtE"}
1
+ {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../src/ai/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAI7D;;;;GAIG;AACH,qBAAa,iBAAkB,SAAQ,UAAU;IAC7C,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,UAAU,CAAgB;gBAEtB,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAI3C,eAAe,IAAI,MAAM;IAInB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAkClC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IA8CpE;;;;OAIG;WACU,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAUtE"}
@@ -47,10 +47,9 @@ export class AnthropicProvider extends AIProvider {
47
47
  return false;
48
48
  }
49
49
  }
50
- async *analyze(context) {
51
- const prompt = this.buildUserPrompt(context);
50
+ async chat(system, messages) {
52
51
  try {
53
- logger.verbose(`Analyzing with Anthropic (${this.model})...`);
52
+ logger.verbose(`Calling Anthropic (${this.model})...`);
54
53
  const response = await fetch(`${this.baseUrl}/messages`, {
55
54
  method: 'POST',
56
55
  headers: {
@@ -63,13 +62,8 @@ export class AnthropicProvider extends AIProvider {
63
62
  // No temperature: Claude 5.x models reject sampling parameters.
64
63
  // Adaptive thinking shares this budget, so leave headroom.
65
64
  max_tokens: 32000,
66
- system: this.getSystemPrompt(),
67
- messages: [
68
- {
69
- role: 'user',
70
- content: prompt,
71
- },
72
- ],
65
+ system,
66
+ messages,
73
67
  }),
74
68
  });
75
69
  if (!response.ok) {
@@ -86,11 +80,7 @@ export class AnthropicProvider extends AIProvider {
86
80
  if (!content) {
87
81
  throw new Error('No content in Anthropic response');
88
82
  }
89
- // Parse suggestions from response
90
- const suggestions = this.parseSuggestions(content);
91
- for (const suggestion of suggestions) {
92
- yield suggestion;
93
- }
83
+ return content;
94
84
  }
95
85
  catch (error) {
96
86
  logger.error('Anthropic analysis error:', error);
@@ -1 +1 @@
1
- {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/ai/anthropic.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/ai/anthropic.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { AIProvider } from './provider.js';
2
- import { CodeContext, Suggestion, AnalyzeOptions } from '../types/index.js';
1
+ import { AIProvider, type ChatMessage } from './provider.js';
2
+ import { AnalyzeOptions } from '../types/index.js';
3
3
  /**
4
4
  * Google Gemini AI Provider
5
5
  * Supports: gemini-1.5-pro, gemini-1.5-flash, gemini-pro
@@ -8,7 +8,7 @@ export declare class GeminiProvider extends AIProvider {
8
8
  private baseUrl;
9
9
  getDefaultModel(): string;
10
10
  testConnection(): Promise<boolean>;
11
- analyze(context: CodeContext, options?: AnalyzeOptions): AsyncGenerator<Suggestion>;
11
+ chat(system: string, messages: ChatMessage[], options?: AnalyzeOptions): Promise<string>;
12
12
  /**
13
13
  * Get available Gemini models
14
14
  */
@@ -1 +1 @@
1
- {"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/ai/gemini.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAmB,MAAM,mBAAmB,CAAC;AA2B7F;;;GAGG;AACH,qBAAa,cAAe,SAAQ,UAAU;IAC1C,OAAO,CAAC,OAAO,CAAkD;IAEjE,eAAe,IAAI,MAAM;IAInB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAejC,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,cAAc,CAAC,UAAU,CAAC;IA2E1F;;OAEG;WACU,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAgClE;;OAEG;IACH,MAAM,CAAC,mBAAmB,IAAI,MAAM;CAGvC"}
1
+ {"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/ai/gemini.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAmB,MAAM,mBAAmB,CAAC;AA2BpE;;;GAGG;AACH,qBAAa,cAAe,SAAQ,UAAU;IAC1C,OAAO,CAAC,OAAO,CAAkD;IAEjE,eAAe,IAAI,MAAM;IAInB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAelC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IA8D9F;;OAEG;WACU,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAgClE;;OAEG;IACH,MAAM,CAAC,mBAAmB,IAAI,MAAM;CAGvC"}
package/dist/ai/gemini.js CHANGED
@@ -26,21 +26,16 @@ export class GeminiProvider extends AIProvider {
26
26
  return false;
27
27
  }
28
28
  }
29
- async *analyze(context, options) {
29
+ async chat(system, messages, options) {
30
30
  try {
31
- logger.verbose(`Analyzing with Gemini (${this.model})...`);
32
- const systemPrompt = this.getSystemPrompt();
33
- const userPrompt = this.buildUserPrompt(context);
31
+ logger.verbose(`Calling Gemini (${this.model})...`);
32
+ // The system prompt rides as the first part of the first user turn, as before
33
+ const contents = messages.map((m, i) => ({
34
+ role: m.role === 'assistant' ? 'model' : 'user',
35
+ parts: i === 0 ? [{ text: system }, { text: m.content }] : [{ text: m.content }],
36
+ }));
34
37
  const request = {
35
- contents: [
36
- {
37
- role: 'user',
38
- parts: [
39
- { text: systemPrompt },
40
- { text: userPrompt },
41
- ],
42
- },
43
- ],
38
+ contents,
44
39
  generationConfig: {
45
40
  // Gemini 3.x is tuned for its default temperature; thinking shares the output budget.
46
41
  ...(options?.temperature !== undefined ? { temperature: options.temperature } : {}),
@@ -72,13 +67,7 @@ export class GeminiProvider extends AIProvider {
72
67
  .join('');
73
68
  logger.verbose('Received response from Gemini');
74
69
  logger.debug('Response:', responseText.substring(0, 200) + '...');
75
- // Parse suggestions from response
76
- const suggestions = this.parseSuggestions(responseText);
77
- logger.success(`Generated ${suggestions.length} suggestions`);
78
- // Yield suggestions one by one (simulating streaming)
79
- for (const suggestion of suggestions) {
80
- yield suggestion;
81
- }
70
+ return responseText;
82
71
  }
83
72
  catch (error) {
84
73
  if (error instanceof AIProviderError) {
@@ -1 +1 @@
1
- {"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../src/ai/gemini.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../src/ai/gemini.ts"],"names":[],"mappings":"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"}
@@ -1,16 +1,20 @@
1
- import { AIProvider } from './provider.js';
2
- import type { CodeContext, Suggestion } from '../types/index.js';
1
+ import { AIProvider, type ChatMessage } from './provider.js';
3
2
  /**
4
3
  * Ollama AI Provider
5
4
  * Supports local LLMs via Ollama (DeepSeek Coder, CodeLlama, etc.)
6
5
  * No API key required - runs completely offline
7
6
  */
7
+ /**
8
+ * Headers for an Ollama request. Ollama Cloud (https://ollama.com) and authenticated
9
+ * proxies take a bearer key, read from OLLAMA_API_KEY as Ollama's own clients do.
10
+ */
11
+ export declare function ollamaHeaders(extra?: Record<string, string>): Record<string, string>;
8
12
  export declare class OllamaProvider extends AIProvider {
9
13
  private baseUrl;
10
14
  constructor(apiKey?: string, model?: string, baseUrl?: string);
11
15
  getDefaultModel(): string;
12
16
  testConnection(): Promise<boolean>;
13
- analyze(context: CodeContext): AsyncGenerator<Suggestion>;
17
+ chat(system: string, messages: ChatMessage[]): Promise<string>;
14
18
  /**
15
19
  * Get available Ollama models
16
20
  * Lists models installed on the local Ollama instance
@@ -1 +1 @@
1
- {"version":3,"file":"ollama.d.ts","sourceRoot":"","sources":["../../src/ai/ollama.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIjE;;;;GAIG;AACH,qBAAa,cAAe,SAAQ,UAAU;IAC1C,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;IAK7D,eAAe,IAAI,MAAM;IAInB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAYjC,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,UAAU,CAAC;IAwChE;;;OAGG;WACU,kBAAkB,CAAC,OAAO,GAAE,MAAiC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAe9F;;OAEG;WACU,eAAe,CAAC,OAAO,GAAE,MAAiC,GAAG,OAAO,CAAC,OAAO,CAAC;IAS1F;;OAEG;WACU,gBAAgB,CACzB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,MAAiC,GAC3C,OAAO,CAAC,OAAO,CAAC;CAItB"}
1
+ {"version":3,"file":"ollama.d.ts","sourceRoot":"","sources":["../../src/ai/ollama.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAI7D;;;;GAIG;AACH;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGxF;AAED,qBAAa,cAAe,SAAQ,UAAU;IAC1C,OAAO,CAAC,OAAO,CAAS;gBAEZ,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;IAK7D,eAAe,IAAI,MAAM;IAInB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAalC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;IA2CpE;;;OAGG;WACU,kBAAkB,CAAC,OAAO,GAAE,MAAiC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAe9F;;OAEG;WACU,eAAe,CAAC,OAAO,GAAE,MAAiC,GAAG,OAAO,CAAC,OAAO,CAAC;IAS1F;;OAEG;WACU,gBAAgB,CACzB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,MAAiC,GAC3C,OAAO,CAAC,OAAO,CAAC;CAItB"}
package/dist/ai/ollama.js CHANGED
@@ -6,6 +6,14 @@ import { DEFAULT_MODELS } from '../config/models.js';
6
6
  * Supports local LLMs via Ollama (DeepSeek Coder, CodeLlama, etc.)
7
7
  * No API key required - runs completely offline
8
8
  */
9
+ /**
10
+ * Headers for an Ollama request. Ollama Cloud (https://ollama.com) and authenticated
11
+ * proxies take a bearer key, read from OLLAMA_API_KEY as Ollama's own clients do.
12
+ */
13
+ export function ollamaHeaders(extra = {}) {
14
+ const key = process.env.OLLAMA_API_KEY?.trim();
15
+ return key ? { ...extra, Authorization: `Bearer ${key}` } : extra;
16
+ }
9
17
  export class OllamaProvider extends AIProvider {
10
18
  baseUrl;
11
19
  constructor(apiKey, model, baseUrl) {
@@ -19,6 +27,7 @@ export class OllamaProvider extends AIProvider {
19
27
  try {
20
28
  const response = await fetch(`${this.baseUrl}/api/tags`, {
21
29
  method: 'GET',
30
+ headers: ollamaHeaders(),
22
31
  });
23
32
  return response.ok;
24
33
  }
@@ -27,20 +36,19 @@ export class OllamaProvider extends AIProvider {
27
36
  return false;
28
37
  }
29
38
  }
30
- async *analyze(context) {
39
+ async chat(system, messages) {
40
+ // A single turn uses /api/generate (unchanged from earlier versions); a conversation uses /api/chat
41
+ const single = messages.length === 1 && messages[0].role === 'user';
42
+ const url = `${this.baseUrl}${single ? '/api/generate' : '/api/chat'}`;
43
+ const payload = single
44
+ ? { model: this.model, system, prompt: messages[0].content, stream: false, options: { temperature: 0.2 } }
45
+ : { model: this.model, messages: [{ role: 'system', content: system }, ...messages], stream: false, options: { temperature: 0.2 } };
31
46
  let response;
32
47
  try {
33
- // Same prompt and JSON contract as every other provider, so suggestions carry diffs.
34
- response = await fetch(`${this.baseUrl}/api/generate`, {
48
+ response = await fetch(url, {
35
49
  method: 'POST',
36
- headers: { 'Content-Type': 'application/json' },
37
- body: JSON.stringify({
38
- model: this.model,
39
- system: this.getSystemPrompt(),
40
- prompt: this.buildUserPrompt(context),
41
- stream: false,
42
- options: { temperature: 0.2 },
43
- }),
50
+ headers: ollamaHeaders({ 'Content-Type': 'application/json' }),
51
+ body: JSON.stringify(payload),
44
52
  });
45
53
  }
46
54
  catch (error) {
@@ -50,17 +58,19 @@ export class OllamaProvider extends AIProvider {
50
58
  }
51
59
  if (!response.ok) {
52
60
  const body = await response.text().catch(() => '');
61
+ if (response.status === 401 || response.status === 403) {
62
+ throw new Error(`Ollama at ${this.baseUrl} rejected the request (${response.status}). ` +
63
+ 'For Ollama Cloud, set OLLAMA_API_KEY to a key from https://ollama.com/settings/keys');
64
+ }
53
65
  if (response.status === 404 && /model/i.test(body)) {
54
66
  throw new Error(`Model "${this.model}" is not installed. Run: ollama pull ${this.model}`);
55
67
  }
56
68
  throw new Error(`Ollama API error: ${response.status} ${response.statusText} ${body}`.trim());
57
69
  }
58
70
  const data = (await response.json());
59
- const text = data.response ?? '';
71
+ const text = data.response ?? data.message?.content ?? '';
60
72
  logger.debug(`Ollama raw response (${text.length} chars): ${text.slice(0, 500)}`);
61
- for (const suggestion of this.parseSuggestions(text)) {
62
- yield suggestion;
63
- }
73
+ return text;
64
74
  }
65
75
  /**
66
76
  * Get available Ollama models
@@ -68,7 +78,7 @@ export class OllamaProvider extends AIProvider {
68
78
  */
69
79
  static async getAvailableModels(baseUrl = 'http://localhost:11434') {
70
80
  try {
71
- const response = await fetch(`${baseUrl}/api/tags`);
81
+ const response = await fetch(`${baseUrl}/api/tags`, { headers: ollamaHeaders() });
72
82
  if (!response.ok) {
73
83
  return [];
74
84
  }
@@ -85,7 +95,7 @@ export class OllamaProvider extends AIProvider {
85
95
  */
86
96
  static async isOllamaRunning(baseUrl = 'http://localhost:11434') {
87
97
  try {
88
- const response = await fetch(`${baseUrl}/api/tags`);
98
+ const response = await fetch(`${baseUrl}/api/tags`, { headers: ollamaHeaders() });
89
99
  return response.ok;
90
100
  }
91
101
  catch {
@@ -1 +1 @@
1
- {"version":3,"file":"ollama.js","sourceRoot":"","sources":["../../src/ai/ollama.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ollama.js","sourceRoot":"","sources":["../../src/ai/ollama.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAoB,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD;;;;GAIG;AACH;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgC,EAAE;IAC5D,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,IAAI,EAAE,CAAC;IAC/C,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,aAAa,EAAE,UAAU,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;AACtE,CAAC;AAED,MAAM,OAAO,cAAe,SAAQ,UAAU;IAClC,OAAO,CAAS;IAExB,YAAY,MAAe,EAAE,KAAc,EAAE,OAAgB;QACzD,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,OAAO,IAAI,wBAAwB,CAAC;IACvD,CAAC;IAED,eAAe;QACX,OAAO,cAAc,CAAC,MAAM,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,cAAc;QAChB,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,WAAW,EAAE;gBACrD,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE,aAAa,EAAE;aAC3B,CAAC,CAAC;YACH,OAAO,QAAQ,CAAC,EAAE,CAAC;QACvB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,CAAC,OAAO,CAAC,kCAAmC,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7E,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,MAAc,EAAE,QAAuB;QAC9C,oGAAoG;QACpG,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;QACpE,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QACvE,MAAM,OAAO,GAAG,MAAM;YAClB,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,EAAE;YAC1G,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,GAAG,QAAQ,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,EAAE,CAAC;QAExI,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACD,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;gBACxB,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,aAAa,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC;gBAC9D,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;aAChC,CAAC,CAAC;QACP,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACX,0BAA0B,IAAI,CAAC,OAAO,KAAM,KAAe,CAAC,OAAO,MAAM;gBACrE,iCAAiC;gBACjC,6EAA6E,CACpF,CAAC;QACN,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACnD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBACrD,MAAM,IAAI,KAAK,CACX,aAAa,IAAI,CAAC,OAAO,0BAA0B,QAAQ,CAAC,MAAM,KAAK;oBACnE,qFAAqF,CAC5F,CAAC;YACN,CAAC;YACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjD,MAAM,IAAI,KAAK,CAAC,UAAU,IAAI,CAAC,KAAK,wCAAwC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YAC9F,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,IAAI,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QAClG,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA0D,CAAC;QAC9F,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;QAC1D,MAAM,CAAC,KAAK,CAAC,wBAAwB,IAAI,CAAC,MAAM,YAAY,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QAClF,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,UAAkB,wBAAwB;QACtE,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,WAAW,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC;YAClF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACf,OAAO,EAAE,CAAC;YACd,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA0C,CAAC;YAC3E,OAAO,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACjD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,CAAC,OAAO,CAAC,gCAAiC,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;YAC3E,OAAO,EAAE,CAAC;QACd,CAAC;IACL,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,UAAkB,wBAAwB;QACnE,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,WAAW,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC;YAClF,OAAO,QAAQ,CAAC,EAAE,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,KAAK,CAAC;QACjB,CAAC;IACL,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,gBAAgB,CACzB,KAAa,EACb,UAAkB,wBAAwB;QAE1C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACtD,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;CACJ"}
@@ -1,5 +1,4 @@
1
- import { AIProvider } from './provider.js';
2
- import type { CodeContext, Suggestion } from '../types/index.js';
1
+ import { AIProvider, type ChatMessage } from './provider.js';
3
2
  export declare class OpenAIProvider extends AIProvider {
4
3
  private baseUrl;
5
4
  /**
@@ -10,7 +9,7 @@ export declare class OpenAIProvider extends AIProvider {
10
9
  testConnection(): Promise<boolean>;
11
10
  /** Chat Completions body; reasoning-era models take max_completion_tokens and no temperature. */
12
11
  private buildBody;
13
- analyze(context: CodeContext): AsyncGenerator<Suggestion>;
12
+ chat(system: string, messages: ChatMessage[]): Promise<string>;
14
13
  static getAvailableModels(apiKey: string): Promise<string[]>;
15
14
  }
16
15
  //# sourceMappingURL=openai.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/ai/openai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIjE,qBAAa,cAAe,SAAQ,UAAU;IAC1C,OAAO,CAAC,OAAO,CAAS;IAExB;;OAEG;gBACS,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;IAK9D,eAAe,IAAI,MAAM;IAInB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAoBxC,iGAAiG;IACjG,OAAO,CAAC,SAAS;IAkBV,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,UAAU,CAAC;WAsDnD,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CA8BrE"}
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../src/ai/openai.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAI7D,qBAAa,cAAe,SAAQ,UAAU;IAC1C,OAAO,CAAC,OAAO,CAAS;IAExB;;OAEG;gBACS,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;IAK9D,eAAe,IAAI,MAAM;IAInB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAoBxC,iGAAiG;IACjG,OAAO,CAAC,SAAS;IAeX,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;WAiDvD,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CA8BrE"}
package/dist/ai/openai.js CHANGED
@@ -32,13 +32,10 @@ export class OpenAIProvider extends AIProvider {
32
32
  }
33
33
  }
34
34
  /** Chat Completions body; reasoning-era models take max_completion_tokens and no temperature. */
35
- buildBody(prompt, reasoning) {
35
+ buildBody(system, messages, reasoning) {
36
36
  const body = {
37
37
  model: this.model,
38
- messages: [
39
- { role: 'system', content: this.getSystemPrompt() },
40
- { role: 'user', content: prompt },
41
- ],
38
+ messages: [{ role: 'system', content: system }, ...messages],
42
39
  };
43
40
  if (reasoning) {
44
41
  // Reasoning tokens count toward this cap, so leave room beyond the visible answer.
@@ -50,17 +47,16 @@ export class OpenAIProvider extends AIProvider {
50
47
  }
51
48
  return body;
52
49
  }
53
- async *analyze(context) {
54
- const prompt = this.buildUserPrompt(context);
50
+ async chat(system, messages) {
55
51
  try {
56
- logger.verbose(`Analyzing with OpenAI (${this.model})...`);
52
+ logger.verbose(`Calling OpenAI (${this.model})...`);
57
53
  const response = await fetch(`${this.baseUrl}/chat/completions`, {
58
54
  method: 'POST',
59
55
  headers: {
60
56
  'Content-Type': 'application/json',
61
57
  'Authorization': `Bearer ${this.apiKey}`,
62
58
  },
63
- body: JSON.stringify(this.buildBody(prompt, isOpenAIReasoningModel(this.model))),
59
+ body: JSON.stringify(this.buildBody(system, messages, isOpenAIReasoningModel(this.model))),
64
60
  });
65
61
  let res = response;
66
62
  if (res.status === 400) {
@@ -73,7 +69,7 @@ export class OpenAIProvider extends AIProvider {
73
69
  'Content-Type': 'application/json',
74
70
  'Authorization': `Bearer ${this.apiKey}`,
75
71
  },
76
- body: JSON.stringify(this.buildBody(prompt, !isOpenAIReasoningModel(this.model))),
72
+ body: JSON.stringify(this.buildBody(system, messages, !isOpenAIReasoningModel(this.model))),
77
73
  });
78
74
  }
79
75
  }
@@ -88,11 +84,7 @@ export class OpenAIProvider extends AIProvider {
88
84
  if (!content) {
89
85
  throw new Error('No content in OpenAI response');
90
86
  }
91
- // Parse suggestions from response
92
- const suggestions = this.parseSuggestions(content);
93
- for (const suggestion of suggestions) {
94
- yield suggestion;
95
- }
87
+ return content;
96
88
  }
97
89
  catch (error) {
98
90
  logger.error('OpenAI analysis error:', error);
@@ -1 +1 @@
1
- {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/ai/openai.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/ai/openai.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,9 @@
1
1
  import { CodeContext, Suggestion, AnalyzeOptions, AIProviderInterface } from '../types/index.js';
2
+ /** One turn of a multi-turn conversation with the model. */
3
+ export interface ChatMessage {
4
+ role: 'user' | 'assistant';
5
+ content: string;
6
+ }
2
7
  /**
3
8
  * Base abstract class for AI providers
4
9
  * All providers (OpenAI, Gemini, Anthropic, Ollama) must implement this interface
@@ -19,24 +24,28 @@ export declare abstract class AIProvider implements AIProviderInterface {
19
24
  */
20
25
  abstract testConnection(): Promise<boolean>;
21
26
  /**
22
- * Analyze code and generate suggestions
23
- * @param context - Code context with files and project info
24
- * @param options - Analysis options (streaming, max tokens, etc.)
25
- * @returns AsyncGenerator yielding suggestions as they're generated
27
+ * Send a conversation to the model and return its text reply.
28
+ * Every provider implements this; one-shot analysis and the review agent both build on it.
29
+ */
30
+ abstract chat(system: string, messages: ChatMessage[], options?: AnalyzeOptions): Promise<string>;
31
+ /**
32
+ * Analyze code in one request and yield suggestions
26
33
  */
27
- abstract analyze(context: CodeContext, options?: AnalyzeOptions): AsyncGenerator<Suggestion>;
34
+ analyze(context: CodeContext, options?: AnalyzeOptions): AsyncGenerator<Suggestion>;
28
35
  /**
29
36
  * Format the system prompt for code analysis
30
37
  */
31
- protected getSystemPrompt(): string;
38
+ getSystemPrompt(): string;
32
39
  /**
33
40
  * Build the user prompt with code context
34
41
  */
35
- protected buildUserPrompt(context: CodeContext): string;
42
+ buildUserPrompt(context: CodeContext): string;
36
43
  /**
37
44
  * Parse AI response and extract suggestions
38
45
  */
39
- protected parseSuggestions(response: string): Suggestion[];
46
+ parseSuggestions(response: string): Suggestion[];
47
+ /** A positive integer line number from a model reply, or undefined. */
48
+ static parseLine(value: unknown): number | undefined;
40
49
  /**
41
50
  * Pull the first JSON array/object out of a model reply (handles ```json fences and chatter).
42
51
  */
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/ai/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAEjG;;;GAGG;AACH,8BAAsB,UAAW,YAAW,mBAAmB;IAC3D,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;gBAEhB,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;IAM9D,wCAAwC;IACxC,QAAQ,IAAI,MAAM;IAIlB;;OAEG;IACH,QAAQ,CAAC,eAAe,IAAI,MAAM;IAElC;;OAEG;IACH,QAAQ,CAAC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAE3C;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CACZ,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,cAAc,GACzB,cAAc,CAAC,UAAU,CAAC;IAE7B;;OAEG;IACH,SAAS,CAAC,eAAe,IAAI,MAAM;IAoCnC;;OAEG;IACH,SAAS,CAAC,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;IAmCvD;;OAEG;IACH,SAAS,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE;IA4B1D;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG;CAwBxC"}
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/ai/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAEjG,4DAA4D;AAC5D,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,8BAAsB,UAAW,YAAW,mBAAmB;IAC3D,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;gBAEhB,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;IAM9D,wCAAwC;IACxC,QAAQ,IAAI,MAAM;IAIlB;;OAEG;IACH,QAAQ,CAAC,eAAe,IAAI,MAAM;IAElC;;OAEG;IACH,QAAQ,CAAC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAE3C;;;OAGG;IACH,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IAEjG;;OAEG;IACI,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,cAAc,CAAC,UAAU,CAAC;IAK1F;;OAEG;IACH,eAAe,IAAI,MAAM;IAsCzB;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;IAmC7C;;OAEG;IACH,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE;IA6BhD,uEAAuE;IACvE,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS;IAKpD;;OAEG;IACH,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG;CAwBxC"}
@@ -15,6 +15,14 @@ export class AIProvider {
15
15
  getModel() {
16
16
  return this.model;
17
17
  }
18
+ /**
19
+ * Analyze code in one request and yield suggestions
20
+ */
21
+ async *analyze(context, options) {
22
+ const text = await this.chat(this.getSystemPrompt(), [{ role: 'user', content: this.buildUserPrompt(context) }], options);
23
+ for (const suggestion of this.parseSuggestions(text))
24
+ yield suggestion;
25
+ }
18
26
  /**
19
27
  * Format the system prompt for code analysis
20
28
  */
@@ -36,6 +44,7 @@ Guidelines:
36
44
  - Use unified diff format for code changes
37
45
  - Categorize suggestions by type and severity
38
46
  - "filePath" must be the file's path relative to the project root, exactly as written in its "###" heading
47
+ - "line" is the 1-based line number in that file where the problem is (the line a reviewer would comment on)
39
48
  - "diff" must be a unified diff for that one file: "--- a/<filePath>", "+++ b/<filePath>", then "@@" hunks
40
49
  with 2-3 unchanged context lines copied exactly from the file (same indentation)
41
50
  - If you cannot produce an exact diff, omit the suggestion
@@ -47,6 +56,7 @@ Return a JSON array of suggestions. Each suggestion must have:
47
56
  "severity": "critical" | "high" | "medium" | "low" | "info",
48
57
  "content": "Brief description of the issue",
49
58
  "filePath": "path/to/file.ts",
59
+ "line": 42,
50
60
  "rationale": "Detailed explanation of why this matters",
51
61
  "diff": "Unified diff format showing the change"
52
62
  }
@@ -107,9 +117,15 @@ Be thorough but practical. Focus on high-impact suggestions.`;
107
117
  filePath: s.filePath || s.file || '',
108
118
  rationale: s.rationale || '',
109
119
  diff: typeof s.diff === 'string' ? s.diff : '',
120
+ line: AIProvider.parseLine(s.line ?? s.lineNumber ?? s.startLine),
110
121
  tags: s.tags,
111
122
  }));
112
123
  }
124
+ /** A positive integer line number from a model reply, or undefined. */
125
+ static parseLine(value) {
126
+ const n = typeof value === 'number' ? value : typeof value === 'string' ? parseInt(value, 10) : NaN;
127
+ return Number.isInteger(n) && n > 0 ? n : undefined;
128
+ }
113
129
  /**
114
130
  * Pull the first JSON array/object out of a model reply (handles ```json fences and chatter).
115
131
  */