fix: robust agent-to-tab connection lines with persistent parent tracking

- Add --session-id flag to Claude CLI startup so Claudeman and Claude share the same session ID
- Set claudeSessionId immediately on session start (no waiting for JSON messages)
- Add persistent subagentParentMap to store agent-to-tab associations permanently
- Add /api/subagent-parents endpoints for server-side persistence
- Add fallback: use active session when claudeSessionId matching fails
- Connection lines now reliably connect agent windows to their parent tabs
- Survives page refresh, reconnect, and server restart

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
arkon
2026-01-29 14:56:11 +01:00
co-authored by Claude Opus 4.5
parent 28f37d9d7c
commit b13b725bd8
6 changed files with 424 additions and 122 deletions
+18 -3
View File
@@ -823,6 +823,10 @@ export class Session extends EventEmitter {
cwd: this.workingDir,
env: { ...process.env, TERM: 'xterm-256color' },
});
// Set claudeSessionId immediately since we passed --session-id to Claude
// The screen-manager passes --session-id ${sessionId} to Claude
this._claudeSessionId = this.id;
} catch (spawnErr) {
console.error('[Session] Failed to spawn PTY for screen attachment:', spawnErr);
this.emit('error', `Failed to attach to screen: ${spawnErr}`);
@@ -873,8 +877,11 @@ export class Session extends EventEmitter {
// Fallback to direct PTY if screen is not used
if (!this.ptyProcess) {
try {
// Pass --session-id to use the SAME ID as the Claudeman session
// This ensures subagents can be directly matched to the correct tab
this.ptyProcess = pty.spawn('claude', [
'--dangerously-skip-permissions'
'--dangerously-skip-permissions',
'--session-id', this.id
], {
name: 'xterm-256color',
cols: 120,
@@ -898,6 +905,10 @@ export class Session extends EventEmitter {
}
}
// Set the claudeSessionId immediately since we passed --session-id
// This ensures subagent matching works without waiting for JSON messages
this._claudeSessionId = this.id;
this._pid = this.ptyProcess.pid;
console.log('[Session] Interactive PTY spawned with PID:', this._pid);
@@ -1358,8 +1369,12 @@ export class Session extends EventEmitter {
this._messages = this._messages.slice(-Math.floor(MAX_MESSAGES * 0.8));
}
if (msg.type === 'system' && msg.session_id) {
this._claudeSessionId = msg.session_id;
// Extract Claude session ID from messages (can be in any message type)
// Support both sessionId (camelCase) and session_id (snake_case)
const msgSessionId = (msg as unknown as Record<string, unknown>).sessionId as string | undefined
?? msg.session_id;
if (msgSessionId && !this._claudeSessionId) {
this._claudeSessionId = msgSessionId;
}
// Process message for task tracking