Skip to content

Commit 3f7c6f3

Browse files
committed
Improve terminal command routing for backend/frontend columns
- Enhanced command detection with regex patterns for Python, Node.js, Go, Rust, and other tech stacks - Added broader command pattern matching for backend vs frontend commands - Improved command prefix stripping to handle 'run:', 'execute:', 'terminal:', 'shell:' prefixes - Added support for removing markdown code block formatting from commands - Better logging with [CHAT_COMMAND_ROUTING] prefixes for debugging
1 parent 78866ef commit 3f7c6f3

File tree

1 file changed

+67
-54
lines changed

1 file changed

+67
-54
lines changed

src/ipc/processors/response_processor.ts

Lines changed: 67 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -313,102 +313,115 @@ export async function processFullResponseActions(
313313
// Handle general terminal command tags - route based on chat mode
314314
if (dyadRunTerminalCmdTags.length > 0) {
315315
for (const cmdTag of dyadRunTerminalCmdTags) {
316-
// Clean up the command - remove any "cmd:" prefix that AI might add
316+
// Clean up the command - remove common prefixes that AI might add
317317
let cleanCommand = cmdTag.command.trim();
318-
if (cleanCommand.startsWith("cmd:")) {
319-
cleanCommand = cleanCommand.substring(4).trim();
318+
319+
// Remove various command prefixes
320+
const prefixes = ['cmd:', 'command:', 'run:', 'execute:', 'terminal:', 'shell:'];
321+
for (const prefix of prefixes) {
322+
if (cleanCommand.toLowerCase().startsWith(prefix)) {
323+
cleanCommand = cleanCommand.substring(prefix.length).trim();
324+
break; // Only remove one prefix
325+
}
320326
}
321-
if (cleanCommand.startsWith("command:")) {
322-
cleanCommand = cleanCommand.substring(8).trim();
327+
328+
// Also remove markdown code block markers if present
329+
if (cleanCommand.startsWith('```') && cleanCommand.includes('\n')) {
330+
const lines = cleanCommand.split('\n');
331+
if (lines[0].startsWith('```')) {
332+
lines.shift(); // Remove opening ```
333+
}
334+
if (lines.length > 0 && lines[lines.length - 1].startsWith('```')) {
335+
lines.pop(); // Remove closing ```
336+
}
337+
cleanCommand = lines.join('\n').trim();
338+
}
339+
// Remove single backticks if wrapping the entire command
340+
if (cleanCommand.startsWith('`') && cleanCommand.endsWith('`') && cleanCommand.split('`').length === 3) {
341+
cleanCommand = cleanCommand.slice(1, -1).trim();
323342
}
324343

325344
try {
326-
327-
// Determine which terminal to route to based on chat mode
345+
// Determine which terminal to route to based on command content and chat mode
328346
let terminalType: "frontend" | "backend" = "backend"; // default
329347
let cwd = cmdTag.cwd ? path.join(appPath, cmdTag.cwd) : appPath;
330348

331-
// Check if this is a Python command - always route to backend
332-
const isPythonCommand = cleanCommand.toLowerCase().includes("python") ||
333-
cleanCommand.toLowerCase().includes("pip") ||
334-
cleanCommand.toLowerCase().includes("conda") ||
335-
cleanCommand.toLowerCase().includes("venv") ||
336-
cleanCommand.toLowerCase().includes("py ");
337-
338-
// Check if this is a Node.js command - always route to frontend
339-
const isNodeCommand = cleanCommand.toLowerCase().includes("npm") ||
340-
cleanCommand.toLowerCase().includes("yarn") ||
341-
cleanCommand.toLowerCase().includes("pnpm") ||
342-
cleanCommand.toLowerCase().includes("node") ||
343-
cleanCommand.toLowerCase().includes("npx") ||
344-
cleanCommand.toLowerCase().includes("vite") ||
345-
cleanCommand.toLowerCase().includes("next") ||
346-
cleanCommand.toLowerCase().includes("react") ||
347-
cleanCommand.toLowerCase().includes("webpack");
349+
// Enhanced command detection with better patterns
350+
const isPythonCommand = /\b(python|pip|conda|venv|py |python3|pip3|django|flask|fastapi)\b/i.test(cleanCommand);
351+
const isNodeCommand = /\b(npm|yarn|pnpm|node|npx|vite|next|react|webpack|create-react-app|vue|angular|typescript|tsc)\b/i.test(cleanCommand);
352+
const isGoCommand = /\b(go|go run|go build|go mod|go get)\b/i.test(cleanCommand);
353+
const isRustCommand = /\b(cargo|cargo build|cargo run|cargo test)\b/i.test(cleanCommand);
354+
355+
// Backend commands (Python, Go, Rust, database, server commands)
356+
const isBackendCommand = isPythonCommand || isGoCommand || isRustCommand ||
357+
/\b(server|backend|api|database|db|postgres|mysql|sqlite|mongodb|redis)\b/i.test(cleanCommand);
358+
359+
// Frontend commands (explicitly Node.js related or client-side)
360+
const isFrontendCommand = isNodeCommand ||
361+
/\b(frontend|client|web|browser|html|css|scss|sass|tailwind|webpack|babel)\b/i.test(cleanCommand);
348362

349363
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Command: "${cleanCommand}"`);
350364
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Chat mode: ${chatMode}`);
351-
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Python command detected: ${isPythonCommand}`);
352-
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Node.js command detected: ${isNodeCommand}`);
365+
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Python: ${isPythonCommand}, Node.js: ${isNodeCommand}, Go: ${isGoCommand}, Rust: ${isRustCommand}`);
366+
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Backend: ${isBackendCommand}, Frontend: ${isFrontendCommand}`);
353367

354-
if (isPythonCommand) {
368+
// Priority-based routing: explicit tech detection first, then general command patterns
369+
if (isPythonCommand || isGoCommand || isRustCommand) {
355370
terminalType = "backend";
356371
if (!cmdTag.cwd) {
357372
cwd = path.join(appPath, "backend");
358-
// Ensure backend directory exists for Python commands
359373
if (!fs.existsSync(cwd)) {
360374
fs.mkdirSync(cwd, { recursive: true });
361-
logger.log(`Created backend directory: ${cwd} for Python command execution`);
375+
logger.log(`Created backend directory: ${cwd} for command execution`);
362376
}
363377
}
364-
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Routing to BACKEND terminal (Python command)`);
378+
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Routing to BACKEND terminal (tech-specific command)`);
365379
} else if (isNodeCommand) {
366380
terminalType = "frontend";
367381
if (!cmdTag.cwd) {
368382
cwd = path.join(appPath, "frontend");
369-
// Ensure frontend directory exists for Node.js commands
370383
if (!fs.existsSync(cwd)) {
371384
fs.mkdirSync(cwd, { recursive: true });
372-
logger.log(`Created frontend directory: ${cwd} for Node.js command execution`);
385+
logger.log(`Created frontend directory: ${cwd} for command execution`);
373386
}
374387
}
375388
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Routing to FRONTEND terminal (Node.js command)`);
376-
} else if (chatMode === "ask") {
377-
// For ask mode, route to frontend terminal (most common for general commands)
378-
terminalType = "frontend";
379-
if (!cmdTag.cwd) {
380-
cwd = path.join(appPath, "frontend");
381-
}
382-
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Routing to FRONTEND terminal (ask mode default)`);
383-
} else if (chatMode === "backend") {
389+
} else if (isBackendCommand && !isFrontendCommand) {
384390
terminalType = "backend";
385-
// For backend mode, adjust cwd to backend directory if not already specified
386391
if (!cmdTag.cwd) {
387392
cwd = path.join(appPath, "backend");
388393
}
389-
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Routing to BACKEND terminal (backend mode)`);
390-
} else if (chatMode === "fullstack") {
391-
// For fullstack mode, check for Node.js commands first, then default to backend
392-
if (isNodeCommand) {
394+
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Routing to BACKEND terminal (backend-related command)`);
395+
} else if (isFrontendCommand) {
396+
terminalType = "frontend";
397+
if (!cmdTag.cwd) {
398+
cwd = path.join(appPath, "frontend");
399+
}
400+
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Routing to FRONTEND terminal (frontend-related command)`);
401+
} else {
402+
// Fallback based on chat mode
403+
if (chatMode === "ask") {
393404
terminalType = "frontend";
394405
if (!cmdTag.cwd) {
395406
cwd = path.join(appPath, "frontend");
396407
}
397-
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Routing to FRONTEND terminal (fullstack + Node.js)`);
398-
} else {
408+
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Routing to FRONTEND terminal (ask mode default)`);
409+
} else if (chatMode === "backend") {
410+
terminalType = "backend";
411+
if (!cmdTag.cwd) {
412+
cwd = path.join(appPath, "backend");
413+
}
414+
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Routing to BACKEND terminal (backend mode)`);
415+
} else if (chatMode === "fullstack") {
416+
// For fullstack, default to backend for unknown commands
399417
terminalType = "backend";
400418
if (!cmdTag.cwd) {
401419
cwd = path.join(appPath, "backend");
402-
// Ensure backend directory exists for backend commands
403-
if (!fs.existsSync(cwd)) {
404-
fs.mkdirSync(cwd, { recursive: true });
405-
logger.log(`Created backend directory: ${cwd} for terminal command execution`);
406-
}
407420
}
408421
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Routing to BACKEND terminal (fullstack default)`);
422+
} else {
423+
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Routing to ${terminalType.toUpperCase()} terminal (fallback default)`);
409424
}
410-
} else {
411-
logger.info(`[CHAT_COMMAND_ROUTING] Chat ${chatId} - Routing to ${terminalType.toUpperCase()} terminal (default)`);
412425
}
413426

414427
logger.log(`Executing general terminal command: ${cleanCommand} in ${cwd} (routing to ${terminalType} terminal) - isPython: ${isPythonCommand}, isNode: ${isNodeCommand}`);

0 commit comments

Comments
 (0)