From 326e09f02f15b3beeddb81096aeb98ff27116f83 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Sun, 21 Sep 2025 23:25:25 +0800 Subject: [PATCH 01/53] { "tool": "Write", "files": [ "scripts/claudebench-init.ts" ], "tasks": [ { "id": "t-1758468266542", "text": "Create claudebench-init CLI tool for bootstrapping external projects" }, { "id": "t-1758465558673", "text": "Create ClaudeBench cli installer to install hooks scripts, configure mcp, setup CLAUDE.local.md." } ], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758468325150 } --- scripts/claudebench-init.ts | 304 ++++++++++++++++++++++++++++++++++++ 1 file changed, 304 insertions(+) create mode 100644 scripts/claudebench-init.ts diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts new file mode 100644 index 0000000..d15acb7 --- /dev/null +++ b/scripts/claudebench-init.ts @@ -0,0 +1,304 @@ +#!/usr/bin/env bun +/** + * ClaudeBench Init - Bootstrap any project with ClaudeBench integration + * + * Usage: bunx claudebench-init [options] + * Run this from any project directory to connect it with ClaudeBench + */ + +import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs"; +import { join, resolve, basename } from "path"; +import { homedir } from "os"; +import readline from "readline/promises"; + +const VERSION = "1.0.0"; + +// Terminal colors +const c = { + reset: "\x1b[0m", + bright: "\x1b[1m", + green: "\x1b[32m", + yellow: "\x1b[33m", + blue: "\x1b[34m", + red: "\x1b[31m", + cyan: "\x1b[36m", +}; + +// Configuration file that will be created in the project +interface ProjectConfig { + version: string; + server: string; + instanceId: string; + projectName: string; + createdAt: string; + hooks: boolean; +} + +async function main() { + console.log(`${c.bright}${c.blue} +╔═══════════════════════════════════════╗ +║ ClaudeBench Project Initializer ║ +║ Version ${VERSION} ║ +╚═══════════════════════════════════════╝ +${c.reset}`); + + const projectDir = process.cwd(); + const projectName = basename(projectDir); + + console.log(`${c.cyan}📁 Initializing: ${projectDir}${c.reset}\n`); + + // Check if already initialized + const configPath = join(projectDir, ".claudebench.json"); + if (existsSync(configPath)) { + console.log(`${c.yellow}⚠️ Project already initialized with ClaudeBench${c.reset}`); + const config = JSON.parse(readFileSync(configPath, "utf-8")); + console.log(` Server: ${config.server}`); + console.log(` Instance: ${config.instanceId}\n`); + + const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); + const answer = await rl.question("Reinitialize? [y/N]: "); + rl.close(); + + if (!answer.toLowerCase().startsWith("y")) { + console.log("Cancelled."); + process.exit(0); + } + } + + // Interactive configuration + const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); + + console.log(`${c.bright}Configuration:${c.reset}\n`); + + const server = await rl.question(`ClaudeBench server URL [http://localhost:3000]: `) || "http://localhost:3000"; + const instanceId = await rl.question(`Instance ID [worker-1]: `) || "worker-1"; + const enableHooks = await rl.question(`Enable hooks for Claude Code? [Y/n]: `); + + rl.close(); + + // Test server connection + console.log(`\n${c.cyan}🔍 Testing connection to ${server}...${c.reset}`); + + try { + const response = await fetch(`${server}/rpc`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + jsonrpc: "2.0", + method: "system.health", + params: {}, + id: 1 + }), + }); + + const result = await response.json(); + if (!result.result?.healthy) { + throw new Error("Server unhealthy"); + } + console.log(`${c.green}✅ Connected successfully${c.reset}\n`); + } catch (err) { + console.log(`${c.red}❌ Cannot connect to ClaudeBench server${c.reset}`); + console.log(` Make sure ClaudeBench is running: ${c.cyan}bun dev${c.reset}`); + process.exit(1); + } + + // Create configuration + console.log(`${c.bright}Creating project files:${c.reset}\n`); + + const config: ProjectConfig = { + version: VERSION, + server, + instanceId, + projectName, + createdAt: new Date().toISOString(), + hooks: !enableHooks.toLowerCase().startsWith("n"), + }; + + // 1. Create .claudebench.json + writeFileSync(configPath, JSON.stringify(config, null, 2)); + console.log(`${c.green}✅${c.reset} Created ${c.bright}.claudebench.json${c.reset}`); + + // 2. Create CLAUDE.local.md + const claudeLocalPath = join(projectDir, "CLAUDE.local.md"); + const claudeContent = generateClaudeLocal(config, server, projectDir); + writeFileSync(claudeLocalPath, claudeContent); + console.log(`${c.green}✅${c.reset} Created ${c.bright}CLAUDE.local.md${c.reset}`); + + // 3. Update Claude Code hooks if enabled + if (config.hooks) { + await setupHooks(config, projectDir); + } + + // 4. Update .gitignore + updateGitignore(projectDir); + console.log(`${c.green}✅${c.reset} Updated ${c.bright}.gitignore${c.reset}`); + + // Success! + console.log(`\n${c.green}${c.bright}🎉 Success! Project initialized with ClaudeBench${c.reset}\n`); + + console.log(`${c.bright}Next steps:${c.reset}`); + console.log(`1. Start ClaudeBench server (if not running):`); + console.log(` ${c.cyan}cd && bun dev${c.reset}`); + console.log(`2. Restart Claude Code to load hooks`); + console.log(`3. Open this project in Claude Code`); + console.log(`\nYour project is now connected to ClaudeBench! 🚀\n`); +} + +function generateClaudeLocal(config: ProjectConfig, server: string, projectDir: string): string { + return `# ClaudeBench Integration + +This project is connected to ClaudeBench for enhanced development capabilities. + +## Configuration +- **Server**: ${server} +- **Instance**: ${config.instanceId} +- **Project**: ${config.projectName} +- **Initialized**: ${config.createdAt} + +## Features +${config.hooks ? "✅ **Hooks**: Tool validation and monitoring enabled" : "❌ **Hooks**: Not configured"} +✅ **Task Management**: Use ClaudeBench tasks instead of TodoWrite +✅ **Auto-commit**: Git commits with task context + +## Usage + +### Start ClaudeBench server +\`\`\`bash +# In ClaudeBench directory +bun dev +\`\`\` + +### Monitor events (optional) +\`\`\`bash +# In ClaudeBench directory +bun relay +\`\`\` + +### Task Management +Use these MCP tools for task management: +- \`mcp__claudebench__task__create\` - Create new tasks +- \`mcp__claudebench__task__claim\` - Claim tasks +- \`mcp__claudebench__task__complete\` - Complete tasks +- \`mcp__claudebench__task__list\` - List tasks + +## Project Instructions + +When working in this project: +1. Always run \`bun relay\` in background to monitor events +2. Use ClaudeBench task tools instead of TodoWrite +3. Document task completions with detailed metadata +4. The backend is the source of truth for all contracts + +## Custom Notes + + +`; +} + +async function setupHooks(config: ProjectConfig, projectDir: string) { + const claudeSettingsPath = join(homedir(), ".claude", "settings.json"); + + // Check if Claude Code settings exist + if (!existsSync(claudeSettingsPath)) { + console.log(`${c.yellow}⚠️${c.reset} Claude Code settings not found at ${claudeSettingsPath}`); + console.log(` Hooks configuration skipped - configure manually later`); + return; + } + + try { + // Read existing settings + const settings = JSON.parse(readFileSync(claudeSettingsPath, "utf-8")); + + // Prepare hook command - this will call the Python bridge script + // We need to know where ClaudeBench is installed + const claudeBenchRoot = resolve(__dirname, ".."); + const hookScript = join(claudeBenchRoot, "scripts", "claude_code_hooks.py"); + + if (!existsSync(hookScript)) { + console.log(`${c.yellow}⚠️${c.reset} Hook script not found: ${hookScript}`); + return; + } + + const hookCommand = `CLAUDEBENCH_RPC_URL="${config.server}/rpc" CLAUDE_PROJECT_DIR="${projectDir}" CLAUDE_INSTANCE_ID="${config.instanceId}" python3 ${hookScript}`; + + // Initialize hooks object if needed + if (!settings.hooks) { + settings.hooks = {}; + } + + // Add hooks for this project (with condition to only run in this directory) + const projectCondition = `cwd:${projectDir}`; + + // Helper to add hook with condition + const addHook = (hookType: string, matcher: string = ".*") => { + if (!settings.hooks[hookType]) { + settings.hooks[hookType] = []; + } + + // Check if hook already exists for this project + const existing = settings.hooks[hookType].find((h: any) => + h.condition === projectCondition + ); + + if (!existing) { + settings.hooks[hookType].push({ + matcher, + condition: projectCondition, + hooks: [{ + type: "command", + command: hookCommand + }] + }); + } + }; + + // Add all hook types + addHook("PreToolUse"); + addHook("PostToolUse"); + addHook("PostToolUse", "TodoWrite"); // Special handling for TodoWrite + addHook("UserPromptSubmit", ""); + + // Save updated settings + writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2)); + console.log(`${c.green}✅${c.reset} Updated Claude Code hooks`); + + } catch (err) { + console.log(`${c.yellow}⚠️${c.reset} Could not update Claude Code settings: ${err}`); + console.log(` You may need to configure hooks manually`); + } +} + +function updateGitignore(projectDir: string) { + const gitignorePath = join(projectDir, ".gitignore"); + const additions = [ + "", + "# ClaudeBench", + ".claudebench.log", + "*.claudebench.tmp", + "" + ]; + + let content = ""; + if (existsSync(gitignorePath)) { + content = readFileSync(gitignorePath, "utf-8"); + + // Check if already has ClaudeBench section + if (content.includes("# ClaudeBench")) { + return; + } + } + + // Add entries + if (!content.endsWith("\n") && content.length > 0) { + content += "\n"; + } + content += additions.join("\n"); + + writeFileSync(gitignorePath, content); +} + +// Run the initializer +main().catch((err) => { + console.error(`${c.red}Error: ${err.message}${c.reset}`); + process.exit(1); +}); \ No newline at end of file From 0c2689ca97ef9994dc3acfbc005210e129a362c7 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Sun, 21 Sep 2025 23:27:54 +0800 Subject: [PATCH 02/53] { "tool": "Edit", "files": [ "scripts/claudebench-init.ts" ], "tasks": [ { "id": "t-1758468266542", "text": "Create claudebench-init CLI tool for bootstrapping external projects" }, { "id": "t-1758465558673", "text": "Create ClaudeBench cli installer to install hooks scripts, configure mcp, setup CLAUDE.local.md." } ], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758468474627 } --- scripts/claudebench-init.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts index d15acb7..be991be 100644 --- a/scripts/claudebench-init.ts +++ b/scripts/claudebench-init.ts @@ -35,6 +35,12 @@ interface ProjectConfig { } async function main() { + // Parse command line arguments + const args = process.argv.slice(2); + const isNonInteractive = args.includes("--non-interactive") || args.includes("-n"); + const serverArg = args.find(a => a.startsWith("--server="))?.split("=")[1]; + const instanceArg = args.find(a => a.startsWith("--instance="))?.split("=")[1]; + console.log(`${c.bright}${c.blue} ╔═══════════════════════════════════════╗ ║ ClaudeBench Project Initializer ║ From 6ecd371bb27727be8a3a35eb38e8c2a59194c1cd Mon Sep 17 00:00:00 2001 From: FBLGit Date: Sun, 21 Sep 2025 23:28:14 +0800 Subject: [PATCH 03/53] { "tool": "Edit", "files": [ "scripts/claudebench-init.ts" ], "tasks": [ { "id": "t-1758468266542", "text": "Create claudebench-init CLI tool for bootstrapping external projects" }, { "id": "t-1758465558673", "text": "Create ClaudeBench cli installer to install hooks scripts, configure mcp, setup CLAUDE.local.md." } ], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758468494747 } --- scripts/claudebench-init.ts | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts index be991be..2b75eb8 100644 --- a/scripts/claudebench-init.ts +++ b/scripts/claudebench-init.ts @@ -71,16 +71,30 @@ ${c.reset}`); } } - // Interactive configuration - const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); + // Configuration - use args or interactive + let server: string; + let instanceId: string; + let enableHooks: string; - console.log(`${c.bright}Configuration:${c.reset}\n`); - - const server = await rl.question(`ClaudeBench server URL [http://localhost:3000]: `) || "http://localhost:3000"; - const instanceId = await rl.question(`Instance ID [worker-1]: `) || "worker-1"; - const enableHooks = await rl.question(`Enable hooks for Claude Code? [Y/n]: `); - - rl.close(); + if (isNonInteractive) { + console.log(`${c.bright}Non-interactive mode${c.reset}\n`); + server = serverArg || "http://localhost:3000"; + instanceId = instanceArg || "worker-1"; + enableHooks = "Y"; + console.log(`Server: ${server}`); + console.log(`Instance: ${instanceId}`); + console.log(`Hooks: enabled\n`); + } else { + const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); + + console.log(`${c.bright}Configuration:${c.reset}\n`); + + server = await rl.question(`ClaudeBench server URL [http://localhost:3000]: `) || "http://localhost:3000"; + instanceId = await rl.question(`Instance ID [worker-1]: `) || "worker-1"; + enableHooks = await rl.question(`Enable hooks for Claude Code? [Y/n]: `); + + rl.close(); + } // Test server connection console.log(`\n${c.cyan}🔍 Testing connection to ${server}...${c.reset}`); From ce68ab4138b4b1ace1624f93e6794b24932bc815 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Sun, 21 Sep 2025 23:28:58 +0800 Subject: [PATCH 04/53] { "tool": "Edit", "files": [ "scripts/claudebench-init.ts" ], "tasks": [ { "id": "t-1758468266542", "text": "Create claudebench-init CLI tool for bootstrapping external projects" }, { "id": "t-1758465558673", "text": "Create ClaudeBench cli installer to install hooks scripts, configure mcp, setup CLAUDE.local.md." } ], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758468538113 } --- scripts/claudebench-init.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts index 2b75eb8..a49fb34 100644 --- a/scripts/claudebench-init.ts +++ b/scripts/claudebench-init.ts @@ -112,7 +112,7 @@ ${c.reset}`); }); const result = await response.json(); - if (!result.result?.healthy) { + if (!result.result?.status || result.result.status !== "healthy") { throw new Error("Server unhealthy"); } console.log(`${c.green}✅ Connected successfully${c.reset}\n`); From 5542e487c56c84c2b0b7d96cb2e8a15a970189e6 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Sun, 21 Sep 2025 23:29:44 +0800 Subject: [PATCH 05/53] { "tool": "Edit", "files": [ "scripts/claudebench-init.ts" ], "tasks": [ { "id": "t-1758468266542", "text": "Create claudebench-init CLI tool for bootstrapping external projects" }, { "id": "t-1758465558673", "text": "Create ClaudeBench cli installer to install hooks scripts, configure mcp, setup CLAUDE.local.md." } ], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758468584519 } --- scripts/claudebench-init.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts index a49fb34..49d9a9f 100644 --- a/scripts/claudebench-init.ts +++ b/scripts/claudebench-init.ts @@ -112,7 +112,7 @@ ${c.reset}`); }); const result = await response.json(); - if (!result.result?.status || result.result.status !== "healthy") { + if (!result.result?.status || (result.result.status !== "healthy" && result.result.status !== "degraded")) { throw new Error("Server unhealthy"); } console.log(`${c.green}✅ Connected successfully${c.reset}\n`); From a3b807ef88c8a6c45bf28a56cc9107181a989371 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Sun, 21 Sep 2025 23:30:01 +0800 Subject: [PATCH 06/53] { "tool": "Edit", "files": [ "scripts/claudebench-init.ts" ], "tasks": [ { "id": "t-1758468266542", "text": "Create claudebench-init CLI tool for bootstrapping external projects" }, { "id": "t-1758465558673", "text": "Create ClaudeBench cli installer to install hooks scripts, configure mcp, setup CLAUDE.local.md." } ], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758468601931 } --- scripts/claudebench-init.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts index 49d9a9f..8ec4082 100644 --- a/scripts/claudebench-init.ts +++ b/scripts/claudebench-init.ts @@ -119,6 +119,7 @@ ${c.reset}`); } catch (err) { console.log(`${c.red}❌ Cannot connect to ClaudeBench server${c.reset}`); console.log(` Make sure ClaudeBench is running: ${c.cyan}bun dev${c.reset}`); + console.log(` Error: ${err}`); process.exit(1); } From cf5ada9ec6522bf48eef59e29e8f1666883610b1 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Sun, 21 Sep 2025 23:30:27 +0800 Subject: [PATCH 07/53] { "tool": "Edit", "files": [ "scripts/claudebench-init.ts" ], "tasks": [ { "id": "t-1758468266542", "text": "Create claudebench-init CLI tool for bootstrapping external projects" }, { "id": "t-1758465558673", "text": "Create ClaudeBench cli installer to install hooks scripts, configure mcp, setup CLAUDE.local.md." } ], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758468627272 } --- scripts/claudebench-init.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts index 8ec4082..7f07299 100644 --- a/scripts/claudebench-init.ts +++ b/scripts/claudebench-init.ts @@ -112,8 +112,9 @@ ${c.reset}`); }); const result = await response.json(); - if (!result.result?.status || (result.result.status !== "healthy" && result.result.status !== "degraded")) { - throw new Error("Server unhealthy"); + // Accept any response with a result object as healthy + if (!result.result) { + throw new Error("Invalid server response"); } console.log(`${c.green}✅ Connected successfully${c.reset}\n`); } catch (err) { From 243aa1cb59919ae5144d94b6aa1a13d795903df7 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Sun, 21 Sep 2025 23:37:06 +0800 Subject: [PATCH 08/53] { "tool": "Edit", "files": [ "scripts/claudebench-init.ts" ], "tasks": [ { "id": "t-1758468836938", "text": "Check system state and register worker-2" } ], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758469026770 } --- scripts/claudebench-init.ts | 136 +++++++++++++++++++----------------- 1 file changed, 72 insertions(+), 64 deletions(-) diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts index 7f07299..2706848 100644 --- a/scripts/claudebench-init.ts +++ b/scripts/claudebench-init.ts @@ -218,76 +218,84 @@ When working in this project: } async function setupHooks(config: ProjectConfig, projectDir: string) { - const claudeSettingsPath = join(homedir(), ".claude", "settings.json"); + // Create project-local .claude directory + const claudeDir = join(projectDir, ".claude"); + const claudeSettingsPath = join(claudeDir, "settings.json"); - // Check if Claude Code settings exist - if (!existsSync(claudeSettingsPath)) { - console.log(`${c.yellow}⚠️${c.reset} Claude Code settings not found at ${claudeSettingsPath}`); - console.log(` Hooks configuration skipped - configure manually later`); + // Create .claude directory if it doesn't exist + if (!existsSync(claudeDir)) { + mkdirSync(claudeDir, { recursive: true }); + } + + // Load the template from scripts/claude_code_hooks.json + const claudeBenchRoot = resolve(__dirname, ".."); + const templatePath = join(claudeBenchRoot, "scripts", "claude_code_hooks.json"); + const hookScript = join(claudeBenchRoot, "scripts", "claude_code_hooks.py"); + + if (!existsSync(templatePath)) { + console.log(`${c.yellow}⚠️${c.reset} Template not found: ${templatePath}`); + return; + } + + if (!existsSync(hookScript)) { + console.log(`${c.yellow}⚠️${c.reset} Hook script not found: ${hookScript}`); return; } - try { - // Read existing settings - const settings = JSON.parse(readFileSync(claudeSettingsPath, "utf-8")); - - // Prepare hook command - this will call the Python bridge script - // We need to know where ClaudeBench is installed - const claudeBenchRoot = resolve(__dirname, ".."); - const hookScript = join(claudeBenchRoot, "scripts", "claude_code_hooks.py"); - - if (!existsSync(hookScript)) { - console.log(`${c.yellow}⚠️${c.reset} Hook script not found: ${hookScript}`); - return; - } - - const hookCommand = `CLAUDEBENCH_RPC_URL="${config.server}/rpc" CLAUDE_PROJECT_DIR="${projectDir}" CLAUDE_INSTANCE_ID="${config.instanceId}" python3 ${hookScript}`; - - // Initialize hooks object if needed - if (!settings.hooks) { - settings.hooks = {}; - } - - // Add hooks for this project (with condition to only run in this directory) - const projectCondition = `cwd:${projectDir}`; - - // Helper to add hook with condition - const addHook = (hookType: string, matcher: string = ".*") => { - if (!settings.hooks[hookType]) { - settings.hooks[hookType] = []; - } - - // Check if hook already exists for this project - const existing = settings.hooks[hookType].find((h: any) => - h.condition === projectCondition - ); - - if (!existing) { - settings.hooks[hookType].push({ - matcher, - condition: projectCondition, - hooks: [{ - type: "command", - command: hookCommand - }] - }); + // Load template settings + const template = JSON.parse(readFileSync(templatePath, "utf-8")); + + // Create the hook command with environment variables + const hookCommand = `CLAUDEBENCH_RPC_URL="${config.server}/rpc" CLAUDE_PROJECT_DIR="${projectDir}" CLAUDE_INSTANCE_ID="${config.instanceId}" python3 ${hookScript}`; + + // Update all hook commands in the template to use our configured command + const settings = JSON.parse(JSON.stringify(template)); // Deep clone + + // Update all hooks to use the configured command + for (const hookType in settings.hooks) { + if (Array.isArray(settings.hooks[hookType])) { + for (const hookConfig of settings.hooks[hookType]) { + if (hookConfig.hooks && Array.isArray(hookConfig.hooks)) { + for (const hook of hookConfig.hooks) { + if (hook.type === "command") { + hook.command = hookCommand; + } + } + } } - }; - - // Add all hook types - addHook("PreToolUse"); - addHook("PostToolUse"); - addHook("PostToolUse", "TodoWrite"); // Special handling for TodoWrite - addHook("UserPromptSubmit", ""); - - // Save updated settings - writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2)); - console.log(`${c.green}✅${c.reset} Updated Claude Code hooks`); - - } catch (err) { - console.log(`${c.yellow}⚠️${c.reset} Could not update Claude Code settings: ${err}`); - console.log(` You may need to configure hooks manually`); + } } + + // Add project-specific metadata + settings.project = config.projectName; + settings.claudebench = { + server: config.server, + instanceId: config.instanceId, + version: config.version + }; + + // Save project-local Claude settings + writeFileSync(claudeSettingsPath, JSON.stringify(settings, null, 2)); + console.log(`${c.green}✅${c.reset} Created .claude/settings.json`); + + // Also create .mcp.json for MCP configuration + const mcpPath = join(projectDir, ".mcp.json"); + const mcpConfig = { + version: "1.0.0", + servers: { + claudebench: { + command: "bun", + args: [join(claudeBenchRoot, "apps", "server", "src", "mcp-server.ts")], + env: { + CLAUDEBENCH_RPC_URL: `${config.server}/rpc`, + NODE_ENV: "production" + } + } + } + }; + + writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2)); + console.log(`${c.green}✅${c.reset} Created .mcp.json`); } function updateGitignore(projectDir: string) { From 0188ef1eb568ff8d7fd8901d1872c5d9a17fb0b9 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Sun, 21 Sep 2025 23:38:21 +0800 Subject: [PATCH 09/53] { "tool": "Edit", "files": [ "scripts/claudebench-init.ts" ], "tasks": [ { "id": "t-1758468836938", "text": "Check system state and register worker-2" } ], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758469101685 } --- scripts/claudebench-init.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts index 2706848..076c41d 100644 --- a/scripts/claudebench-init.ts +++ b/scripts/claudebench-init.ts @@ -146,7 +146,7 @@ ${c.reset}`); writeFileSync(claudeLocalPath, claudeContent); console.log(`${c.green}✅${c.reset} Created ${c.bright}CLAUDE.local.md${c.reset}`); - // 3. Update Claude Code hooks if enabled + // 3. Setup hooks and MCP configuration if (config.hooks) { await setupHooks(config, projectDir); } From 38197717ac3f85ccb33ef86c537ffd9ac45a41c6 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Sun, 21 Sep 2025 23:38:47 +0800 Subject: [PATCH 10/53] { "tool": "Edit", "files": [ "scripts/claudebench-init.ts" ], "tasks": [ { "id": "t-1758468836938", "text": "Check system state and register worker-2" } ], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758469127094 } --- scripts/claudebench-init.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts index 076c41d..77ccec2 100644 --- a/scripts/claudebench-init.ts +++ b/scripts/claudebench-init.ts @@ -246,7 +246,8 @@ async function setupHooks(config: ProjectConfig, projectDir: string) { const template = JSON.parse(readFileSync(templatePath, "utf-8")); // Create the hook command with environment variables - const hookCommand = `CLAUDEBENCH_RPC_URL="${config.server}/rpc" CLAUDE_PROJECT_DIR="${projectDir}" CLAUDE_INSTANCE_ID="${config.instanceId}" python3 ${hookScript}`; + // CLAUDE_INSTANCE_ID comes from the environment when Claude Code runs + const hookCommand = `CLAUDEBENCH_RPC_URL="${config.server}/rpc" CLAUDE_PROJECT_DIR="${projectDir}" python3 ${hookScript}`; // Update all hook commands in the template to use our configured command const settings = JSON.parse(JSON.stringify(template)); // Deep clone From c4cb7f761475e048fc1e6e6982efe83ceea6f519 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Sun, 21 Sep 2025 23:47:48 +0800 Subject: [PATCH 11/53] { "tool": "Edit", "files": [ "scripts/claudebench-init.ts" ], "tasks": [ { "id": "t-1758468836938", "text": "Check system state and register worker-2" } ], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758469668588 } --- scripts/claudebench-init.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts index 77ccec2..967486e 100644 --- a/scripts/claudebench-init.ts +++ b/scripts/claudebench-init.ts @@ -282,15 +282,10 @@ async function setupHooks(config: ProjectConfig, projectDir: string) { // Also create .mcp.json for MCP configuration const mcpPath = join(projectDir, ".mcp.json"); const mcpConfig = { - version: "1.0.0", - servers: { + mcpServers: { claudebench: { - command: "bun", - args: [join(claudeBenchRoot, "apps", "server", "src", "mcp-server.ts")], - env: { - CLAUDEBENCH_RPC_URL: `${config.server}/rpc`, - NODE_ENV: "production" - } + type: "http", + url: `${config.server}/mcp` } } }; From 44feff3822a8d352d3c3f09c94f7de3babf9cc20 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Sun, 21 Sep 2025 23:53:40 +0800 Subject: [PATCH 12/53] { "tool": "Edit", "files": [ "scripts/claudebench-init.ts" ], "tasks": [ { "id": "t-1758468836938", "text": "Check system state and register worker-2" } ], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758470020413 } --- scripts/claudebench-init.ts | 52 +++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts index 967486e..195bdfd 100644 --- a/scripts/claudebench-init.ts +++ b/scripts/claudebench-init.ts @@ -140,9 +140,57 @@ ${c.reset}`); writeFileSync(configPath, JSON.stringify(config, null, 2)); console.log(`${c.green}✅${c.reset} Created ${c.bright}.claudebench.json${c.reset}`); - // 2. Create CLAUDE.local.md + // 2. Create/append CLAUDE.local.md const claudeLocalPath = join(projectDir, "CLAUDE.local.md"); - const claudeContent = generateClaudeLocal(config, server, projectDir); + const claudeBenchRoot = resolve(__dirname, ".."); + const templatePath = join(claudeBenchRoot, "scripts", "CLAUDE.local.md"); + + let claudeContent = ""; + + // Start with template if it exists + if (existsSync(templatePath)) { + claudeContent = readFileSync(templatePath, "utf-8"); + } + + // Add project-specific configuration + claudeContent += `\n\n## ClaudeBench Project Configuration + +This project has been initialized with ClaudeBench integration. + +### Configuration +- **Server**: ${config.server} +- **Project**: ${config.projectName} +- **Initialized**: ${config.createdAt} + +### Active Features +${config.hooks ? "✅ **Hooks**: Tool validation and monitoring via .claude/settings.json" : "❌ **Hooks**: Not configured"} +✅ **MCP**: ClaudeBench server available via .mcp.json +✅ **Task Management**: Use ClaudeBench task tools + +### Usage + +1. **Start ClaudeBench server** (if not running): + \`\`\`bash + cd ${claudeBenchRoot} + bun dev + \`\`\` + +2. **Monitor events** (optional): + \`\`\`bash + cd ${claudeBenchRoot} + bun relay + \`\`\` + +3. **Task Management**: + - \`mcp__claudebench__task__create\` - Create new tasks + - \`mcp__claudebench__task__claim\` - Claim tasks + - \`mcp__claudebench__task__complete\` - Complete tasks + - \`mcp__claudebench__task__list\` - List tasks + +### Project Notes + +`; + writeFileSync(claudeLocalPath, claudeContent); console.log(`${c.green}✅${c.reset} Created ${c.bright}CLAUDE.local.md${c.reset}`); From a39bbf191017fd852f373c3daa111931cc1e4a98 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Sun, 21 Sep 2025 23:54:10 +0800 Subject: [PATCH 13/53] { "tool": "Edit", "files": [ "scripts/claudebench-init.ts" ], "tasks": [ { "id": "t-1758468836938", "text": "Check system state and register worker-2" } ], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758470050180 } --- scripts/claudebench-init.ts | 50 ------------------------------------- 1 file changed, 50 deletions(-) diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts index 195bdfd..3e72799 100644 --- a/scripts/claudebench-init.ts +++ b/scripts/claudebench-init.ts @@ -214,56 +214,6 @@ ${config.hooks ? "✅ **Hooks**: Tool validation and monitoring via .claude/sett console.log(`\nYour project is now connected to ClaudeBench! 🚀\n`); } -function generateClaudeLocal(config: ProjectConfig, server: string, projectDir: string): string { - return `# ClaudeBench Integration - -This project is connected to ClaudeBench for enhanced development capabilities. - -## Configuration -- **Server**: ${server} -- **Instance**: ${config.instanceId} -- **Project**: ${config.projectName} -- **Initialized**: ${config.createdAt} - -## Features -${config.hooks ? "✅ **Hooks**: Tool validation and monitoring enabled" : "❌ **Hooks**: Not configured"} -✅ **Task Management**: Use ClaudeBench tasks instead of TodoWrite -✅ **Auto-commit**: Git commits with task context - -## Usage - -### Start ClaudeBench server -\`\`\`bash -# In ClaudeBench directory -bun dev -\`\`\` - -### Monitor events (optional) -\`\`\`bash -# In ClaudeBench directory -bun relay -\`\`\` - -### Task Management -Use these MCP tools for task management: -- \`mcp__claudebench__task__create\` - Create new tasks -- \`mcp__claudebench__task__claim\` - Claim tasks -- \`mcp__claudebench__task__complete\` - Complete tasks -- \`mcp__claudebench__task__list\` - List tasks - -## Project Instructions - -When working in this project: -1. Always run \`bun relay\` in background to monitor events -2. Use ClaudeBench task tools instead of TodoWrite -3. Document task completions with detailed metadata -4. The backend is the source of truth for all contracts - -## Custom Notes - - -`; -} async function setupHooks(config: ProjectConfig, projectDir: string) { // Create project-local .claude directory From 0db9022e783148b1630dc72c5d5fa99f3c96a8fd Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 00:00:28 +0800 Subject: [PATCH 14/53] { "tool": "Write", "files": [ "docs/docs/guides/cli-installer.md" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758470428190 } --- docs/docs/guides/cli-installer.md | 247 ++++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 docs/docs/guides/cli-installer.md diff --git a/docs/docs/guides/cli-installer.md b/docs/docs/guides/cli-installer.md new file mode 100644 index 0000000..ca602bd --- /dev/null +++ b/docs/docs/guides/cli-installer.md @@ -0,0 +1,247 @@ +--- +title: ClaudeBench CLI Installer +sidebar_label: CLI Installer +description: Bootstrap any project with ClaudeBench integration +--- + +# ClaudeBench CLI Installer + +The ClaudeBench CLI installer (`claudebench-init`) is a tool that bootstraps any project directory with ClaudeBench integration. It sets up hooks, MCP configuration, and documentation to connect your project with the ClaudeBench ecosystem. + +## Overview + +The installer creates project-local configuration files that: +- Enable tool validation and monitoring through hooks +- Configure MCP server connection for enhanced AI capabilities +- Set up task management integration with ClaudeBench +- Provide project-specific documentation and instructions + +## Installation & Usage + +### Running the Installer + +From any project directory, run: + +```bash +# Interactive mode (with prompts) +cd /path/to/your/project +bun /path/to/claudebench/scripts/claudebench-init.ts + +# Non-interactive mode (with defaults) +bun /path/to/claudebench/scripts/claudebench-init.ts --non-interactive + +# With custom options +bun /path/to/claudebench/scripts/claudebench-init.ts \ + --non-interactive \ + --server=http://localhost:3000 \ + --instance=worker-1 +``` + +### Command Line Options + +| Option | Description | Default | +|--------|-------------|---------| +| `--non-interactive`, `-n` | Run without prompts | `false` | +| `--server=` | ClaudeBench server URL | `http://localhost:3000` | +| `--instance=` | Instance identifier | `worker-1` | + +## What Gets Created + +The installer creates the following files in your project: + +### 1. `.claudebench.json` + +Project configuration file containing: + +```json +{ + "version": "1.0.0", + "server": "http://localhost:3000", + "instanceId": "worker-1", + "projectName": "your-project", + "createdAt": "2025-09-21T15:00:00.000Z", + "hooks": true +} +``` + +### 2. `.claude/settings.json` + +Local Claude Code settings with hooks configuration. This file: +- Uses the template from `scripts/claude_code_hooks.json` +- Configures hooks for tool validation and monitoring +- Sets up environment variables for the ClaudeBench connection +- Includes all hook types (PreToolUse, PostToolUse, SessionStart, etc.) + +Example structure: +```json +{ + "project": "your-project", + "claudebench": { + "server": "http://localhost:3000", + "instanceId": "worker-1", + "version": "1.0.0" + }, + "hooks": { + "PreToolUse": [...], + "PostToolUse": [...], + "UserPromptSubmit": [...] + } +} +``` + +### 3. `.mcp.json` + +MCP (Model Context Protocol) configuration: + +```json +{ + "mcpServers": { + "claudebench": { + "type": "http", + "url": "http://localhost:3000/mcp" + } + } +} +``` + +### 4. `CLAUDE.local.md` + +Project-specific instructions that combine: +- Template content from `scripts/CLAUDE.local.md` +- Project configuration details +- Usage instructions +- Task management guidelines + +### 5. `.gitignore` Updates + +Adds ClaudeBench-related entries: +```gitignore +# ClaudeBench +.claudebench.log +*.claudebench.tmp +``` + +## How It Works + +### Hook Integration + +The hooks work by: +1. Claude Code triggers hooks on various events (tool use, prompts, sessions) +2. Hooks execute the Python bridge script (`claude_code_hooks.py`) +3. The bridge script communicates with ClaudeBench server via JSONRPC +4. ClaudeBench validates, monitors, and tracks all activities + +Environment variables passed to hooks: +- `CLAUDEBENCH_RPC_URL`: Server RPC endpoint +- `CLAUDE_PROJECT_DIR`: Project directory path +- `CLAUDE_INSTANCE_ID`: Inherited from Claude Code environment + +### MCP Integration + +The MCP configuration enables: +- Direct access to ClaudeBench tools in Claude Desktop +- Task management capabilities +- System monitoring and metrics +- Event-driven architecture integration + +## Prerequisites + +Before running the installer, ensure: + +1. **ClaudeBench is running**: + ```bash + cd /path/to/claudebench + bun dev + ``` + +2. **Python 3 is installed** (for hooks): + ```bash + python3 --version + ``` + +3. **Bun is installed** (for running the installer): + ```bash + bun --version + ``` + +## Post-Installation Steps + +After successful initialization: + +1. **Restart Claude Code** to load the new hooks configuration +2. **Start ClaudeBench server** if not already running +3. **Open your project** in Claude Code +4. **Verify integration** by checking the relay output when using tools + +## Task Management + +Once initialized, use ClaudeBench task tools instead of TodoWrite: + +- `mcp__claudebench__task__create` - Create new tasks +- `mcp__claudebench__task__claim` - Claim tasks for work +- `mcp__claudebench__task__complete` - Complete tasks with metadata +- `mcp__claudebench__task__list` - List available tasks + +## Troubleshooting + +### Connection Issues + +If the installer can't connect to ClaudeBench: +1. Verify the server is running: `bun dev` +2. Check the server URL is correct +3. Ensure no firewall is blocking port 3000 + +### Hook Issues + +If hooks aren't firing: +1. Restart Claude Code after installation +2. Verify Python 3 is in your PATH +3. Check `.claude/settings.json` exists in your project +4. Ensure you're working in the initialized project directory + +### MCP Issues + +If MCP tools aren't available: +1. Check `.mcp.json` exists in your project +2. Verify the MCP server URL is correct +3. Restart Claude Desktop if using it + +## Advanced Usage + +### Customizing the Template + +You can modify `scripts/CLAUDE.local.md` to change the default instructions that get added to every project. + +### Multiple Projects + +Each project maintains its own configuration. You can initialize multiple projects, each with different settings: + +```bash +# Project A with default server +cd /path/to/projectA +bun claudebench-init --non-interactive + +# Project B with custom server +cd /path/to/projectB +bun claudebench-init --non-interactive --server=http://localhost:4000 +``` + +### Updating Configuration + +To update an existing project's configuration: +1. Delete the configuration files (`.claudebench.json`, `.claude/`, `.mcp.json`) +2. Run the installer again with new settings + +## Security Considerations + +- Hook commands are executed with your user permissions +- Environment variables may contain sensitive information +- Store `.claudebench.json` in version control for team sharing +- Consider adding `.claude/settings.json` to `.gitignore` if it contains sensitive data + +## Related Documentation + +- [Hooks Setup Guide](../architecture/hooks.md) +- [MCP Integration](../architecture/mcp.md) +- [Task Management](../api/task/index.md) +- [Event-Driven Architecture](../architecture/event-bus.md) \ No newline at end of file From c97a0d5ef9eb3725ec364b714817746cc20535e9 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 00:05:20 +0800 Subject: [PATCH 15/53] { "tool": "Write", "files": [ "docs/docs/guides/onboard-repository.md" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758470720300 } --- docs/docs/guides/onboard-repository.md | 291 +++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 docs/docs/guides/onboard-repository.md diff --git a/docs/docs/guides/onboard-repository.md b/docs/docs/guides/onboard-repository.md new file mode 100644 index 0000000..bac35f1 --- /dev/null +++ b/docs/docs/guides/onboard-repository.md @@ -0,0 +1,291 @@ +--- +title: Onboard Repository +sidebar_label: Onboard Repository +description: Connect any repository to ClaudeBench +--- + +# Onboard Repository to ClaudeBench + +This guide walks you through connecting any repository or project to ClaudeBench for enhanced development capabilities. + +## Overview + +The ClaudeBench repository onboarding process: +- Connects your project to the ClaudeBench server +- Enables tool validation and monitoring through hooks +- Sets up task management integration +- Configures MCP for enhanced AI capabilities +- Creates project-specific documentation + +## Prerequisites + +Before onboarding your repository: + +- **Bun** installed ([installation guide](https://bun.sh/)) +- **Python 3** installed (for hooks integration) +- **ClaudeBench** cloned and running +- **Claude Code** or **Claude Desktop** installed + +## Step 1: Start ClaudeBench Server + +First, ensure ClaudeBench is running: + +```bash +# In the ClaudeBench directory +cd /path/to/claudebench +bun dev +``` + +The server runs on `http://localhost:3000` by default. + +## Step 2: Run the Onboarding Script + +Navigate to your repository and run the initializer: + +```bash +# Go to your repository +cd /path/to/your/repo + +# Run the onboarding script +bun /path/to/claudebench/scripts/claudebench-init.ts +``` + +### Interactive Mode + +The script will prompt you for: +- ClaudeBench server URL (default: `http://localhost:3000`) +- Instance ID (default: `worker-1`) +- Enable hooks for Claude Code (default: Yes) + +### Non-Interactive Mode + +For automated onboarding: + +```bash +bun /path/to/claudebench/scripts/claudebench-init.ts --non-interactive +``` + +With custom options: + +```bash +bun /path/to/claudebench/scripts/claudebench-init.ts \ + --non-interactive \ + --server=http://localhost:3000 \ + --instance=my-worker +``` + +## Step 3: Verify Installation + +After successful onboarding, your repository will have: + +``` +your-repo/ +├── .claudebench.json # Project configuration +├── .claude/ +│ └── settings.json # Claude Code hooks +├── .mcp.json # MCP server configuration +├── CLAUDE.local.md # Project instructions +└── .gitignore # Updated with ClaudeBench entries +``` + +## Step 4: Restart Claude Code + +Restart Claude Code to load the new hooks configuration. + +## Using ClaudeBench Features + +### Task Management + +Use ClaudeBench task tools instead of TodoWrite: + +```typescript +// Create a task +mcp__claudebench__task__create({ + text: "Implement feature X", + priority: 80 +}) + +// Claim tasks +mcp__claudebench__task__claim({ + workerId: "worker-1", + maxTasks: 1 +}) + +// Complete tasks +mcp__claudebench__task__complete({ + taskId: "t-123", + workerId: "worker-1", + result: { + description: "Implemented feature X", + files: ["src/feature.ts"] + } +}) +``` + +### Monitor Events + +Run the event relay to see real-time activity: + +```bash +# In ClaudeBench directory +bun relay +``` + +### Auto-Commit with Context + +When hooks are enabled, code changes are automatically committed with task context when working on protected branches. + +## Configuration Files + +### .claudebench.json + +Stores project configuration: + +```json +{ + "version": "1.0.0", + "server": "http://localhost:3000", + "instanceId": "worker-1", + "projectName": "your-repo", + "createdAt": "2025-09-21T15:00:00.000Z", + "hooks": true +} +``` + +### .claude/settings.json + +Contains Claude Code hooks configuration: +- PreToolUse hooks for validation +- PostToolUse hooks for monitoring +- Session hooks for tracking +- All hooks run the Python bridge script with proper environment variables + +### .mcp.json + +MCP server configuration: + +```json +{ + "mcpServers": { + "claudebench": { + "type": "http", + "url": "http://localhost:3000/mcp" + } + } +} +``` + +### CLAUDE.local.md + +Combines: +- Template instructions from ClaudeBench +- Project-specific configuration +- Usage guidelines +- Custom notes + +## Multiple Repository Setup + +You can onboard multiple repositories, each with its own configuration: + +```bash +# Repository A +cd ~/repo-a +bun ~/claudebench/scripts/claudebench-init.ts --non-interactive + +# Repository B with custom server +cd ~/repo-b +bun ~/claudebench/scripts/claudebench-init.ts \ + --non-interactive \ + --server=http://localhost:4000 +``` + +## Updating Configuration + +To update an existing onboarded repository: + +1. Remove existing configuration: +```bash +rm -rf .claudebench.json .claude/ .mcp.json +``` + +2. Run the onboarding script again with new settings + +## Troubleshooting + +### Connection Failed + +If the script can't connect to ClaudeBench: +- Verify the server is running: `bun dev` +- Check the server URL is correct +- Ensure port 3000 is not blocked + +### Hooks Not Working + +If hooks aren't triggering: +- Restart Claude Code after onboarding +- Verify Python 3 is available: `python3 --version` +- Check you're working in the onboarded repository +- Verify `.claude/settings.json` exists + +### MCP Tools Not Available + +If MCP tools aren't accessible: +- Check `.mcp.json` exists in your repository +- Verify the MCP server URL is correct +- Restart Claude Desktop if using it + +## Environment Variables + +The hooks use these environment variables: +- `CLAUDEBENCH_RPC_URL`: Set from server URL in config +- `CLAUDE_PROJECT_DIR`: Set to repository path +- `CLAUDE_INSTANCE_ID`: Inherited from Claude Code + +## Security Notes + +- Hook scripts execute with your user permissions +- Configuration files can be committed to version control +- Sensitive data should not be stored in configuration files +- The Python bridge script is executed from ClaudeBench installation + +## Examples + +### Frontend Project + +```bash +cd ~/my-react-app +bun ~/claudebench/scripts/claudebench-init.ts --non-interactive +``` + +### Backend API + +```bash +cd ~/my-api-server +bun ~/claudebench/scripts/claudebench-init.ts \ + --instance=api-worker \ + --non-interactive +``` + +### Monorepo Package + +```bash +cd ~/monorepo/packages/core +bun ~/claudebench/scripts/claudebench-init.ts --non-interactive +``` + +## Next Steps + +After onboarding your repository: + +1. Start using ClaudeBench task management tools +2. Monitor events with the relay +3. Customize `CLAUDE.local.md` with project-specific instructions +4. Explore [swarm intelligence](../api/swarm/index.md) for complex tasks +5. Read about the [event-driven architecture](../architecture/event-bus.md) + +## Related Documentation + +- [CLI Installer Technical Details](cli-installer.md) +- [Hooks Architecture](../architecture/hooks.md) +- [Task Management API](../api/task/index.md) +- [MCP Integration](../architecture/mcp.md) \ No newline at end of file From 4af0502e9c5fa242adb651a7f80a2702bd66c944 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 00:05:33 +0800 Subject: [PATCH 16/53] { "tool": "Edit", "files": [ "docs/docs/guides/cli-installer.md" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758470733589 } --- docs/docs/guides/cli-installer.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/docs/guides/cli-installer.md b/docs/docs/guides/cli-installer.md index ca602bd..a01d4f0 100644 --- a/docs/docs/guides/cli-installer.md +++ b/docs/docs/guides/cli-installer.md @@ -1,12 +1,12 @@ --- -title: ClaudeBench CLI Installer +title: CLI Installer Technical Reference sidebar_label: CLI Installer -description: Bootstrap any project with ClaudeBench integration +description: Technical details of the ClaudeBench initialization script --- -# ClaudeBench CLI Installer +# CLI Installer Technical Reference -The ClaudeBench CLI installer (`claudebench-init`) is a tool that bootstraps any project directory with ClaudeBench integration. It sets up hooks, MCP configuration, and documentation to connect your project with the ClaudeBench ecosystem. +Technical documentation for the ClaudeBench initialization script (`claudebench-init.ts`) that bootstraps repositories with ClaudeBench integration. ## Overview From 66f063de53d140fda059e281d0653768e8bb5f89 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 00:31:50 +0800 Subject: [PATCH 17/53] { "tool": "Edit", "files": [ "scripts/claudebench-init.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758472310275 } --- scripts/claudebench-init.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts index 3e72799..3b333f9 100644 --- a/scripts/claudebench-init.ts +++ b/scripts/claudebench-init.ts @@ -199,7 +199,10 @@ ${config.hooks ? "✅ **Hooks**: Tool validation and monitoring via .claude/sett await setupHooks(config, projectDir); } - // 4. Update .gitignore + // 4. Setup relay capability + await setupRelay(config, projectDir); + + // 5. Update .gitignore updateGitignore(projectDir); console.log(`${c.green}✅${c.reset} Updated ${c.bright}.gitignore${c.reset}`); From 3cf5b590cba93422f57c0e5429b929e5f7afd7ff Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 00:32:57 +0800 Subject: [PATCH 18/53] { "tool": "Edit", "files": [ "scripts/claudebench-init.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758472377234 } --- scripts/claudebench-init.ts | 96 +++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts index 3b333f9..795b7f7 100644 --- a/scripts/claudebench-init.ts +++ b/scripts/claudebench-init.ts @@ -218,6 +218,102 @@ ${config.hooks ? "✅ **Hooks**: Tool validation and monitoring via .claude/sett } +async function setupRelay(config: ProjectConfig, projectDir: string) { + // Copy the Python relay script to .claude/relay.py + const claudeDir = join(projectDir, ".claude"); + const relayDestPath = join(claudeDir, "relay.py"); + const claudeBenchRoot = resolve(__dirname, ".."); + const relaySourcePath = join(claudeBenchRoot, "scripts", "claude_event_relay.py"); + + // Ensure .claude directory exists + if (!existsSync(claudeDir)) { + mkdirSync(claudeDir, { recursive: true }); + } + + // Copy the relay script + if (existsSync(relaySourcePath)) { + copyFileSync(relaySourcePath, relayDestPath); + console.log(`${c.green}✅${c.reset} Created .claude/relay.py`); + } else { + console.log(`${c.yellow}⚠️${c.reset} Relay script not found: ${relaySourcePath}`); + return; + } + + // Create or update package.json with relay script + const packageJsonPath = join(projectDir, "package.json"); + let packageJson: any = {}; + + if (existsSync(packageJsonPath)) { + try { + packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8")); + } catch { + // Invalid package.json, start fresh + packageJson = {}; + } + } + + // Add scripts section if it doesn't exist + if (!packageJson.scripts) { + packageJson.scripts = {}; + } + + // Add relay script + packageJson.scripts.relay = `CLAUDE_INSTANCE_ID="${config.instanceId}" python3 .claude/relay.py`; + + // Save updated package.json + writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2)); + console.log(`${c.green}✅${c.reset} Added 'relay' script to package.json`); + + // Create a simple relay.ts wrapper for bun + const relayTsPath = join(projectDir, ".claude", "relay.ts"); + const relayTsContent = `#!/usr/bin/env bun +// ClaudeBench Event Relay Wrapper +// Run with: bun relay + +import { spawn } from "child_process"; +import { resolve } from "path"; + +const config = JSON.parse(await Bun.file(".claudebench.json").text()); +const instanceId = process.argv[2] || process.env.CLAUDE_INSTANCE_ID || config.instanceId || "worker-1"; + +console.log(\`🚀 Starting Event Relay for \${config.projectName}\`); +console.log(\` Instance: \${instanceId}\`); +console.log(\` Server: \${config.server}\`); +console.log(\` Press Ctrl+C to stop\\n\`); + +const relay = spawn("python3", [resolve(import.meta.dir, "relay.py")], { + env: { + ...process.env, + CLAUDE_INSTANCE_ID: instanceId, + CLAUDEBENCH_SERVER: config.server, + PYTHONUNBUFFERED: "1", + }, + stdio: "inherit", +}); + +process.on("SIGINT", () => { + console.log("\\n⏹️ Stopping relay..."); + relay.kill("SIGINT"); + process.exit(0); +}); + +relay.on("error", (err) => { + console.error("❌ Failed to start relay:", err); + console.error("Make sure Python 3 is installed"); + process.exit(1); +}); + +relay.on("exit", (code) => { + if (code !== 0 && code !== null) { + process.exit(code); + } +}); +`; + + writeFileSync(relayTsPath, relayTsContent); + console.log(`${c.green}✅${c.reset} Created .claude/relay.ts wrapper`); +} + async function setupHooks(config: ProjectConfig, projectDir: string) { // Create project-local .claude directory const claudeDir = join(projectDir, ".claude"); From 40030df9558a0bd5af2cd16c720d512a5fbb7bed Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 00:34:11 +0800 Subject: [PATCH 19/53] { "tool": "Edit", "files": [ "scripts/claudebench-init.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758472451706 } --- scripts/claudebench-init.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts index 795b7f7..8375a08 100644 --- a/scripts/claudebench-init.ts +++ b/scripts/claudebench-init.ts @@ -6,7 +6,7 @@ * Run this from any project directory to connect it with ClaudeBench */ -import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs"; +import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from "fs"; import { join, resolve, basename } from "path"; import { homedir } from "os"; import readline from "readline/promises"; From 1c0a05642a823f43b9bfe3bff6c394c4b0c89b06 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 01:00:13 +0800 Subject: [PATCH 20/53] { "tool": "Edit", "files": [ "scripts/claudebench-init.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758474013617 } --- scripts/claudebench-init.ts | 95 +++++++++++++++++++++++++++++++++---- 1 file changed, 85 insertions(+), 10 deletions(-) diff --git a/scripts/claudebench-init.ts b/scripts/claudebench-init.ts index 8375a08..c16f02d 100644 --- a/scripts/claudebench-init.ts +++ b/scripts/claudebench-init.ts @@ -264,47 +264,122 @@ async function setupRelay(config: ProjectConfig, projectDir: string) { writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2)); console.log(`${c.green}✅${c.reset} Added 'relay' script to package.json`); - // Create a simple relay.ts wrapper for bun + // Create a relay.ts wrapper that properly configures the Python relay const relayTsPath = join(projectDir, ".claude", "relay.ts"); const relayTsContent = `#!/usr/bin/env bun -// ClaudeBench Event Relay Wrapper -// Run with: bun relay +/** + * ClaudeBench Event Relay Wrapper + * + * This runs the Python relay with proper configuration for this project. + * The Python relay handles: + * - Filtering events from own instance to reduce noise + * - Subscribing to relevant Redis channels + * - Auto-reconnection and heartbeats + * - Forwarding events to Claude Code via stdout + */ import { spawn } from "child_process"; import { resolve } from "path"; +// Load project configuration const config = JSON.parse(await Bun.file(".claudebench.json").text()); + +// Instance ID priority: CLI arg > ENV > config > default const instanceId = process.argv[2] || process.env.CLAUDE_INSTANCE_ID || config.instanceId || "worker-1"; -console.log(\`🚀 Starting Event Relay for \${config.projectName}\`); -console.log(\` Instance: \${instanceId}\`); +// Session ID for this relay session +const sessionId = \`session-\${Date.now()}\`; + +// Extract Redis URL from server URL (same logic as Python relay) +function getRedisUrl(serverUrl: string): string { + if (serverUrl.includes("localhost") || serverUrl.includes("127.0.0.1")) { + return "redis://localhost:6379/0"; + } + const url = new URL(serverUrl); + return \`redis://\${url.hostname}:6379/0\`; +} + +// Extract RPC URL from server URL +function getRpcUrl(serverUrl: string): string { + return \`\${serverUrl}/rpc\`; +} + +// Display startup banner +console.log(\` +╔══════════════════════════════════════════════════════════╗ +║ Claude Event Relay for ClaudeBench ║ +║ ║ +║ Project: \${config.projectName.padEnd(46)}\` + \`║ +║ Instance: \${instanceId.padEnd(45)}\` + \`║ +╚══════════════════════════════════════════════════════════╝ +\`); + +console.log(\`🚀 Starting Event Relay\`); +console.log(\` Instance ID: \${instanceId}\`); +console.log(\` Session ID: \${sessionId}\`); console.log(\` Server: \${config.server}\`); +console.log(\` Redis: \${getRedisUrl(config.server)}\`); console.log(\` Press Ctrl+C to stop\\n\`); +// Spawn the Python relay with full configuration +// The Python script will handle all the complex logic including: +// - Self-filtering (lines 106-128 in Python script) +// - Redis pub/sub subscriptions +// - Auto-reconnection +// - Heartbeats to maintain registration const relay = spawn("python3", [resolve(import.meta.dir, "relay.py")], { env: { ...process.env, + // Core configuration CLAUDE_INSTANCE_ID: instanceId, - CLAUDEBENCH_SERVER: config.server, + CLAUDE_SESSION_ID: sessionId, + CLAUDEBENCH_RPC_URL: getRpcUrl(config.server), + REDIS_URL: getRedisUrl(config.server), + + // Relay configuration + RELAY_ROLES: "general,backend,frontend,docs,tests,relay", + HEARTBEAT_INTERVAL: "15", + EVENT_CHANNELS: "task.*,hook.*,system.*,instance.*", + + // Enable debug if requested + DEBUG: process.env.DEBUG || "false", + + // Ensure Python outputs immediately PYTHONUNBUFFERED: "1", }, - stdio: "inherit", + stdio: "inherit", // Pass through all I/O }); +// Handle graceful shutdown process.on("SIGINT", () => { - console.log("\\n⏹️ Stopping relay..."); + console.log("\\n⏹️ Shutting down relay gracefully..."); relay.kill("SIGINT"); + // Give Python time to cleanup + setTimeout(() => process.exit(0), 1000); +}); + +process.on("SIGTERM", () => { + relay.kill("SIGTERM"); process.exit(0); }); +// Handle relay errors relay.on("error", (err) => { console.error("❌ Failed to start relay:", err); - console.error("Make sure Python 3 is installed"); + console.error("\\nTroubleshooting:"); + console.error("1. Ensure Python 3.7+ is installed: python3 --version"); + console.error("2. Install Redis client: pip3 install redis"); + console.error("3. Check relay script exists: ls .claude/relay.py"); process.exit(1); }); -relay.on("exit", (code) => { +// Handle relay exit +relay.on("exit", (code, signal) => { if (code !== 0 && code !== null) { + console.error(\`\\n❌ Relay exited with code \${code}\`); + if (signal) { + console.error(\` Signal: \${signal}\`); + } process.exit(code); } }); From 3993206ae82b530402f257da45f53743a4b93226 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:23:48 +0800 Subject: [PATCH 21/53] { "tool": "Edit", "files": [ "scripts/claude_event_relay.py" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758518628735 } --- scripts/claude_event_relay.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/claude_event_relay.py b/scripts/claude_event_relay.py index ac1efb5..e25b5b4 100755 --- a/scripts/claude_event_relay.py +++ b/scripts/claude_event_relay.py @@ -200,9 +200,15 @@ async def register(self) -> bool: if self.debug: self.log('INFO', f"Registering event relay with roles: {self.roles}") + # Include working directory in metadata + metadata = { + 'workingDirectory': os.getcwd() + } + result = await self.make_jsonrpc_request('system.register', { 'id': self.instance_id, - 'roles': self.roles + 'roles': self.roles, + 'metadata': metadata }) if result.get('registered'): From 774829ab01127ff2e8d3b82d4e84ce91ce2d420d Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:24:26 +0800 Subject: [PATCH 22/53] { "tool": "Edit", "files": [ "apps/server/src/schemas/system.schema.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758518665967 } --- apps/server/src/schemas/system.schema.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/server/src/schemas/system.schema.ts b/apps/server/src/schemas/system.schema.ts index 2ce3176..92317fc 100644 --- a/apps/server/src/schemas/system.schema.ts +++ b/apps/server/src/schemas/system.schema.ts @@ -18,6 +18,9 @@ export const systemHealthOutput = z.object({ export const systemRegisterInput = z.object({ id: z.string().min(1), roles: z.array(z.string()), + metadata: z.object({ + workingDirectory: z.string().optional(), + }).optional(), }); export const systemRegisterOutput = z.object({ From 838a93c049e80a342f4d29ec1dcc5259b82b17be Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:24:35 +0800 Subject: [PATCH 23/53] { "tool": "Edit", "files": [ "apps/server/src/handlers/system/system.register.handler.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758518675647 } --- apps/server/src/handlers/system/system.register.handler.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/server/src/handlers/system/system.register.handler.ts b/apps/server/src/handlers/system/system.register.handler.ts index d3f6fc7..a84ec70 100644 --- a/apps/server/src/handlers/system/system.register.handler.ts +++ b/apps/server/src/handlers/system/system.register.handler.ts @@ -33,7 +33,8 @@ export class SystemRegisterHandler { const result = await redisScripts.registerInstance( input.id, input.roles, - ttl + ttl, + input.metadata ); console.log(`[SystemRegister] Registration result for ${input.id}:`, result); From 807ed8a120ef0197a73b36e568020fa0eb45a153 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:25:06 +0800 Subject: [PATCH 24/53] { "tool": "Edit", "files": [ "apps/server/src/core/redis-scripts.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758518706612 } --- apps/server/src/core/redis-scripts.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/server/src/core/redis-scripts.ts b/apps/server/src/core/redis-scripts.ts index fea0ed0..00e1529 100644 --- a/apps/server/src/core/redis-scripts.ts +++ b/apps/server/src/core/redis-scripts.ts @@ -354,7 +354,8 @@ export class RedisScriptExecutor { async registerInstance( instanceId: string, roles: string[], - ttl: number + ttl: number, + metadata?: any ): Promise<{ success: boolean; becameLeader: boolean }> { const result = await this.redis.stream.eval( scripts.INSTANCE_REGISTER, @@ -364,7 +365,8 @@ export class RedisScriptExecutor { instanceId, JSON.stringify(roles), Date.now().toString(), - ttl.toString() + ttl.toString(), + JSON.stringify(metadata || {}) ) as [number, number]; return { From 06e538c0d51aebdeebd2c49d7705c30bc18d35e8 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:29:21 +0800 Subject: [PATCH 25/53] { "tool": "Edit", "files": [ "apps/server/src/core/lua-scripts.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758518961797 } --- apps/server/src/core/lua-scripts.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/server/src/core/lua-scripts.ts b/apps/server/src/core/lua-scripts.ts index bfa9678..f7df8c1 100644 --- a/apps/server/src/core/lua-scripts.ts +++ b/apps/server/src/core/lua-scripts.ts @@ -842,6 +842,7 @@ local instance_id = ARGV[1] local roles_json = ARGV[2] local timestamp = ARGV[3] local ttl = tonumber(ARGV[4]) +local metadata_json = ARGV[5] or '{}' -- Register instance redis.call('hset', instance_key, @@ -849,7 +850,8 @@ redis.call('hset', instance_key, 'roles', roles_json, 'health', 'healthy', 'status', 'ACTIVE', - 'lastSeen', timestamp + 'lastSeen', timestamp, + 'metadata', metadata_json ) redis.call('expire', instance_key, ttl) From e6a5bd59c52ed9b9c8cf2cb02d9519c45bf45950 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:29:57 +0800 Subject: [PATCH 26/53] { "tool": "Edit", "files": [ "apps/server/src/handlers/task/task.context.handler.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758518997770 } --- .../src/handlers/task/task.context.handler.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/apps/server/src/handlers/task/task.context.handler.ts b/apps/server/src/handlers/task/task.context.handler.ts index 27c0a61..caea2a8 100644 --- a/apps/server/src/handlers/task/task.context.handler.ts +++ b/apps/server/src/handlers/task/task.context.handler.ts @@ -171,6 +171,27 @@ export class TaskContextHandler { throw new Error("No session ID available for sampling"); } + // Get worker's working directory from instance metadata + let workingDirectory: string | undefined; + if (ctx.instanceId) { + const instanceKey = `cb:instance:${ctx.instanceId}`; + const instanceMetadata = await redis.pub.hget(instanceKey, 'metadata'); + if (instanceMetadata) { + try { + const metadata = JSON.parse(instanceMetadata); + workingDirectory = metadata.workingDirectory; + console.log(`[TaskContext] Using working directory from instance ${ctx.instanceId}: ${workingDirectory}`); + } catch (e) { + console.warn(`[TaskContext] Failed to parse instance metadata:`, e); + } + } + } + + // Add working directory to task info if available + if (workingDirectory) { + (taskInfo as any).workingDirectory = workingDirectory; + } + // Call the context generation endpoint with task info const response = await samplingService.generateContext( sessionId, From 9914dbe6d9686363116866f85a8a537e13ae94c7 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:35:39 +0800 Subject: [PATCH 27/53] { "tool": "Edit", "files": [ "apps/inference/src/claudebench_inference/sampling.py" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758519339689 } --- apps/inference/src/claudebench_inference/sampling.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/apps/inference/src/claudebench_inference/sampling.py b/apps/inference/src/claudebench_inference/sampling.py index 6e772ca..c2c6aa3 100644 --- a/apps/inference/src/claudebench_inference/sampling.py +++ b/apps/inference/src/claudebench_inference/sampling.py @@ -50,7 +50,8 @@ async def sample( max_tokens: int = 2000, # Note: not directly used by SDK temperature: float = 0.7, # Note: not directly used by SDK system_prompt: Optional[str] = None, - max_turns: int = 50 # Allow extensive exploration + max_turns: int = 50, # Allow extensive exploration + working_directory: Optional[str] = None # Working directory for the context ) -> str: """ Perform sampling using claude-code-sdk @@ -61,6 +62,7 @@ async def sample( temperature: Sampling temperature (not used by SDK) system_prompt: Override the default system prompt max_turns: Maximum number of turns for tool usage + working_directory: Working directory to run the SDK in Returns: The response text from Claude @@ -71,11 +73,16 @@ async def sample( try: self.stats["total_requests"] += 1 + # Log the working directory if provided + if working_directory: + logger.info(f"Using working directory: {working_directory}") + options = ClaudeCodeOptions( max_turns=max_turns, # Allow multiple turns for exploration system_prompt=system_prompt or self.default_system_prompt, allowed_tools=self.allowed_tools, - permission_mode='bypassPermissions' # Allow tool use without prompting + permission_mode='bypassPermissions', # Allow tool use without prompting + cwd=working_directory # Set the working directory for the SDK ) response_text = "" From caca83097d8b42802dcad66afe74d4ad204dbe76 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:36:10 +0800 Subject: [PATCH 28/53] { "tool": "Edit", "files": [ "apps/inference/src/claudebench_inference/sampling.py" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758519370502 } --- apps/inference/src/claudebench_inference/sampling.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/inference/src/claudebench_inference/sampling.py b/apps/inference/src/claudebench_inference/sampling.py index c2c6aa3..577d49f 100644 --- a/apps/inference/src/claudebench_inference/sampling.py +++ b/apps/inference/src/claudebench_inference/sampling.py @@ -140,7 +140,8 @@ async def sample_json( max_tokens: int = 2000, temperature: float = 0.7, system_prompt: Optional[str] = None, - max_turns: int = 50 # Allow extensive exploration + max_turns: int = 50, # Allow extensive exploration + working_directory: Optional[str] = None ) -> Dict[str, Any]: """ Sample and parse JSON response @@ -151,6 +152,7 @@ async def sample_json( temperature: Sampling temperature system_prompt: Override the default system prompt max_turns: Maximum number of turns for tool usage + working_directory: Working directory to run the SDK in Returns: Parsed JSON response as dictionary @@ -158,7 +160,7 @@ async def sample_json( Raises: Exception: If sampling or parsing fails """ - response = await self.sample(prompt, max_tokens, temperature, system_prompt, max_turns) + response = await self.sample(prompt, max_tokens, temperature, system_prompt, max_turns, working_directory) return self.extract_json(response) def get_stats(self) -> Dict[str, Any]: From c8dd211730b4798374898b88ad89e2e0391ab0ad Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:36:25 +0800 Subject: [PATCH 29/53] { "tool": "Edit", "files": [ "apps/inference/src/claudebench_inference/main.py" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758519385471 } --- apps/inference/src/claudebench_inference/main.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/inference/src/claudebench_inference/main.py b/apps/inference/src/claudebench_inference/main.py index 75ab330..8e922ee 100644 --- a/apps/inference/src/claudebench_inference/main.py +++ b/apps/inference/src/claudebench_inference/main.py @@ -222,6 +222,13 @@ async def generate_context(request: ContextRequest): logger.info(f"Context generation for subtask {request.subtaskId}") try: + # Extract working directory from subtask metadata if provided + working_directory = None + if request.subtask and isinstance(request.subtask, dict): + working_directory = request.subtask.get('workingDirectory') + if working_directory: + logger.info(f"Using working directory: {working_directory}") + # Build the prompt prompt = prompt_builder.build_context_prompt( subtaskId=request.subtaskId, @@ -229,11 +236,12 @@ async def generate_context(request: ContextRequest): subtask=request.subtask ) - # Perform sampling + # Perform sampling with working directory result = await sampling_engine.sample_json( prompt=prompt, max_tokens=16384, - temperature=0.5 # Lower temperature for more focused context + temperature=0.5, # Lower temperature for more focused context + working_directory=working_directory ) # Validate and return response From 5d195737035ee1395926212950bd3413c2121322 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:38:26 +0800 Subject: [PATCH 30/53] { "tool": "Edit", "files": [ "apps/inference/src/claudebench_inference/models.py" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758519506857 } --- apps/inference/src/claudebench_inference/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/inference/src/claudebench_inference/models.py b/apps/inference/src/claudebench_inference/models.py index 0f80dcb..5490a0e 100644 --- a/apps/inference/src/claudebench_inference/models.py +++ b/apps/inference/src/claudebench_inference/models.py @@ -52,6 +52,7 @@ class DecompositionContext(BaseModel): specialists: List[Specialist] priority: int = Field(ge=0, le=100) constraints: Optional[List[str]] = Field(default_factory=list) + workingDirectory: Optional[str] = None # Working directory for codebase exploration class DecompositionRequest(BaseModel): From bc0e6938bac6a028b240f5ee971f1fc1c2ff22de Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:38:40 +0800 Subject: [PATCH 31/53] { "tool": "Edit", "files": [ "apps/inference/src/claudebench_inference/main.py" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758519520046 } --- apps/inference/src/claudebench_inference/main.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/inference/src/claudebench_inference/main.py b/apps/inference/src/claudebench_inference/main.py index 8e922ee..5551f37 100644 --- a/apps/inference/src/claudebench_inference/main.py +++ b/apps/inference/src/claudebench_inference/main.py @@ -159,17 +159,25 @@ async def decompose_task(request: DecompositionRequest): logger.info(f"Decomposition request for session {request.sessionId}: {request.task[:50]}...") try: + # Extract working directory from context if provided + working_directory = None + if request.context and hasattr(request.context, 'workingDirectory'): + working_directory = request.context.workingDirectory + if working_directory: + logger.info(f"Using working directory for decomposition: {working_directory}") + # Build the prompt prompt = prompt_builder.build_decomposition_prompt( task=request.task, context=request.context ) - # Perform sampling + # Perform sampling with working directory result = await sampling_engine.sample_json( prompt=prompt, max_tokens=8192, - temperature=0.7 + temperature=0.7, + working_directory=working_directory ) # Validate and return response From 7c3f69cb0b74648d8bdcd66dd4ede7989f5909b7 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:39:48 +0800 Subject: [PATCH 32/53] { "tool": "Edit", "files": [ "apps/server/src/handlers/task/task.decompose.handler.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758519588610 } --- .../handlers/task/task.decompose.handler.ts | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/apps/server/src/handlers/task/task.decompose.handler.ts b/apps/server/src/handlers/task/task.decompose.handler.ts index 8bc3007..d7ad091 100644 --- a/apps/server/src/handlers/task/task.decompose.handler.ts +++ b/apps/server/src/handlers/task/task.decompose.handler.ts @@ -115,6 +115,22 @@ export class TaskDecomposeHandler { throw new Error("No session ID available for sampling"); } + // Get worker's working directory from instance metadata + let workingDirectory: string | undefined; + if (ctx.instanceId) { + const instanceKey = `cb:instance:${ctx.instanceId}`; + const instanceMetadata = await redis.pub.hget(instanceKey, 'metadata'); + if (instanceMetadata) { + try { + const metadata = JSON.parse(instanceMetadata); + workingDirectory = metadata.workingDirectory; + console.log(`[TaskDecompose] Using working directory from instance ${ctx.instanceId}: ${workingDirectory}`); + } catch (e) { + console.warn(`[TaskDecompose] Failed to parse instance metadata:`, e); + } + } + } + // Request decomposition via sampling const decomposition = await samplingService.requestDecomposition( sessionId, @@ -122,8 +138,9 @@ export class TaskDecomposeHandler { { specialists, priority: input.priority, - constraints: input.constraints - } + constraints: input.constraints, + workingDirectory + } as any ); // Store decomposition in Redis for quick access From f655d77db382a5f0b56d9ad91bc64b489b91dc12 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:40:31 +0800 Subject: [PATCH 33/53] { "tool": "Edit", "files": [ "apps/server/src/core/sampling.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758519630959 } --- apps/server/src/core/sampling.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/server/src/core/sampling.ts b/apps/server/src/core/sampling.ts index 46ea0ec..2e6d0b1 100644 --- a/apps/server/src/core/sampling.ts +++ b/apps/server/src/core/sampling.ts @@ -16,6 +16,7 @@ export interface DecompositionContext { }>; priority: number; constraints?: string[]; + workingDirectory?: string; } export interface Decomposition { From e7ac8a2b7d8fb006b9a83e67cf6a7acfdc3fd737 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:40:42 +0800 Subject: [PATCH 34/53] { "tool": "Edit", "files": [ "apps/server/src/handlers/task/task.decompose.handler.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758519642578 } --- apps/server/src/handlers/task/task.decompose.handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/server/src/handlers/task/task.decompose.handler.ts b/apps/server/src/handlers/task/task.decompose.handler.ts index d7ad091..65111bf 100644 --- a/apps/server/src/handlers/task/task.decompose.handler.ts +++ b/apps/server/src/handlers/task/task.decompose.handler.ts @@ -140,7 +140,7 @@ export class TaskDecomposeHandler { priority: input.priority, constraints: input.constraints, workingDirectory - } as any + } ); // Store decomposition in Redis for quick access From b228328743725511f4dee032e03efa23649bcd4a Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:41:17 +0800 Subject: [PATCH 35/53] { "tool": "Edit", "files": [ "apps/server/src/handlers/swarm/swarm.decompose.handler.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758519677757 } --- .../handlers/swarm/swarm.decompose.handler.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/server/src/handlers/swarm/swarm.decompose.handler.ts b/apps/server/src/handlers/swarm/swarm.decompose.handler.ts index 3644705..d2bd85f 100644 --- a/apps/server/src/handlers/swarm/swarm.decompose.handler.ts +++ b/apps/server/src/handlers/swarm/swarm.decompose.handler.ts @@ -82,6 +82,22 @@ export class SwarmDecomposeHandler { throw new Error("No session ID available for sampling"); } + // Get worker's working directory from instance metadata + let workingDirectory: string | undefined; + if (ctx.instanceId) { + const instanceKey = `cb:instance:${ctx.instanceId}`; + const instanceMetadata = await redis.pub.hget(instanceKey, 'metadata'); + if (instanceMetadata) { + try { + const metadata = JSON.parse(instanceMetadata); + workingDirectory = metadata.workingDirectory; + console.log(`[SwarmDecompose] Using working directory from instance ${ctx.instanceId}: ${workingDirectory}`); + } catch (e) { + console.warn(`[SwarmDecompose] Failed to parse instance metadata:`, e); + } + } + } + // Request decomposition via sampling const decomposition = await samplingService.requestDecomposition( sessionId, @@ -89,7 +105,8 @@ export class SwarmDecomposeHandler { { specialists, priority: input.priority, - constraints: input.constraints + constraints: input.constraints, + workingDirectory } ); From bfbb29c3917f8506f86bf5122e5dd88f33751bf3 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:41:50 +0800 Subject: [PATCH 36/53] { "tool": "Edit", "files": [ "apps/server/src/handlers/swarm/swarm.decompose.handler.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758519710919 } --- apps/server/src/handlers/swarm/swarm.decompose.handler.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/server/src/handlers/swarm/swarm.decompose.handler.ts b/apps/server/src/handlers/swarm/swarm.decompose.handler.ts index d2bd85f..175b1f3 100644 --- a/apps/server/src/handlers/swarm/swarm.decompose.handler.ts +++ b/apps/server/src/handlers/swarm/swarm.decompose.handler.ts @@ -3,6 +3,7 @@ import type { EventContext } from "@/core/context"; import { swarmDecomposeInput, swarmDecomposeOutput } from "@/schemas/swarm.schema"; import type { SwarmDecomposeInput, SwarmDecomposeOutput } from "@/schemas/swarm.schema"; import { redisScripts } from "@/core/redis-scripts"; +import { getRedis } from "@/core/redis"; import { getSamplingService } from "@/core/sampling"; import { registry } from "@/core/registry"; From 56fb5a66701482722522b7628b2ae1bd4c43ffc3 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:42:09 +0800 Subject: [PATCH 37/53] { "tool": "Edit", "files": [ "apps/server/src/handlers/swarm/swarm.decompose.handler.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758519729605 } --- apps/server/src/handlers/swarm/swarm.decompose.handler.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/server/src/handlers/swarm/swarm.decompose.handler.ts b/apps/server/src/handlers/swarm/swarm.decompose.handler.ts index 175b1f3..c99f798 100644 --- a/apps/server/src/handlers/swarm/swarm.decompose.handler.ts +++ b/apps/server/src/handlers/swarm/swarm.decompose.handler.ts @@ -84,6 +84,7 @@ export class SwarmDecomposeHandler { } // Get worker's working directory from instance metadata + const redis = getRedis(); let workingDirectory: string | undefined; if (ctx.instanceId) { const instanceKey = `cb:instance:${ctx.instanceId}`; From c8624aad7c5df5a77f0058203098f4010fd8c1ce Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:46:50 +0800 Subject: [PATCH 38/53] { "tool": "Edit", "files": [ "apps/web/src/components/ContextGenerationDialog.tsx" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758520010220 } --- apps/web/src/components/ContextGenerationDialog.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/ContextGenerationDialog.tsx b/apps/web/src/components/ContextGenerationDialog.tsx index 1ecc86f..2f1c8a8 100644 --- a/apps/web/src/components/ContextGenerationDialog.tsx +++ b/apps/web/src/components/ContextGenerationDialog.tsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, useEffect } from "react"; import { Dialog, DialogContent, @@ -33,8 +33,10 @@ import { Zap, CheckCircle, XCircle, + User, + FolderOpen, } from "lucide-react"; -import { useGenerateContext } from "@/services/event-client"; +import { useGenerateContext, useSystemState } from "@/services/event-client"; interface Task { id: string; From baabb971134bf48924a7b360f446562d3db9bea7 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:47:16 +0800 Subject: [PATCH 39/53] { "tool": "Edit", "files": [ "apps/web/src/components/ContextGenerationDialog.tsx" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758520035944 } --- .../src/components/ContextGenerationDialog.tsx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/apps/web/src/components/ContextGenerationDialog.tsx b/apps/web/src/components/ContextGenerationDialog.tsx index 2f1c8a8..29081b4 100644 --- a/apps/web/src/components/ContextGenerationDialog.tsx +++ b/apps/web/src/components/ContextGenerationDialog.tsx @@ -59,6 +59,7 @@ export function ContextGenerationDialog({ onSuccess, }: ContextGenerationDialogProps) { const [specialist, setSpecialist] = useState("general"); + const [selectedWorker, setSelectedWorker] = useState(""); const [customDescription, setCustomDescription] = useState(""); const [constraints, setConstraints] = useState(""); const [requirements, setRequirements] = useState(""); @@ -69,6 +70,21 @@ export function ContextGenerationDialog({ const [error, setError] = useState(null); const generateContextMutation = useGenerateContext(); + const { data: systemState } = useSystemState(); + + // Extract active workers from system state + const activeWorkers = systemState?.instances?.filter((instance: any) => + instance.roles?.includes("worker") || + instance.roles?.includes("relay") || + instance.id?.startsWith("worker-") + ) || []; + + // Set default worker when available + useEffect(() => { + if (activeWorkers.length > 0 && !selectedWorker) { + setSelectedWorker(activeWorkers[0].id); + } + }, [activeWorkers, selectedWorker]); const handleGenerateContext = async () => { if (!task) return; From 802bbfbf11d24638a086e6ffd794e510aeac975c Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:47:52 +0800 Subject: [PATCH 40/53] { "tool": "Edit", "files": [ "apps/web/src/components/ContextGenerationDialog.tsx" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758520072497 } --- .../components/ContextGenerationDialog.tsx | 124 ++++++++++++------ 1 file changed, 85 insertions(+), 39 deletions(-) diff --git a/apps/web/src/components/ContextGenerationDialog.tsx b/apps/web/src/components/ContextGenerationDialog.tsx index 29081b4..19e1adf 100644 --- a/apps/web/src/components/ContextGenerationDialog.tsx +++ b/apps/web/src/components/ContextGenerationDialog.tsx @@ -351,45 +351,91 @@ export function ContextGenerationDialog({ -
- - +
+
+ + +
+ +
+ + + {selectedWorker && ( +

+ Context will be generated using this worker's environment +

+ )} +
From faced02c6e463c35567b15972095618a2b1c28b0 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:48:24 +0800 Subject: [PATCH 41/53] { "tool": "Edit", "files": [ "apps/web/src/components/ContextGenerationDialog.tsx" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758520103962 } --- apps/web/src/components/ContextGenerationDialog.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/web/src/components/ContextGenerationDialog.tsx b/apps/web/src/components/ContextGenerationDialog.tsx index 19e1adf..bc686c9 100644 --- a/apps/web/src/components/ContextGenerationDialog.tsx +++ b/apps/web/src/components/ContextGenerationDialog.tsx @@ -107,6 +107,9 @@ export function ContextGenerationDialog({ requirements: requirementsList, existingFiles: filesList, additionalContext: additionalContext || undefined, + metadata: { + workerId: selectedWorker || undefined, + }, }); setGeneratedContext(result); From e6b6f9a854a63555d27ab0075f8afc6385468b2c Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:49:03 +0800 Subject: [PATCH 42/53] { "tool": "Edit", "files": [ "apps/server/src/handlers/task/task.context.handler.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758520143823 } --- .../src/handlers/task/task.context.handler.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/apps/server/src/handlers/task/task.context.handler.ts b/apps/server/src/handlers/task/task.context.handler.ts index caea2a8..6241707 100644 --- a/apps/server/src/handlers/task/task.context.handler.ts +++ b/apps/server/src/handlers/task/task.context.handler.ts @@ -173,17 +173,23 @@ export class TaskContextHandler { // Get worker's working directory from instance metadata let workingDirectory: string | undefined; - if (ctx.instanceId) { - const instanceKey = `cb:instance:${ctx.instanceId}`; + // First check if a specific worker was requested in the input metadata + const requestedWorkerId = input.metadata?.workerId; + const workerId = requestedWorkerId || ctx.instanceId; + + if (workerId) { + const instanceKey = `cb:instance:${workerId}`; const instanceMetadata = await redis.pub.hget(instanceKey, 'metadata'); if (instanceMetadata) { try { const metadata = JSON.parse(instanceMetadata); workingDirectory = metadata.workingDirectory; - console.log(`[TaskContext] Using working directory from instance ${ctx.instanceId}: ${workingDirectory}`); + console.log(`[TaskContext] Using working directory from instance ${workerId}: ${workingDirectory}`); } catch (e) { - console.warn(`[TaskContext] Failed to parse instance metadata:`, e); + console.warn(`[TaskContext] Failed to parse instance metadata for ${workerId}:`, e); } + } else if (requestedWorkerId) { + console.warn(`[TaskContext] Requested worker ${requestedWorkerId} not found or has no metadata`); } } From 376d43a4ee510fe01e40a1067a19e314258cd9d4 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:51:25 +0800 Subject: [PATCH 43/53] { "tool": "Edit", "files": [ "apps/server/src/handlers/task/task.context.handler.ts" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758520285337 } --- .../src/handlers/task/task.context.handler.ts | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/apps/server/src/handlers/task/task.context.handler.ts b/apps/server/src/handlers/task/task.context.handler.ts index 6241707..abf3685 100644 --- a/apps/server/src/handlers/task/task.context.handler.ts +++ b/apps/server/src/handlers/task/task.context.handler.ts @@ -148,21 +148,6 @@ export class TaskContextHandler { url: att.url || null })); - // Prepare task info for context generation - const taskInfo = { - id: input.taskId, - description: input.customDescription || taskData.text || "No description", - specialist: input.specialist, - status: taskData.status, - priority: parseInt(taskData.priority || "50"), - metadata: taskData.metadata ? JSON.parse(taskData.metadata) : {}, - attachments: processedAttachments, // Include processed attachments - constraints: input.constraints || [], - requirements: input.requirements || [], - existingFiles: input.existingFiles || [], - additionalContext: input.additionalContext || "" - }; - // Generate context via sampling service const samplingService = getSamplingService(); const sessionId = ctx.metadata?.sessionId || ctx.metadata?.clientId || ctx.instanceId; @@ -193,10 +178,21 @@ export class TaskContextHandler { } } - // Add working directory to task info if available - if (workingDirectory) { - (taskInfo as any).workingDirectory = workingDirectory; - } + // Prepare task info for context generation - include workingDirectory + const taskInfo = { + id: input.taskId, + description: input.customDescription || taskData.text || "No description", + specialist: input.specialist, + status: taskData.status, + priority: parseInt(taskData.priority || "50"), + metadata: taskData.metadata ? JSON.parse(taskData.metadata) : {}, + attachments: processedAttachments, // Include processed attachments + constraints: input.constraints || [], + requirements: input.requirements || [], + existingFiles: input.existingFiles || [], + additionalContext: input.additionalContext || "", + workingDirectory: workingDirectory // Now properly typed in the object + }; // Call the context generation endpoint with task info const response = await samplingService.generateContext( From f5a6d35ab66536e6c1f7e11390aff627ba3e4c90 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:55:01 +0800 Subject: [PATCH 44/53] { "tool": "Edit", "files": [ "apps/web/src/components/InstanceManager.tsx" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758520501852 } --- apps/web/src/components/InstanceManager.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/web/src/components/InstanceManager.tsx b/apps/web/src/components/InstanceManager.tsx index e014ff5..bf5bbb7 100644 --- a/apps/web/src/components/InstanceManager.tsx +++ b/apps/web/src/components/InstanceManager.tsx @@ -43,6 +43,7 @@ import { Server, Zap, Heart, + FolderOpen, } from "lucide-react"; import { useEventMutation, useEventQuery } from "@/services/event-client"; import { formatDistanceToNow } from "date-fns"; From 8d6b8079843af556567a2104a96b53f07ec54184 Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:55:10 +0800 Subject: [PATCH 45/53] { "tool": "Edit", "files": [ "apps/web/src/components/InstanceManager.tsx" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758520510448 } --- apps/web/src/components/InstanceManager.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/web/src/components/InstanceManager.tsx b/apps/web/src/components/InstanceManager.tsx index bf5bbb7..8370933 100644 --- a/apps/web/src/components/InstanceManager.tsx +++ b/apps/web/src/components/InstanceManager.tsx @@ -55,6 +55,8 @@ interface Instance { health?: string; lastSeen?: string; taskCount?: number; + workingDirectory?: string; + metadata?: any; } interface InstanceManagerProps { From db9db0c2f0fdf7e65043131f0c0a357764af945d Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:55:26 +0800 Subject: [PATCH 46/53] { "tool": "Edit", "files": [ "apps/web/src/components/InstanceManager.tsx" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758520526119 } --- apps/web/src/components/InstanceManager.tsx | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/apps/web/src/components/InstanceManager.tsx b/apps/web/src/components/InstanceManager.tsx index 8370933..ef719f6 100644 --- a/apps/web/src/components/InstanceManager.tsx +++ b/apps/web/src/components/InstanceManager.tsx @@ -115,6 +115,21 @@ export function InstanceManager({ onInstancesChange, className }: InstanceManage } } } + + // Extract working directory from metadata + let workingDirectory: string | undefined; + let metadata = inst.metadata; + if (metadata) { + if (typeof metadata === 'string') { + try { + metadata = JSON.parse(metadata); + } catch { + // Keep as is if not valid JSON + } + } + workingDirectory = metadata?.workingDirectory; + } + return { id: inst.id || inst.instanceId, roles, @@ -122,6 +137,8 @@ export function InstanceManager({ onInstancesChange, className }: InstanceManage health: inst.health || "healthy", lastSeen: inst.lastSeen || inst.lastHeartbeat || new Date().toISOString(), taskCount: inst.taskCount || 0, + workingDirectory, + metadata, }; }); setInstances(instanceList); From adcaed147e98ff99c39d1fdc5033c5584e8c0a9a Mon Sep 17 00:00:00 2001 From: FBLGit Date: Mon, 22 Sep 2025 13:55:40 +0800 Subject: [PATCH 47/53] { "tool": "Edit", "files": [ "apps/web/src/components/InstanceManager.tsx" ], "tasks": [], "todos": [], "sessionId": "ef468340-f3f2-4ada-a2bb-2ea4433d9517", "instanceId": "worker-1", "timestamp": 1758520540212 } --- apps/web/src/components/InstanceManager.tsx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/web/src/components/InstanceManager.tsx b/apps/web/src/components/InstanceManager.tsx index ef719f6..dc03002 100644 --- a/apps/web/src/components/InstanceManager.tsx +++ b/apps/web/src/components/InstanceManager.tsx @@ -464,6 +464,14 @@ export function InstanceManager({ onInstancesChange, className }: InstanceManage
)}
+ {instance.workingDirectory && ( +
+ + + {instance.workingDirectory} + +
+ )}
+ {/* Worker Selection */} +
+ + +

+ The project will be created and decomposed using this worker's environment. +

+
+ {/* Constraints */}