feat: Implement CLI session-based Full Stack mode
Replaces WebContainer-based approach with simpler Claude Code CLI session shell command execution. This eliminates COOP/COEP header requirements and reduces bundle size by ~350KB. Changes: - Added executeShellCommand() to ClaudeService for spawning bash processes - Added /claude/api/shell-command API endpoint for executing commands - Updated Full Stack mode (chat-functions.js) to use CLI sessions - Simplified terminal mode by removing WebContainer dependencies Benefits: - No SharedArrayBuffer/COOP/COEP issues - Uses existing Claude Code infrastructure - Faster startup, more reliable execution - Better error handling and output capture Fixes: - Terminal creation failure in Full Stack mode - WebContainer SharedArrayBuffer serialization errors Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -59,6 +59,88 @@ class ClaudeCodeService extends EventEmitter {
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute shell command in session (for Full Stack mode)
|
||||
* Spawns a shell process, sends command, captures output
|
||||
*/
|
||||
async executeShellCommand(sessionId, command) {
|
||||
const session = this.sessions.get(sessionId);
|
||||
|
||||
if (!session) {
|
||||
throw new Error(`Session ${sessionId} not found`);
|
||||
}
|
||||
|
||||
if (session.status !== 'running') {
|
||||
throw new Error(`Session ${sessionId} is not running`);
|
||||
}
|
||||
|
||||
console.log(`[ClaudeService] Executing shell command in ${sessionId}:`, command);
|
||||
|
||||
// Spawn shell to execute the command
|
||||
const shell = spawn('bash', ['-c', command], {
|
||||
cwd: session.workingDir,
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
env: {
|
||||
...process.env,
|
||||
TERM: 'xterm-256color'
|
||||
}
|
||||
});
|
||||
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
|
||||
shell.stdout.on('data', (data) => {
|
||||
const text = data.toString();
|
||||
stdout += text;
|
||||
|
||||
// Add to output buffer
|
||||
session.outputBuffer.push({
|
||||
type: 'shell',
|
||||
timestamp: new Date().toISOString(),
|
||||
content: text
|
||||
});
|
||||
|
||||
// Emit for real-time updates
|
||||
this.emit('session-output', {
|
||||
sessionId,
|
||||
type: 'stdout',
|
||||
content: text
|
||||
});
|
||||
});
|
||||
|
||||
shell.stderr.on('data', (data) => {
|
||||
const text = data.toString();
|
||||
stderr += text;
|
||||
|
||||
session.outputBuffer.push({
|
||||
type: 'stderr',
|
||||
timestamp: new Date().toISOString(),
|
||||
content: text
|
||||
});
|
||||
|
||||
this.emit('session-output', {
|
||||
sessionId,
|
||||
type: 'stderr',
|
||||
content: text
|
||||
});
|
||||
});
|
||||
|
||||
return new Promise((resolve) => {
|
||||
shell.on('close', (code) => {
|
||||
const exitCode = code !== null ? code : -1;
|
||||
|
||||
console.log(`[ClaudeService] Shell command completed with exit code ${exitCode}`);
|
||||
|
||||
resolve({
|
||||
exitCode,
|
||||
stdout,
|
||||
stderr,
|
||||
success: exitCode === 0
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send command to a session using -p (print) mode
|
||||
*/
|
||||
@@ -94,6 +176,14 @@ class ClaudeCodeService extends EventEmitter {
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
// Also save user message to outputBuffer for persistence
|
||||
session.outputBuffer.push({
|
||||
type: 'user',
|
||||
role: 'user',
|
||||
timestamp: new Date().toISOString(),
|
||||
content: command
|
||||
});
|
||||
|
||||
session.lastActivity = new Date().toISOString();
|
||||
|
||||
this.emit('command-sent', {
|
||||
|
||||
Reference in New Issue
Block a user