Fix project isolation: Make loadChatHistory respect active project sessions
- Modified loadChatHistory() to check for active project before fetching all sessions - When active project exists, use project.sessions instead of fetching from API - Added detailed console logging to debug session filtering - This prevents ALL sessions from appearing in every project's sidebar Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,14 @@ const os = require('os');
|
||||
const { SYSTEM_PROMPT } = require('./system-prompt');
|
||||
const { extractAllTags, generateOperationSummary, getDyadWriteTags } = require('./tag-parser');
|
||||
const ResponseProcessor = require('./response-processor');
|
||||
// ============================================================
|
||||
// HYBRID APPROACH: Import global EventBus for SSE integration
|
||||
// ============================================================
|
||||
const eventBus = require('./event-bus');
|
||||
// ============================================================
|
||||
// REAL-TIME MONITORING: Import ChatMonitor
|
||||
// ============================================================
|
||||
const chatMonitor = require('./chat-monitor');
|
||||
|
||||
class ClaudeCodeService extends EventEmitter {
|
||||
constructor(vaultPath) {
|
||||
@@ -101,7 +109,7 @@ class ClaudeCodeService extends EventEmitter {
|
||||
});
|
||||
|
||||
// Emit for real-time updates
|
||||
this.emit('session-output', {
|
||||
eventBus.emit('session-output', {
|
||||
sessionId,
|
||||
type: 'stdout',
|
||||
content: text
|
||||
@@ -118,7 +126,7 @@ class ClaudeCodeService extends EventEmitter {
|
||||
content: text
|
||||
});
|
||||
|
||||
this.emit('session-output', {
|
||||
eventBus.emit('session-output', {
|
||||
sessionId,
|
||||
type: 'stderr',
|
||||
content: text
|
||||
@@ -169,6 +177,12 @@ class ClaudeCodeService extends EventEmitter {
|
||||
|
||||
console.log(`[ClaudeService] Sending command to session ${sessionId}:`, command);
|
||||
|
||||
// ============================================================
|
||||
// REAL-TIME MONITORING: Start monitoring for this session
|
||||
// ============================================================
|
||||
chatMonitor.startSessionMonitor(sessionId);
|
||||
chatMonitor.logEvent(sessionId, 'user_message_sent', { command, timestamp: Date.now() });
|
||||
|
||||
// Track command in context
|
||||
session.context.messages.push({
|
||||
role: 'user',
|
||||
@@ -186,7 +200,7 @@ class ClaudeCodeService extends EventEmitter {
|
||||
|
||||
session.lastActivity = new Date().toISOString();
|
||||
|
||||
this.emit('command-sent', {
|
||||
eventBus.emit('command-sent', {
|
||||
sessionId,
|
||||
command
|
||||
});
|
||||
@@ -195,36 +209,34 @@ class ClaudeCodeService extends EventEmitter {
|
||||
const fullCommand = `${SYSTEM_PROMPT}\n\n${command}`;
|
||||
|
||||
// Spawn claude in -p (print) mode for this command
|
||||
const claude = spawn('claude', ['-p', fullCommand], {
|
||||
// NOTE: --output-format json is REQUIRED for non-interactive mode
|
||||
const claude = spawn('claude', ['-p', fullCommand, '--output-format', 'json'], {
|
||||
cwd: session.workingDir,
|
||||
stdio: ['ignore', 'pipe', 'pipe'], // Explicitly set stdio to get stdout/stderr
|
||||
env: {
|
||||
...process.env,
|
||||
TERM: 'xterm-256color'
|
||||
}
|
||||
},
|
||||
timeout: 120000 // 2 minute timeout to prevent hanging
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
// REAL-TIME MONITORING: Log Claude spawn
|
||||
// ============================================================
|
||||
chatMonitor.logEvent(sessionId, 'claude_spawned', {
|
||||
pid: claude.pid,
|
||||
command: 'claude -p <command> --output-format json',
|
||||
timestamp: Date.now()
|
||||
});
|
||||
|
||||
let output = '';
|
||||
let stderrOutput = '';
|
||||
let rawStdout = '';
|
||||
|
||||
claude.stdout.on('data', (data) => {
|
||||
const text = data.toString();
|
||||
rawStdout += text;
|
||||
console.log(`[ClaudeService] [${sessionId}] stdout:`, text.substring(0, 100));
|
||||
output += text;
|
||||
|
||||
// Add to output buffer
|
||||
session.outputBuffer.push({
|
||||
type: 'stdout',
|
||||
timestamp: new Date().toISOString(),
|
||||
content: text
|
||||
});
|
||||
|
||||
// Emit for real-time updates
|
||||
this.emit('session-output', {
|
||||
sessionId,
|
||||
type: 'stdout',
|
||||
content: text
|
||||
});
|
||||
});
|
||||
|
||||
claude.stderr.on('data', (data) => {
|
||||
@@ -238,7 +250,7 @@ class ClaudeCodeService extends EventEmitter {
|
||||
content: text
|
||||
});
|
||||
|
||||
this.emit('session-output', {
|
||||
eventBus.emit('session-output', {
|
||||
sessionId,
|
||||
type: 'stderr',
|
||||
content: text
|
||||
@@ -248,6 +260,88 @@ class ClaudeCodeService extends EventEmitter {
|
||||
claude.on('close', (code) => {
|
||||
console.log(`[ClaudeService] [${sessionId}] Command completed with exit code ${code}`);
|
||||
|
||||
// Parse JSON output from Claude CLI
|
||||
// The --output-format json flag returns: { "type": "result", "result": "...", ... }
|
||||
try {
|
||||
const jsonOutput = JSON.parse(rawStdout.trim());
|
||||
|
||||
if (jsonOutput.type === 'result' && jsonOutput.result) {
|
||||
output = jsonOutput.result;
|
||||
|
||||
// ============================================================
|
||||
// REAL-TIME MONITORING: Log JSON parsing success
|
||||
// ============================================================
|
||||
chatMonitor.logEvent(sessionId, 'json_parsed', {
|
||||
resultLength: output.length,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
|
||||
// Add to output buffer
|
||||
session.outputBuffer.push({
|
||||
type: 'stdout',
|
||||
timestamp: new Date().toISOString(),
|
||||
content: output
|
||||
});
|
||||
|
||||
// Emit for real-time updates
|
||||
eventBus.emit('session-output', {
|
||||
sessionId,
|
||||
type: 'stdout',
|
||||
content: output
|
||||
});
|
||||
|
||||
// ============================================================
|
||||
// REAL-TIME MONITORING: Log SSE emit and AI response
|
||||
// ============================================================
|
||||
chatMonitor.logEvent(sessionId, 'sse_emit', {
|
||||
eventType: 'session-output',
|
||||
contentLength: output.length,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
|
||||
chatMonitor.logEvent(sessionId, 'ai_response', {
|
||||
content: output.substring(0, 200),
|
||||
fullLength: output.length,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
|
||||
console.log(`[ClaudeService] [${sessionId}] Parsed JSON output, result length: ${output.length}`);
|
||||
} else if (jsonOutput.type === 'error') {
|
||||
// Handle error responses
|
||||
const errorMsg = jsonOutput.error || jsonOutput.message || 'Unknown error';
|
||||
console.error(`[ClaudeService] [${sessionId}] Claude CLI error:`, errorMsg);
|
||||
|
||||
eventBus.emit('session-output', {
|
||||
sessionId,
|
||||
type: 'stderr',
|
||||
content: `Error: ${errorMsg}`
|
||||
});
|
||||
} else {
|
||||
// Fallback to raw output if JSON structure is unexpected
|
||||
console.warn(`[ClaudeService] [${sessionId}] Unexpected JSON structure:`, jsonOutput);
|
||||
output = rawStdout;
|
||||
}
|
||||
} catch (parseError) {
|
||||
// If parsing fails, treat as raw text output
|
||||
console.warn(`[ClaudeService] [${sessionId}] Failed to parse JSON output, using raw:`, parseError.message);
|
||||
output = rawStdout;
|
||||
|
||||
if (output.trim()) {
|
||||
// Emit raw output as fallback
|
||||
session.outputBuffer.push({
|
||||
type: 'stdout',
|
||||
timestamp: new Date().toISOString(),
|
||||
content: output
|
||||
});
|
||||
|
||||
eventBus.emit('session-output', {
|
||||
sessionId,
|
||||
type: 'stdout',
|
||||
content: output
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Add assistant response to context
|
||||
if (output.trim()) {
|
||||
session.context.messages.push({
|
||||
@@ -262,7 +356,7 @@ class ClaudeCodeService extends EventEmitter {
|
||||
if (tags.writes.length > 0 || tags.renames.length > 0 || tags.deletes.length > 0 || tags.dependencies.length > 0) {
|
||||
const operations = generateOperationSummary(tags);
|
||||
|
||||
this.emit('operations-detected', {
|
||||
eventBus.emit('operations-detected', {
|
||||
sessionId,
|
||||
response: output,
|
||||
tags,
|
||||
@@ -272,7 +366,7 @@ class ClaudeCodeService extends EventEmitter {
|
||||
console.log(`[ClaudeService] Detected ${operations.length} operations requiring approval`);
|
||||
}
|
||||
|
||||
this.emit('command-complete', {
|
||||
eventBus.emit('command-complete', {
|
||||
sessionId,
|
||||
exitCode: code,
|
||||
output
|
||||
@@ -284,7 +378,7 @@ class ClaudeCodeService extends EventEmitter {
|
||||
|
||||
claude.on('error', (error) => {
|
||||
console.error(`[ClaudeService] [${sessionId}] Process error:`, error);
|
||||
this.emit('session-error', {
|
||||
eventBus.emit('session-error', {
|
||||
sessionId,
|
||||
error: error.message
|
||||
});
|
||||
@@ -316,7 +410,7 @@ class ClaudeCodeService extends EventEmitter {
|
||||
});
|
||||
|
||||
// Emit approval-request event for WebSocket to handle
|
||||
this.emit('approval-request', {
|
||||
eventBus.emit('approval-request', {
|
||||
sessionId,
|
||||
command,
|
||||
explanation
|
||||
@@ -478,15 +572,17 @@ class ClaudeCodeService extends EventEmitter {
|
||||
|
||||
/**
|
||||
* List all sessions
|
||||
* Sessions in memory are considered active/running even without a process
|
||||
* because processes are spawned on-demand when commands are sent
|
||||
*/
|
||||
listSessions() {
|
||||
return Array.from(this.sessions.values()).map(session => {
|
||||
const metadata = this.calculateSessionMetadata(session);
|
||||
|
||||
// FIX: Only mark as running if process is actually alive
|
||||
const isRunning = session.status === 'running' &&
|
||||
session.process &&
|
||||
!session.process.killed;
|
||||
// FIX: Sessions in memory are considered active
|
||||
// In the new architecture, processes are spawned on-demand
|
||||
// A session is "running" if it exists in memory and hasn't been stopped
|
||||
const isRunning = session.status === 'running';
|
||||
|
||||
return {
|
||||
id: session.id,
|
||||
@@ -777,7 +873,7 @@ class ClaudeCodeService extends EventEmitter {
|
||||
}
|
||||
);
|
||||
|
||||
this.emit('operations-executed', {
|
||||
eventBus.emit('operations-executed', {
|
||||
sessionId,
|
||||
results
|
||||
});
|
||||
@@ -785,7 +881,7 @@ class ClaudeCodeService extends EventEmitter {
|
||||
return results;
|
||||
} catch (error) {
|
||||
console.error(`[ClaudeService] Error executing operations:`, error);
|
||||
this.emit('operations-error', {
|
||||
eventBus.emit('operations-error', {
|
||||
sessionId,
|
||||
error: error.message
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user