Initial commit: Discord-Claude Gateway with event-driven agent runtime

This commit is contained in:
2026-02-22 01:00:10 -05:00
parent b69e669638
commit ffcbcd874a

View File

@@ -1,4 +1,8 @@
import { execFile } from "node:child_process"; import { execFile } from "node:child_process";
import { writeFile, unlink } from "node:fs/promises";
import { join } from "node:path";
import { tmpdir } from "node:os";
import { randomUUID } from "node:crypto";
import type { Event, MessagePayload, HeartbeatPayload, CronPayload, HookPayload } from "./event-queue.js"; import type { Event, MessagePayload, HeartbeatPayload, CronPayload, HookPayload } from "./event-queue.js";
import type { MarkdownConfigLoader } from "./markdown-config-loader.js"; import type { MarkdownConfigLoader } from "./markdown-config-loader.js";
import type { SystemPromptAssembler } from "./system-prompt-assembler.js"; import type { SystemPromptAssembler } from "./system-prompt-assembler.js";
@@ -145,40 +149,53 @@ export class AgentRuntime {
} }
} }
private executeClaude( private async executeClaude(
promptText: string, promptText: string,
systemPrompt: string, systemPrompt: string,
sessionId?: string, sessionId?: string,
): Promise<ClaudeJsonResponse> {
// Write system prompt to a temp file to avoid CLI arg length limits
const tmpFile = join(tmpdir(), `aetheel-prompt-${randomUUID()}.txt`);
await writeFile(tmpFile, systemPrompt, "utf-8");
try {
return await this.runClaude(promptText, tmpFile, sessionId);
} finally {
unlink(tmpFile).catch(() => {});
}
}
private runClaude(
promptText: string,
systemPromptFile: string,
sessionId?: string,
): Promise<ClaudeJsonResponse> { ): Promise<ClaudeJsonResponse> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const args: string[] = [ const args: string[] = [
"-p", promptText, "-p", promptText,
"--output-format", "json", "--output-format", "json",
"--system-prompt", systemPrompt, "--system-prompt-file", systemPromptFile,
"--dangerously-skip-permissions", "--dangerously-skip-permissions",
]; ];
// Resume existing session
if (sessionId) { if (sessionId) {
args.push("--resume", sessionId); args.push("--resume", sessionId);
} }
// Allowed tools
if (this.config.allowedTools.length > 0) { if (this.config.allowedTools.length > 0) {
args.push("--allowedTools", ...this.config.allowedTools); args.push("--allowedTools", ...this.config.allowedTools);
} }
// Max turns to prevent runaway loops
args.push("--max-turns", "25"); args.push("--max-turns", "25");
console.log(`[DEBUG] Spawning Claude CLI: ${this.config.claudeCliPath} ${args.slice(0, 4).join(" ")} ... (${args.length} args total)`); console.log(`[DEBUG] Spawning Claude CLI: ${this.config.claudeCliPath} -p "${promptText}" --output-format json --system-prompt-file ${systemPromptFile} ... (${args.length} args total)`);
const child = execFile( const child = execFile(
this.config.claudeCliPath, this.config.claudeCliPath,
args, args,
{ {
timeout: this.config.queryTimeoutMs, timeout: this.config.queryTimeoutMs,
maxBuffer: 10 * 1024 * 1024, // 10MB maxBuffer: 10 * 1024 * 1024,
encoding: "utf-8", encoding: "utf-8",
}, },
(error, stdout, stderr) => { (error, stdout, stderr) => {