miyabi-agent-sdk
Version:
Miyabi Autonomous Agent SDK - 7 Agents based on Shikigaku Theory with 100% cost reduction mode
204 lines (195 loc) • 6.71 kB
JavaScript
/**
* Claude Code Client
*
* Phase 9: Integration with Claude Code CLI
*
* This client replaces AnthropicClient by using the local Claude Code CLI
* instead of calling external Anthropic API.
*
* Usage:
* const client = new ClaudeCodeClient();
* const response = await client.executePrompt("Analyze this issue...");
*/
import { spawn } from "child_process";
export class ClaudeCodeClient {
codexCommand;
constructor(codexCommand = "codex") {
this.codexCommand = codexCommand;
}
/**
* Execute a prompt using Claude Code CLI
*
* @param prompt - The prompt to execute
* @param options - Additional options
* @returns The response from Claude Code
*/
async executePrompt(prompt, options) {
return new Promise((resolve, reject) => {
const args = ["exec", prompt];
const proc = spawn(this.codexCommand, args, {
cwd: options?.workingDir || process.cwd(),
shell: true,
});
let stdout = "";
let stderr = "";
proc.stdout.on("data", (data) => {
stdout += data.toString();
});
proc.stderr.on("data", (data) => {
stderr += data.toString();
});
// Handle timeout
const timeoutId = options?.timeout
? setTimeout(() => {
proc.kill();
reject(new Error(`Claude Code execution timed out after ${options.timeout}ms`));
}, options.timeout)
: null;
proc.on("close", (code) => {
if (timeoutId)
clearTimeout(timeoutId);
if (code === 0) {
resolve({
content: stdout.trim(),
// Claude Code doesn't provide token usage, so we estimate
tokensUsed: {
input: Math.floor(prompt.length / 4), // rough estimate
output: Math.floor(stdout.length / 4),
},
cost: 0, // Free when using local Claude Code
});
}
else {
reject(new Error(`Claude Code failed with exit code ${code}\nStderr: ${stderr}`));
}
});
proc.on("error", (error) => {
if (timeoutId)
clearTimeout(timeoutId);
reject(new Error(`Failed to spawn Claude Code: ${error.message}`));
});
});
}
/**
* Analyze a GitHub issue using Claude Code
*
* @param issueData - Issue data to analyze
* @returns Analysis result
*/
async analyzeIssue(issueData) {
const prompt = `Analyze this GitHub issue and return ONLY a JSON object (no markdown code blocks):
Issue #${issueData.number}: ${issueData.title}
${issueData.body}
Return JSON format:
{
"type": "bug|feature|refactor|docs|test",
"complexity": "small|medium|large|xlarge",
"priority": "P0|P1|P2|P3",
"relatedFiles": ["file1.ts", "file2.ts"],
"labels": ["🏷️ type:bug", "🎯 priority:P2-Medium", ...]
}`;
const response = await this.executePrompt(prompt, { timeout: 60000 });
try {
// Try to extract JSON from response
const jsonMatch = response.content.match(/\{[\s\S]*\}/);
if (!jsonMatch) {
throw new Error("No JSON found in response");
}
const parsed = JSON.parse(jsonMatch[0]);
return parsed;
}
catch (error) {
console.error("[ClaudeCodeClient] Failed to parse issue analysis:", error);
console.error("[ClaudeCodeClient] Response:", response.content);
throw new Error(`Failed to parse issue analysis: ${error}`);
}
}
/**
* Generate code using Claude Code
*
* @param requirements - Code generation requirements
* @returns Generated files
*/
async generateCode(requirements) {
const prompt = `Generate code for this task. Return ONLY a JSON object (no markdown code blocks):
Task: ${requirements.requirements}
Context: ${requirements.context}
Language: ${requirements.language}
Return JSON format:
{
"files": [
{
"path": "src/example.ts",
"content": "...",
"action": "create"
}
],
"tests": [
{
"path": "src/example.test.ts",
"content": "...",
"action": "create"
}
],
"qualityScore": 95
}`;
const response = await this.executePrompt(prompt, { timeout: 120000 });
try {
// Try to extract JSON from response
const jsonMatch = response.content.match(/\{[\s\S]*\}/);
if (!jsonMatch) {
throw new Error("No JSON found in response");
}
const parsed = JSON.parse(jsonMatch[0]);
return parsed;
}
catch (error) {
console.error("[ClaudeCodeClient] Failed to parse code generation:", error);
console.error("[ClaudeCodeClient] Response:", response.content);
throw new Error(`Failed to parse code generation: ${error}`);
}
}
/**
* Review code using Claude Code
*
* @param files - Files to review
* @returns Review result
*/
async reviewCode(files) {
const filesStr = files
.map((f) => `File: ${f.path}\n\`\`\`\n${f.content}\n\`\`\``)
.join("\n\n");
const prompt = `Review this code and return ONLY a JSON object (no markdown code blocks):
${filesStr}
Return JSON format:
{
"qualityScore": 85,
"passed": true,
"issues": [
{
"severity": "warning",
"message": "Consider adding error handling",
"file": "src/example.ts",
"line": 42
}
],
"suggestions": ["Add more test cases", "Improve documentation"]
}`;
const response = await this.executePrompt(prompt, { timeout: 90000 });
try {
// Try to extract JSON from response
const jsonMatch = response.content.match(/\{[\s\S]*\}/);
if (!jsonMatch) {
throw new Error("No JSON found in response");
}
const parsed = JSON.parse(jsonMatch[0]);
return parsed;
}
catch (error) {
console.error("[ClaudeCodeClient] Failed to parse code review:", error);
console.error("[ClaudeCodeClient] Response:", response.content);
throw new Error(`Failed to parse code review: ${error}`);
}
}
}
//# sourceMappingURL=ClaudeCodeClient.js.map