labgate 0.5.27 → 0.5.29

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.
@@ -0,0 +1,54 @@
1
+ export type WebTerminalAgent = 'claude' | 'codex';
2
+ export type WebTerminalStatus = 'running' | 'exited' | 'failed';
3
+ export interface WebTerminalRecord {
4
+ id: string;
5
+ agent: WebTerminalAgent;
6
+ workdir: string;
7
+ node: string;
8
+ tmuxSession: string;
9
+ createdAt: string;
10
+ updatedAt: string;
11
+ status: WebTerminalStatus;
12
+ exitCode: number | null;
13
+ error: string | null;
14
+ }
15
+ export interface WebTerminalExitInfo {
16
+ exitCode: number;
17
+ finishedAt: string;
18
+ }
19
+ export declare function isValidWebTerminalId(raw: string): boolean;
20
+ export declare function getWebTerminalsDir(): string;
21
+ export declare function getWebTerminalRecordPath(id: string): string;
22
+ export declare function getWebTerminalExitPath(id: string): string;
23
+ export declare function ensureWebTerminalsDir(): void;
24
+ export declare function tmuxSessionNameForWebTerminalId(id: string): string;
25
+ export declare function createWebTerminalRecord(input: {
26
+ id: string;
27
+ agent: WebTerminalAgent;
28
+ workdir: string;
29
+ }): WebTerminalRecord;
30
+ export declare function writeWebTerminalRecord(record: WebTerminalRecord): void;
31
+ export declare function clearWebTerminalExitInfo(id: string): void;
32
+ export declare function readWebTerminalRecord(id: string): WebTerminalRecord | null;
33
+ export declare function listWebTerminalRecords(): WebTerminalRecord[];
34
+ export declare function resolveWebTerminalRecord(idOrPrefix: string): {
35
+ record: WebTerminalRecord | null;
36
+ matches: WebTerminalRecord[];
37
+ };
38
+ export declare function updateWebTerminalRecordStatus(id: string, next: {
39
+ status: WebTerminalStatus;
40
+ exitCode?: number | null;
41
+ error?: string | null;
42
+ }): WebTerminalRecord | null;
43
+ export declare function readWebTerminalExitInfo(id: string): WebTerminalExitInfo | null;
44
+ export declare function getTmuxBinary(): Promise<string>;
45
+ export declare function ensureTmuxAvailable(): Promise<{
46
+ ok: true;
47
+ } | {
48
+ ok: false;
49
+ error: string;
50
+ }>;
51
+ export declare function hasTmuxSession(sessionName: string): Promise<boolean>;
52
+ export declare function startTmuxWebTerminalSession(record: WebTerminalRecord, cliEntrypoint: string): Promise<void>;
53
+ export declare function killTmuxSession(sessionName: string): Promise<void>;
54
+ export declare function sanitizeExistingWebTerminalRecords(): void;
@@ -0,0 +1,327 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isValidWebTerminalId = isValidWebTerminalId;
4
+ exports.getWebTerminalsDir = getWebTerminalsDir;
5
+ exports.getWebTerminalRecordPath = getWebTerminalRecordPath;
6
+ exports.getWebTerminalExitPath = getWebTerminalExitPath;
7
+ exports.ensureWebTerminalsDir = ensureWebTerminalsDir;
8
+ exports.tmuxSessionNameForWebTerminalId = tmuxSessionNameForWebTerminalId;
9
+ exports.createWebTerminalRecord = createWebTerminalRecord;
10
+ exports.writeWebTerminalRecord = writeWebTerminalRecord;
11
+ exports.clearWebTerminalExitInfo = clearWebTerminalExitInfo;
12
+ exports.readWebTerminalRecord = readWebTerminalRecord;
13
+ exports.listWebTerminalRecords = listWebTerminalRecords;
14
+ exports.resolveWebTerminalRecord = resolveWebTerminalRecord;
15
+ exports.updateWebTerminalRecordStatus = updateWebTerminalRecordStatus;
16
+ exports.readWebTerminalExitInfo = readWebTerminalExitInfo;
17
+ exports.getTmuxBinary = getTmuxBinary;
18
+ exports.ensureTmuxAvailable = ensureTmuxAvailable;
19
+ exports.hasTmuxSession = hasTmuxSession;
20
+ exports.startTmuxWebTerminalSession = startTmuxWebTerminalSession;
21
+ exports.killTmuxSession = killTmuxSession;
22
+ exports.sanitizeExistingWebTerminalRecords = sanitizeExistingWebTerminalRecords;
23
+ const fs_1 = require("fs");
24
+ const path_1 = require("path");
25
+ const os_1 = require("os");
26
+ const child_process_1 = require("child_process");
27
+ const util_1 = require("util");
28
+ const config_js_1 = require("./config.js");
29
+ const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
30
+ const TMUX_BIN_OVERRIDE_ENV = 'LABGATE_TMUX_BIN';
31
+ const TMUX_BIN_CANDIDATES = ['tmux', '/opt/homebrew/bin/tmux', '/usr/local/bin/tmux', '/usr/bin/tmux'];
32
+ let cachedTmuxBinary = null;
33
+ function normalizeId(raw) {
34
+ return (raw || '').trim();
35
+ }
36
+ function isValidWebTerminalId(raw) {
37
+ const id = normalizeId(raw);
38
+ return /^wt-[a-z0-9_-]{4,80}$/i.test(id);
39
+ }
40
+ function getWebTerminalsDir() {
41
+ return (0, path_1.join)(config_js_1.LABGATE_DIR, 'web-terminals');
42
+ }
43
+ function getWebTerminalRecordPath(id) {
44
+ return (0, path_1.join)(getWebTerminalsDir(), `${id}.json`);
45
+ }
46
+ function getWebTerminalExitPath(id) {
47
+ return (0, path_1.join)(getWebTerminalsDir(), `${id}.exit.json`);
48
+ }
49
+ function ensureWebTerminalsDir() {
50
+ (0, config_js_1.ensurePrivateDir)(getWebTerminalsDir());
51
+ }
52
+ function tmuxSessionNameForWebTerminalId(id) {
53
+ const safe = id.replace(/[^a-zA-Z0-9_-]/g, '').slice(0, 64) || 'session';
54
+ return `labgate-${safe}`;
55
+ }
56
+ function createWebTerminalRecord(input) {
57
+ const now = new Date().toISOString();
58
+ return {
59
+ id: input.id,
60
+ agent: input.agent,
61
+ workdir: input.workdir,
62
+ node: (0, os_1.hostname)(),
63
+ tmuxSession: tmuxSessionNameForWebTerminalId(input.id),
64
+ createdAt: now,
65
+ updatedAt: now,
66
+ status: 'running',
67
+ exitCode: null,
68
+ error: null,
69
+ };
70
+ }
71
+ function writeWebTerminalRecord(record) {
72
+ ensureWebTerminalsDir();
73
+ const target = getWebTerminalRecordPath(record.id);
74
+ const temp = `${target}.${process.pid}.${Date.now()}.tmp`;
75
+ try {
76
+ (0, fs_1.writeFileSync)(temp, JSON.stringify(record, null, 2) + '\n', { encoding: 'utf-8', mode: config_js_1.PRIVATE_FILE_MODE });
77
+ (0, config_js_1.ensurePrivateFile)(temp);
78
+ (0, fs_1.renameSync)(temp, target);
79
+ (0, config_js_1.ensurePrivateFile)(target);
80
+ }
81
+ finally {
82
+ try {
83
+ if ((0, fs_1.existsSync)(temp))
84
+ (0, fs_1.unlinkSync)(temp);
85
+ }
86
+ catch {
87
+ // Best effort cleanup.
88
+ }
89
+ }
90
+ }
91
+ function clearWebTerminalExitInfo(id) {
92
+ const path = getWebTerminalExitPath(id);
93
+ try {
94
+ if ((0, fs_1.existsSync)(path))
95
+ (0, fs_1.unlinkSync)(path);
96
+ }
97
+ catch {
98
+ // Best effort.
99
+ }
100
+ }
101
+ function readWebTerminalRecord(id) {
102
+ if (!isValidWebTerminalId(id))
103
+ return null;
104
+ const path = getWebTerminalRecordPath(id);
105
+ if (!(0, fs_1.existsSync)(path))
106
+ return null;
107
+ try {
108
+ const raw = (0, fs_1.readFileSync)(path, 'utf-8');
109
+ const parsed = JSON.parse(raw);
110
+ if (!parsed || typeof parsed !== 'object')
111
+ return null;
112
+ return parsed;
113
+ }
114
+ catch {
115
+ return null;
116
+ }
117
+ }
118
+ function listWebTerminalRecords() {
119
+ ensureWebTerminalsDir();
120
+ const dir = getWebTerminalsDir();
121
+ const out = [];
122
+ for (const file of (0, fs_1.readdirSync)(dir)) {
123
+ if (!file.endsWith('.json'))
124
+ continue;
125
+ try {
126
+ const parsed = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(dir, file), 'utf-8'));
127
+ if (!parsed || typeof parsed !== 'object' || !isValidWebTerminalId(parsed.id || ''))
128
+ continue;
129
+ out.push(parsed);
130
+ }
131
+ catch {
132
+ // Skip malformed records.
133
+ }
134
+ }
135
+ out.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
136
+ return out;
137
+ }
138
+ function resolveWebTerminalRecord(idOrPrefix) {
139
+ const query = normalizeId(idOrPrefix);
140
+ if (!query)
141
+ return { record: null, matches: [] };
142
+ if (isValidWebTerminalId(query)) {
143
+ const exact = readWebTerminalRecord(query);
144
+ if (exact)
145
+ return { record: exact, matches: [exact] };
146
+ }
147
+ const all = listWebTerminalRecords();
148
+ const matches = all.filter((r) => r.id.startsWith(query));
149
+ return { record: matches.length === 1 ? matches[0] : null, matches };
150
+ }
151
+ function updateWebTerminalRecordStatus(id, next) {
152
+ const existing = readWebTerminalRecord(id);
153
+ if (!existing)
154
+ return null;
155
+ const updated = {
156
+ ...existing,
157
+ status: next.status,
158
+ exitCode: next.exitCode !== undefined ? next.exitCode : existing.exitCode,
159
+ error: next.error !== undefined ? next.error : existing.error,
160
+ updatedAt: new Date().toISOString(),
161
+ };
162
+ writeWebTerminalRecord(updated);
163
+ return updated;
164
+ }
165
+ function readWebTerminalExitInfo(id) {
166
+ if (!isValidWebTerminalId(id))
167
+ return null;
168
+ const path = getWebTerminalExitPath(id);
169
+ if (!(0, fs_1.existsSync)(path))
170
+ return null;
171
+ try {
172
+ const raw = (0, fs_1.readFileSync)(path, 'utf-8');
173
+ const parsed = JSON.parse(raw || '{}');
174
+ const code = Number(parsed.exitCode);
175
+ const finishedAt = typeof parsed.finishedAt === 'string' ? parsed.finishedAt : '';
176
+ if (!Number.isFinite(code))
177
+ return null;
178
+ return {
179
+ exitCode: Math.trunc(code),
180
+ finishedAt: finishedAt || new Date().toISOString(),
181
+ };
182
+ }
183
+ catch {
184
+ return null;
185
+ }
186
+ }
187
+ function shellQuote(value) {
188
+ return `'${value.replace(/'/g, `'\\''`)}'`;
189
+ }
190
+ function tmuxErrorDetail(err) {
191
+ return [
192
+ err?.message,
193
+ err?.stderr,
194
+ err?.stdout,
195
+ err?.cause?.message,
196
+ err?.cause?.stderr,
197
+ err?.cause?.stdout,
198
+ ].filter((part) => typeof part === 'string').join('\n');
199
+ }
200
+ function isMissingTmuxSessionError(err) {
201
+ return /(can't find session|no such session)/i.test(tmuxErrorDetail(err));
202
+ }
203
+ async function getTmuxBinary() {
204
+ const override = (process.env[TMUX_BIN_OVERRIDE_ENV] || '').trim();
205
+ if (override) {
206
+ try {
207
+ await execFileAsync(override, ['-V'], { timeout: 5_000 });
208
+ cachedTmuxBinary = override;
209
+ return override;
210
+ }
211
+ catch (err) {
212
+ const detail = err?.message ?? String(err);
213
+ throw new Error(`${TMUX_BIN_OVERRIDE_ENV} is set to "${override}" but unusable: ${detail}`);
214
+ }
215
+ }
216
+ if (cachedTmuxBinary) {
217
+ try {
218
+ await execFileAsync(cachedTmuxBinary, ['-V'], { timeout: 5_000 });
219
+ return cachedTmuxBinary;
220
+ }
221
+ catch {
222
+ cachedTmuxBinary = null;
223
+ }
224
+ }
225
+ let lastError = 'spawn tmux ENOENT';
226
+ for (const candidate of TMUX_BIN_CANDIDATES) {
227
+ try {
228
+ await execFileAsync(candidate, ['-V'], { timeout: 5_000 });
229
+ cachedTmuxBinary = candidate;
230
+ return candidate;
231
+ }
232
+ catch (err) {
233
+ lastError = err?.message ?? String(err);
234
+ }
235
+ }
236
+ throw new Error(lastError);
237
+ }
238
+ async function ensureTmuxAvailable() {
239
+ try {
240
+ await getTmuxBinary();
241
+ return { ok: true };
242
+ }
243
+ catch (err) {
244
+ const detail = err?.message ?? String(err);
245
+ const guidance = [
246
+ 'tmux is required but unavailable.',
247
+ `Detected error: ${detail}`,
248
+ 'HPC quick fixes:',
249
+ ' 1. If your cluster uses environment modules: `module avail tmux` then `module load tmux`',
250
+ ' 2. Verify availability: `tmux -V`',
251
+ ' 3. If still missing, ask your platform admin to provide tmux on login/compute node PATH',
252
+ ` 4. If tmux exists but PATH differs, set ${TMUX_BIN_OVERRIDE_ENV}=<absolute-tmux-path> before \`labgate ui\``,
253
+ ].join('\n');
254
+ return { ok: false, error: guidance };
255
+ }
256
+ }
257
+ async function hasTmuxSession(sessionName) {
258
+ try {
259
+ const tmuxBin = await getTmuxBinary();
260
+ await execFileAsync(tmuxBin, ['has-session', '-t', sessionName], { timeout: 5_000 });
261
+ return true;
262
+ }
263
+ catch {
264
+ return false;
265
+ }
266
+ }
267
+ async function startTmuxWebTerminalSession(record, cliEntrypoint) {
268
+ const tmuxBin = await getTmuxBinary();
269
+ clearWebTerminalExitInfo(record.id);
270
+ const launchInner = [
271
+ `LABGATE_WEB_TERMINAL_ID=${shellQuote(record.id)}`,
272
+ shellQuote(process.execPath),
273
+ shellQuote(cliEntrypoint),
274
+ shellQuote(record.agent),
275
+ shellQuote(record.workdir),
276
+ '--no-footer',
277
+ ].join(' ');
278
+ const exitsDir = shellQuote(getWebTerminalsDir());
279
+ const exitFile = shellQuote(getWebTerminalExitPath(record.id));
280
+ const launchScript = [
281
+ 'set +e',
282
+ `${launchInner}`,
283
+ 'labgate_exit_code=$?',
284
+ `mkdir -p ${exitsDir}`,
285
+ `printf '{"exitCode":%s,"finishedAt":"%s"}\\n' "$labgate_exit_code" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > ${exitFile}`,
286
+ `chmod 600 ${exitFile} 2>/dev/null || true`,
287
+ 'exit "$labgate_exit_code"',
288
+ ].join('; ');
289
+ const shell = (process.env.SHELL || '/bin/bash').trim() || '/bin/bash';
290
+ const launch = `${shellQuote(shell)} -lc ${shellQuote(launchScript)}`;
291
+ await execFileAsync(tmuxBin, ['new-session', '-d', '-s', record.tmuxSession, '-c', record.workdir, launch], { timeout: 120_000 });
292
+ try {
293
+ // Web terminal sessions should not render tmux status/footer lines.
294
+ await execFileAsync(tmuxBin, ['set-option', '-t', record.tmuxSession, 'status', 'off'], { timeout: 10_000 });
295
+ }
296
+ catch (err) {
297
+ // If the command exited immediately, the session may already be gone.
298
+ if (!isMissingTmuxSessionError(err))
299
+ throw err;
300
+ }
301
+ }
302
+ async function killTmuxSession(sessionName) {
303
+ const tmuxBin = await getTmuxBinary();
304
+ try {
305
+ await execFileAsync(tmuxBin, ['kill-session', '-t', sessionName], { timeout: 10_000 });
306
+ }
307
+ catch (err) {
308
+ // Treat missing sessions as already stopped to keep stop/restart idempotent.
309
+ if (isMissingTmuxSessionError(err))
310
+ return;
311
+ throw err;
312
+ }
313
+ }
314
+ function sanitizeExistingWebTerminalRecords() {
315
+ const dir = getWebTerminalsDir();
316
+ if (!(0, fs_1.existsSync)(dir))
317
+ return;
318
+ try {
319
+ const fd = (0, fs_1.openSync)(dir, 'r');
320
+ (0, fs_1.closeSync)(fd);
321
+ }
322
+ catch {
323
+ (0, config_js_1.ensurePrivateDir)((0, path_1.dirname)(dir));
324
+ (0, config_js_1.ensurePrivateDir)(dir);
325
+ }
326
+ }
327
+ //# sourceMappingURL=web-terminal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web-terminal.js","sourceRoot":"","sources":["../../src/lib/web-terminal.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "labgate",
3
- "version": "0.5.27",
4
- "description": "Policy-controlled sandboxes for AI coding agents — https://labgate.dev",
3
+ "version": "0.5.29",
4
+ "description": "Secure HPC wrapper for AI coding agents (Claude-first): policy controls, Apptainer sandboxes, and SLURM workflows — https://labgate.dev",
5
5
  "homepage": "https://labgate.dev",
