1 line
80 KiB
JSON
1 line
80 KiB
JSON
{"repo": "astrolexisai/kcode", "files": {"src/core/swarm.ts": {"85181c5b18adac160fa14184c70ba5be3565187d": {"t": 1785745599.9479752, "n": 8130, "h": "34658fb075f00f22", "c": "// KCode - Agent Swarm\n// Run N agents in parallel with task delegation, message bus, and result merging.\n// Usage: /swarm \"analyze all test files for coverage gaps\" --agents 4\n\nimport { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { log } from \"./logger\";\n\nexport interface SwarmTask {\n id: number;\n prompt: string;\n files?: string[];\n status: \"pending\" | \"running\" | \"done\" | \"error\";\n result?: string;\n durationMs?: number;\n error?: string;\n}\n\nexport interface SwarmResult {\n tasks: SwarmTask[];\n totalDurationMs: number;\n successCount: number;\n errorCount: number;\n merged: string;\n}\n\nconst MAX_AGENTS = 8;\nconst AGENT_TIMEOUT = 120_000; // 2 minutes per agent\n\n/**\n * Split a list of files into N roughly equal chunks.\n */\nexport function chunkFiles(files: string[], n: number): string[][] {\n if (n <= 0 || files.length === 0) return [];\n const count = Math.min(n, files.length);\n const chunks: string[][] = Array.from({ length: count }, () => []);\n for (let i = 0; i < files.length; i++) {\n chunks[i % count]!.push(files[i]!);\n }\n return chunks.filter((c) => c.length > 0);\n}\n\n/**\n * Run a single agent task using kcode subprocess.\n * Returns the agent's text output.\n */\nfunction runAgent(\n prompt: string,\n cwd: string,\n model?: string,\n): Promise<{ output: string; durationMs: number }> {\n const start = Date.now();\n const args = [\"--print\", \"--permission\", \"deny\", prompt];\n if (model) {\n args.unshift(\"-m\", model);\n }\n const kcodebin = findKCodeBinary();\n\n return new Promise((resolve, reject) => {\n // Inherit the parent's environment including API keys so subagents\n // can authenticate with cloud providers. Subagents are child processes\n // of the same user — there is no additional credential-leakage surface.\n const subEnv = { ...process.env };\n\n // Warn when a cloud model appears to lack an API key\n if (model) {\n const lower = model.toLowerCase();\n const isLikelyCloud =\n lower.startsWith(\"claude-\") ||\n lower.startsWith(\"claude_\") ||\n lower.startsWith(\"gpt-\") ||\n lower.startsWith(\"o1\") ||\n lower.startsWith(\"o3\") ||\n lower.startsWith(\"o4\") ||\n lower.includes(\"gemini\") ||\n lower.includes(\"deepseek\") ||\n lower.includes(\"groq\") ||\n lower.includes(\"together\") ||\n lower.startsWith(\"grok\") ||\n lower.startsWith(\"xai\");\n if (\n isLikelyCloud &&\n !subEnv.KCODE_API_KEY &&\n !subEnv.ANTHROPIC_API_KEY &&\n !subEnv.OPENAI_API_KEY &&\n !subEnv.GROQ_API_KEY &&\n !subEnv.DEEPSEEK_API_KEY &&\n !subEnv.TOGETHER_API_KEY &&\n !subEnv.GEMINI_API_KEY &&\n !subEnv.XAI_API_KEY\n ) {\n log.warn(\n \"swarm\",\n `Subagent model \"${model}\" looks like a cloud model but no API key ` +\n `env var is set — the subagent will likely fail to authenticate.`,\n );\n }\n }\n\n execFile(\n kcodebin,\n args,\n {\n cwd,\n timeout: AGENT_TIMEOUT,\n maxBuffer: 512 * 1024,\n env: subEnv,\n },\n (err, stdout, stderr) => {\n if (err) {\n const msg = stderr || err.message;\n // Non-zero exit code means the agent failed — reject so runSwarm catches it\n reject(new Error(msg.slice(0, 500)));\n } else {\n resolve({ output: stdout.trim(), durationMs: Date.now() - start });\n }\n },\n );\n });\n}\n\n/**\n * Find the kcode binary path.\n */\n/**\n * Find the kcode binary for subprocess spawning.\n * Works from any CWD — checks standard install locations then falls back to PATH.\n */\nexport function findKCodeBinary(): string {\n const home = process.env.HOME ?? \"/home\";\n const candidates = [\n join(home, \".local\", \"bin\", \"kcode\"),\n join(home, \".bun\", \"bin\", \"kcode\"),\n join(home, \"KCode\", \"dist\", \"kcode\"),\n \"/usr/local/bin/kcode\",\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return \"kcode\"; // fall back to PATH\n}\n\n/**\n * Run a swarm of agents in parallel.\n *\n * @param masterPrompt - The overall task description\n * @param tasks - Individual task prompts for each agent\n * @param cwd - Working directory\n * @param model - Optional model to use\n */\nexport async function runSwarm(\n masterPrompt: string,\n tasks: string[],\n cwd: string,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const agentCount = Math.min(tasks.length, maxAgents);\n const start = Date.now();\n\n const swarmTasks: SwarmTask[] = tasks.slice(0, agentCount).map((prompt, i) => ({\n id: i + 1,\n prompt,\n status: \"pending\" as const,\n }));\n\n // Run all agents in parallel\n const promises = swarmTasks.map(async (task) => {\n task.status = \"running\";\n try {\n const { output, durationMs } = await runAgent(task.prompt, cwd, model);\n task.status = \"done\";\n task.result = output;\n task.durationMs = durationMs;\n } catch (err) {\n task.status = \"error\";\n task.error = err instanceof Error ? err.message : String(err);\n }\n });\n\n await Promise.all(promises);\n\n const successCount = swarmTasks.filter((t) => t.status === \"done\").length;\n const errorCount = swarmTasks.filter((t) => t.status === \"error\").length;\n\n // Merge results\n const mergedParts: string[] = [];\n for (const task of swarmTasks) {\n mergedParts.push(`── Agent ${task.id} (${task.durationMs ?? 0}ms) ──`);\n mergedParts.push(task.result ?? task.error ?? \"(no output)\");\n mergedParts.push(\"\");\n }\n\n return {\n tasks: swarmTasks,\n totalDurationMs: Date.now() - start,\n successCount,\n errorCount,\n merged: mergedParts.join(\"\\n\"),\n };\n}\n\n/**\n * Auto-split a task across files and run swarm.\n * Given a prompt and list of files, distributes files among N agents.\n */\nexport async function runSwarmOnFiles(\n prompt: string,\n files: string[],\n cwd: string,\n agentCount: number = 4,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const effectiveAgentCount = Math.min(agentCount, maxAgents);\n\n const chunks = chunkFiles(files, effectiveAgentCount);\n\n const tasks = chunks.map((fileGroup, i) => {\n const fileList = fileGroup.join(\"\\n \");\n return `${prompt}\\n\\nYou are agent ${i + 1}/${chunks.length}. Focus ONLY on these files:\\n ${fileList}`;\n });\n\n return runSwarm(prompt, tasks, cwd, model);\n}\n\n// ─── Coordinator Mode Integration ──────────────────────────────\n\nexport {\n Coordinator,\n detectCoordinatorSession,\n loadCoordinatorProgress,\n parseCoordinatorConfig,\n} from \"./coordinator/coordinator\";\nexport { MessageBus } from \"./coordinator/message-bus\";\nexport { Scratchpad } from \"./coordinator/scratchpad\";\nexport type {\n CoordinatorConfig,\n WorkerConfig,\n WorkerMode,\n WorkerResult,\n} from \"./coordinator/types\";\nexport { DEFAULT_COORDINATOR_CONFIG } from \"./coordinator/types\";\nexport { COORDINATOR_ONLY_TOOLS, getWorkerTools, WORKER_TOOLS } from \"./coordinator/worker\";\n\n/**\n * Format swarm results for display.\n */\nexport function formatSwarmResult(result: SwarmResult): string {\n const lines: string[] = [\n ` Swarm Results\\n`,\n ` Agents: ${result.tasks.length} Success: ${result.successCount} Errors: ${result.errorCount}`,\n ` Total time: ${(result.totalDurationMs / 1000).toFixed(1)}s\\n`,\n ];\n\n for (const task of result.tasks) {\n const icon = task.status === \"done\" ? \"\\u2713\" : \"\\u2717\";\n const dur = task.durationMs ? `${(task.durationMs / 1000).toFixed(1)}s` : \"?\";\n lines.push(` ${icon} Agent ${task.id} (${dur})`);\n\n const output = task.result ?? task.error ?? \"(no output)\";\n const preview = output.split(\"\\n\").slice(0, 5);\n for (const line of preview) {\n lines.push(` ${line.slice(0, 120)}`);\n }\n if (output.split(\"\\n\").length > 5) {\n lines.push(` ... (${output.split(\"\\n\").length - 5} more lines)`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n"}, "36283dcee4f1a24d838f41c000ca514de8095c1b": {"t": 1785754656.9347665, "n": 8130, "h": "34658fb075f00f22", "c": "// KCode - Agent Swarm\n// Run N agents in parallel with task delegation, message bus, and result merging.\n// Usage: /swarm \"analyze all test files for coverage gaps\" --agents 4\n\nimport { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { log } from \"./logger\";\n\nexport interface SwarmTask {\n id: number;\n prompt: string;\n files?: string[];\n status: \"pending\" | \"running\" | \"done\" | \"error\";\n result?: string;\n durationMs?: number;\n error?: string;\n}\n\nexport interface SwarmResult {\n tasks: SwarmTask[];\n totalDurationMs: number;\n successCount: number;\n errorCount: number;\n merged: string;\n}\n\nconst MAX_AGENTS = 8;\nconst AGENT_TIMEOUT = 120_000; // 2 minutes per agent\n\n/**\n * Split a list of files into N roughly equal chunks.\n */\nexport function chunkFiles(files: string[], n: number): string[][] {\n if (n <= 0 || files.length === 0) return [];\n const count = Math.min(n, files.length);\n const chunks: string[][] = Array.from({ length: count }, () => []);\n for (let i = 0; i < files.length; i++) {\n chunks[i % count]!.push(files[i]!);\n }\n return chunks.filter((c) => c.length > 0);\n}\n\n/**\n * Run a single agent task using kcode subprocess.\n * Returns the agent's text output.\n */\nfunction runAgent(\n prompt: string,\n cwd: string,\n model?: string,\n): Promise<{ output: string; durationMs: number }> {\n const start = Date.now();\n const args = [\"--print\", \"--permission\", \"deny\", prompt];\n if (model) {\n args.unshift(\"-m\", model);\n }\n const kcodebin = findKCodeBinary();\n\n return new Promise((resolve, reject) => {\n // Inherit the parent's environment including API keys so subagents\n // can authenticate with cloud providers. Subagents are child processes\n // of the same user — there is no additional credential-leakage surface.\n const subEnv = { ...process.env };\n\n // Warn when a cloud model appears to lack an API key\n if (model) {\n const lower = model.toLowerCase();\n const isLikelyCloud =\n lower.startsWith(\"claude-\") ||\n lower.startsWith(\"claude_\") ||\n lower.startsWith(\"gpt-\") ||\n lower.startsWith(\"o1\") ||\n lower.startsWith(\"o3\") ||\n lower.startsWith(\"o4\") ||\n lower.includes(\"gemini\") ||\n lower.includes(\"deepseek\") ||\n lower.includes(\"groq\") ||\n lower.includes(\"together\") ||\n lower.startsWith(\"grok\") ||\n lower.startsWith(\"xai\");\n if (\n isLikelyCloud &&\n !subEnv.KCODE_API_KEY &&\n !subEnv.ANTHROPIC_API_KEY &&\n !subEnv.OPENAI_API_KEY &&\n !subEnv.GROQ_API_KEY &&\n !subEnv.DEEPSEEK_API_KEY &&\n !subEnv.TOGETHER_API_KEY &&\n !subEnv.GEMINI_API_KEY &&\n !subEnv.XAI_API_KEY\n ) {\n log.warn(\n \"swarm\",\n `Subagent model \"${model}\" looks like a cloud model but no API key ` +\n `env var is set — the subagent will likely fail to authenticate.`,\n );\n }\n }\n\n execFile(\n kcodebin,\n args,\n {\n cwd,\n timeout: AGENT_TIMEOUT,\n maxBuffer: 512 * 1024,\n env: subEnv,\n },\n (err, stdout, stderr) => {\n if (err) {\n const msg = stderr || err.message;\n // Non-zero exit code means the agent failed — reject so runSwarm catches it\n reject(new Error(msg.slice(0, 500)));\n } else {\n resolve({ output: stdout.trim(), durationMs: Date.now() - start });\n }\n },\n );\n });\n}\n\n/**\n * Find the kcode binary path.\n */\n/**\n * Find the kcode binary for subprocess spawning.\n * Works from any CWD — checks standard install locations then falls back to PATH.\n */\nexport function findKCodeBinary(): string {\n const home = process.env.HOME ?? \"/home\";\n const candidates = [\n join(home, \".local\", \"bin\", \"kcode\"),\n join(home, \".bun\", \"bin\", \"kcode\"),\n join(home, \"KCode\", \"dist\", \"kcode\"),\n \"/usr/local/bin/kcode\",\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return \"kcode\"; // fall back to PATH\n}\n\n/**\n * Run a swarm of agents in parallel.\n *\n * @param masterPrompt - The overall task description\n * @param tasks - Individual task prompts for each agent\n * @param cwd - Working directory\n * @param model - Optional model to use\n */\nexport async function runSwarm(\n masterPrompt: string,\n tasks: string[],\n cwd: string,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const agentCount = Math.min(tasks.length, maxAgents);\n const start = Date.now();\n\n const swarmTasks: SwarmTask[] = tasks.slice(0, agentCount).map((prompt, i) => ({\n id: i + 1,\n prompt,\n status: \"pending\" as const,\n }));\n\n // Run all agents in parallel\n const promises = swarmTasks.map(async (task) => {\n task.status = \"running\";\n try {\n const { output, durationMs } = await runAgent(task.prompt, cwd, model);\n task.status = \"done\";\n task.result = output;\n task.durationMs = durationMs;\n } catch (err) {\n task.status = \"error\";\n task.error = err instanceof Error ? err.message : String(err);\n }\n });\n\n await Promise.all(promises);\n\n const successCount = swarmTasks.filter((t) => t.status === \"done\").length;\n const errorCount = swarmTasks.filter((t) => t.status === \"error\").length;\n\n // Merge results\n const mergedParts: string[] = [];\n for (const task of swarmTasks) {\n mergedParts.push(`── Agent ${task.id} (${task.durationMs ?? 0}ms) ──`);\n mergedParts.push(task.result ?? task.error ?? \"(no output)\");\n mergedParts.push(\"\");\n }\n\n return {\n tasks: swarmTasks,\n totalDurationMs: Date.now() - start,\n successCount,\n errorCount,\n merged: mergedParts.join(\"\\n\"),\n };\n}\n\n/**\n * Auto-split a task across files and run swarm.\n * Given a prompt and list of files, distributes files among N agents.\n */\nexport async function runSwarmOnFiles(\n prompt: string,\n files: string[],\n cwd: string,\n agentCount: number = 4,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const effectiveAgentCount = Math.min(agentCount, maxAgents);\n\n const chunks = chunkFiles(files, effectiveAgentCount);\n\n const tasks = chunks.map((fileGroup, i) => {\n const fileList = fileGroup.join(\"\\n \");\n return `${prompt}\\n\\nYou are agent ${i + 1}/${chunks.length}. Focus ONLY on these files:\\n ${fileList}`;\n });\n\n return runSwarm(prompt, tasks, cwd, model);\n}\n\n// ─── Coordinator Mode Integration ──────────────────────────────\n\nexport {\n Coordinator,\n detectCoordinatorSession,\n loadCoordinatorProgress,\n parseCoordinatorConfig,\n} from \"./coordinator/coordinator\";\nexport { MessageBus } from \"./coordinator/message-bus\";\nexport { Scratchpad } from \"./coordinator/scratchpad\";\nexport type {\n CoordinatorConfig,\n WorkerConfig,\n WorkerMode,\n WorkerResult,\n} from \"./coordinator/types\";\nexport { DEFAULT_COORDINATOR_CONFIG } from \"./coordinator/types\";\nexport { COORDINATOR_ONLY_TOOLS, getWorkerTools, WORKER_TOOLS } from \"./coordinator/worker\";\n\n/**\n * Format swarm results for display.\n */\nexport function formatSwarmResult(result: SwarmResult): string {\n const lines: string[] = [\n ` Swarm Results\\n`,\n ` Agents: ${result.tasks.length} Success: ${result.successCount} Errors: ${result.errorCount}`,\n ` Total time: ${(result.totalDurationMs / 1000).toFixed(1)}s\\n`,\n ];\n\n for (const task of result.tasks) {\n const icon = task.status === \"done\" ? \"\\u2713\" : \"\\u2717\";\n const dur = task.durationMs ? `${(task.durationMs / 1000).toFixed(1)}s` : \"?\";\n lines.push(` ${icon} Agent ${task.id} (${dur})`);\n\n const output = task.result ?? task.error ?? \"(no output)\";\n const preview = output.split(\"\\n\").slice(0, 5);\n for (const line of preview) {\n lines.push(` ${line.slice(0, 120)}`);\n }\n if (output.split(\"\\n\").length > 5) {\n lines.push(` ... (${output.split(\"\\n\").length - 5} more lines)`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n"}, "270f72715ae1aed2a594f94c418d7d68ac185c7c": {"t": 1785754658.5954373, "n": 8028, "h": "534e0fe1107874ca", "c": "// KCode - Agent Swarm\n// Run N agents in parallel with task delegation, message bus, and result merging.\n// Usage: /swarm \"analyze all test files for coverage gaps\" --agents 4\n\nimport { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { log } from \"./logger\";\n\nexport interface SwarmTask {\n id: number;\n prompt: string;\n files?: string[];\n status: \"pending\" | \"running\" | \"done\" | \"error\";\n result?: string;\n durationMs?: number;\n error?: string;\n}\n\nexport interface SwarmResult {\n tasks: SwarmTask[];\n totalDurationMs: number;\n successCount: number;\n errorCount: number;\n merged: string;\n}\n\nconst MAX_AGENTS = 8;\nconst AGENT_TIMEOUT = 120_000; // 2 minutes per agent\n\n/**\n * Split a list of files into N roughly equal chunks.\n */\nexport function chunkFiles(files: string[], n: number): string[][] {\n if (n <= 0 || files.length === 0) return [];\n const count = Math.min(n, files.length);\n const chunks: string[][] = Array.from({ length: count }, () => []);\n for (let i = 0; i < files.length; i++) {\n chunks[i % count]!.push(files[i]!);\n }\n return chunks.filter((c) => c.length > 0);\n}\n\n/**\n * Run a single agent task using kcode subprocess.\n * Returns the agent's text output.\n */\nfunction runAgent(\n prompt: string,\n cwd: string,\n model?: string,\n): Promise<{ output: string; durationMs: number }> {\n const start = Date.now();\n const args = [\"--print\", \"--permission\", \"deny\", prompt];\n if (model) {\n args.unshift(\"-m\", model);\n }\n const kcodebin = findKCodeBinary();\n\n return new Promise((resolve, reject) => {\n // Inherit the parent's environment including API keys so subagents\n // can authenticate with cloud providers. Subagents are child processes\n // of the same user — there is no additional credential-leakage surface.\n const subEnv = { ...process.env };\n\n // Warn when a cloud model appears to lack an API key\n if (model) {\n const lower = model.toLowerCase();\n const isLikelyCloud =\n lower.startsWith(\"claude-\") ||\n lower.startsWith(\"claude_\") ||\n lower.startsWith(\"gpt-\") ||\n lower.startsWith(\"o1\") ||\n lower.startsWith(\"o3\") ||\n lower.startsWith(\"o4\") ||\n lower.includes(\"gemini\") ||\n lower.includes(\"deepseek\") ||\n lower.includes(\"groq\") ||\n lower.includes(\"together\");\n if (\n isLikelyCloud &&\n !subEnv.KCODE_API_KEY &&\n !subEnv.ANTHROPIC_API_KEY &&\n !subEnv.OPENAI_API_KEY &&\n !subEnv.GROQ_API_KEY &&\n !subEnv.DEEPSEEK_API_KEY &&\n !subEnv.TOGETHER_API_KEY &&\n !subEnv.GEMINI_API_KEY\n ) {\n log.warn(\n \"swarm\",\n `Subagent model \"${model}\" looks like a cloud model but no API key ` +\n `env var is set — the subagent will likely fail to authenticate.`,\n );\n }\n }\n\n execFile(\n kcodebin,\n args,\n {\n cwd,\n timeout: AGENT_TIMEOUT,\n maxBuffer: 512 * 1024,\n env: subEnv,\n },\n (err, stdout, stderr) => {\n if (err) {\n const msg = stderr || err.message;\n // Non-zero exit code means the agent failed — reject so runSwarm catches it\n reject(new Error(msg.slice(0, 500)));\n } else {\n resolve({ output: stdout.trim(), durationMs: Date.now() - start });\n }\n },\n );\n });\n}\n\n/**\n * Find the kcode binary path.\n */\n/**\n * Find the kcode binary for subprocess spawning.\n * Works from any CWD — checks standard install locations then falls back to PATH.\n */\nexport function findKCodeBinary(): string {\n const home = process.env.HOME ?? \"/home\";\n const candidates = [\n join(home, \".local\", \"bin\", \"kcode\"),\n join(home, \".bun\", \"bin\", \"kcode\"),\n join(home, \"KCode\", \"dist\", \"kcode\"),\n \"/usr/local/bin/kcode\",\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return \"kcode\"; // fall back to PATH\n}\n\n/**\n * Run a swarm of agents in parallel.\n *\n * @param masterPrompt - The overall task description\n * @param tasks - Individual task prompts for each agent\n * @param cwd - Working directory\n * @param model - Optional model to use\n */\nexport async function runSwarm(\n masterPrompt: string,\n tasks: string[],\n cwd: string,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const agentCount = Math.min(tasks.length, maxAgents);\n const start = Date.now();\n\n const swarmTasks: SwarmTask[] = tasks.slice(0, agentCount).map((prompt, i) => ({\n id: i + 1,\n prompt,\n status: \"pending\" as const,\n }));\n\n // Run all agents in parallel\n const promises = swarmTasks.map(async (task) => {\n task.status = \"running\";\n try {\n const { output, durationMs } = await runAgent(task.prompt, cwd, model);\n task.status = \"done\";\n task.result = output;\n task.durationMs = durationMs;\n } catch (err) {\n task.status = \"error\";\n task.error = err instanceof Error ? err.message : String(err);\n }\n });\n\n await Promise.all(promises);\n\n const successCount = swarmTasks.filter((t) => t.status === \"done\").length;\n const errorCount = swarmTasks.filter((t) => t.status === \"error\").length;\n\n // Merge results\n const mergedParts: string[] = [];\n for (const task of swarmTasks) {\n mergedParts.push(`── Agent ${task.id} (${task.durationMs ?? 0}ms) ──`);\n mergedParts.push(task.result ?? task.error ?? \"(no output)\");\n mergedParts.push(\"\");\n }\n\n return {\n tasks: swarmTasks,\n totalDurationMs: Date.now() - start,\n successCount,\n errorCount,\n merged: mergedParts.join(\"\\n\"),\n };\n}\n\n/**\n * Auto-split a task across files and run swarm.\n * Given a prompt and list of files, distributes files among N agents.\n */\nexport async function runSwarmOnFiles(\n prompt: string,\n files: string[],\n cwd: string,\n agentCount: number = 4,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const effectiveAgentCount = Math.min(agentCount, maxAgents);\n\n const chunks = chunkFiles(files, effectiveAgentCount);\n\n const tasks = chunks.map((fileGroup, i) => {\n const fileList = fileGroup.join(\"\\n \");\n return `${prompt}\\n\\nYou are agent ${i + 1}/${chunks.length}. Focus ONLY on these files:\\n ${fileList}`;\n });\n\n return runSwarm(prompt, tasks, cwd, model);\n}\n\n// ─── Coordinator Mode Integration ──────────────────────────────\n\nexport {\n Coordinator,\n detectCoordinatorSession,\n loadCoordinatorProgress,\n parseCoordinatorConfig,\n} from \"./coordinator/coordinator\";\nexport { MessageBus } from \"./coordinator/message-bus\";\nexport { Scratchpad } from \"./coordinator/scratchpad\";\nexport type {\n CoordinatorConfig,\n WorkerConfig,\n WorkerMode,\n WorkerResult,\n} from \"./coordinator/types\";\nexport { DEFAULT_COORDINATOR_CONFIG } from \"./coordinator/types\";\nexport { COORDINATOR_ONLY_TOOLS, getWorkerTools, WORKER_TOOLS } from \"./coordinator/worker\";\n\n/**\n * Format swarm results for display.\n */\nexport function formatSwarmResult(result: SwarmResult): string {\n const lines: string[] = [\n ` Swarm Results\\n`,\n ` Agents: ${result.tasks.length} Success: ${result.successCount} Errors: ${result.errorCount}`,\n ` Total time: ${(result.totalDurationMs / 1000).toFixed(1)}s\\n`,\n ];\n\n for (const task of result.tasks) {\n const icon = task.status === \"done\" ? \"\\u2713\" : \"\\u2717\";\n const dur = task.durationMs ? `${(task.durationMs / 1000).toFixed(1)}s` : \"?\";\n lines.push(` ${icon} Agent ${task.id} (${dur})`);\n\n const output = task.result ?? task.error ?? \"(no output)\";\n const preview = output.split(\"\\n\").slice(0, 5);\n for (const line of preview) {\n lines.push(` ${line.slice(0, 120)}`);\n }\n if (output.split(\"\\n\").length > 5) {\n lines.push(` ... (${output.split(\"\\n\").length - 5} more lines)`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n"}, "d8cf284a552fc1db19c71a9c480d0053a357f9f2": {"t": 1785754660.252464, "n": 7842, "h": "1a753206007c049f", "c": "// KCode - Agent Swarm\n// Run N agents in parallel with task delegation, message bus, and result merging.\n// Usage: /swarm \"analyze all test files for coverage gaps\" --agents 4\n\nimport { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { log } from \"./logger\";\n\nexport interface SwarmTask {\n id: number;\n prompt: string;\n files?: string[];\n status: \"pending\" | \"running\" | \"done\" | \"error\";\n result?: string;\n durationMs?: number;\n error?: string;\n}\n\nexport interface SwarmResult {\n tasks: SwarmTask[];\n totalDurationMs: number;\n successCount: number;\n errorCount: number;\n merged: string;\n}\n\nconst MAX_AGENTS = 8;\nconst AGENT_TIMEOUT = 120_000; // 2 minutes per agent\n\n/**\n * Split a list of files into N roughly equal chunks.\n */\nexport function chunkFiles(files: string[], n: number): string[][] {\n if (n <= 0 || files.length === 0) return [];\n const count = Math.min(n, files.length);\n const chunks: string[][] = Array.from({ length: count }, () => []);\n for (let i = 0; i < files.length; i++) {\n chunks[i % count]!.push(files[i]!);\n }\n return chunks.filter((c) => c.length > 0);\n}\n\n/**\n * Run a single agent task using kcode subprocess.\n * Returns the agent's text output.\n */\nfunction runAgent(\n prompt: string,\n cwd: string,\n model?: string,\n): Promise<{ output: string; durationMs: number }> {\n const start = Date.now();\n const args = [\"--print\", \"--permission\", \"deny\", prompt];\n if (model) {\n args.unshift(\"-m\", model);\n }\n const kcodebin = findKCodeBinary();\n\n return new Promise((resolve, reject) => {\n // Inherit the parent's environment including API keys so subagents\n // can authenticate with cloud providers. Subagents are child processes\n // of the same user — there is no additional credential-leakage surface.\n const subEnv = { ...process.env };\n\n // Warn when a cloud model appears to lack an API key\n if (model) {\n const lower = model.toLowerCase();\n const isLikelyCloud =\n lower.startsWith(\"claude-\") ||\n lower.startsWith(\"claude_\") ||\n lower.startsWith(\"gpt-\") ||\n lower.startsWith(\"o1\") ||\n lower.startsWith(\"o3\") ||\n lower.startsWith(\"o4\") ||\n lower.includes(\"gemini\") ||\n lower.includes(\"deepseek\") ||\n lower.includes(\"groq\") ||\n lower.includes(\"together\");\n if (\n isLikelyCloud &&\n !subEnv.KCODE_API_KEY &&\n !subEnv.ANTHROPIC_API_KEY &&\n !subEnv.OPENAI_API_KEY &&\n !subEnv.GROQ_API_KEY &&\n !subEnv.DEEPSEEK_API_KEY &&\n !subEnv.TOGETHER_API_KEY &&\n !subEnv.GEMINI_API_KEY\n ) {\n log.warn(\n \"swarm\",\n `Subagent model \"${model}\" looks like a cloud model but no API key ` +\n `env var is set — the subagent will likely fail to authenticate.`,\n );\n }\n }\n\n execFile(\n kcodebin,\n args,\n {\n cwd,\n timeout: AGENT_TIMEOUT,\n maxBuffer: 512 * 1024,\n env: subEnv,\n },\n (err, stdout, stderr) => {\n if (err) {\n const msg = stderr || err.message;\n // Non-zero exit code means the agent failed — reject so runSwarm catches it\n reject(new Error(msg.slice(0, 500)));\n } else {\n resolve({ output: stdout.trim(), durationMs: Date.now() - start });\n }\n },\n );\n });\n}\n\n/**\n * Find the kcode binary path.\n */\nfunction findKCodeBinary(): string {\n const candidates = [\n join(process.env.HOME ?? \"/home\", \".local\", \"bin\", \"kcode\"),\n join(process.env.HOME ?? \"/home\", \"KCode\", \"dist\", \"kcode\"),\n \"/usr/local/bin/kcode\",\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return \"kcode\"; // fall back to PATH\n}\n\n/**\n * Run a swarm of agents in parallel.\n *\n * @param masterPrompt - The overall task description\n * @param tasks - Individual task prompts for each agent\n * @param cwd - Working directory\n * @param model - Optional model to use\n */\nexport async function runSwarm(\n masterPrompt: string,\n tasks: string[],\n cwd: string,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const agentCount = Math.min(tasks.length, maxAgents);\n const start = Date.now();\n\n const swarmTasks: SwarmTask[] = tasks.slice(0, agentCount).map((prompt, i) => ({\n id: i + 1,\n prompt,\n status: \"pending\" as const,\n }));\n\n // Run all agents in parallel\n const promises = swarmTasks.map(async (task) => {\n task.status = \"running\";\n try {\n const { output, durationMs } = await runAgent(task.prompt, cwd, model);\n task.status = \"done\";\n task.result = output;\n task.durationMs = durationMs;\n } catch (err) {\n task.status = \"error\";\n task.error = err instanceof Error ? err.message : String(err);\n }\n });\n\n await Promise.all(promises);\n\n const successCount = swarmTasks.filter((t) => t.status === \"done\").length;\n const errorCount = swarmTasks.filter((t) => t.status === \"error\").length;\n\n // Merge results\n const mergedParts: string[] = [];\n for (const task of swarmTasks) {\n mergedParts.push(`── Agent ${task.id} (${task.durationMs ?? 0}ms) ──`);\n mergedParts.push(task.result ?? task.error ?? \"(no output)\");\n mergedParts.push(\"\");\n }\n\n return {\n tasks: swarmTasks,\n totalDurationMs: Date.now() - start,\n successCount,\n errorCount,\n merged: mergedParts.join(\"\\n\"),\n };\n}\n\n/**\n * Auto-split a task across files and run swarm.\n * Given a prompt and list of files, distributes files among N agents.\n */\nexport async function runSwarmOnFiles(\n prompt: string,\n files: string[],\n cwd: string,\n agentCount: number = 4,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const effectiveAgentCount = Math.min(agentCount, maxAgents);\n\n const chunks = chunkFiles(files, effectiveAgentCount);\n\n const tasks = chunks.map((fileGroup, i) => {\n const fileList = fileGroup.join(\"\\n \");\n return `${prompt}\\n\\nYou are agent ${i + 1}/${chunks.length}. Focus ONLY on these files:\\n ${fileList}`;\n });\n\n return runSwarm(prompt, tasks, cwd, model);\n}\n\n// ─── Coordinator Mode Integration ──────────────────────────────\n\nexport {\n Coordinator,\n detectCoordinatorSession,\n loadCoordinatorProgress,\n parseCoordinatorConfig,\n} from \"./coordinator/coordinator\";\nexport { MessageBus } from \"./coordinator/message-bus\";\nexport { Scratchpad } from \"./coordinator/scratchpad\";\nexport type {\n CoordinatorConfig,\n WorkerConfig,\n WorkerMode,\n WorkerResult,\n} from \"./coordinator/types\";\nexport { DEFAULT_COORDINATOR_CONFIG } from \"./coordinator/types\";\nexport { COORDINATOR_ONLY_TOOLS, getWorkerTools, WORKER_TOOLS } from \"./coordinator/worker\";\n\n/**\n * Format swarm results for display.\n */\nexport function formatSwarmResult(result: SwarmResult): string {\n const lines: string[] = [\n ` Swarm Results\\n`,\n ` Agents: ${result.tasks.length} Success: ${result.successCount} Errors: ${result.errorCount}`,\n ` Total time: ${(result.totalDurationMs / 1000).toFixed(1)}s\\n`,\n ];\n\n for (const task of result.tasks) {\n const icon = task.status === \"done\" ? \"\\u2713\" : \"\\u2717\";\n const dur = task.durationMs ? `${(task.durationMs / 1000).toFixed(1)}s` : \"?\";\n lines.push(` ${icon} Agent ${task.id} (${dur})`);\n\n const output = task.result ?? task.error ?? \"(no output)\";\n const preview = output.split(\"\\n\").slice(0, 5);\n for (const line of preview) {\n lines.push(` ${line.slice(0, 120)}`);\n }\n if (output.split(\"\\n\").length > 5) {\n lines.push(` ... (${output.split(\"\\n\").length - 5} more lines)`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n"}, "e53659e471799c87b628b3e4a8046f1748e65e85": {"t": 1785754661.5497975, "n": 7761, "h": "512ad76dcc20dc9d", "c": "// KCode - Agent Swarm\n// Run N agents in parallel with task delegation, message bus, and result merging.\n// Usage: /swarm \"analyze all test files for coverage gaps\" --agents 4\n\nimport { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { log } from \"./logger\";\n\nexport interface SwarmTask {\n id: number;\n prompt: string;\n files?: string[];\n status: \"pending\" | \"running\" | \"done\" | \"error\";\n result?: string;\n durationMs?: number;\n error?: string;\n}\n\nexport interface SwarmResult {\n tasks: SwarmTask[];\n totalDurationMs: number;\n successCount: number;\n errorCount: number;\n merged: string;\n}\n\nconst MAX_AGENTS = 8;\nconst AGENT_TIMEOUT = 120_000; // 2 minutes per agent\n\n/**\n * Split a list of files into N roughly equal chunks.\n */\nexport function chunkFiles(files: string[], n: number): string[][] {\n if (n <= 0 || files.length === 0) return [];\n const count = Math.min(n, files.length);\n const chunks: string[][] = Array.from({ length: count }, () => []);\n for (let i = 0; i < files.length; i++) {\n chunks[i % count]!.push(files[i]!);\n }\n return chunks.filter(c => c.length > 0);\n}\n\n/**\n * Run a single agent task using kcode subprocess.\n * Returns the agent's text output.\n */\nfunction runAgent(\n prompt: string,\n cwd: string,\n model?: string,\n): Promise<{ output: string; durationMs: number }> {\n const start = Date.now();\n const args = [\"--print\", \"--permission\", \"deny\", prompt];\n if (model) {\n args.unshift(\"-m\", model);\n }\n const kcodebin = findKCodeBinary();\n\n return new Promise((resolve, reject) => {\n // Inherit the parent's environment including API keys so subagents\n // can authenticate with cloud providers. Subagents are child processes\n // of the same user — there is no additional credential-leakage surface.\n const subEnv = { ...process.env };\n\n // Warn when a cloud model appears to lack an API key\n if (model) {\n const lower = model.toLowerCase();\n const isLikelyCloud =\n lower.startsWith(\"claude-\") ||\n lower.startsWith(\"claude_\") ||\n lower.startsWith(\"gpt-\") ||\n lower.startsWith(\"o1\") ||\n lower.startsWith(\"o3\") ||\n lower.startsWith(\"o4\") ||\n lower.includes(\"gemini\") ||\n lower.includes(\"deepseek\") ||\n lower.includes(\"groq\") ||\n lower.includes(\"together\");\n if (\n isLikelyCloud &&\n !subEnv.KCODE_API_KEY &&\n !subEnv.ANTHROPIC_API_KEY &&\n !subEnv.OPENAI_API_KEY &&\n !subEnv.GROQ_API_KEY &&\n !subEnv.DEEPSEEK_API_KEY &&\n !subEnv.TOGETHER_API_KEY &&\n !subEnv.GEMINI_API_KEY\n ) {\n log.warn(\n \"swarm\",\n `Subagent model \"${model}\" looks like a cloud model but no API key ` +\n `env var is set — the subagent will likely fail to authenticate.`,\n );\n }\n }\n\n execFile(kcodebin, args, {\n cwd,\n timeout: AGENT_TIMEOUT,\n maxBuffer: 512 * 1024,\n env: subEnv,\n }, (err, stdout, stderr) => {\n if (err) {\n const msg = stderr || err.message;\n // Non-zero exit code means the agent failed — reject so runSwarm catches it\n reject(new Error(msg.slice(0, 500)));\n } else {\n resolve({ output: stdout.trim(), durationMs: Date.now() - start });\n }\n });\n });\n}\n\n/**\n * Find the kcode binary path.\n */\nfunction findKCodeBinary(): string {\n const candidates = [\n join(process.env.HOME ?? \"/home\", \".local\", \"bin\", \"kcode\"),\n join(process.env.HOME ?? \"/home\", \"KCode\", \"dist\", \"kcode\"),\n \"/usr/local/bin/kcode\",\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return \"kcode\"; // fall back to PATH\n}\n\n/**\n * Run a swarm of agents in parallel.\n *\n * @param masterPrompt - The overall task description\n * @param tasks - Individual task prompts for each agent\n * @param cwd - Working directory\n * @param model - Optional model to use\n */\nexport async function runSwarm(\n masterPrompt: string,\n tasks: string[],\n cwd: string,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const agentCount = Math.min(tasks.length, maxAgents);\n const start = Date.now();\n\n const swarmTasks: SwarmTask[] = tasks.slice(0, agentCount).map((prompt, i) => ({\n id: i + 1,\n prompt,\n status: \"pending\" as const,\n }));\n\n // Run all agents in parallel\n const promises = swarmTasks.map(async (task) => {\n task.status = \"running\";\n try {\n const { output, durationMs } = await runAgent(task.prompt, cwd, model);\n task.status = \"done\";\n task.result = output;\n task.durationMs = durationMs;\n } catch (err) {\n task.status = \"error\";\n task.error = err instanceof Error ? err.message : String(err);\n }\n });\n\n await Promise.all(promises);\n\n const successCount = swarmTasks.filter(t => t.status === \"done\").length;\n const errorCount = swarmTasks.filter(t => t.status === \"error\").length;\n\n // Merge results\n const mergedParts: string[] = [];\n for (const task of swarmTasks) {\n mergedParts.push(`── Agent ${task.id} (${task.durationMs ?? 0}ms) ──`);\n mergedParts.push(task.result ?? task.error ?? \"(no output)\");\n mergedParts.push(\"\");\n }\n\n return {\n tasks: swarmTasks,\n totalDurationMs: Date.now() - start,\n successCount,\n errorCount,\n merged: mergedParts.join(\"\\n\"),\n };\n}\n\n/**\n * Auto-split a task across files and run swarm.\n * Given a prompt and list of files, distributes files among N agents.\n */\nexport async function runSwarmOnFiles(\n prompt: string,\n files: string[],\n cwd: string,\n agentCount: number = 4,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const effectiveAgentCount = Math.min(agentCount, maxAgents);\n\n const chunks = chunkFiles(files, effectiveAgentCount);\n\n const tasks = chunks.map((fileGroup, i) => {\n const fileList = fileGroup.join(\"\\n \");\n return `${prompt}\\n\\nYou are agent ${i + 1}/${chunks.length}. Focus ONLY on these files:\\n ${fileList}`;\n });\n\n return runSwarm(prompt, tasks, cwd, model);\n}\n\n// ─── Coordinator Mode Integration ──────────────────────────────\n\nexport { Coordinator, detectCoordinatorSession, loadCoordinatorProgress, parseCoordinatorConfig } from \"./coordinator/coordinator\";\nexport { Scratchpad } from \"./coordinator/scratchpad\";\nexport { MessageBus } from \"./coordinator/message-bus\";\nexport { getWorkerTools, WORKER_TOOLS, COORDINATOR_ONLY_TOOLS } from \"./coordinator/worker\";\nexport type { CoordinatorConfig, WorkerConfig, WorkerResult, WorkerMode } from \"./coordinator/types\";\nexport { DEFAULT_COORDINATOR_CONFIG } from \"./coordinator/types\";\n\n/**\n * Format swarm results for display.\n */\nexport function formatSwarmResult(result: SwarmResult): string {\n const lines: string[] = [\n ` Swarm Results\\n`,\n ` Agents: ${result.tasks.length} Success: ${result.successCount} Errors: ${result.errorCount}`,\n ` Total time: ${(result.totalDurationMs / 1000).toFixed(1)}s\\n`,\n ];\n\n for (const task of result.tasks) {\n const icon = task.status === \"done\" ? \"\\u2713\" : \"\\u2717\";\n const dur = task.durationMs ? `${(task.durationMs / 1000).toFixed(1)}s` : \"?\";\n lines.push(` ${icon} Agent ${task.id} (${dur})`);\n\n const output = task.result ?? task.error ?? \"(no output)\";\n const preview = output.split(\"\\n\").slice(0, 5);\n for (const line of preview) {\n lines.push(` ${line.slice(0, 120)}`);\n }\n if (output.split(\"\\n\").length > 5) {\n lines.push(` ... (${output.split(\"\\n\").length - 5} more lines)`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n"}, "8eb4bf3b89237eebada9defeadbb20c126775659": {"t": 1785754662.9295325, "n": 7188, "h": "1b0f3acf3b520c53", "c": "// KCode - Agent Swarm\n// Run N agents in parallel with task delegation, message bus, and result merging.\n// Usage: /swarm \"analyze all test files for coverage gaps\" --agents 4\n\nimport { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { log } from \"./logger\";\n\nexport interface SwarmTask {\n id: number;\n prompt: string;\n files?: string[];\n status: \"pending\" | \"running\" | \"done\" | \"error\";\n result?: string;\n durationMs?: number;\n error?: string;\n}\n\nexport interface SwarmResult {\n tasks: SwarmTask[];\n totalDurationMs: number;\n successCount: number;\n errorCount: number;\n merged: string;\n}\n\nconst MAX_AGENTS = 8;\nconst AGENT_TIMEOUT = 120_000; // 2 minutes per agent\n\n/**\n * Split a list of files into N roughly equal chunks.\n */\nexport function chunkFiles(files: string[], n: number): string[][] {\n if (n <= 0 || files.length === 0) return [];\n const count = Math.min(n, files.length);\n const chunks: string[][] = Array.from({ length: count }, () => []);\n for (let i = 0; i < files.length; i++) {\n chunks[i % count]!.push(files[i]!);\n }\n return chunks.filter(c => c.length > 0);\n}\n\n/**\n * Run a single agent task using kcode subprocess.\n * Returns the agent's text output.\n */\nfunction runAgent(\n prompt: string,\n cwd: string,\n model?: string,\n): Promise<{ output: string; durationMs: number }> {\n const start = Date.now();\n const args = [\"--print\", \"--permission\", \"deny\", prompt];\n if (model) {\n args.unshift(\"-m\", model);\n }\n const kcodebin = findKCodeBinary();\n\n return new Promise((resolve, reject) => {\n // Inherit the parent's environment including API keys so subagents\n // can authenticate with cloud providers. Subagents are child processes\n // of the same user — there is no additional credential-leakage surface.\n const subEnv = { ...process.env };\n\n // Warn when a cloud model appears to lack an API key\n if (model) {\n const lower = model.toLowerCase();\n const isLikelyCloud =\n lower.startsWith(\"claude-\") ||\n lower.startsWith(\"claude_\") ||\n lower.startsWith(\"gpt-\") ||\n lower.startsWith(\"o1\") ||\n lower.startsWith(\"o3\") ||\n lower.startsWith(\"o4\") ||\n lower.includes(\"gemini\") ||\n lower.includes(\"deepseek\") ||\n lower.includes(\"groq\") ||\n lower.includes(\"together\");\n if (\n isLikelyCloud &&\n !subEnv.KCODE_API_KEY &&\n !subEnv.ANTHROPIC_API_KEY &&\n !subEnv.OPENAI_API_KEY &&\n !subEnv.GROQ_API_KEY &&\n !subEnv.DEEPSEEK_API_KEY &&\n !subEnv.TOGETHER_API_KEY &&\n !subEnv.GEMINI_API_KEY\n ) {\n log.warn(\n \"swarm\",\n `Subagent model \"${model}\" looks like a cloud model but no API key ` +\n `env var is set — the subagent will likely fail to authenticate.`,\n );\n }\n }\n\n execFile(kcodebin, args, {\n cwd,\n timeout: AGENT_TIMEOUT,\n maxBuffer: 512 * 1024,\n env: subEnv,\n }, (err, stdout, stderr) => {\n if (err) {\n const msg = stderr || err.message;\n // Non-zero exit code means the agent failed — reject so runSwarm catches it\n reject(new Error(msg.slice(0, 500)));\n } else {\n resolve({ output: stdout.trim(), durationMs: Date.now() - start });\n }\n });\n });\n}\n\n/**\n * Find the kcode binary path.\n */\nfunction findKCodeBinary(): string {\n const candidates = [\n join(process.env.HOME ?? \"/home\", \".local\", \"bin\", \"kcode\"),\n join(process.env.HOME ?? \"/home\", \"KCode\", \"dist\", \"kcode\"),\n \"/usr/local/bin/kcode\",\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return \"kcode\"; // fall back to PATH\n}\n\n/**\n * Run a swarm of agents in parallel.\n *\n * @param masterPrompt - The overall task description\n * @param tasks - Individual task prompts for each agent\n * @param cwd - Working directory\n * @param model - Optional model to use\n */\nexport async function runSwarm(\n masterPrompt: string,\n tasks: string[],\n cwd: string,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const agentCount = Math.min(tasks.length, maxAgents);\n const start = Date.now();\n\n const swarmTasks: SwarmTask[] = tasks.slice(0, agentCount).map((prompt, i) => ({\n id: i + 1,\n prompt,\n status: \"pending\" as const,\n }));\n\n // Run all agents in parallel\n const promises = swarmTasks.map(async (task) => {\n task.status = \"running\";\n try {\n const { output, durationMs } = await runAgent(task.prompt, cwd, model);\n task.status = \"done\";\n task.result = output;\n task.durationMs = durationMs;\n } catch (err) {\n task.status = \"error\";\n task.error = err instanceof Error ? err.message : String(err);\n }\n });\n\n await Promise.all(promises);\n\n const successCount = swarmTasks.filter(t => t.status === \"done\").length;\n const errorCount = swarmTasks.filter(t => t.status === \"error\").length;\n\n // Merge results\n const mergedParts: string[] = [];\n for (const task of swarmTasks) {\n mergedParts.push(`── Agent ${task.id} (${task.durationMs ?? 0}ms) ──`);\n mergedParts.push(task.result ?? task.error ?? \"(no output)\");\n mergedParts.push(\"\");\n }\n\n return {\n tasks: swarmTasks,\n totalDurationMs: Date.now() - start,\n successCount,\n errorCount,\n merged: mergedParts.join(\"\\n\"),\n };\n}\n\n/**\n * Auto-split a task across files and run swarm.\n * Given a prompt and list of files, distributes files among N agents.\n */\nexport async function runSwarmOnFiles(\n prompt: string,\n files: string[],\n cwd: string,\n agentCount: number = 4,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const effectiveAgentCount = Math.min(agentCount, maxAgents);\n\n const chunks = chunkFiles(files, effectiveAgentCount);\n\n const tasks = chunks.map((fileGroup, i) => {\n const fileList = fileGroup.join(\"\\n \");\n return `${prompt}\\n\\nYou are agent ${i + 1}/${chunks.length}. Focus ONLY on these files:\\n ${fileList}`;\n });\n\n return runSwarm(prompt, tasks, cwd, model);\n}\n\n/**\n * Format swarm results for display.\n */\nexport function formatSwarmResult(result: SwarmResult): string {\n const lines: string[] = [\n ` Swarm Results\\n`,\n ` Agents: ${result.tasks.length} Success: ${result.successCount} Errors: ${result.errorCount}`,\n ` Total time: ${(result.totalDurationMs / 1000).toFixed(1)}s\\n`,\n ];\n\n for (const task of result.tasks) {\n const icon = task.status === \"done\" ? \"\\u2713\" : \"\\u2717\";\n const dur = task.durationMs ? `${(task.durationMs / 1000).toFixed(1)}s` : \"?\";\n lines.push(` ${icon} Agent ${task.id} (${dur})`);\n\n const output = task.result ?? task.error ?? \"(no output)\";\n const preview = output.split(\"\\n\").slice(0, 5);\n for (const line of preview) {\n lines.push(` ${line.slice(0, 120)}`);\n }\n if (output.split(\"\\n\").length > 5) {\n lines.push(` ... (${output.split(\"\\n\").length - 5} more lines)`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n"}, "7556f34b251ffe7db4eccdad65c6489c2356ed3c": {"t": 1785754664.6524773, "n": 6306, "h": "ecef56474a1e6830", "c": "// KCode - Agent Swarm\n// Run N agents in parallel with task delegation, message bus, and result merging.\n// Usage: /swarm \"analyze all test files for coverage gaps\" --agents 4\n\nimport { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface SwarmTask {\n id: number;\n prompt: string;\n files?: string[];\n status: \"pending\" | \"running\" | \"done\" | \"error\";\n result?: string;\n durationMs?: number;\n error?: string;\n}\n\nexport interface SwarmResult {\n tasks: SwarmTask[];\n totalDurationMs: number;\n successCount: number;\n errorCount: number;\n merged: string;\n}\n\nconst MAX_AGENTS = 8;\nconst AGENT_TIMEOUT = 120_000; // 2 minutes per agent\n\n/**\n * Split a list of files into N roughly equal chunks.\n */\nexport function chunkFiles(files: string[], n: number): string[][] {\n if (n <= 0 || files.length === 0) return [];\n const count = Math.min(n, files.length);\n const chunks: string[][] = Array.from({ length: count }, () => []);\n for (let i = 0; i < files.length; i++) {\n chunks[i % count]!.push(files[i]!);\n }\n return chunks.filter(c => c.length > 0);\n}\n\n/**\n * Run a single agent task using kcode subprocess.\n * Returns the agent's text output.\n */\nfunction runAgent(\n prompt: string,\n cwd: string,\n model?: string,\n): Promise<{ output: string; durationMs: number }> {\n const start = Date.now();\n const args = [\"--print\", \"--permission\", \"deny\", prompt];\n if (model) {\n args.unshift(\"-m\", model);\n }\n const kcodebin = findKCodeBinary();\n\n return new Promise((resolve, reject) => {\n // Strip sensitive API keys from subagent environment to prevent credential leakage\n const subEnv = { ...process.env };\n const sensitiveKeyPatterns = /^(KCODE_API_KEY|ANTHROPIC_API_KEY|OPENAI_API_KEY|GROQ_API_KEY|DEEPSEEK_API_KEY|TOGETHER_API_KEY|GEMINI_API_KEY|ASTROLEXIS_API_KEY)$/i;\n for (const key of Object.keys(subEnv)) {\n if (sensitiveKeyPatterns.test(key)) {\n delete subEnv[key];\n }\n }\n\n execFile(kcodebin, args, {\n cwd,\n timeout: AGENT_TIMEOUT,\n maxBuffer: 512 * 1024,\n env: subEnv,\n }, (err, stdout, stderr) => {\n if (err) {\n const msg = stderr || err.message;\n // Non-zero exit code means the agent failed — reject so runSwarm catches it\n reject(new Error(msg.slice(0, 500)));\n } else {\n resolve({ output: stdout.trim(), durationMs: Date.now() - start });\n }\n });\n });\n}\n\n/**\n * Find the kcode binary path.\n */\nfunction findKCodeBinary(): string {\n const candidates = [\n join(process.env.HOME ?? \"/home\", \".local\", \"bin\", \"kcode\"),\n join(process.env.HOME ?? \"/home\", \"KCode\", \"dist\", \"kcode\"),\n \"/usr/local/bin/kcode\",\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return \"kcode\"; // fall back to PATH\n}\n\n/**\n * Run a swarm of agents in parallel.\n *\n * @param masterPrompt - The overall task description\n * @param tasks - Individual task prompts for each agent\n * @param cwd - Working directory\n * @param model - Optional model to use\n */\nexport async function runSwarm(\n masterPrompt: string,\n tasks: string[],\n cwd: string,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const agentCount = Math.min(tasks.length, maxAgents);\n const start = Date.now();\n\n const swarmTasks: SwarmTask[] = tasks.slice(0, agentCount).map((prompt, i) => ({\n id: i + 1,\n prompt,\n status: \"pending\" as const,\n }));\n\n // Run all agents in parallel\n const promises = swarmTasks.map(async (task) => {\n task.status = \"running\";\n try {\n const { output, durationMs } = await runAgent(task.prompt, cwd, model);\n task.status = \"done\";\n task.result = output;\n task.durationMs = durationMs;\n } catch (err) {\n task.status = \"error\";\n task.error = err instanceof Error ? err.message : String(err);\n }\n });\n\n await Promise.all(promises);\n\n const successCount = swarmTasks.filter(t => t.status === \"done\").length;\n const errorCount = swarmTasks.filter(t => t.status === \"error\").length;\n\n // Merge results\n const mergedParts: string[] = [];\n for (const task of swarmTasks) {\n mergedParts.push(`── Agent ${task.id} (${task.durationMs ?? 0}ms) ──`);\n mergedParts.push(task.result ?? task.error ?? \"(no output)\");\n mergedParts.push(\"\");\n }\n\n return {\n tasks: swarmTasks,\n totalDurationMs: Date.now() - start,\n successCount,\n errorCount,\n merged: mergedParts.join(\"\\n\"),\n };\n}\n\n/**\n * Auto-split a task across files and run swarm.\n * Given a prompt and list of files, distributes files among N agents.\n */\nexport async function runSwarmOnFiles(\n prompt: string,\n files: string[],\n cwd: string,\n agentCount: number = 4,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const effectiveAgentCount = Math.min(agentCount, maxAgents);\n\n const chunks = chunkFiles(files, effectiveAgentCount);\n\n const tasks = chunks.map((fileGroup, i) => {\n const fileList = fileGroup.join(\"\\n \");\n return `${prompt}\\n\\nYou are agent ${i + 1}/${chunks.length}. Focus ONLY on these files:\\n ${fileList}`;\n });\n\n return runSwarm(prompt, tasks, cwd, model);\n}\n\n/**\n * Format swarm results for display.\n */\nexport function formatSwarmResult(result: SwarmResult): string {\n const lines: string[] = [\n ` Swarm Results\\n`,\n ` Agents: ${result.tasks.length} Success: ${result.successCount} Errors: ${result.errorCount}`,\n ` Total time: ${(result.totalDurationMs / 1000).toFixed(1)}s\\n`,\n ];\n\n for (const task of result.tasks) {\n const icon = task.status === \"done\" ? \"\\u2713\" : \"\\u2717\";\n const dur = task.durationMs ? `${(task.durationMs / 1000).toFixed(1)}s` : \"?\";\n lines.push(` ${icon} Agent ${task.id} (${dur})`);\n\n const output = task.result ?? task.error ?? \"(no output)\";\n const preview = output.split(\"\\n\").slice(0, 5);\n for (const line of preview) {\n lines.push(` ${line.slice(0, 120)}`);\n }\n if (output.split(\"\\n\").length > 5) {\n lines.push(` ... (${output.split(\"\\n\").length - 5} more lines)`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n"}, "5bf2767ab8a7afab4d3123d391fdd9a6866f6dd3": {"t": 1785754666.2347088, "n": 5890, "h": "10b52264fc62ddb2", "c": "// KCode - Agent Swarm\n// Run N agents in parallel with task delegation, message bus, and result merging.\n// Usage: /swarm \"analyze all test files for coverage gaps\" --agents 4\n\nimport { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface SwarmTask {\n id: number;\n prompt: string;\n files?: string[];\n status: \"pending\" | \"running\" | \"done\" | \"error\";\n result?: string;\n durationMs?: number;\n error?: string;\n}\n\nexport interface SwarmResult {\n tasks: SwarmTask[];\n totalDurationMs: number;\n successCount: number;\n errorCount: number;\n merged: string;\n}\n\nconst MAX_AGENTS = 8;\nconst AGENT_TIMEOUT = 120_000; // 2 minutes per agent\n\n/**\n * Split a list of files into N roughly equal chunks.\n */\nexport function chunkFiles(files: string[], n: number): string[][] {\n if (n <= 0 || files.length === 0) return [];\n const count = Math.min(n, files.length);\n const chunks: string[][] = Array.from({ length: count }, () => []);\n for (let i = 0; i < files.length; i++) {\n chunks[i % count]!.push(files[i]!);\n }\n return chunks.filter(c => c.length > 0);\n}\n\n/**\n * Run a single agent task using kcode subprocess.\n * Returns the agent's text output.\n */\nfunction runAgent(\n prompt: string,\n cwd: string,\n model?: string,\n): Promise<{ output: string; durationMs: number }> {\n const start = Date.now();\n const args = [\"--print\", \"--permission\", \"deny\", prompt];\n if (model) {\n args.unshift(\"-m\", model);\n }\n const kcodebin = findKCodeBinary();\n\n return new Promise((resolve, reject) => {\n execFile(kcodebin, args, {\n cwd,\n timeout: AGENT_TIMEOUT,\n maxBuffer: 512 * 1024,\n env: { ...process.env },\n }, (err, stdout, stderr) => {\n if (err) {\n const msg = stderr || err.message;\n // Non-zero exit code means the agent failed — reject so runSwarm catches it\n reject(new Error(msg.slice(0, 500)));\n } else {\n resolve({ output: stdout.trim(), durationMs: Date.now() - start });\n }\n });\n });\n}\n\n/**\n * Find the kcode binary path.\n */\nfunction findKCodeBinary(): string {\n const candidates = [\n join(process.env.HOME ?? \"/home\", \".local\", \"bin\", \"kcode\"),\n join(process.env.HOME ?? \"/home\", \"KCode\", \"dist\", \"kcode\"),\n \"/usr/local/bin/kcode\",\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return \"kcode\"; // fall back to PATH\n}\n\n/**\n * Run a swarm of agents in parallel.\n *\n * @param masterPrompt - The overall task description\n * @param tasks - Individual task prompts for each agent\n * @param cwd - Working directory\n * @param model - Optional model to use\n */\nexport async function runSwarm(\n masterPrompt: string,\n tasks: string[],\n cwd: string,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const agentCount = Math.min(tasks.length, maxAgents);\n const start = Date.now();\n\n const swarmTasks: SwarmTask[] = tasks.slice(0, agentCount).map((prompt, i) => ({\n id: i + 1,\n prompt,\n status: \"pending\" as const,\n }));\n\n // Run all agents in parallel\n const promises = swarmTasks.map(async (task) => {\n task.status = \"running\";\n try {\n const { output, durationMs } = await runAgent(task.prompt, cwd, model);\n task.status = \"done\";\n task.result = output;\n task.durationMs = durationMs;\n } catch (err) {\n task.status = \"error\";\n task.error = err instanceof Error ? err.message : String(err);\n }\n });\n\n await Promise.all(promises);\n\n const successCount = swarmTasks.filter(t => t.status === \"done\").length;\n const errorCount = swarmTasks.filter(t => t.status === \"error\").length;\n\n // Merge results\n const mergedParts: string[] = [];\n for (const task of swarmTasks) {\n mergedParts.push(`── Agent ${task.id} (${task.durationMs ?? 0}ms) ──`);\n mergedParts.push(task.result ?? task.error ?? \"(no output)\");\n mergedParts.push(\"\");\n }\n\n return {\n tasks: swarmTasks,\n totalDurationMs: Date.now() - start,\n successCount,\n errorCount,\n merged: mergedParts.join(\"\\n\"),\n };\n}\n\n/**\n * Auto-split a task across files and run swarm.\n * Given a prompt and list of files, distributes files among N agents.\n */\nexport async function runSwarmOnFiles(\n prompt: string,\n files: string[],\n cwd: string,\n agentCount: number = 4,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const effectiveAgentCount = Math.min(agentCount, maxAgents);\n\n const chunks = chunkFiles(files, effectiveAgentCount);\n\n const tasks = chunks.map((fileGroup, i) => {\n const fileList = fileGroup.join(\"\\n \");\n return `${prompt}\\n\\nYou are agent ${i + 1}/${chunks.length}. Focus ONLY on these files:\\n ${fileList}`;\n });\n\n return runSwarm(prompt, tasks, cwd, model);\n}\n\n/**\n * Format swarm results for display.\n */\nexport function formatSwarmResult(result: SwarmResult): string {\n const lines: string[] = [\n ` Swarm Results\\n`,\n ` Agents: ${result.tasks.length} Success: ${result.successCount} Errors: ${result.errorCount}`,\n ` Total time: ${(result.totalDurationMs / 1000).toFixed(1)}s\\n`,\n ];\n\n for (const task of result.tasks) {\n const icon = task.status === \"done\" ? \"\\u2713\" : \"\\u2717\";\n const dur = task.durationMs ? `${(task.durationMs / 1000).toFixed(1)}s` : \"?\";\n lines.push(` ${icon} Agent ${task.id} (${dur})`);\n\n const output = task.result ?? task.error ?? \"(no output)\";\n const preview = output.split(\"\\n\").slice(0, 5);\n for (const line of preview) {\n lines.push(` ${line.slice(0, 120)}`);\n }\n if (output.split(\"\\n\").length > 5) {\n lines.push(` ... (${output.split(\"\\n\").length - 5} more lines)`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n"}, "f43f20ef5e25c0f26120db2f137b24387c3bdba0": {"t": 1785754667.781069, "n": 5843, "h": "e699371e255eb16f", "c": "// KCode - Agent Swarm\n// Run N agents in parallel with task delegation, message bus, and result merging.\n// Usage: /swarm \"analyze all test files for coverage gaps\" --agents 4\n\nimport { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface SwarmTask {\n id: number;\n prompt: string;\n files?: string[];\n status: \"pending\" | \"running\" | \"done\" | \"error\";\n result?: string;\n durationMs?: number;\n error?: string;\n}\n\nexport interface SwarmResult {\n tasks: SwarmTask[];\n totalDurationMs: number;\n successCount: number;\n errorCount: number;\n merged: string;\n}\n\nconst MAX_AGENTS = 8;\nconst AGENT_TIMEOUT = 120_000; // 2 minutes per agent\n\n/**\n * Split a list of files into N roughly equal chunks.\n */\nexport function chunkFiles(files: string[], n: number): string[][] {\n const count = Math.min(n, files.length);\n const chunks: string[][] = Array.from({ length: count }, () => []);\n for (let i = 0; i < files.length; i++) {\n chunks[i % count]!.push(files[i]!);\n }\n return chunks.filter(c => c.length > 0);\n}\n\n/**\n * Run a single agent task using kcode subprocess.\n * Returns the agent's text output.\n */\nfunction runAgent(\n prompt: string,\n cwd: string,\n model?: string,\n): Promise<{ output: string; durationMs: number }> {\n const start = Date.now();\n const args = [\"--print\", \"--permission\", \"deny\", prompt];\n if (model) {\n args.unshift(\"-m\", model);\n }\n const kcodebin = findKCodeBinary();\n\n return new Promise((resolve, reject) => {\n execFile(kcodebin, args, {\n cwd,\n timeout: AGENT_TIMEOUT,\n maxBuffer: 512 * 1024,\n env: { ...process.env },\n }, (err, stdout, stderr) => {\n if (err) {\n const msg = stderr || err.message;\n // Non-zero exit code means the agent failed — reject so runSwarm catches it\n reject(new Error(msg.slice(0, 500)));\n } else {\n resolve({ output: stdout.trim(), durationMs: Date.now() - start });\n }\n });\n });\n}\n\n/**\n * Find the kcode binary path.\n */\nfunction findKCodeBinary(): string {\n const candidates = [\n join(process.env.HOME ?? \"/home\", \".local\", \"bin\", \"kcode\"),\n join(process.env.HOME ?? \"/home\", \"KCode\", \"dist\", \"kcode\"),\n \"/usr/local/bin/kcode\",\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return \"kcode\"; // fall back to PATH\n}\n\n/**\n * Run a swarm of agents in parallel.\n *\n * @param masterPrompt - The overall task description\n * @param tasks - Individual task prompts for each agent\n * @param cwd - Working directory\n * @param model - Optional model to use\n */\nexport async function runSwarm(\n masterPrompt: string,\n tasks: string[],\n cwd: string,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const agentCount = Math.min(tasks.length, maxAgents);\n const start = Date.now();\n\n const swarmTasks: SwarmTask[] = tasks.slice(0, agentCount).map((prompt, i) => ({\n id: i + 1,\n prompt,\n status: \"pending\" as const,\n }));\n\n // Run all agents in parallel\n const promises = swarmTasks.map(async (task) => {\n task.status = \"running\";\n try {\n const { output, durationMs } = await runAgent(task.prompt, cwd, model);\n task.status = \"done\";\n task.result = output;\n task.durationMs = durationMs;\n } catch (err) {\n task.status = \"error\";\n task.error = err instanceof Error ? err.message : String(err);\n }\n });\n\n await Promise.all(promises);\n\n const successCount = swarmTasks.filter(t => t.status === \"done\").length;\n const errorCount = swarmTasks.filter(t => t.status === \"error\").length;\n\n // Merge results\n const mergedParts: string[] = [];\n for (const task of swarmTasks) {\n mergedParts.push(`── Agent ${task.id} (${task.durationMs ?? 0}ms) ──`);\n mergedParts.push(task.result ?? task.error ?? \"(no output)\");\n mergedParts.push(\"\");\n }\n\n return {\n tasks: swarmTasks,\n totalDurationMs: Date.now() - start,\n successCount,\n errorCount,\n merged: mergedParts.join(\"\\n\"),\n };\n}\n\n/**\n * Auto-split a task across files and run swarm.\n * Given a prompt and list of files, distributes files among N agents.\n */\nexport async function runSwarmOnFiles(\n prompt: string,\n files: string[],\n cwd: string,\n agentCount: number = 4,\n model?: string,\n): Promise<SwarmResult> {\n const { getMaxSwarmAgents } = await import(\"./pro.js\");\n const maxAgents = await getMaxSwarmAgents();\n const effectiveAgentCount = Math.min(agentCount, maxAgents);\n\n const chunks = chunkFiles(files, effectiveAgentCount);\n\n const tasks = chunks.map((fileGroup, i) => {\n const fileList = fileGroup.join(\"\\n \");\n return `${prompt}\\n\\nYou are agent ${i + 1}/${chunks.length}. Focus ONLY on these files:\\n ${fileList}`;\n });\n\n return runSwarm(prompt, tasks, cwd, model);\n}\n\n/**\n * Format swarm results for display.\n */\nexport function formatSwarmResult(result: SwarmResult): string {\n const lines: string[] = [\n ` Swarm Results\\n`,\n ` Agents: ${result.tasks.length} Success: ${result.successCount} Errors: ${result.errorCount}`,\n ` Total time: ${(result.totalDurationMs / 1000).toFixed(1)}s\\n`,\n ];\n\n for (const task of result.tasks) {\n const icon = task.status === \"done\" ? \"\\u2713\" : \"\\u2717\";\n const dur = task.durationMs ? `${(task.durationMs / 1000).toFixed(1)}s` : \"?\";\n lines.push(` ${icon} Agent ${task.id} (${dur})`);\n\n const output = task.result ?? task.error ?? \"(no output)\";\n const preview = output.split(\"\\n\").slice(0, 5);\n for (const line of preview) {\n lines.push(` ${line.slice(0, 120)}`);\n }\n if (output.split(\"\\n\").length > 5) {\n lines.push(` ... (${output.split(\"\\n\").length - 5} more lines)`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n"}, "4ad6d15d87000899deda2ce5461a98b4824feda3": {"t": 1785754669.3129957, "n": 5723, "h": "b5780a8b1ffe2640", "c": "// KCode - Agent Swarm\n// Run N agents in parallel with task delegation, message bus, and result merging.\n// Usage: /swarm \"analyze all test files for coverage gaps\" --agents 4\n\nimport { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface SwarmTask {\n id: number;\n prompt: string;\n files?: string[];\n status: \"pending\" | \"running\" | \"done\" | \"error\";\n result?: string;\n durationMs?: number;\n error?: string;\n}\n\nexport interface SwarmResult {\n tasks: SwarmTask[];\n totalDurationMs: number;\n successCount: number;\n errorCount: number;\n merged: string;\n}\n\nconst MAX_AGENTS = 8;\nconst AGENT_TIMEOUT = 120_000; // 2 minutes per agent\n\n/**\n * Split a list of files into N roughly equal chunks.\n */\nexport function chunkFiles(files: string[], n: number): string[][] {\n const count = Math.min(n, files.length);\n const chunks: string[][] = Array.from({ length: count }, () => []);\n for (let i = 0; i < files.length; i++) {\n chunks[i % count]!.push(files[i]!);\n }\n return chunks.filter(c => c.length > 0);\n}\n\n/**\n * Run a single agent task using kcode subprocess.\n * Returns the agent's text output.\n */\nfunction runAgent(\n prompt: string,\n cwd: string,\n model?: string,\n): Promise<{ output: string; durationMs: number }> {\n const start = Date.now();\n const args = [\"--print\", \"--permission\", \"deny\", prompt];\n if (model) {\n args.unshift(\"-m\", model);\n }\n const kcodebin = findKCodeBinary();\n\n return new Promise((resolve, reject) => {\n execFile(kcodebin, args, {\n cwd,\n timeout: AGENT_TIMEOUT,\n maxBuffer: 512 * 1024,\n env: { ...process.env },\n }, (err, stdout, stderr) => {\n if (err) {\n const msg = stderr || err.message;\n // Non-zero exit code means the agent failed — reject so runSwarm catches it\n reject(new Error(msg.slice(0, 500)));\n } else {\n resolve({ output: stdout.trim(), durationMs: Date.now() - start });\n }\n });\n });\n}\n\n/**\n * Find the kcode binary path.\n */\nfunction findKCodeBinary(): string {\n const candidates = [\n join(process.env.HOME ?? \"/home\", \".local\", \"bin\", \"kcode\"),\n join(process.env.HOME ?? \"/home\", \"KCode\", \"dist\", \"kcode\"),\n \"/usr/local/bin/kcode\",\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return \"kcode\"; // fall back to PATH\n}\n\n/**\n * Run a swarm of agents in parallel.\n *\n * @param masterPrompt - The overall task description\n * @param tasks - Individual task prompts for each agent\n * @param cwd - Working directory\n * @param model - Optional model to use\n */\nexport async function runSwarm(\n masterPrompt: string,\n tasks: string[],\n cwd: string,\n model?: string,\n): Promise<SwarmResult> {\n const { requirePro } = await import(\"./pro.js\");\n await requirePro(\"swarm\");\n\n const agentCount = Math.min(tasks.length, MAX_AGENTS);\n const start = Date.now();\n\n const swarmTasks: SwarmTask[] = tasks.slice(0, agentCount).map((prompt, i) => ({\n id: i + 1,\n prompt,\n status: \"pending\" as const,\n }));\n\n // Run all agents in parallel\n const promises = swarmTasks.map(async (task) => {\n task.status = \"running\";\n try {\n const { output, durationMs } = await runAgent(task.prompt, cwd, model);\n task.status = \"done\";\n task.result = output;\n task.durationMs = durationMs;\n } catch (err) {\n task.status = \"error\";\n task.error = err instanceof Error ? err.message : String(err);\n }\n });\n\n await Promise.all(promises);\n\n const successCount = swarmTasks.filter(t => t.status === \"done\").length;\n const errorCount = swarmTasks.filter(t => t.status === \"error\").length;\n\n // Merge results\n const mergedParts: string[] = [];\n for (const task of swarmTasks) {\n mergedParts.push(`── Agent ${task.id} (${task.durationMs ?? 0}ms) ──`);\n mergedParts.push(task.result ?? task.error ?? \"(no output)\");\n mergedParts.push(\"\");\n }\n\n return {\n tasks: swarmTasks,\n totalDurationMs: Date.now() - start,\n successCount,\n errorCount,\n merged: mergedParts.join(\"\\n\"),\n };\n}\n\n/**\n * Auto-split a task across files and run swarm.\n * Given a prompt and list of files, distributes files among N agents.\n */\nexport async function runSwarmOnFiles(\n prompt: string,\n files: string[],\n cwd: string,\n agentCount: number = 4,\n model?: string,\n): Promise<SwarmResult> {\n const { requirePro } = await import(\"./pro.js\");\n await requirePro(\"swarm\");\n\n const chunks = chunkFiles(files, agentCount);\n\n const tasks = chunks.map((fileGroup, i) => {\n const fileList = fileGroup.join(\"\\n \");\n return `${prompt}\\n\\nYou are agent ${i + 1}/${chunks.length}. Focus ONLY on these files:\\n ${fileList}`;\n });\n\n return runSwarm(prompt, tasks, cwd, model);\n}\n\n/**\n * Format swarm results for display.\n */\nexport function formatSwarmResult(result: SwarmResult): string {\n const lines: string[] = [\n ` Swarm Results\\n`,\n ` Agents: ${result.tasks.length} Success: ${result.successCount} Errors: ${result.errorCount}`,\n ` Total time: ${(result.totalDurationMs / 1000).toFixed(1)}s\\n`,\n ];\n\n for (const task of result.tasks) {\n const icon = task.status === \"done\" ? \"\\u2713\" : \"\\u2717\";\n const dur = task.durationMs ? `${(task.durationMs / 1000).toFixed(1)}s` : \"?\";\n lines.push(` ${icon} Agent ${task.id} (${dur})`);\n\n const output = task.result ?? task.error ?? \"(no output)\";\n const preview = output.split(\"\\n\").slice(0, 5);\n for (const line of preview) {\n lines.push(` ${line.slice(0, 120)}`);\n }\n if (output.split(\"\\n\").length > 5) {\n lines.push(` ... (${output.split(\"\\n\").length - 5} more lines)`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n"}, "18f323e8ed28e2d13ac43c6073697c52e4361e2a": {"t": 1785754670.676166, "n": 5561, "h": "2333b250c8d79199", "c": "// KCode - Agent Swarm\n// Run N agents in parallel with task delegation, message bus, and result merging.\n// Usage: /swarm \"analyze all test files for coverage gaps\" --agents 4\n\nimport { execFile } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport interface SwarmTask {\n id: number;\n prompt: string;\n files?: string[];\n status: \"pending\" | \"running\" | \"done\" | \"error\";\n result?: string;\n durationMs?: number;\n error?: string;\n}\n\nexport interface SwarmResult {\n tasks: SwarmTask[];\n totalDurationMs: number;\n successCount: number;\n errorCount: number;\n merged: string;\n}\n\nconst MAX_AGENTS = 8;\nconst AGENT_TIMEOUT = 120_000; // 2 minutes per agent\n\n/**\n * Split a list of files into N roughly equal chunks.\n */\nexport function chunkFiles(files: string[], n: number): string[][] {\n const count = Math.min(n, files.length);\n const chunks: string[][] = Array.from({ length: count }, () => []);\n for (let i = 0; i < files.length; i++) {\n chunks[i % count]!.push(files[i]!);\n }\n return chunks.filter(c => c.length > 0);\n}\n\n/**\n * Run a single agent task using kcode subprocess.\n * Returns the agent's text output.\n */\nfunction runAgent(\n prompt: string,\n cwd: string,\n model?: string,\n): Promise<{ output: string; durationMs: number }> {\n const start = Date.now();\n const args = [\"--print\", \"--permission\", \"deny\", prompt];\n if (model) {\n args.unshift(\"-m\", model);\n }\n const kcodebin = findKCodeBinary();\n\n return new Promise((resolve, reject) => {\n execFile(kcodebin, args, {\n cwd,\n timeout: AGENT_TIMEOUT,\n maxBuffer: 512 * 1024,\n env: { ...process.env },\n }, (err, stdout, stderr) => {\n if (err) {\n const msg = stderr || err.message;\n // Non-zero exit code means the agent failed — reject so runSwarm catches it\n reject(new Error(msg.slice(0, 500)));\n } else {\n resolve({ output: stdout.trim(), durationMs: Date.now() - start });\n }\n });\n });\n}\n\n/**\n * Find the kcode binary path.\n */\nfunction findKCodeBinary(): string {\n const candidates = [\n join(process.env.HOME ?? \"/home\", \".local\", \"bin\", \"kcode\"),\n join(process.env.HOME ?? \"/home\", \"KCode\", \"dist\", \"kcode\"),\n \"/usr/local/bin/kcode\",\n ];\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n return \"kcode\"; // fall back to PATH\n}\n\n/**\n * Run a swarm of agents in parallel.\n *\n * @param masterPrompt - The overall task description\n * @param tasks - Individual task prompts for each agent\n * @param cwd - Working directory\n * @param model - Optional model to use\n */\nexport async function runSwarm(\n masterPrompt: string,\n tasks: string[],\n cwd: string,\n model?: string,\n): Promise<SwarmResult> {\n const agentCount = Math.min(tasks.length, MAX_AGENTS);\n const start = Date.now();\n\n const swarmTasks: SwarmTask[] = tasks.slice(0, agentCount).map((prompt, i) => ({\n id: i + 1,\n prompt,\n status: \"pending\" as const,\n }));\n\n // Run all agents in parallel\n const promises = swarmTasks.map(async (task) => {\n task.status = \"running\";\n try {\n const { output, durationMs } = await runAgent(task.prompt, cwd, model);\n task.status = \"done\";\n task.result = output;\n task.durationMs = durationMs;\n } catch (err) {\n task.status = \"error\";\n task.error = err instanceof Error ? err.message : String(err);\n }\n });\n\n await Promise.all(promises);\n\n const successCount = swarmTasks.filter(t => t.status === \"done\").length;\n const errorCount = swarmTasks.filter(t => t.status === \"error\").length;\n\n // Merge results\n const mergedParts: string[] = [];\n for (const task of swarmTasks) {\n mergedParts.push(`── Agent ${task.id} (${task.durationMs ?? 0}ms) ──`);\n mergedParts.push(task.result ?? task.error ?? \"(no output)\");\n mergedParts.push(\"\");\n }\n\n return {\n tasks: swarmTasks,\n totalDurationMs: Date.now() - start,\n successCount,\n errorCount,\n merged: mergedParts.join(\"\\n\"),\n };\n}\n\n/**\n * Auto-split a task across files and run swarm.\n * Given a prompt and list of files, distributes files among N agents.\n */\nexport async function runSwarmOnFiles(\n prompt: string,\n files: string[],\n cwd: string,\n agentCount: number = 4,\n model?: string,\n): Promise<SwarmResult> {\n const chunks = chunkFiles(files, agentCount);\n\n const tasks = chunks.map((fileGroup, i) => {\n const fileList = fileGroup.join(\"\\n \");\n return `${prompt}\\n\\nYou are agent ${i + 1}/${chunks.length}. Focus ONLY on these files:\\n ${fileList}`;\n });\n\n return runSwarm(prompt, tasks, cwd, model);\n}\n\n/**\n * Format swarm results for display.\n */\nexport function formatSwarmResult(result: SwarmResult): string {\n const lines: string[] = [\n ` Swarm Results\\n`,\n ` Agents: ${result.tasks.length} Success: ${result.successCount} Errors: ${result.errorCount}`,\n ` Total time: ${(result.totalDurationMs / 1000).toFixed(1)}s\\n`,\n ];\n\n for (const task of result.tasks) {\n const icon = task.status === \"done\" ? \"\\u2713\" : \"\\u2717\";\n const dur = task.durationMs ? `${(task.durationMs / 1000).toFixed(1)}s` : \"?\";\n lines.push(` ${icon} Agent ${task.id} (${dur})`);\n\n const output = task.result ?? task.error ?? \"(no output)\";\n const preview = output.split(\"\\n\").slice(0, 5);\n for (const line of preview) {\n lines.push(` ${line.slice(0, 120)}`);\n }\n if (output.split(\"\\n\").length > 5) {\n lines.push(` ... (${output.split(\"\\n\").length - 5} more lines)`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n"}}}} |