@cluesmith/codev 2.0.0-rc.72 → 2.0.0-rc.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dashboard/dist/assets/{index-C7FtNK6Y.css → index-4n9zpWLY.css} +1 -1
  2. package/dashboard/dist/assets/{index-CDAINZKT.js → index-CH_utkcW.js} +32 -27
  3. package/dashboard/dist/assets/index-CH_utkcW.js.map +1 -0
  4. package/dashboard/dist/index.html +2 -2
  5. package/dist/agent-farm/commands/spawn-roles.d.ts +80 -0
  6. package/dist/agent-farm/commands/spawn-roles.d.ts.map +1 -0
  7. package/dist/agent-farm/commands/spawn-roles.js +278 -0
  8. package/dist/agent-farm/commands/spawn-roles.js.map +1 -0
  9. package/dist/agent-farm/commands/spawn-worktree.d.ts +96 -0
  10. package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -0
  11. package/dist/agent-farm/commands/spawn-worktree.js +305 -0
  12. package/dist/agent-farm/commands/spawn-worktree.js.map +1 -0
  13. package/dist/agent-farm/commands/spawn.d.ts +5 -1
  14. package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
  15. package/dist/agent-farm/commands/spawn.js +65 -725
  16. package/dist/agent-farm/commands/spawn.js.map +1 -1
  17. package/dist/agent-farm/servers/tower-instances.d.ts +82 -0
  18. package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -0
  19. package/dist/agent-farm/servers/tower-instances.js +441 -0
  20. package/dist/agent-farm/servers/tower-instances.js.map +1 -0
  21. package/dist/agent-farm/servers/tower-routes.d.ts +34 -0
  22. package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -0
  23. package/dist/agent-farm/servers/tower-routes.js +1445 -0
  24. package/dist/agent-farm/servers/tower-routes.js.map +1 -0
  25. package/dist/agent-farm/servers/tower-server.d.ts +5 -2
  26. package/dist/agent-farm/servers/tower-server.d.ts.map +1 -1
  27. package/dist/agent-farm/servers/tower-server.js +74 -2860
  28. package/dist/agent-farm/servers/tower-server.js.map +1 -1
  29. package/dist/agent-farm/servers/tower-terminals.d.ts +119 -0
  30. package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -0
  31. package/dist/agent-farm/servers/tower-terminals.js +629 -0
  32. package/dist/agent-farm/servers/tower-terminals.js.map +1 -0
  33. package/dist/agent-farm/servers/tower-tunnel.d.ts +34 -0
  34. package/dist/agent-farm/servers/tower-tunnel.d.ts.map +1 -0
  35. package/dist/agent-farm/servers/tower-tunnel.js +299 -0
  36. package/dist/agent-farm/servers/tower-tunnel.js.map +1 -0
  37. package/dist/agent-farm/servers/tower-types.d.ts +85 -0
  38. package/dist/agent-farm/servers/tower-types.d.ts.map +1 -0
  39. package/dist/agent-farm/servers/tower-types.js +6 -0
  40. package/dist/agent-farm/servers/tower-types.js.map +1 -0
  41. package/dist/agent-farm/servers/tower-utils.d.ts +51 -0
  42. package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -0
  43. package/dist/agent-farm/servers/tower-utils.js +161 -0
  44. package/dist/agent-farm/servers/tower-utils.js.map +1 -0
  45. package/dist/agent-farm/servers/tower-websocket.d.ts +25 -0
  46. package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -0
  47. package/dist/agent-farm/servers/tower-websocket.js +171 -0
  48. package/dist/agent-farm/servers/tower-websocket.js.map +1 -0
  49. package/package.json +1 -1
  50. package/dashboard/dist/assets/index-CDAINZKT.js.map +0 -1