6
6
  "keywords": [
7
7
  "sandbox",
@@ -43,19 +43,24 @@
43
43
  ],
44
44
  "dependencies": {
45
45
  "@modelcontextprotocol/sdk": "^1.26.0",
46
+ "@xterm/addon-fit": "^0.11.0",
47
+ "@xterm/addon-web-links": "^0.12.0",
48
+ "@xterm/xterm": "^6.0.0",
46
49
  "commander": "^12.1.0",
47
- "fast-glob": "^3.3.3"
50
+ "fast-glob": "^3.3.3",
51
+ "ws": "^8.19.0"
48
52
  },
49
53
  "optionalDependencies": {
50
54
  "better-sqlite3": "^12.6.2",
51
- "node-pty": "^1.1.0"
55
+ "node-pty": "^1.2.0-beta.11"
52
56
  },
53
57
  "devDependencies": {
54
58
  "@types/better-sqlite3": "^7.6.13",
55
59
  "@types/node": "^22.0.0",
60
+ "@types/ws": "^8.18.1",
61
+ "esbuild": "^0.25.0",
56
62
  "geist": "^1.7.0",
57
63
  "typescript": "^5.6.0",
58
- "esbuild": "^0.25.0",
59
64
  "vitest": "^4.0.18"
60
65
  },
61
66
  "engines": {