@devness/coverit 0.1.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.
- package/LICENSE +21 -0
- package/README.md +169 -0
- package/dist/agents/orchestrator.d.ts +21 -0
- package/dist/agents/orchestrator.d.ts.map +1 -0
- package/dist/agents/orchestrator.js +235 -0
- package/dist/agents/orchestrator.js.map +1 -0
- package/dist/agents/reporter.d.ts +13 -0
- package/dist/agents/reporter.d.ts.map +1 -0
- package/dist/agents/reporter.js +323 -0
- package/dist/agents/reporter.js.map +1 -0
- package/dist/ai/anthropic-provider.d.ts +19 -0
- package/dist/ai/anthropic-provider.d.ts.map +1 -0
- package/dist/ai/anthropic-provider.js +83 -0
- package/dist/ai/anthropic-provider.js.map +1 -0
- package/dist/ai/claude-cli-provider.d.ts +22 -0
- package/dist/ai/claude-cli-provider.d.ts.map +1 -0
- package/dist/ai/claude-cli-provider.js +197 -0
- package/dist/ai/claude-cli-provider.js.map +1 -0
- package/dist/ai/index.d.ts +15 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +16 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/ollama-provider.d.ts +17 -0
- package/dist/ai/ollama-provider.d.ts.map +1 -0
- package/dist/ai/ollama-provider.js +88 -0
- package/dist/ai/ollama-provider.js.map +1 -0
- package/dist/ai/openai-provider.d.ts +20 -0
- package/dist/ai/openai-provider.d.ts.map +1 -0
- package/dist/ai/openai-provider.js +74 -0
- package/dist/ai/openai-provider.js.map +1 -0
- package/dist/ai/prompts.d.ts +36 -0
- package/dist/ai/prompts.d.ts.map +1 -0
- package/dist/ai/prompts.js +259 -0
- package/dist/ai/prompts.js.map +1 -0
- package/dist/ai/provider-factory.d.ts +26 -0
- package/dist/ai/provider-factory.d.ts.map +1 -0
- package/dist/ai/provider-factory.js +111 -0
- package/dist/ai/provider-factory.js.map +1 -0
- package/dist/ai/types.d.ts +37 -0
- package/dist/ai/types.d.ts.map +1 -0
- package/dist/ai/types.js +10 -0
- package/dist/ai/types.js.map +1 -0
- package/dist/analysis/code-scanner.d.ts +9 -0
- package/dist/analysis/code-scanner.d.ts.map +1 -0
- package/dist/analysis/code-scanner.js +409 -0
- package/dist/analysis/code-scanner.js.map +1 -0
- package/dist/analysis/dependency-graph.d.ts +9 -0
- package/dist/analysis/dependency-graph.d.ts.map +1 -0
- package/dist/analysis/dependency-graph.js +149 -0
- package/dist/analysis/dependency-graph.js.map +1 -0
- package/dist/analysis/diff-analyzer.d.ts +9 -0
- package/dist/analysis/diff-analyzer.d.ts.map +1 -0
- package/dist/analysis/diff-analyzer.js +232 -0
- package/dist/analysis/diff-analyzer.js.map +1 -0
- package/dist/analysis/index.d.ts +5 -0
- package/dist/analysis/index.d.ts.map +1 -0
- package/dist/analysis/index.js +5 -0
- package/dist/analysis/index.js.map +1 -0
- package/dist/analysis/strategy-planner.d.ts +11 -0
- package/dist/analysis/strategy-planner.d.ts.map +1 -0
- package/dist/analysis/strategy-planner.js +384 -0
- package/dist/analysis/strategy-planner.js.map +1 -0
- package/dist/cli/index.d.ts +9 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +288 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/executors/base-executor.d.ts +35 -0
- package/dist/executors/base-executor.d.ts.map +1 -0
- package/dist/executors/base-executor.js +138 -0
- package/dist/executors/base-executor.js.map +1 -0
- package/dist/executors/browser-runner.d.ts +24 -0
- package/dist/executors/browser-runner.d.ts.map +1 -0
- package/dist/executors/browser-runner.js +194 -0
- package/dist/executors/browser-runner.js.map +1 -0
- package/dist/executors/cloud-runner.d.ts +41 -0
- package/dist/executors/cloud-runner.d.ts.map +1 -0
- package/dist/executors/cloud-runner.js +153 -0
- package/dist/executors/cloud-runner.js.map +1 -0
- package/dist/executors/index.d.ts +12 -0
- package/dist/executors/index.d.ts.map +1 -0
- package/dist/executors/index.js +28 -0
- package/dist/executors/index.js.map +1 -0
- package/dist/executors/local-runner.d.ts +40 -0
- package/dist/executors/local-runner.d.ts.map +1 -0
- package/dist/executors/local-runner.js +395 -0
- package/dist/executors/local-runner.js.map +1 -0
- package/dist/executors/reporter.d.ts +6 -0
- package/dist/executors/reporter.d.ts.map +1 -0
- package/dist/executors/reporter.js +6 -0
- package/dist/executors/reporter.js.map +1 -0
- package/dist/executors/simulator-runner.d.ts +30 -0
- package/dist/executors/simulator-runner.d.ts.map +1 -0
- package/dist/executors/simulator-runner.js +339 -0
- package/dist/executors/simulator-runner.js.map +1 -0
- package/dist/generators/api-test.d.ts +22 -0
- package/dist/generators/api-test.d.ts.map +1 -0
- package/dist/generators/api-test.js +235 -0
- package/dist/generators/api-test.js.map +1 -0
- package/dist/generators/base-generator.d.ts +79 -0
- package/dist/generators/base-generator.d.ts.map +1 -0
- package/dist/generators/base-generator.js +234 -0
- package/dist/generators/base-generator.js.map +1 -0
- package/dist/generators/desktop-test.d.ts +22 -0
- package/dist/generators/desktop-test.d.ts.map +1 -0
- package/dist/generators/desktop-test.js +290 -0
- package/dist/generators/desktop-test.js.map +1 -0
- package/dist/generators/e2e-browser.d.ts +19 -0
- package/dist/generators/e2e-browser.d.ts.map +1 -0
- package/dist/generators/e2e-browser.js +233 -0
- package/dist/generators/e2e-browser.js.map +1 -0
- package/dist/generators/index.d.ts +21 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +66 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/generators/mobile-test.d.ts +22 -0
- package/dist/generators/mobile-test.d.ts.map +1 -0
- package/dist/generators/mobile-test.js +286 -0
- package/dist/generators/mobile-test.js.map +1 -0
- package/dist/generators/unit-test.d.ts +23 -0
- package/dist/generators/unit-test.d.ts.map +1 -0
- package/dist/generators/unit-test.js +282 -0
- package/dist/generators/unit-test.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +8 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +217 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/types/index.d.ts +295 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/framework-detector.d.ts +28 -0
- package/dist/utils/framework-detector.d.ts.map +1 -0
- package/dist/utils/framework-detector.js +184 -0
- package/dist/utils/framework-detector.js.map +1 -0
- package/dist/utils/git.d.ts +33 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +82 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/logger.d.ts +17 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +47 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +86 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude CLI Provider
|
|
3
|
+
*
|
|
4
|
+
* Leverages the user's existing Claude Code installation by spawning
|
|
5
|
+
* the `claude` CLI binary. This is the preferred provider since it
|
|
6
|
+
* uses the user's existing Claude Pro/Max subscription with zero
|
|
7
|
+
* additional cost or API key configuration.
|
|
8
|
+
*
|
|
9
|
+
* The CLI is invoked with `--output-format=stream-json` and we parse
|
|
10
|
+
* the streaming NDJSON to extract the assistant's text response.
|
|
11
|
+
*/
|
|
12
|
+
import { spawn } from "node:child_process";
|
|
13
|
+
import { access, constants } from "node:fs/promises";
|
|
14
|
+
import { homedir } from "node:os";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
/** Known filesystem locations where the claude binary might live */
|
|
17
|
+
const CLAUDE_BINARY_PATHS = [
|
|
18
|
+
"/opt/homebrew/bin/claude",
|
|
19
|
+
"/usr/local/bin/claude",
|
|
20
|
+
join(homedir(), ".claude", "bin", "claude"),
|
|
21
|
+
join(homedir(), ".local", "bin", "claude"),
|
|
22
|
+
];
|
|
23
|
+
/**
|
|
24
|
+
* Resolve the path to the claude CLI binary.
|
|
25
|
+
* Tries `which` first, then falls back to known filesystem locations.
|
|
26
|
+
*/
|
|
27
|
+
async function findClaudeBinary() {
|
|
28
|
+
// Fast path: check if `claude` is on PATH
|
|
29
|
+
const whichResult = await new Promise((resolve) => {
|
|
30
|
+
const proc = spawn("which", ["claude"]);
|
|
31
|
+
let stdout = "";
|
|
32
|
+
proc.stdout.on("data", (chunk) => {
|
|
33
|
+
stdout += chunk.toString();
|
|
34
|
+
});
|
|
35
|
+
proc.on("close", (code) => {
|
|
36
|
+
resolve(code === 0 ? stdout.trim() : null);
|
|
37
|
+
});
|
|
38
|
+
proc.on("error", () => resolve(null));
|
|
39
|
+
});
|
|
40
|
+
if (whichResult)
|
|
41
|
+
return whichResult;
|
|
42
|
+
// Fallback: probe known locations
|
|
43
|
+
for (const binPath of CLAUDE_BINARY_PATHS) {
|
|
44
|
+
try {
|
|
45
|
+
await access(binPath, constants.X_OK);
|
|
46
|
+
return binPath;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Not found or not executable at this path
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Parse streaming JSON lines from the claude CLI.
|
|
56
|
+
*
|
|
57
|
+
* The CLI emits newline-delimited JSON objects. We look for assistant
|
|
58
|
+
* messages that contain text content blocks and accumulate them into
|
|
59
|
+
* the final response string.
|
|
60
|
+
*/
|
|
61
|
+
function parseStreamingOutput(raw) {
|
|
62
|
+
const lines = raw.split("\n").filter((line) => line.trim().length > 0);
|
|
63
|
+
const textParts = [];
|
|
64
|
+
let model = "claude-cli";
|
|
65
|
+
for (const line of lines) {
|
|
66
|
+
try {
|
|
67
|
+
const parsed = JSON.parse(line);
|
|
68
|
+
if (!parsed || typeof parsed !== "object")
|
|
69
|
+
continue;
|
|
70
|
+
const obj = parsed;
|
|
71
|
+
// Extract model info from any message that carries it
|
|
72
|
+
if (typeof obj["model"] === "string") {
|
|
73
|
+
model = obj["model"];
|
|
74
|
+
}
|
|
75
|
+
// Look for assistant messages with content blocks
|
|
76
|
+
if (obj["type"] === "assistant" && Array.isArray(obj["content"])) {
|
|
77
|
+
for (const block of obj["content"]) {
|
|
78
|
+
if (block["type"] === "text" && typeof block["text"] === "string") {
|
|
79
|
+
textParts.push(block["text"]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Also handle content_block_delta streaming events
|
|
84
|
+
if (obj["type"] === "content_block_delta" &&
|
|
85
|
+
obj["delta"] &&
|
|
86
|
+
typeof obj["delta"] === "object") {
|
|
87
|
+
const delta = obj["delta"];
|
|
88
|
+
if (delta["type"] === "text_delta" && typeof delta["text"] === "string") {
|
|
89
|
+
textParts.push(delta["text"]);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
// Handle result messages that wrap the final content
|
|
93
|
+
if (obj["type"] === "result" && typeof obj["result"] === "string") {
|
|
94
|
+
textParts.push(obj["result"]);
|
|
95
|
+
}
|
|
96
|
+
// Handle result messages with nested content
|
|
97
|
+
if (obj["type"] === "result" &&
|
|
98
|
+
obj["result"] &&
|
|
99
|
+
typeof obj["result"] === "object" &&
|
|
100
|
+
!Array.isArray(obj["result"])) {
|
|
101
|
+
const result = obj["result"];
|
|
102
|
+
if (Array.isArray(result["content"])) {
|
|
103
|
+
for (const block of result["content"]) {
|
|
104
|
+
if (block["type"] === "text" &&
|
|
105
|
+
typeof block["text"] === "string") {
|
|
106
|
+
textParts.push(block["text"]);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
// Skip malformed JSON lines (progress indicators, etc.)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return { content: textParts.join(""), model };
|
|
117
|
+
}
|
|
118
|
+
export class ClaudeCliProvider {
|
|
119
|
+
name = "claude-cli";
|
|
120
|
+
model;
|
|
121
|
+
binaryPath = null;
|
|
122
|
+
constructor(config) {
|
|
123
|
+
this.model = config?.model ?? "sonnet";
|
|
124
|
+
}
|
|
125
|
+
async isAvailable() {
|
|
126
|
+
this.binaryPath = await findClaudeBinary();
|
|
127
|
+
return this.binaryPath !== null;
|
|
128
|
+
}
|
|
129
|
+
async generate(messages, _options) {
|
|
130
|
+
if (!this.binaryPath) {
|
|
131
|
+
this.binaryPath = await findClaudeBinary();
|
|
132
|
+
}
|
|
133
|
+
if (!this.binaryPath) {
|
|
134
|
+
throw new Error("Claude CLI binary not found. Install Claude Code: https://docs.anthropic.com/en/docs/claude-code");
|
|
135
|
+
}
|
|
136
|
+
// Flatten messages into a single prompt string.
|
|
137
|
+
const prompt = messages
|
|
138
|
+
.map((msg) => {
|
|
139
|
+
if (msg.role === "system")
|
|
140
|
+
return `[System Instructions]\n${msg.content}\n`;
|
|
141
|
+
if (msg.role === "user")
|
|
142
|
+
return `[User]\n${msg.content}\n`;
|
|
143
|
+
return `[Assistant]\n${msg.content}\n`;
|
|
144
|
+
})
|
|
145
|
+
.join("\n");
|
|
146
|
+
// Use --print with prompt piped via stdin to avoid CLI arg length limits.
|
|
147
|
+
const args = [
|
|
148
|
+
"--print",
|
|
149
|
+
"--output-format",
|
|
150
|
+
"stream-json",
|
|
151
|
+
"--verbose",
|
|
152
|
+
"--model",
|
|
153
|
+
this.model,
|
|
154
|
+
];
|
|
155
|
+
const result = await this.spawnClaude(args, prompt);
|
|
156
|
+
if (result.exitCode !== 0 && !result.stdout.trim()) {
|
|
157
|
+
throw new Error(`Claude CLI exited with code ${result.exitCode}: ${result.stderr || "Unknown error"}`);
|
|
158
|
+
}
|
|
159
|
+
const { content, model } = parseStreamingOutput(result.stdout);
|
|
160
|
+
if (!content) {
|
|
161
|
+
throw new Error("Claude CLI returned no text content. stderr: " +
|
|
162
|
+
(result.stderr || "(empty)"));
|
|
163
|
+
}
|
|
164
|
+
return { content, model };
|
|
165
|
+
}
|
|
166
|
+
spawnClaude(args, stdinData) {
|
|
167
|
+
return new Promise((resolve, reject) => {
|
|
168
|
+
const proc = spawn(this.binaryPath, args, {
|
|
169
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
170
|
+
env: { ...process.env },
|
|
171
|
+
});
|
|
172
|
+
let stdout = "";
|
|
173
|
+
let stderr = "";
|
|
174
|
+
proc.stdout.on("data", (chunk) => {
|
|
175
|
+
stdout += chunk.toString();
|
|
176
|
+
});
|
|
177
|
+
proc.stderr.on("data", (chunk) => {
|
|
178
|
+
stderr += chunk.toString();
|
|
179
|
+
});
|
|
180
|
+
proc.on("close", (code) => {
|
|
181
|
+
resolve({ stdout, stderr, exitCode: code ?? 1 });
|
|
182
|
+
});
|
|
183
|
+
proc.on("error", (err) => {
|
|
184
|
+
reject(new Error(`Failed to spawn Claude CLI: ${err.message}`));
|
|
185
|
+
});
|
|
186
|
+
// Pipe prompt via stdin and close to signal EOF
|
|
187
|
+
if (stdinData) {
|
|
188
|
+
proc.stdin.write(stdinData);
|
|
189
|
+
proc.stdin.end();
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
proc.stdin.end();
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=claude-cli-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-cli-provider.js","sourceRoot":"","sources":["../../src/ai/claude-cli-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Provider Layer — Barrel Exports
|
|
3
|
+
*
|
|
4
|
+
* This module is the public API for coverit's AI integration.
|
|
5
|
+
* Import everything you need from "@coverit/ai" (or "./ai").
|
|
6
|
+
*/
|
|
7
|
+
export type { AIProviderType, AIProviderConfig, AIMessage, AIResponse, AIGenerateOptions, AIProvider, } from "./types.js";
|
|
8
|
+
export { ClaudeCliProvider } from "./claude-cli-provider.js";
|
|
9
|
+
export { AnthropicProvider } from "./anthropic-provider.js";
|
|
10
|
+
export { OpenAIProvider } from "./openai-provider.js";
|
|
11
|
+
export { OllamaProvider } from "./ollama-provider.js";
|
|
12
|
+
export { createAIProvider, detectBestProvider } from "./provider-factory.js";
|
|
13
|
+
export { buildTestGenerationPrompt, buildTestRefinementPrompt, } from "./prompts.js";
|
|
14
|
+
export type { TestGenerationParams, TestRefinementParams, } from "./prompts.js";
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,YAAY,EACV,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,UAAU,GACX,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAG7E,OAAO,EACL,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,oBAAoB,EACpB,oBAAoB,GACrB,MAAM,cAAc,CAAC"}
|
package/dist/ai/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Provider Layer — Barrel Exports
|
|
3
|
+
*
|
|
4
|
+
* This module is the public API for coverit's AI integration.
|
|
5
|
+
* Import everything you need from "@coverit/ai" (or "./ai").
|
|
6
|
+
*/
|
|
7
|
+
// Providers
|
|
8
|
+
export { ClaudeCliProvider } from "./claude-cli-provider.js";
|
|
9
|
+
export { AnthropicProvider } from "./anthropic-provider.js";
|
|
10
|
+
export { OpenAIProvider } from "./openai-provider.js";
|
|
11
|
+
export { OllamaProvider } from "./ollama-provider.js";
|
|
12
|
+
// Factory
|
|
13
|
+
export { createAIProvider, detectBestProvider } from "./provider-factory.js";
|
|
14
|
+
// Prompts
|
|
15
|
+
export { buildTestGenerationPrompt, buildTestRefinementPrompt, } from "./prompts.js";
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAYH,YAAY;AACZ,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,UAAU;AACV,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE7E,UAAU;AACV,OAAO,EACL,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ollama Local Provider
|
|
3
|
+
*
|
|
4
|
+
* Connects to a locally running Ollama instance for fully offline,
|
|
5
|
+
* zero-cost AI inference. Ollama must be running before use.
|
|
6
|
+
* Default model is llama3.1 but any Ollama-supported model works.
|
|
7
|
+
*/
|
|
8
|
+
import type { AIProvider, AIMessage, AIResponse, AIGenerateOptions, AIProviderConfig } from "./types.js";
|
|
9
|
+
export declare class OllamaProvider implements AIProvider {
|
|
10
|
+
readonly name = "ollama";
|
|
11
|
+
private readonly model;
|
|
12
|
+
private readonly baseUrl;
|
|
13
|
+
constructor(config?: Partial<AIProviderConfig>);
|
|
14
|
+
isAvailable(): Promise<boolean>;
|
|
15
|
+
generate(messages: AIMessage[], options?: AIGenerateOptions): Promise<AIResponse>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=ollama-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollama-provider.d.ts","sourceRoot":"","sources":["../../src/ai/ollama-provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAoBpB,qBAAa,cAAe,YAAW,UAAU;IAC/C,QAAQ,CAAC,IAAI,YAAY;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC;IAKxC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAqB/B,QAAQ,CACZ,QAAQ,EAAE,SAAS,EAAE,EACrB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,UAAU,CAAC;CA6DvB"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ollama Local Provider
|
|
3
|
+
*
|
|
4
|
+
* Connects to a locally running Ollama instance for fully offline,
|
|
5
|
+
* zero-cost AI inference. Ollama must be running before use.
|
|
6
|
+
* Default model is llama3.1 but any Ollama-supported model works.
|
|
7
|
+
*/
|
|
8
|
+
const DEFAULT_MODEL = "llama3.1";
|
|
9
|
+
const DEFAULT_BASE_URL = "http://localhost:11434";
|
|
10
|
+
export class OllamaProvider {
|
|
11
|
+
name = "ollama";
|
|
12
|
+
model;
|
|
13
|
+
baseUrl;
|
|
14
|
+
constructor(config) {
|
|
15
|
+
this.model = config?.model ?? DEFAULT_MODEL;
|
|
16
|
+
this.baseUrl = (config?.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
17
|
+
}
|
|
18
|
+
async isAvailable() {
|
|
19
|
+
try {
|
|
20
|
+
const controller = new AbortController();
|
|
21
|
+
const timeout = setTimeout(() => controller.abort(), 2000);
|
|
22
|
+
const response = await fetch(`${this.baseUrl}/api/tags`, {
|
|
23
|
+
signal: controller.signal,
|
|
24
|
+
});
|
|
25
|
+
clearTimeout(timeout);
|
|
26
|
+
if (!response.ok)
|
|
27
|
+
return false;
|
|
28
|
+
// Verify the response looks like Ollama (has a models array)
|
|
29
|
+
const data = (await response.json());
|
|
30
|
+
return Array.isArray(data.models);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Connection refused, timeout, or parse error means Ollama is not running
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async generate(messages, options) {
|
|
38
|
+
// Ollama's chat endpoint accepts the same message format as OpenAI
|
|
39
|
+
const ollamaMessages = messages.map((m) => ({
|
|
40
|
+
role: m.role,
|
|
41
|
+
content: m.content,
|
|
42
|
+
}));
|
|
43
|
+
const body = {
|
|
44
|
+
model: this.model,
|
|
45
|
+
messages: ollamaMessages,
|
|
46
|
+
stream: false,
|
|
47
|
+
};
|
|
48
|
+
// Ollama uses an `options` object for generation parameters
|
|
49
|
+
const ollamaOptions = {};
|
|
50
|
+
if (options?.maxTokens) {
|
|
51
|
+
ollamaOptions["num_predict"] = options.maxTokens;
|
|
52
|
+
}
|
|
53
|
+
if (options?.temperature !== undefined) {
|
|
54
|
+
ollamaOptions["temperature"] = options.temperature;
|
|
55
|
+
}
|
|
56
|
+
if (Object.keys(ollamaOptions).length > 0) {
|
|
57
|
+
body["options"] = ollamaOptions;
|
|
58
|
+
}
|
|
59
|
+
let response;
|
|
60
|
+
try {
|
|
61
|
+
response = await fetch(`${this.baseUrl}/api/chat`, {
|
|
62
|
+
method: "POST",
|
|
63
|
+
headers: { "Content-Type": "application/json" },
|
|
64
|
+
body: JSON.stringify(body),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
throw new Error(`Failed to connect to Ollama at ${this.baseUrl}. Is Ollama running? Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
69
|
+
}
|
|
70
|
+
if (!response.ok) {
|
|
71
|
+
const errorBody = await response.text();
|
|
72
|
+
throw new Error(`Ollama API error (${response.status}): ${errorBody}`);
|
|
73
|
+
}
|
|
74
|
+
const data = (await response.json());
|
|
75
|
+
if (data.error) {
|
|
76
|
+
throw new Error(`Ollama error: ${data.error}`);
|
|
77
|
+
}
|
|
78
|
+
if (!data.message?.content) {
|
|
79
|
+
throw new Error("Ollama returned no content in the response.");
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
content: data.message.content,
|
|
83
|
+
model: data.model,
|
|
84
|
+
tokensUsed: data.eval_count,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=ollama-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollama-provider.js","sourceRoot":"","sources":["../../src/ai/ollama-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI-Compatible Provider
|
|
3
|
+
*
|
|
4
|
+
* Works with OpenAI, Azure OpenAI, Groq, Together, and any other
|
|
5
|
+
* service that implements the OpenAI Chat Completions API contract.
|
|
6
|
+
* Uses fetch directly to avoid SDK dependencies.
|
|
7
|
+
*/
|
|
8
|
+
import type { AIProvider, AIMessage, AIResponse, AIGenerateOptions, AIProviderConfig } from "./types.js";
|
|
9
|
+
export declare class OpenAIProvider implements AIProvider {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
private readonly model;
|
|
12
|
+
private readonly apiKey;
|
|
13
|
+
private readonly baseUrl;
|
|
14
|
+
private readonly maxTokens;
|
|
15
|
+
private readonly temperature;
|
|
16
|
+
constructor(config?: Partial<AIProviderConfig>);
|
|
17
|
+
isAvailable(): Promise<boolean>;
|
|
18
|
+
generate(messages: AIMessage[], options?: AIGenerateOptions): Promise<AIResponse>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=openai-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-provider.d.ts","sourceRoot":"","sources":["../../src/ai/openai-provider.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,UAAU,EACV,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAkBpB,qBAAa,cAAe,YAAW,UAAU;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAqB;gBAErC,MAAM,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC;IAcxC,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAI/B,QAAQ,CACZ,QAAQ,EAAE,SAAS,EAAE,EACrB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,UAAU,CAAC;CAuDvB"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI-Compatible Provider
|
|
3
|
+
*
|
|
4
|
+
* Works with OpenAI, Azure OpenAI, Groq, Together, and any other
|
|
5
|
+
* service that implements the OpenAI Chat Completions API contract.
|
|
6
|
+
* Uses fetch directly to avoid SDK dependencies.
|
|
7
|
+
*/
|
|
8
|
+
const DEFAULT_MODEL = "gpt-4o";
|
|
9
|
+
const DEFAULT_BASE_URL = "https://api.openai.com/v1";
|
|
10
|
+
const DEFAULT_MAX_TOKENS = 8192;
|
|
11
|
+
export class OpenAIProvider {
|
|
12
|
+
name;
|
|
13
|
+
model;
|
|
14
|
+
apiKey;
|
|
15
|
+
baseUrl;
|
|
16
|
+
maxTokens;
|
|
17
|
+
temperature;
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.model = config?.model ?? DEFAULT_MODEL;
|
|
20
|
+
this.apiKey = config?.apiKey ?? process.env["OPENAI_API_KEY"];
|
|
21
|
+
this.baseUrl = (config?.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
22
|
+
this.maxTokens = config?.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
23
|
+
this.temperature = config?.temperature;
|
|
24
|
+
// Name reflects whether this is standard OpenAI or a compatible endpoint
|
|
25
|
+
this.name =
|
|
26
|
+
config?.provider === "openai-compatible"
|
|
27
|
+
? `openai-compatible (${this.baseUrl})`
|
|
28
|
+
: "openai";
|
|
29
|
+
}
|
|
30
|
+
async isAvailable() {
|
|
31
|
+
return typeof this.apiKey === "string" && this.apiKey.length > 0;
|
|
32
|
+
}
|
|
33
|
+
async generate(messages, options) {
|
|
34
|
+
const apiKey = this.apiKey;
|
|
35
|
+
if (!apiKey) {
|
|
36
|
+
throw new Error("OpenAI API key not configured. Set OPENAI_API_KEY or pass apiKey in config.");
|
|
37
|
+
}
|
|
38
|
+
const temperature = options?.temperature ?? this.temperature;
|
|
39
|
+
const body = {
|
|
40
|
+
model: this.model,
|
|
41
|
+
max_tokens: options?.maxTokens ?? this.maxTokens,
|
|
42
|
+
messages: messages.map((m) => ({ role: m.role, content: m.content })),
|
|
43
|
+
};
|
|
44
|
+
if (temperature !== undefined) {
|
|
45
|
+
body["temperature"] = temperature;
|
|
46
|
+
}
|
|
47
|
+
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
48
|
+
method: "POST",
|
|
49
|
+
headers: {
|
|
50
|
+
Authorization: `Bearer ${apiKey}`,
|
|
51
|
+
"Content-Type": "application/json",
|
|
52
|
+
},
|
|
53
|
+
body: JSON.stringify(body),
|
|
54
|
+
});
|
|
55
|
+
if (!response.ok) {
|
|
56
|
+
const errorBody = await response.text();
|
|
57
|
+
throw new Error(`OpenAI API error (${response.status}): ${errorBody}`);
|
|
58
|
+
}
|
|
59
|
+
const data = (await response.json());
|
|
60
|
+
if (data.error) {
|
|
61
|
+
throw new Error(`OpenAI API error: [${data.error.type}] ${data.error.message}`);
|
|
62
|
+
}
|
|
63
|
+
const firstChoice = data.choices[0];
|
|
64
|
+
if (!firstChoice?.message.content) {
|
|
65
|
+
throw new Error("OpenAI API returned no content in the response.");
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
content: firstChoice.message.content,
|
|
69
|
+
model: data.model,
|
|
70
|
+
tokensUsed: data.usage?.total_tokens,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=openai-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-provider.js","sourceRoot":"","sources":["../../src/ai/openai-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Templates for AI-Powered Test Generation
|
|
3
|
+
*
|
|
4
|
+
* These prompts combine AST analysis context with structured LLM
|
|
5
|
+
* instructions to produce high-quality, runnable test files.
|
|
6
|
+
* Each prompt is designed to be provider-agnostic — they work
|
|
7
|
+
* identically whether sent to Claude, GPT, or a local model.
|
|
8
|
+
*/
|
|
9
|
+
import type { AIMessage } from "./types.js";
|
|
10
|
+
import type { CodeScanResult, TestType, TestFramework, TestFailure } from "../types/index.js";
|
|
11
|
+
export interface TestGenerationParams {
|
|
12
|
+
sourceCode: string;
|
|
13
|
+
scanResult: CodeScanResult;
|
|
14
|
+
testType: TestType;
|
|
15
|
+
framework: TestFramework;
|
|
16
|
+
existingTests?: string[];
|
|
17
|
+
projectContext?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Build the message array for generating tests from source code
|
|
21
|
+
* and AST analysis results. The system message establishes the
|
|
22
|
+
* persona and hard constraints; the user message provides all
|
|
23
|
+
* the context needed to write tests.
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildTestGenerationPrompt(params: TestGenerationParams): AIMessage[];
|
|
26
|
+
export interface TestRefinementParams {
|
|
27
|
+
testCode: string;
|
|
28
|
+
failures: TestFailure[];
|
|
29
|
+
sourceCode: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Build the message array for refining tests that failed.
|
|
33
|
+
* This is used in the feedback loop: generate -> run -> failures -> refine -> run again.
|
|
34
|
+
*/
|
|
35
|
+
export declare function buildTestRefinementPrompt(params: TestRefinementParams): AIMessage[];
|
|
36
|
+
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/ai/prompts.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EACV,cAAc,EACd,QAAQ,EACR,aAAa,EACb,WAAW,EACZ,MAAM,mBAAmB,CAAC;AAI3B,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,cAAc,CAAC;IAC3B,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,aAAa,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,oBAAoB,GAC3B,SAAS,EAAE,CAwBb;AA8PD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,oBAAoB,GAC3B,SAAS,EAAE,CAoCb"}
|