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:
uroma
2026-01-20 16:08:56 +00:00
Unverified
parent 6894c8bed4
commit 9b9ff5456d
3 changed files with 748 additions and 53 deletions

View File

@@ -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', {