@stackmemoryai/stackmemory
Version:
Project-scoped memory for AI coding tools. Durable context across sessions with MCP integration, frames, smart retrieval, Claude Code skills, and automatic hooks.
99 lines (98 loc) • 3.56 kB
JavaScript
import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { spawnSync } from "child_process";
async function callClaude(prompt, options) {
const apiKey = process.env["ANTHROPIC_API_KEY"];
if (!apiKey) {
const sys = (options.system || "").toLowerCase();
if (sys.includes("strict code reviewer") || sys.includes("return a json object") || sys.includes("approved")) {
return JSON.stringify({ approved: true, issues: [], suggestions: [] });
}
return `STUB: No ANTHROPIC_API_KEY set. Returning heuristic plan for prompt: ${prompt.slice(0, 80).trim()}...`;
}
const { Anthropic } = await import("@anthropic-ai/sdk");
const client = new Anthropic({ apiKey });
const model = options.model || "claude-sonnet-4-20250514";
const system = options.system || "You are a precise software planning assistant.";
try {
const msg = await client.messages.create({
model,
max_tokens: 4096,
system,
messages: [{ role: "user", content: prompt }]
});
const block = msg?.content?.[0];
const text = block && "text" in block ? block.text : JSON.stringify(msg);
return text;
} catch {
const sys = (options.system || "").toLowerCase();
if (sys.includes("strict code reviewer") || sys.includes("return a json object") || sys.includes("approved")) {
return JSON.stringify({ approved: true, issues: [], suggestions: [] });
}
return `STUB: Offline/failed Claude call. Heuristic plan for: ${prompt.slice(0, 80).trim()}...`;
}
}
function callCodexCLI(prompt, args = [], dryRun = true, cwd) {
const filteredArgs = args.filter((a) => a !== "--no-trace");
const cdArgs = cwd ? ["-C", cwd] : [];
const fullArgs = ["exec", "--full-auto", ...cdArgs, prompt, ...filteredArgs];
const printable = `codex ${fullArgs.map((a) => a.includes(" ") ? `'${a}'` : a).join(" ")}`;
if (dryRun) {
return {
ok: true,
output: "[DRY RUN] Skipped execution",
command: printable
};
}
try {
const whichCodex = spawnSync("which", ["codex"], { encoding: "utf8" });
if (whichCodex.status !== 0) {
return {
ok: true,
output: "[OFFLINE] Codex CLI not found; skipping execution",
command: printable
};
}
const res = spawnSync("codex", fullArgs, {
encoding: "utf8",
timeout: 3e5,
// 5 minute timeout
maxBuffer: 10 * 1024 * 1024
// 10MB buffer
});
if (res.status !== 0) {
const errorOutput = res.stderr || res.stdout || "Unknown error";
return {
ok: false,
output: `[ERROR] Codex failed (exit ${res.status}): ${errorOutput.slice(0, 500)}`,
command: printable
};
}
return {
ok: true,
output: (res.stdout || "") + (res.stderr || ""),
command: printable
};
} catch (e) {
return { ok: false, output: e?.message || String(e), command: printable };
}
}
async function implementWithClaude(prompt, options) {
try {
const out = await callClaude(prompt, {
model: options.model || "claude-sonnet-4-20250514",
system: options.system || "You generate minimal diffs/patches for the described change, focusing on one file at a time."
});
return { ok: true, output: out };
} catch (e) {
return { ok: false, output: e?.message || String(e) };
}
}
export {
callClaude,
callCodexCLI,
implementWithClaude
};
//# sourceMappingURL=providers.js.map