@cluesmith/codev 2.0.0-rc.72 → 2.0.0-rc.74
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.
- package/dashboard/dist/assets/{index-C7FtNK6Y.css → index-4n9zpWLY.css} +1 -1
- package/dashboard/dist/assets/{index-CDAINZKT.js → index-b38SaXk5.js} +33 -28
- package/dashboard/dist/assets/index-b38SaXk5.js.map +1 -0
- package/dashboard/dist/index.html +2 -2
- package/dist/agent-farm/commands/spawn-roles.d.ts +80 -0
- package/dist/agent-farm/commands/spawn-roles.d.ts.map +1 -0
- package/dist/agent-farm/commands/spawn-roles.js +278 -0
- package/dist/agent-farm/commands/spawn-roles.js.map +1 -0
- package/dist/agent-farm/commands/spawn-worktree.d.ts +96 -0
- package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -0
- package/dist/agent-farm/commands/spawn-worktree.js +305 -0
- package/dist/agent-farm/commands/spawn-worktree.js.map +1 -0
- package/dist/agent-farm/commands/spawn.d.ts +5 -1
- package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn.js +65 -725
- package/dist/agent-farm/commands/spawn.js.map +1 -1
- package/dist/agent-farm/db/index.d.ts.map +1 -1
- package/dist/agent-farm/db/index.js +56 -2
- package/dist/agent-farm/db/index.js.map +1 -1
- package/dist/agent-farm/db/schema.d.ts +1 -1
- package/dist/agent-farm/db/schema.js +3 -3
- package/dist/agent-farm/servers/tower-instances.d.ts +82 -0
- package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -0
- package/dist/agent-farm/servers/tower-instances.js +454 -0
- package/dist/agent-farm/servers/tower-instances.js.map +1 -0
- package/dist/agent-farm/servers/tower-routes.d.ts +34 -0
- package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -0
- package/dist/agent-farm/servers/tower-routes.js +1445 -0
- package/dist/agent-farm/servers/tower-routes.js.map +1 -0
- package/dist/agent-farm/servers/tower-server.d.ts +5 -2
- package/dist/agent-farm/servers/tower-server.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-server.js +89 -2875
- package/dist/agent-farm/servers/tower-server.js.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.d.ts +119 -0
- package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -0
- package/dist/agent-farm/servers/tower-terminals.js +629 -0
- package/dist/agent-farm/servers/tower-terminals.js.map +1 -0
- package/dist/agent-farm/servers/tower-tunnel.d.ts +34 -0
- package/dist/agent-farm/servers/tower-tunnel.d.ts.map +1 -0
- package/dist/agent-farm/servers/tower-tunnel.js +299 -0
- package/dist/agent-farm/servers/tower-tunnel.js.map +1 -0
- package/dist/agent-farm/servers/tower-types.d.ts +86 -0
- package/dist/agent-farm/servers/tower-types.d.ts.map +1 -0
- package/dist/agent-farm/servers/tower-types.js +6 -0
- package/dist/agent-farm/servers/tower-types.js.map +1 -0
- package/dist/agent-farm/servers/tower-utils.d.ts +58 -0
- package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -0
- package/dist/agent-farm/servers/tower-utils.js +182 -0
- package/dist/agent-farm/servers/tower-utils.js.map +1 -0
- package/dist/agent-farm/servers/tower-websocket.d.ts +25 -0
- package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -0
- package/dist/agent-farm/servers/tower-websocket.js +171 -0
- package/dist/agent-farm/servers/tower-websocket.js.map +1 -0
- package/dist/agent-farm/utils/shell.d.ts +1 -1
- package/dist/agent-farm/utils/shell.js +1 -1
- package/dist/commands/porch/next.js +4 -4
- package/dist/commands/porch/next.js.map +1 -1
- package/dist/terminal/pty-manager.d.ts +1 -1
- package/dist/terminal/pty-manager.js +5 -5
- package/dist/terminal/pty-session.d.ts +20 -20
- package/dist/terminal/pty-session.js +55 -55
- package/dist/terminal/session-manager.d.ts +15 -15
- package/dist/terminal/session-manager.js +34 -34
- package/dist/terminal/{shepherd-client.d.ts → shellper-client.d.ts} +10 -10
- package/dist/terminal/{shepherd-client.d.ts.map → shellper-client.d.ts.map} +1 -1
- package/dist/terminal/{shepherd-client.js → shellper-client.js} +20 -20
- package/dist/terminal/{shepherd-client.js.map → shellper-client.js.map} +1 -1
- package/dist/terminal/{shepherd-main.d.ts → shellper-main.d.ts} +3 -3
- package/dist/terminal/shellper-main.d.ts.map +1 -0
- package/dist/terminal/{shepherd-main.js → shellper-main.js} +17 -17
- package/dist/terminal/{shepherd-main.js.map → shellper-main.js.map} +1 -1
- package/dist/terminal/{shepherd-process.d.ts → shellper-process.d.ts} +8 -8
- package/dist/terminal/{shepherd-process.d.ts.map → shellper-process.d.ts.map} +1 -1
- package/dist/terminal/{shepherd-process.js → shellper-process.js} +11 -11
- package/dist/terminal/{shepherd-process.js.map → shellper-process.js.map} +1 -1
- package/dist/terminal/{shepherd-protocol.d.ts → shellper-protocol.d.ts} +5 -5
- package/dist/terminal/{shepherd-protocol.d.ts.map → shellper-protocol.d.ts.map} +1 -1
- package/dist/terminal/{shepherd-protocol.js → shellper-protocol.js} +5 -5
- package/dist/terminal/{shepherd-protocol.js.map → shellper-protocol.js.map} +1 -1
- package/dist/terminal/{shepherd-replay-buffer.d.ts → shellper-replay-buffer.d.ts} +4 -4
- package/dist/terminal/{shepherd-replay-buffer.d.ts.map → shellper-replay-buffer.d.ts.map} +1 -1
- package/dist/terminal/{shepherd-replay-buffer.js → shellper-replay-buffer.js} +4 -4
- package/dist/terminal/{shepherd-replay-buffer.js.map → shellper-replay-buffer.js.map} +1 -1
- package/package.json +1 -1
- package/skeleton/protocols/bugfix/builder-prompt.md +7 -1
- package/skeleton/protocols/maintain/protocol.md +3 -3
- package/skeleton/protocols/spir/builder-prompt.md +7 -0
- package/skeleton/resources/commands/agent-farm.md +2 -2
- package/skeleton/roles/builder.md +15 -1
- package/dashboard/dist/assets/index-CDAINZKT.js.map +0 -1
- package/dist/terminal/shepherd-main.d.ts.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, buildArchitectArgs } 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, shellperSocket = null, shellperPid = null, shellperStartTime = 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, shellper_socket, shellper_pid, shellper_start_time)
|
|
125
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
126
|
+
`).run(terminalId, normalizedPath, type, roleId, pid, shellperSocket, shellperPid, shellperStartTime);
|
|
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 (shellper-backed).
|
|
135
|
+
* A session is persistent if it can survive a Tower restart.
|
|
136
|
+
*/
|
|
137
|
+
export function isSessionPersistent(_terminalId, session) {
|
|
138
|
+
return session.shellperBacked;
|
|
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 (shellper + SQLite):
|
|
248
|
+
*
|
|
249
|
+
* Phase 1 — Shellper reconnection:
|
|
250
|
+
* For SQLite rows with shellper_socket IS NOT NULL, attempt to reconnect
|
|
251
|
+
* via SessionManager.reconnectSession(). Shellper 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 shellperReconnected = 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: Shellper 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 shellperSessions = allDbSessions.filter(s => s.shellper_socket !== null);
|
|
281
|
+
if (shellperSessions.length > 0) {
|
|
282
|
+
_deps.log('INFO', `Found ${shellperSessions.length} shellper session(s) in SQLite — reconnecting...`);
|
|
283
|
+
}
|
|
284
|
+
for (const dbSession of shellperSessions) {
|
|
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 shellper session ${dbSession.id} — project path no longer exists: ${projectPath}`);
|
|
289
|
+
// Kill orphaned shellper process before removing row
|
|
290
|
+
if (dbSession.shellper_pid && processExists(dbSession.shellper_pid)) {
|
|
291
|
+
try {
|
|
292
|
+
process.kill(dbSession.shellper_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 shellper session ${dbSession.id} — project is in temp directory: ${projectPath}`);
|
|
304
|
+
// Kill orphaned shellper process before removing row
|
|
305
|
+
if (dbSession.shellper_pid && processExists(dbSession.shellper_pid)) {
|
|
306
|
+
try {
|
|
307
|
+
process.kill(dbSession.shellper_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.shellperManager) {
|
|
317
|
+
_deps.log('WARN', `Shellper 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: buildArchitectArgs(cmdParts.slice(1), projectPath),
|
|
341
|
+
cwd: projectPath,
|
|
342
|
+
env: cleanEnv,
|
|
343
|
+
restartDelay: 2000,
|
|
344
|
+
maxRestarts: 50,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
const client = await _deps.shellperManager.reconnectSession(dbSession.id, dbSession.shellper_socket, dbSession.shellper_pid, dbSession.shellper_start_time, restartOptions);
|
|
348
|
+
if (!client) {
|
|
349
|
+
_deps.log('INFO', `Shellper 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 shellper client
|
|
355
|
+
const session = manager.createSessionRaw({ label, cwd: projectPath });
|
|
356
|
+
const ptySession = manager.getSession(session.id);
|
|
357
|
+
if (ptySession) {
|
|
358
|
+
ptySession.attachShellper(client, replayData, dbSession.shellper_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.shellper_pid, dbSession.shellper_socket, dbSession.shellper_pid, dbSession.shellper_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
|
+
shellperReconnected++;
|
|
387
|
+
_deps.log('INFO', `Reconnected shellper session → ${session.id} (${dbSession.type} for ${path.basename(projectPath)})`);
|
|
388
|
+
}
|
|
389
|
+
catch (err) {
|
|
390
|
+
_deps.log('WARN', `Failed to reconnect shellper 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 = shellperReconnected + orphanReconnected;
|
|
413
|
+
if (total > 0 || killed > 0 || cleaned > 0) {
|
|
414
|
+
_deps.log('INFO', `Reconciliation complete: ${shellperReconnected} shellper, ${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 shellper 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.shellper_socket && _deps?.shellperManager) {
|
|
482
|
+
// PTY session gone but shellper 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: buildArchitectArgs(cmdParts.slice(1), dbSession.project_path),
|
|
504
|
+
cwd: dbSession.project_path,
|
|
505
|
+
env: cleanEnv,
|
|
506
|
+
restartDelay: 2000,
|
|
507
|
+
maxRestarts: 50,
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
const client = await _deps.shellperManager.reconnectSession(dbSession.id, dbSession.shellper_socket, dbSession.shellper_pid, dbSession.shellper_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.attachShellper(client, replayData, dbSession.shellper_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.shellper_pid, dbSession.shellper_socket, dbSession.shellper_pid, dbSession.shellper_start_time);
|
|
529
|
+
dbSession.id = newSession.id;
|
|
530
|
+
session = manager.getSession(newSession.id);
|
|
531
|
+
_deps.log('INFO', `Reconnected to shellper on-the-fly → ${newSession.id}`);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
catch (err) {
|
|
535
|
+
_deps.log('WARN', `Failed shellper 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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"}
|