Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 91 additions & 24 deletions src/adapters/base-adapter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { spawn, ChildProcess } from "child_process";
import path from "path";
import { logger } from "../shared/logger";
import { IDEAdapter, ModelInfo, TrackedFiles } from "../shared/types";

Expand Down Expand Up @@ -60,7 +59,8 @@ const FILE_READ_PATTERNS = [
/(?:read(?:ing)?|analyz(?:e|ed|ing)|inspect(?:ed|ing)?|review(?:ed|ing)?|look(?:ed|ing)?\s+at|open(?:ed|ing)?)\s+[`'"]?([^\s`'"]+\.\w{1,10})[`'"]?/gi,
];

const FILE_PATH_PATTERN = /(?:^|\s)([a-zA-Z]?:?(?:\/|\\)?(?:[\w.\-]+(?:\/|\\))+[\w.\-]+\.\w{1,10})(?:\s|$|[,;:)`'"])/g;
const FILE_PATH_PATTERN =
/(?:^|\s)([a-zA-Z]?:?(?:\/|\\)?(?:[\w.-]+(?:\/|\\))+[\w.-]+\.\w{1,10})(?:\s|$|[,;:)`'"])/g;

export abstract class BaseAdapter implements IDEAdapter {
protected connected: boolean = false;
Expand All @@ -85,7 +85,7 @@ export abstract class BaseAdapter implements IDEAdapter {
return formatted;
}

protected exitCodeIndicatesSuccess(code: number | null, output: string): boolean {
protected exitCodeIndicatesSuccess(code: number | null, _output: string): boolean {
return code === 0;
}

Expand All @@ -96,9 +96,12 @@ export abstract class BaseAdapter implements IDEAdapter {
try {
const { exec } = require("child_process");
await new Promise((resolve, reject) => {
exec(`${config.cliCommand} --version`, (error: any, stdout: string) => {
if (error) reject(error);
else resolve(stdout);
exec(`${config.cliCommand} --version`, (error: Error | null, stdout: string) => {
if (error) {
reject(error);
} else {
resolve(stdout);
}
});
});
logger.debug(`${config.displayName} installed`);
Expand Down Expand Up @@ -288,10 +291,17 @@ export abstract class BaseAdapter implements IDEAdapter {
try {
const { exec } = require("child_process");
await new Promise((resolve, reject) => {
exec(`${config.cliCommand} --version`, { timeout: 5000 }, (error: any, stdout: string) => {
if (error) reject(error);
else resolve(stdout);
});
exec(
`${config.cliCommand} --version`,
{ timeout: 5000 },
(error: Error | null, stdout: string) => {
if (error) {
reject(error);
} else {
resolve(stdout);
}
},
);
});
return true;
} catch (error) {
Expand Down Expand Up @@ -327,7 +337,9 @@ export abstract class BaseAdapter implements IDEAdapter {
let match;
while ((match = pattern.exec(cleaned)) !== null) {
const fp = this.normalizeFilePath(match[1]);
if (fp) this.modifiedFiles.add(fp);
if (fp) {
this.modifiedFiles.add(fp);
}
}
}

Expand All @@ -336,7 +348,9 @@ export abstract class BaseAdapter implements IDEAdapter {
let match;
while ((match = pattern.exec(cleaned)) !== null) {
const fp = this.normalizeFilePath(match[1]);
if (fp) this.readFiles.add(fp);
if (fp) {
this.readFiles.add(fp);
}
}
}

Expand All @@ -352,18 +366,60 @@ export abstract class BaseAdapter implements IDEAdapter {

private normalizeFilePath(raw: string): string | null {
const trimmed = raw.trim().replace(/['"`,;:)]+$/, "");
if (!trimmed || trimmed.length < 3) return null;
if (!trimmed || trimmed.length < 3) {
return null;
}

const ext = trimmed.split(".").pop() || "";
const codeExtensions = [
"ts", "tsx", "js", "jsx", "py", "rs", "go", "java", "c", "cpp", "h", "hpp",
"cs", "rb", "php", "swift", "kt", "scala", "vue", "svelte", "html", "css",
"scss", "less", "json", "yaml", "yml", "toml", "xml", "md", "txt", "sql",
"sh", "bash", "zsh", "ps1", "bat", "cmd", "dockerfile", "makefile",
"ts",
"tsx",
"js",
"jsx",
"py",
"rs",
"go",
"java",
"c",
"cpp",
"h",
"hpp",
"cs",
"rb",
"php",
"swift",
"kt",
"scala",
"vue",
"svelte",
"html",
"css",
"scss",
"less",
"json",
"yaml",
"yml",
"toml",
"xml",
"md",
"txt",
"sql",
"sh",
"bash",
"zsh",
"ps1",
"bat",
"cmd",
"dockerfile",
"makefile",
];
if (!codeExtensions.includes(ext.toLowerCase())) return null;
if (!codeExtensions.includes(ext.toLowerCase())) {
return null;
}

if (trimmed.includes("node_modules") || trimmed.includes(".git/")) return null;
if (trimmed.includes("node_modules") || trimmed.includes(".git/")) {
return null;
}

return trimmed;
}
Expand Down Expand Up @@ -395,9 +451,15 @@ export abstract class BaseAdapter implements IDEAdapter {

for (const line of lines) {
const trimmed = line.trim();
if (!trimmed) continue;
if (isCliNoiseLine(trimmed)) continue;
if (isDiffLine(trimmed)) continue;
if (!trimmed) {
continue;
}
if (isCliNoiseLine(trimmed)) {
continue;
}
if (isDiffLine(trimmed)) {
continue;
}
kept.push(line);
}

Expand All @@ -411,7 +473,9 @@ export abstract class BaseAdapter implements IDEAdapter {

for (const line of lines) {
const trimmed = line.trim();
if (isCliNoiseLine(trimmed)) continue;
if (isCliNoiseLine(trimmed)) {
continue;
}
kept.push(line);
}

Expand Down Expand Up @@ -470,6 +534,7 @@ export abstract class BaseAdapter implements IDEAdapter {
}

export function stripAnsi(text: string): string {
// eslint-disable-next-line no-control-regex
return text.replace(/\x1b\[[0-9;]*m/g, "").replace(/\x1b\[[0-9;]*[A-Za-z]/g, "");
}

Expand All @@ -492,7 +557,9 @@ export function isDiffLine(trimmed: string): boolean {
}

export function isCliNoiseLine(trimmed: string): boolean {
if (!trimmed) return true;
if (!trimmed) {
return true;
}
return CLI_NOISE_PATTERNS.some((p) => p.test(trimmed));
}

Expand Down
31 changes: 19 additions & 12 deletions src/adapters/ollama-claude-code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,17 @@ export class OllamaClaudeCodeAdapter extends BaseAdapter {
throw new Error("Ollama not responding");
}

const data: any = await response.json();
const data = (await response.json()) as { models?: Array<{ name: string }> };
const models = data.models || [];

if (models.length === 0) {
throw new Error("No models found. Please pull a model first.");
}

const modelExists = models.some((m: any) => m.name === this.ollamaModel);
const modelExists = models.some((m) => m.name === this.ollamaModel);
if (!modelExists) {
logger.debug(`Model ${this.ollamaModel} not found`);
logger.debug(` Available models: ${models.map((m: any) => m.name).join(", ")}`);
logger.debug(` Available models: ${models.map((m) => m.name).join(", ")}`);
throw new Error(`Model ${this.ollamaModel} not available`);
}

Expand Down Expand Up @@ -97,7 +97,7 @@ Session: ${this.currentSessionId || "None"}`;

try {
const response = await fetch("http://localhost:11434/api/tags");
const data: any = await response.json();
const data = (await response.json()) as { models?: Array<{ name: string }> };
const models = data.models || [];

return `${this.getStatusText()}
Expand All @@ -112,10 +112,17 @@ Available models: ${models.length}`;
const config = this.getConfig();
const { exec } = require("child_process");
await new Promise((resolve, reject) => {
exec(`${config.cliCommand} --version`, { timeout: 5000 }, (error: any, stdout: string) => {
if (error) reject(error);
else resolve(stdout);
});
exec(
`${config.cliCommand} --version`,
{ timeout: 5000 },
(error: Error | null, stdout: string) => {
if (error) {
reject(error);
} else {
resolve(stdout);
}
},
);
});

const response = await fetch("http://localhost:11434/api/tags", {
Expand All @@ -125,9 +132,9 @@ Available models: ${models.length}`;
return false;
}

const data: any = await response.json();
const data = (await response.json()) as { models?: Array<{ name: string }> };
const models = data.models || [];
return models.some((m: any) => m.name === this.ollamaModel);
return models.some((m) => m.name === this.ollamaModel);
} catch (error) {
logger.debug(`Ollama health check failed: ${error}`);
return false;
Expand Down Expand Up @@ -160,9 +167,9 @@ Available models: ${models.length}`;
try {
const response = await fetch("http://localhost:11434/api/tags");
if (response.ok) {
const data: any = await response.json();
const data = (await response.json()) as { models?: Array<{ name: string }> };
const models = data.models || [];
this.cachedModels = models.map((m: any) => ({
this.cachedModels = models.map((m) => ({
id: m.name,
name: m.name,
}));
Expand Down
10 changes: 9 additions & 1 deletion src/adapters/openai-codex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,15 @@ export class CodexAdapter extends BaseAdapter {
}

protected buildArgs(fullInstruction: string): string[] {
return ["exec", "--full-auto", "-m", this.codexModel, "--cd", this.projectPath, fullInstruction];
return [
"exec",
"--full-auto",
"-m",
this.codexModel,
"--cd",
this.projectPath,
fullInstruction,
];
}

protected exitCodeIndicatesSuccess(code: number | null, output: string): boolean {
Expand Down
Loading