@@ -0,0 +1,629 @@
1
+ /**
2
+ * Terminal state management for tower server.
3
+ * Spec 0105: Tower Server Decomposition — Phase 4
4
+ *
5
+ * Contains: terminal session CRUD, file tab persistence, shell ID allocation,
6
+ * terminal reconciliation, gate watcher, and terminal list assembly.
7
+ */
8
+ import fs from 'node:fs';
9
+ import path from 'node:path';
10
+ import { homedir } from 'node:os';
11
+ import { getGlobalDb } from '../db/index.js';
12
+ import { getGateStatusForProject } from '../utils/gate-status.js';
13
+ import { GateWatcher } from '../utils/gate-watcher.js';
14
+ import { saveFileTab as saveFileTabToDb, deleteFileTab as deleteFileTabFromDb, loadFileTabsForProject as loadFileTabsFromDb, } from '../utils/file-tabs.js';
15
+ import { TerminalManager } from '../../terminal/pty-manager.js';
16
+ import { normalizeProjectPath } from './tower-utils.js';
17
+ // ============================================================================
18
+ // Module-private state (lifecycle driven by orchestrator)
19
+ // ============================================================================
20
+ let _deps = null;
21
+ /** Project terminal registry — tracks which terminals belong to which project */
22
+ const projectTerminals = new Map();
23
+ /** Global TerminalManager instance (lazy singleton) */
24
+ let terminalManager = null;
25
+ /** Gate watcher state */
26
+ const gateWatcher = new GateWatcher((...args) => {
27
+ if (_deps)
28
+ _deps.log(...args);
29
+ });
30
+ let gateWatcherInterval = null;
31
+ // ============================================================================
32
+ // Lifecycle
33
+ // ============================================================================
34
+ /** Initialize the terminal module with external dependencies */
35
+ export function initTerminals(deps) {
36
+ _deps = deps;
37
+ }
38
+ /** Tear down the terminal module */
39
+ export function shutdownTerminals() {
40
+ if (gateWatcherInterval) {
41
+ clearInterval(gateWatcherInterval);
42
+ gateWatcherInterval = null;
43
+ }
44
+ if (terminalManager) {
45
+ terminalManager.shutdown();
46
+ terminalManager = null;
47
+ }
48
+ _deps = null;
49
+ }
50
+ // ============================================================================
51
+ // Accessors for shared state
52
+ // ============================================================================
53
+ /** Get the project terminals registry (returns the Map reference) */
54
+ export function getProjectTerminals() {
55
+ return projectTerminals;
56
+ }
57
+ /**
58
+ * Get or create the global TerminalManager instance.
59
+ * Uses a temporary directory as projectRoot since terminals can be for any project.
60
+ */
61
+ export function getTerminalManager() {
62
+ if (!terminalManager) {
63
+ const projectRoot = process.env.HOME || '/tmp';
64
+ terminalManager = new TerminalManager({
65
+ projectRoot,
66
+ logDir: path.join(homedir(), '.agent-farm', 'logs'),
67
+ maxSessions: 100,
68
+ ringBufferLines: 10000,
69
+ diskLogEnabled: true,
70
+ diskLogMaxBytes: 50 * 1024 * 1024,
71
+ reconnectTimeoutMs: 300_000,
72
+ });
73
+ }
74
+ return terminalManager;
75
+ }
76
+ // ============================================================================
77
+ // Terminal session CRUD
78
+ // ============================================================================
79
+ /**
80
+ * Get or create project terminal registry entry.
81
+ * On first access for a project, hydrates file tabs from SQLite so
82
+ * persisted tabs are available immediately (not just after /api/state).
83
+ */
84
+ export function getProjectTerminalsEntry(projectPath) {
85
+ let entry = projectTerminals.get(projectPath);
86
+ if (!entry) {
87
+ entry = { builders: new Map(), shells: new Map(), fileTabs: loadFileTabsForProject(projectPath) };
88
+ projectTerminals.set(projectPath, entry);
89
+ }
90
+ // Migration: ensure fileTabs exists for older entries
91
+ if (!entry.fileTabs) {
92
+ entry.fileTabs = new Map();
93
+ }
94
+ return entry;
95
+ }
96
+ /**
97
+ * Generate next shell ID for a project
98
+ */
99
+ export function getNextShellId(projectPath) {
100
+ const entry = getProjectTerminalsEntry(projectPath);
101
+ let maxId = 0;
102
+ for (const id of entry.shells.keys()) {
103
+ const num = parseInt(id.replace('shell-', ''), 10);
104
+ if (!isNaN(num) && num > maxId)
105
+ maxId = num;
106
+ }
107
+ return `shell-${maxId + 1}`;
108
+ }
109
+ /**
110
+ * Save a terminal session to SQLite.
111
+ * Guards against race conditions by checking if project is still active.
112
+ */
113
+ export function saveTerminalSession(terminalId, projectPath, type, roleId, pid, shepherdSocket = null, shepherdPid = null, shepherdStartTime = null) {
114
+ try {
115
+ const normalizedPath = normalizeProjectPath(projectPath);
116
+ // Race condition guard: only save if project is still in the active registry
117
+ // This prevents zombie rows when stop races with session creation
118
+ if (!projectTerminals.has(normalizedPath) && !projectTerminals.has(projectPath)) {
119
+ _deps?.log('INFO', `Skipping session save - project no longer active: ${projectPath}`);
120
+ return;
121
+ }
122
+ const db = getGlobalDb();
123
+ db.prepare(`
124
+ INSERT OR REPLACE INTO terminal_sessions (id, project_path, type, role_id, pid, shepherd_socket, shepherd_pid, shepherd_start_time)
125
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
126
+ `).run(terminalId, normalizedPath, type, roleId, pid, shepherdSocket, shepherdPid, shepherdStartTime);
127
+ _deps?.log('INFO', `Saved terminal session to SQLite: ${terminalId} (${type}) for ${path.basename(normalizedPath)}`);
128
+ }
129
+ catch (err) {
130
+ _deps?.log('WARN', `Failed to save terminal session: ${err.message}`);
131
+ }
132
+ }
133
+ /**
134
+ * Check if a terminal session is persistent (shepherd-backed).
135
+ * A session is persistent if it can survive a Tower restart.
136
+ */
137
+ export function isSessionPersistent(_terminalId, session) {
138
+ return session.shepherdBacked;
139
+ }
140
+ /**
141
+ * Delete a terminal session from SQLite
142
+ */
143
+ export function deleteTerminalSession(terminalId) {
144
+ try {
145
+ const db = getGlobalDb();
146
+ db.prepare('DELETE FROM terminal_sessions WHERE id = ?').run(terminalId);
147
+ }
148
+ catch (err) {
149
+ _deps?.log('WARN', `Failed to delete terminal session: ${err.message}`);
150
+ }
151
+ }
152
+ /**
153
+ * Delete all terminal sessions for a project from SQLite.
154
+ * Normalizes path to ensure consistent cleanup regardless of how path was provided.
155
+ */
156
+ export function deleteProjectTerminalSessions(projectPath) {
157
+ try {
158
+ const normalizedPath = normalizeProjectPath(projectPath);
159
+ const db = getGlobalDb();
160
+ // Delete both normalized and raw path to handle any inconsistencies
161
+ db.prepare('DELETE FROM terminal_sessions WHERE project_path = ?').run(normalizedPath);
162
+ if (normalizedPath !== projectPath) {
163
+ db.prepare('DELETE FROM terminal_sessions WHERE project_path = ?').run(projectPath);
164
+ }
165
+ }
166
+ catch (err) {
167
+ _deps?.log('WARN', `Failed to delete project terminal sessions: ${err.message}`);
168
+ }
169
+ }
170
+ /**
171
+ * Get terminal sessions from SQLite for a project.
172
+ * Normalizes path for consistent lookup.
173
+ */
174
+ export function getTerminalSessionsForProject(projectPath) {
175
+ try {
176
+ const normalizedPath = normalizeProjectPath(projectPath);
177
+ const db = getGlobalDb();
178
+ return db.prepare('SELECT * FROM terminal_sessions WHERE project_path = ?').all(normalizedPath);
179
+ }
180
+ catch {
181
+ return [];
182
+ }
183
+ }
184
+ // ============================================================================
185
+ // File tab persistence
186
+ // ============================================================================
187
+ /**
188
+ * Save a file tab to SQLite for persistence across Tower restarts.
189
+ * Thin wrapper around utils/file-tabs.ts with error handling and path normalization.
190
+ */
191
+ export function saveFileTab(id, projectPath, filePath, createdAt) {
192
+ try {
193
+ const normalizedPath = normalizeProjectPath(projectPath);
194
+ saveFileTabToDb(getGlobalDb(), id, normalizedPath, filePath, createdAt);
195
+ }
196
+ catch (err) {
197
+ _deps?.log('WARN', `Failed to save file tab: ${err.message}`);
198
+ }
199
+ }
200
+ /**
201
+ * Delete a file tab from SQLite.
202
+ * Thin wrapper around utils/file-tabs.ts with error handling.
203
+ */
204
+ export function deleteFileTab(id) {
205
+ try {
206
+ deleteFileTabFromDb(getGlobalDb(), id);
207
+ }
208
+ catch (err) {
209
+ _deps?.log('WARN', `Failed to delete file tab: ${err.message}`);
210
+ }
211
+ }
212
+ /**
213
+ * Load file tabs for a project from SQLite.
214
+ * Thin wrapper around utils/file-tabs.ts with error handling and path normalization.
215
+ */
216
+ export function loadFileTabsForProject(projectPath) {
217
+ try {
218
+ const normalizedPath = normalizeProjectPath(projectPath);
219
+ return loadFileTabsFromDb(getGlobalDb(), normalizedPath);
220
+ }
221
+ catch (err) {
222
+ _deps?.log('WARN', `Failed to load file tabs: ${err.message}`);
223
+ }
224
+ return new Map();
225
+ }
226
+ // ============================================================================
227
+ // Process utilities
228
+ // ============================================================================
229
+ /**
230
+ * Check if a process is running
231
+ */
232
+ export function processExists(pid) {
233
+ try {
234
+ process.kill(pid, 0);
235
+ return true;
236
+ }
237
+ catch {
238
+ return false;
239
+ }
240
+ }
241
+ // ============================================================================
242
+ // Terminal reconciliation
243
+ // ============================================================================
244
+ /**
245
+ * Reconcile terminal sessions on startup.
246
+ *
247
+ * DUAL-SOURCE STRATEGY (shepherd + SQLite):
248
+ *
249
+ * Phase 1 — Shepherd reconnection:
250
+ * For SQLite rows with shepherd_socket IS NOT NULL, attempt to reconnect
251
+ * via SessionManager.reconnectSession(). Shepherd processes survive Tower
252
+ * restarts as detached OS processes.
253
+ *
254
+ * Phase 2 — SQLite sweep:
255
+ * Any rows not matched in Phase 1 are stale → clean up.
256
+ *
257
+ * File tabs are the exception: they have no backing process, so SQLite is
258
+ * the sole source of truth for their persistence (see file_tabs table).
259
+ */
260
+ export async function reconcileTerminalSessions() {
261
+ if (!_deps)
262
+ return;
263
+ const manager = getTerminalManager();
264
+ const db = getGlobalDb();
265
+ let shepherdReconnected = 0;
266
+ let orphanReconnected = 0;
267
+ let killed = 0;
268
+ let cleaned = 0;
269
+ // Track matched session IDs across all phases
270
+ const matchedSessionIds = new Set();
271
+ // ---- Phase 1: Shepherd reconnection ----
272
+ let allDbSessions;
273
+ try {
274
+ allDbSessions = db.prepare('SELECT * FROM terminal_sessions').all();
275
+ }
276
+ catch (err) {
277
+ _deps.log('WARN', `Failed to read terminal sessions: ${err.message}`);
278
+ allDbSessions = [];
279
+ }
280
+ const shepherdSessions = allDbSessions.filter(s => s.shepherd_socket !== null);
281
+ if (shepherdSessions.length > 0) {
282
+ _deps.log('INFO', `Found ${shepherdSessions.length} shepherd session(s) in SQLite — reconnecting...`);
283
+ }
284
+ for (const dbSession of shepherdSessions) {
285
+ const projectPath = dbSession.project_path;
286
+ // Skip sessions whose project path doesn't exist or is in temp directory
287
+ if (!fs.existsSync(projectPath)) {
288
+ _deps.log('INFO', `Skipping shepherd session ${dbSession.id} — project path no longer exists: ${projectPath}`);
289
+ // Kill orphaned shepherd process before removing row
290
+ if (dbSession.shepherd_pid && processExists(dbSession.shepherd_pid)) {
291
+ try {
292
+ process.kill(dbSession.shepherd_pid, 'SIGTERM');
293
+ killed++;
294
+ }
295
+ catch { /* not killable */ }
296
+ }
297
+ db.prepare('DELETE FROM terminal_sessions WHERE id = ?').run(dbSession.id);
298
+ cleaned++;
299
+ continue;
300
+ }
301
+ const tmpDirs = ['/tmp', '/private/tmp', '/var/folders', '/private/var/folders'];
302
+ if (tmpDirs.some(d => projectPath === d || projectPath.startsWith(d + '/'))) {
303
+ _deps.log('INFO', `Skipping shepherd session ${dbSession.id} — project is in temp directory: ${projectPath}`);
304
+ // Kill orphaned shepherd process before removing row
305
+ if (dbSession.shepherd_pid && processExists(dbSession.shepherd_pid)) {
306
+ try {
307
+ process.kill(dbSession.shepherd_pid, 'SIGTERM');
308
+ killed++;
309
+ }
310
+ catch { /* not killable */ }
311
+ }
312
+ db.prepare('DELETE FROM terminal_sessions WHERE id = ?').run(dbSession.id);
313
+ cleaned++;
314
+ continue;
315
+ }
316
+ if (!_deps.shepherdManager) {
317
+ _deps.log('WARN', `Shepherd manager not initialized — cannot reconnect ${dbSession.id}`);
318
+ continue;
319
+ }
320
+ try {
321
+ // For architect sessions, restore auto-restart behavior after reconnection
322
+ let restartOptions;
323
+ if (dbSession.type === 'architect') {
324
+ let architectCmd = 'claude';
325
+ const configPath = path.join(projectPath, 'af-config.json');
326
+ if (fs.existsSync(configPath)) {
327
+ try {
328
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
329
+ if (config.shell?.architect) {
330
+ architectCmd = config.shell.architect;
331
+ }
332
+ }
333
+ catch { /* use default */ }
334
+ }
335
+ const cmdParts = architectCmd.split(/\s+/);
336
+ const cleanEnv = { ...process.env };
337
+ delete cleanEnv['CLAUDECODE'];
338
+ restartOptions = {
339
+ command: cmdParts[0],
340
+ args: cmdParts.slice(1),
341
+ cwd: projectPath,
342
+ env: cleanEnv,
343
+ restartDelay: 2000,
344
+ maxRestarts: 50,
345
+ };
346
+ }
347
+ const client = await _deps.shepherdManager.reconnectSession(dbSession.id, dbSession.shepherd_socket, dbSession.shepherd_pid, dbSession.shepherd_start_time, restartOptions);
348
+ if (!client) {
349
+ _deps.log('INFO', `Shepherd session ${dbSession.id} is stale (PID/socket dead) — will clean up`);
350
+ continue; // Will be cleaned up in Phase 2
351
+ }
352
+ const replayData = client.getReplayData() ?? Buffer.alloc(0);
353
+ const label = dbSession.type === 'architect' ? 'Architect' : `${dbSession.type} ${dbSession.role_id || 'unknown'}`;
354
+ // Create a PtySession backed by the reconnected shepherd client
355
+ const session = manager.createSessionRaw({ label, cwd: projectPath });
356
+ const ptySession = manager.getSession(session.id);
357
+ if (ptySession) {
358
+ ptySession.attachShepherd(client, replayData, dbSession.shepherd_pid, dbSession.id);
359
+ }
360
+ // Register in projectTerminals Map
361
+ const entry = getProjectTerminalsEntry(projectPath);
362
+ if (dbSession.type === 'architect') {
363
+ entry.architect = session.id;
364
+ }
365
+ else if (dbSession.type === 'builder') {
366
+ entry.builders.set(dbSession.role_id || dbSession.id, session.id);
367
+ }
368
+ else if (dbSession.type === 'shell') {
369
+ entry.shells.set(dbSession.role_id || dbSession.id, session.id);
370
+ }
371
+ // Update SQLite with new terminal ID
372
+ db.prepare('DELETE FROM terminal_sessions WHERE id = ?').run(dbSession.id);
373
+ saveTerminalSession(session.id, projectPath, dbSession.type, dbSession.role_id, dbSession.shepherd_pid, dbSession.shepherd_socket, dbSession.shepherd_pid, dbSession.shepherd_start_time);
374
+ _deps.registerKnownProject(projectPath);
375
+ // Clean up on exit
376
+ if (ptySession) {
377
+ ptySession.on('exit', () => {
378
+ const currentEntry = getProjectTerminalsEntry(projectPath);
379
+ if (dbSession.type === 'architect' && currentEntry.architect === session.id) {
380
+ currentEntry.architect = undefined;
381
+ }
382
+ deleteTerminalSession(session.id);
383
+ });
384
+ }
385
+ matchedSessionIds.add(dbSession.id);
386
+ shepherdReconnected++;
387
+ _deps.log('INFO', `Reconnected shepherd session → ${session.id} (${dbSession.type} for ${path.basename(projectPath)})`);
388
+ }
389
+ catch (err) {
390
+ _deps.log('WARN', `Failed to reconnect shepherd session ${dbSession.id}: ${err.message}`);
391
+ }
392
+ }
393
+ // ---- Phase 2: Sweep stale SQLite rows ----
394
+ for (const session of allDbSessions) {
395
+ if (matchedSessionIds.has(session.id))
396
+ continue;
397
+ const existing = manager.getSession(session.id);
398
+ if (existing && existing.status !== 'exited')
399
+ continue;
400
+ // Stale row — kill orphaned process if any, then delete
401
+ if (session.pid && processExists(session.pid)) {
402
+ _deps.log('INFO', `Killing orphaned process: PID ${session.pid} (${session.type} for ${path.basename(session.project_path)})`);
403
+ try {
404
+ process.kill(session.pid, 'SIGTERM');
405
+ killed++;
406
+ }
407
+ catch { /* process not killable */ }
408
+ }
409
+ db.prepare('DELETE FROM terminal_sessions WHERE id = ?').run(session.id);
410
+ cleaned++;
411
+ }
412
+ const total = shepherdReconnected + orphanReconnected;
413
+ if (total > 0 || killed > 0 || cleaned > 0) {
414
+ _deps.log('INFO', `Reconciliation complete: ${shepherdReconnected} shepherd, ${orphanReconnected} orphan, ${killed} killed, ${cleaned} stale rows cleaned`);
415
+ }
416
+ else {
417
+ _deps.log('INFO', 'No terminal sessions to reconcile');
418
+ }
419
+ }
420
+ // ============================================================================
421
+ // Gate watcher
422
+ // ============================================================================
423
+ /** Start periodic gate status polling */
424
+ export function startGateWatcher() {
425
+ if (!_deps)
426
+ return;
427
+ gateWatcherInterval = setInterval(async () => {
428
+ if (!_deps)
429
+ return;
430
+ const projectPaths = _deps.getKnownProjectPaths();
431
+ for (const projectPath of projectPaths) {
432
+ try {
433
+ const gateStatus = getGateStatusForProject(projectPath);
434
+ await gateWatcher.checkAndNotify(gateStatus, projectPath);
435
+ }
436
+ catch (err) {
437
+ _deps.log('WARN', `Gate watcher error for ${projectPath}: ${err instanceof Error ? err.message : String(err)}`);
438
+ }
439
+ }
440
+ }, 10_000);
441
+ }
442
+ /** Stop the gate watcher interval */
443
+ export function stopGateWatcher() {
444
+ if (gateWatcherInterval) {
445
+ clearInterval(gateWatcherInterval);
446
+ gateWatcherInterval = null;
447
+ }
448
+ }
449
+ // ============================================================================
450
+ // Terminal list assembly
451
+ // ============================================================================
452
+ /**
453
+ * Get terminal list for a project from tower's registry.
454
+ * Phase 4 (Spec 0090): Tower manages terminals directly, no dashboard-server fetch.
455
+ * Returns architect, builders, and shells with their URLs.
456
+ */
457
+ export async function getTerminalsForProject(projectPath, proxyUrl) {
458
+ const manager = getTerminalManager();
459
+ const terminals = [];
460
+ // Query SQLite first, then augment with shepherd reconnection
461
+ const dbSessions = getTerminalSessionsForProject(projectPath);
462
+ // Use normalized path for cache consistency
463
+ const normalizedPath = normalizeProjectPath(projectPath);
464
+ // Build a fresh entry from SQLite, then replace atomically to avoid
465
+ // destroying in-memory state that was registered via POST /api/terminals.
466
+ // Previous approach cleared the cache then rebuilt, which lost terminals
467
+ // if their SQLite rows were deleted by external interference (e.g., tests).
468
+ const freshEntry = { builders: new Map(), shells: new Map(), fileTabs: new Map() };
469
+ // Load file tabs from SQLite (persisted across restarts)
470
+ const existingEntry = projectTerminals.get(normalizedPath);
471
+ if (existingEntry && existingEntry.fileTabs.size > 0) {
472
+ // Use in-memory state if already populated (avoids redundant DB reads)
473
+ freshEntry.fileTabs = existingEntry.fileTabs;
474
+ }
475
+ else {
476
+ freshEntry.fileTabs = loadFileTabsForProject(projectPath);
477
+ }
478
+ for (const dbSession of dbSessions) {
479
+ // Verify session still exists in TerminalManager (runtime state)
480
+ let session = manager.getSession(dbSession.id);
481
+ if (!session && dbSession.shepherd_socket && _deps?.shepherdManager) {
482
+ // PTY session gone but shepherd may still be alive — reconnect on-the-fly
483
+ try {
484
+ // Restore auto-restart for architect sessions (same as startup reconciliation)
485
+ let restartOptions;
486
+ if (dbSession.type === 'architect') {
487
+ let architectCmd = 'claude';
488
+ const configPath = path.join(dbSession.project_path, 'af-config.json');
489
+ if (fs.existsSync(configPath)) {
490
+ try {
491
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
492
+ if (config.shell?.architect) {
493
+ architectCmd = config.shell.architect;
494
+ }
495
+ }
496
+ catch { /* use default */ }
497
+ }
498
+ const cmdParts = architectCmd.split(/\s+/);
499
+ const cleanEnv = { ...process.env };
500
+ delete cleanEnv['CLAUDECODE'];
501
+ restartOptions = {
502
+ command: cmdParts[0],
503
+ args: cmdParts.slice(1),
504
+ cwd: dbSession.project_path,
505
+ env: cleanEnv,
506
+ restartDelay: 2000,
507
+ maxRestarts: 50,
508
+ };
509
+ }
510
+ const client = await _deps.shepherdManager.reconnectSession(dbSession.id, dbSession.shepherd_socket, dbSession.shepherd_pid, dbSession.shepherd_start_time, restartOptions);
511
+ if (client) {
512
+ const replayData = client.getReplayData() ?? Buffer.alloc(0);
513
+ const label = dbSession.type === 'architect' ? 'Architect' : `${dbSession.type} ${dbSession.role_id || dbSession.id}`;
514
+ const newSession = manager.createSessionRaw({ label, cwd: dbSession.project_path });
515
+ const ptySession = manager.getSession(newSession.id);
516
+ if (ptySession) {
517
+ ptySession.attachShepherd(client, replayData, dbSession.shepherd_pid, dbSession.id);
518
+ // Clean up on exit (same as startup reconciliation path)
519
+ ptySession.on('exit', () => {
520
+ const currentEntry = getProjectTerminalsEntry(dbSession.project_path);
521
+ if (dbSession.type === 'architect' && currentEntry.architect === newSession.id) {
522
+ currentEntry.architect = undefined;
523
+ }
524
+ deleteTerminalSession(newSession.id);
525
+ });
526
+ }
527
+ deleteTerminalSession(dbSession.id);
528
+ saveTerminalSession(newSession.id, dbSession.project_path, dbSession.type, dbSession.role_id, dbSession.shepherd_pid, dbSession.shepherd_socket, dbSession.shepherd_pid, dbSession.shepherd_start_time);
529
+ dbSession.id = newSession.id;
530
+ session = manager.getSession(newSession.id);
531
+ _deps.log('INFO', `Reconnected to shepherd on-the-fly → ${newSession.id}`);
532
+ }
533
+ }
534
+ catch (err) {
535
+ _deps.log('WARN', `Failed shepherd on-the-fly reconnect for ${dbSession.id}: ${err.message}`);
536
+ }
537
+ }
538
+ if (!session) {
539
+ // Stale row, nothing to reconnect — clean up
540
+ deleteTerminalSession(dbSession.id);
541
+ continue;
542
+ }
543
+ if (dbSession.type === 'architect') {
544
+ freshEntry.architect = dbSession.id;
545
+ terminals.push({
546
+ type: 'architect',
547
+ id: 'architect',
548
+ label: 'Architect',
549
+ url: `${proxyUrl}?tab=architect`,
550
+ active: true,
551
+ });
552
+ }
553
+ else if (dbSession.type === 'builder') {
554
+ const builderId = dbSession.role_id || dbSession.id;
555
+ freshEntry.builders.set(builderId, dbSession.id);
556
+ terminals.push({
557
+ type: 'builder',
558
+ id: builderId,
559
+ label: `Builder ${builderId}`,
560
+ url: `${proxyUrl}?tab=builder-${builderId}`,
561
+ active: true,
562
+ });
563
+ }
564
+ else if (dbSession.type === 'shell') {
565
+ const shellId = dbSession.role_id || dbSession.id;
566
+ freshEntry.shells.set(shellId, dbSession.id);
567
+ terminals.push({
568
+ type: 'shell',
569
+ id: shellId,
570
+ label: `Shell ${shellId.replace('shell-', '')}`,
571
+ url: `${proxyUrl}?tab=shell-${shellId}`,
572
+ active: true,
573
+ });
574
+ }
575
+ }
576
+ // Also merge in-memory entries that may not be in SQLite yet
577
+ // (e.g., registered via POST /api/terminals but SQLite row was lost)
578
+ if (existingEntry) {
579
+ if (existingEntry.architect && !freshEntry.architect) {
580
+ const session = manager.getSession(existingEntry.architect);
581
+ if (session && session.status === 'running') {
582
+ freshEntry.architect = existingEntry.architect;
583
+ terminals.push({
584
+ type: 'architect',
585
+ id: 'architect',
586
+ label: 'Architect',
587
+ url: `${proxyUrl}?tab=architect`,
588
+ active: true,
589
+ });
590
+ }
591
+ }
592
+ for (const [builderId, terminalId] of existingEntry.builders) {
593
+ if (!freshEntry.builders.has(builderId)) {
594
+ const session = manager.getSession(terminalId);
595
+ if (session && session.status === 'running') {
596
+ freshEntry.builders.set(builderId, terminalId);
597
+ terminals.push({
598
+ type: 'builder',
599
+ id: builderId,
600
+ label: `Builder ${builderId}`,
601
+ url: `${proxyUrl}?tab=builder-${builderId}`,
602
+ active: true,
603
+ });
604
+ }
605
+ }
606
+ }
607
+ for (const [shellId, terminalId] of existingEntry.shells) {
608
+ if (!freshEntry.shells.has(shellId)) {
609
+ const session = manager.getSession(terminalId);
610
+ if (session && session.status === 'running') {
611
+ freshEntry.shells.set(shellId, terminalId);
612
+ terminals.push({
613
+ type: 'shell',
614
+ id: shellId,
615
+ label: `Shell ${shellId.replace('shell-', '')}`,
616
+ url: `${proxyUrl}?tab=shell-${shellId}`,
617
+ active: true,
618
+ });
619
+ }
620
+ }
621
+ }
622
+ }
623
+ // Atomically replace the cache entry
624
+ projectTerminals.set(normalizedPath, freshEntry);
625
+ // Read gate status from porch YAML files
626
+ const gateStatus = getGateStatusForProject(projectPath);
627
+ return { terminals, gateStatus };
628
+ }
629
+ //# sourceMappingURL=tower-terminals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tower-terminals.js","sourceRoot":"","sources":["../../../src/agent-farm/servers/tower-terminals.ts"],"names":[],"mappings":"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"}