labgate 0.5.3 → 0.5.4

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 (40) hide show
  1. package/README.md +48 -3
  2. package/dist/cli.js +322 -19
  3. package/dist/cli.js.map +1 -1
  4. package/dist/lib/audit.d.ts +5 -1
  5. package/dist/lib/audit.js +19 -3
  6. package/dist/lib/audit.js.map +1 -1
  7. package/dist/lib/config.d.ts +71 -2
  8. package/dist/lib/config.js +192 -8
  9. package/dist/lib/config.js.map +1 -1
  10. package/dist/lib/container.d.ts +54 -0
  11. package/dist/lib/container.js +650 -178
  12. package/dist/lib/container.js.map +1 -1
  13. package/dist/lib/init.js +22 -9
  14. package/dist/lib/init.js.map +1 -1
  15. package/dist/lib/license.d.ts +44 -0
  16. package/dist/lib/license.js +164 -0
  17. package/dist/lib/license.js.map +1 -0
  18. package/dist/lib/policy.d.ts +85 -0
  19. package/dist/lib/policy.js +321 -0
  20. package/dist/lib/policy.js.map +1 -0
  21. package/dist/lib/runtime.d.ts +2 -2
  22. package/dist/lib/runtime.js +19 -36
  23. package/dist/lib/runtime.js.map +1 -1
  24. package/dist/lib/slurm-db.d.ts +51 -0
  25. package/dist/lib/slurm-db.js +179 -0
  26. package/dist/lib/slurm-db.js.map +1 -0
  27. package/dist/lib/slurm-mcp.d.ts +12 -0
  28. package/dist/lib/slurm-mcp.js +347 -0
  29. package/dist/lib/slurm-mcp.js.map +1 -0
  30. package/dist/lib/slurm-poller.d.ts +36 -0
  31. package/dist/lib/slurm-poller.js +423 -0
  32. package/dist/lib/slurm-poller.js.map +1 -0
  33. package/dist/lib/test/integration-harness.d.ts +44 -0
  34. package/dist/lib/test/integration-harness.js +260 -0
  35. package/dist/lib/test/integration-harness.js.map +1 -0
  36. package/dist/lib/ui.d.ts +34 -1
  37. package/dist/lib/ui.html +3081 -356
  38. package/dist/lib/ui.js +2123 -106
  39. package/dist/lib/ui.js.map +1 -1
  40. package/package.json +11 -3
@@ -0,0 +1,423 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SlurmPoller = void 0;
4
+ const child_process_1 = require("child_process");
5
+ const fs_1 = require("fs");
6
+ const path_1 = require("path");
7
+ const os_1 = require("os");
8
+ const config_js_1 = require("./config.js");
9
+ // ── Poller ────────────────────────────────────────────────
10
+ class SlurmPoller {
11
+ db;
12
+ pollIntervalMs;
13
+ sacctLookbackHours;
14
+ username;
15
+ timer = null;
16
+ sacctTimer = null;
17
+ backoffMs = 0;
18
+ squeueSupportsJson = null;
19
+ localHost = (0, os_1.hostname)();
20
+ constructor(opts) {
21
+ this.db = opts.db;
22
+ this.pollIntervalMs = opts.pollIntervalMs ?? 5000;
23
+ this.sacctLookbackHours = opts.sacctLookbackHours ?? 24;
24
+ this.username = opts.username ?? process.env.USER ?? process.env.LOGNAME ?? '';
25
+ }
26
+ start() {
27
+ if (this.timer)
28
+ return;
29
+ // Initial poll immediately
30
+ this.pollOnce().catch(() => { });
31
+ // Recurring squeue poll
32
+ this.timer = setInterval(() => {
33
+ if (this.backoffMs > 0) {
34
+ this.backoffMs = Math.max(0, this.backoffMs - this.pollIntervalMs);
35
+ return;
36
+ }
37
+ this.pollOnce().catch(() => { });
38
+ }, this.pollIntervalMs);
39
+ // Recurring sacct poll (every 30s)
40
+ this.sacctTimer = setInterval(() => {
41
+ this.pollSacct().catch(() => { });
42
+ }, 30_000);
43
+ }
44
+ stop() {
45
+ if (this.timer) {
46
+ clearInterval(this.timer);
47
+ this.timer = null;
48
+ }
49
+ if (this.sacctTimer) {
50
+ clearInterval(this.sacctTimer);
51
+ this.sacctTimer = null;
52
+ }
53
+ }
54
+ async pollOnce() {
55
+ const result = { squeueJobs: 0, sacctJobs: 0, errors: [] };
56
+ try {
57
+ result.squeueJobs = await this.pollSqueue();
58
+ this.backoffMs = 0;
59
+ }
60
+ catch (err) {
61
+ result.errors.push(`squeue: ${err.message}`);
62
+ // Exponential backoff on failure, max 60s
63
+ this.backoffMs = Math.min((this.backoffMs || this.pollIntervalMs) * 2, 60_000);
64
+ }
65
+ // Also stat output files for active jobs
66
+ this.updateOutputFileStats();
67
+ return result;
68
+ }
69
+ // ── squeue polling ────────────────────────────────────────
70
+ async pollSqueue() {
71
+ if (!this.username)
72
+ return 0;
73
+ // Try JSON format first, fall back to delimited format
74
+ if (this.squeueSupportsJson === null || this.squeueSupportsJson) {
75
+ try {
76
+ const output = await this.exec('squeue', ['-u', this.username, '--json']);
77
+ const jobs = this.parseSqueueJson(output);
78
+ for (const job of jobs) {
79
+ this.upsertWithSessionCorrelation(job);
80
+ }
81
+ this.squeueSupportsJson = true;
82
+ return jobs.length;
83
+ }
84
+ catch {
85
+ // Fall back to delimited mode on unsupported/unstable JSON output.
86
+ this.squeueSupportsJson = false;
87
+ }
88
+ }
89
+ // Fallback: delimited format
90
+ const delimiter = '\u001f'; // ASCII Unit Separator to avoid collisions in command/workdir
91
+ const format = `%i${delimiter}%j${delimiter}%T${delimiter}%V${delimiter}%S${delimiter}%e${delimiter}%P${delimiter}%N${delimiter}%D${delimiter}%n${delimiter}%C${delimiter}%m${delimiter}%o${delimiter}%Z`;
92
+ const output = await this.exec('squeue', ['-u', this.username, '-o', format, '--noheader']);
93
+ const jobs = this.parseSqueueDelimited(output, delimiter);
94
+ for (const job of jobs) {
95
+ this.upsertWithSessionCorrelation(job);
96
+ }
97
+ return jobs.length;
98
+ }
99
+ parseSqueueJson(output) {
100
+ const data = JSON.parse(output);
101
+ const jobs = [];
102
+ for (const j of data.jobs ?? []) {
103
+ const jobId = String(j.job_id ?? '').trim();
104
+ if (!jobId)
105
+ continue;
106
+ const submitTime = toIsoTimestamp(j.submit_time, new Date().toISOString());
107
+ const startTime = toIsoTimestamp(j.start_time, null);
108
+ jobs.push({
109
+ job_id: jobId,
110
+ name: j.name ?? j.job_name ?? null,
111
+ state: normalizeSlurmState(j.job_state ?? j.state),
112
+ submit_time: submitTime,
113
+ start_time: startTime,
114
+ partition: j.partition ?? null,
115
+ nodes: j.nodes ?? j.node_list ?? null,
116
+ num_nodes: j.node_count ?? j.num_nodes ?? null,
117
+ num_tasks: j.tasks ?? j.num_tasks ?? null,
118
+ cpus_per_task: j.cpus_per_task ?? null,
119
+ mem: j.memory_per_node ? `${j.memory_per_node}` : null,
120
+ stdout_path: j.standard_output ?? null,
121
+ stderr_path: j.standard_error ?? null,
122
+ command: j.command ?? null,
123
+ workdir: j.work_dir ?? j.current_working_directory ?? null,
124
+ account: j.account ?? null,
125
+ qos: j.qos ?? null,
126
+ time_limit: j.time_limit ? formatTimelimit(j.time_limit) : null,
127
+ });
128
+ }
129
+ return jobs;
130
+ }
131
+ parseSqueueDelimited(output, delimiter = '|') {
132
+ const jobs = [];
133
+ for (const line of output.split('\n')) {
134
+ const trimmed = line.trim();
135
+ if (!trimmed)
136
+ continue;
137
+ const parts = trimmed.split(delimiter);
138
+ if (parts.length < 14)
139
+ continue;
140
+ const [jobId, name, state, submitTime, startTime, endTime, partition, nodes, numNodes, numTasks, cpus, mem, command, workdir,] = parts;
141
+ if (!jobId)
142
+ continue;
143
+ jobs.push({
144
+ job_id: jobId,
145
+ name: name || null,
146
+ state: normalizeSlurmState(state),
147
+ submit_time: parseTimestamp(submitTime),
148
+ start_time: startTime && startTime !== 'N/A' ? parseTimestamp(startTime) : null,
149
+ end_time: endTime && endTime !== 'N/A' ? parseTimestamp(endTime) : null,
150
+ partition: partition || null,
151
+ nodes: nodes || null,
152
+ num_nodes: numNodes ? parseInt(numNodes, 10) || null : null,
153
+ num_tasks: numTasks ? parseInt(numTasks, 10) || null : null,
154
+ cpus_per_task: cpus ? parseInt(cpus, 10) || null : null,
155
+ mem: mem || null,
156
+ command: command || null,
157
+ workdir: workdir || null,
158
+ });
159
+ }
160
+ return jobs;
161
+ }
162
+ // ── sacct polling for completed jobs ──────────────────────
163
+ async pollSacct() {
164
+ if (!this.username)
165
+ return 0;
166
+ // Only look up jobs that were active but are no longer in squeue
167
+ const activeIds = this.db.getActiveJobIds();
168
+ if (activeIds.length === 0)
169
+ return 0;
170
+ try {
171
+ const starttime = `now-${this.sacctLookbackHours}hours`;
172
+ const output = await this.exec('sacct', [
173
+ '-u', this.username,
174
+ '--starttime', starttime,
175
+ '--format=JobID,JobName,State,Start,End,ExitCode,Partition,NodeList,NNodes,NTasks,CPUTimeRAW,TimelimitRaw',
176
+ '--parsable2',
177
+ '--noheader',
178
+ ]);
179
+ const jobs = this.parseSacctOutput(output);
180
+ const activeSet = new Set(activeIds);
181
+ let count = 0;
182
+ for (const job of jobs) {
183
+ // Only update jobs we're already tracking
184
+ if (job.job_id && activeSet.has(job.job_id)) {
185
+ this.db.upsertJob(job);
186
+ count++;
187
+ }
188
+ }
189
+ return count;
190
+ }
191
+ catch {
192
+ // sacct may not be available on all nodes
193
+ return 0;
194
+ }
195
+ }
196
+ parseSacctOutput(output) {
197
+ const jobs = [];
198
+ for (const line of output.split('\n')) {
199
+ const trimmed = line.trim();
200
+ if (!trimmed)
201
+ continue;
202
+ const parts = trimmed.split('|');
203
+ if (parts.length < 12)
204
+ continue;
205
+ const [jobId, name, state, startTime, endTime, exitCodeStr, partition, nodes, numNodes, numTasks, _cpuTimeRaw, _timeLimitRaw,] = parts;
206
+ // Skip job steps (e.g. "12345.batch", "12345.0")
207
+ if (jobId.includes('.'))
208
+ continue;
209
+ // Parse exit code "0:0" format
210
+ let exitCode = null;
211
+ if (exitCodeStr) {
212
+ const match = exitCodeStr.match(/^(\d+):/);
213
+ if (match)
214
+ exitCode = parseInt(match[1], 10);
215
+ }
216
+ // Normalize state (sacct can return "CANCELLED by 1000" etc.)
217
+ const normalizedState = normalizeSlurmState(state);
218
+ jobs.push({
219
+ job_id: jobId,
220
+ name: name || null,
221
+ state: normalizedState,
222
+ start_time: startTime && startTime !== 'Unknown' ? parseTimestamp(startTime) : null,
223
+ end_time: endTime && endTime !== 'Unknown' ? parseTimestamp(endTime) : null,
224
+ exit_code: exitCode,
225
+ partition: partition || null,
226
+ nodes: nodes || null,
227
+ num_nodes: numNodes ? parseInt(numNodes, 10) || null : null,
228
+ num_tasks: numTasks ? parseInt(numTasks, 10) || null : null,
229
+ });
230
+ }
231
+ return jobs;
232
+ }
233
+ // ── Session correlation ──────────────────────────────────
234
+ upsertWithSessionCorrelation(job) {
235
+ if (!job.job_id)
236
+ return;
237
+ // If job already has a session_id, keep it
238
+ const existing = this.db.getJob(job.job_id);
239
+ if (existing?.session_id) {
240
+ this.db.upsertJob(job);
241
+ return;
242
+ }
243
+ // Try to correlate with an active LabGate session
244
+ const sessionId = this.findMatchingSession(job);
245
+ if (sessionId) {
246
+ job.session_id = sessionId;
247
+ }
248
+ this.db.upsertJob(job);
249
+ }
250
+ findMatchingSession(job) {
251
+ try {
252
+ const sessionsDir = (0, config_js_1.getSessionsDir)();
253
+ if (!(0, fs_1.existsSync)(sessionsDir))
254
+ return null;
255
+ const files = (0, fs_1.readdirSync)(sessionsDir).filter(f => f.endsWith('.json'));
256
+ let bestMatch = null;
257
+ for (const file of files) {
258
+ try {
259
+ const raw = (0, fs_1.readFileSync)((0, path_1.join)(sessionsDir, file), 'utf-8');
260
+ const session = JSON.parse(raw);
261
+ if (session?.node && session.node !== this.localHost) {
262
+ continue;
263
+ }
264
+ if (typeof session?.pid !== 'number') {
265
+ continue;
266
+ }
267
+ // Session must have started before the job was submitted
268
+ if (job.submit_time && session.started && new Date(session.started) > new Date(job.submit_time)) {
269
+ continue;
270
+ }
271
+ // Check if the session PID is still alive
272
+ try {
273
+ process.kill(session.pid, 0);
274
+ }
275
+ catch {
276
+ continue; // Session is dead
277
+ }
278
+ let score = 1;
279
+ // Prefer sessions whose workdir matches the job workdir
280
+ if (job.workdir && session.workdir && job.workdir.startsWith(session.workdir)) {
281
+ score += 10;
282
+ }
283
+ if (!bestMatch || score > bestMatch.score) {
284
+ bestMatch = { id: session.id, score };
285
+ }
286
+ }
287
+ catch {
288
+ continue;
289
+ }
290
+ }
291
+ return bestMatch?.id ?? null;
292
+ }
293
+ catch {
294
+ return null;
295
+ }
296
+ }
297
+ // ── Output file stat ─────────────────────────────────────
298
+ updateOutputFileStats() {
299
+ const activeIds = this.db.getActiveJobIds();
300
+ // Also check recently completed jobs (state changed in last poll)
301
+ const jobs = this.db.listJobs({ limit: 200 });
302
+ for (const job of jobs) {
303
+ let changed = false;
304
+ if (job.stdout_path) {
305
+ try {
306
+ const st = (0, fs_1.statSync)(job.stdout_path);
307
+ if (job.stdout_size !== st.size) {
308
+ changed = true;
309
+ }
310
+ }
311
+ catch {
312
+ // File doesn't exist yet or is inaccessible
313
+ }
314
+ }
315
+ if (job.stderr_path) {
316
+ try {
317
+ const st = (0, fs_1.statSync)(job.stderr_path);
318
+ if (job.stderr_size !== st.size) {
319
+ changed = true;
320
+ }
321
+ }
322
+ catch { }
323
+ }
324
+ if (changed || activeIds.includes(job.job_id)) {
325
+ const update = { job_id: job.job_id };
326
+ if (job.stdout_path) {
327
+ try {
328
+ update.stdout_size = (0, fs_1.statSync)(job.stdout_path).size;
329
+ }
330
+ catch {
331
+ update.stdout_size = null;
332
+ }
333
+ }
334
+ if (job.stderr_path) {
335
+ try {
336
+ update.stderr_size = (0, fs_1.statSync)(job.stderr_path).size;
337
+ }
338
+ catch {
339
+ update.stderr_size = null;
340
+ }
341
+ }
342
+ this.db.upsertJob(update);
343
+ }
344
+ }
345
+ }
346
+ // ── Helpers ──────────────────────────────────────────────
347
+ exec(cmd, args) {
348
+ return new Promise((resolve, reject) => {
349
+ (0, child_process_1.execFile)(cmd, args, { timeout: 10_000 }, (err, stdout, stderr) => {
350
+ if (err) {
351
+ reject(new Error(`${cmd} failed: ${err.message}${stderr ? ` (${stderr.trim()})` : ''}`));
352
+ }
353
+ else {
354
+ resolve(stdout);
355
+ }
356
+ });
357
+ });
358
+ }
359
+ }
360
+ exports.SlurmPoller = SlurmPoller;
361
+ // ── Utility functions ─────────────────────────────────────
362
+ function parseTimestamp(ts) {
363
+ if (!ts || ts === 'N/A' || ts === 'Unknown')
364
+ return new Date().toISOString();
365
+ // SLURM timestamps are typically YYYY-MM-DDTHH:MM:SS
366
+ const d = new Date(ts);
367
+ return isNaN(d.getTime()) ? new Date().toISOString() : d.toISOString();
368
+ }
369
+ function normalizeSlurmState(state) {
370
+ const raw = String(state ?? 'UNKNOWN').trim().toUpperCase();
371
+ const token = raw.split(/\s+/)[0].replace(/\+$/, '');
372
+ if (token.startsWith('CANCELLED'))
373
+ return 'CANCELLED';
374
+ if (token === 'PENDING')
375
+ return 'PENDING';
376
+ if (token === 'RUNNING')
377
+ return 'RUNNING';
378
+ if (token === 'COMPLETING')
379
+ return 'COMPLETING';
380
+ if (token === 'COMPLETED')
381
+ return 'COMPLETED';
382
+ if (token === 'FAILED')
383
+ return 'FAILED';
384
+ if (token === 'TIMEOUT')
385
+ return 'TIMEOUT';
386
+ if (token === 'NODE_FAIL')
387
+ return 'NODE_FAIL';
388
+ if (token === 'PREEMPTED')
389
+ return 'PREEMPTED';
390
+ if (token === 'OUT_OF_MEMORY')
391
+ return 'OUT_OF_MEMORY';
392
+ if (token === 'SUSPENDED')
393
+ return 'SUSPENDED';
394
+ return 'UNKNOWN';
395
+ }
396
+ function toIsoTimestamp(value, fallback) {
397
+ if (value === null || value === undefined || value === '' || value === 'N/A' || value === 'Unknown') {
398
+ return fallback;
399
+ }
400
+ if (typeof value === 'number' && value <= 0) {
401
+ return fallback;
402
+ }
403
+ const parsed = typeof value === 'number'
404
+ ? new Date(value > 1_000_000_000_000 ? value : value * 1000)
405
+ : new Date(String(value));
406
+ if (isNaN(parsed.getTime())) {
407
+ return fallback;
408
+ }
409
+ return parsed.toISOString();
410
+ }
411
+ function formatTimelimit(minutes) {
412
+ if (typeof minutes === 'string')
413
+ return minutes;
414
+ const m = typeof minutes === 'object' ? minutes.number : minutes;
415
+ if (!m || m <= 0)
416
+ return 'UNLIMITED';
417
+ const h = Math.floor(m / 60);
418
+ const min = m % 60;
419
+ if (h > 0)
420
+ return `${h}:${String(min).padStart(2, '0')}:00`;
421
+ return `${min}:00`;
422
+ }
423
+ //# sourceMappingURL=slurm-poller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slurm-poller.js","sourceRoot":"","sources":["../../src/lib/slurm-poller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ import { ChildProcess } from 'child_process';
2
+ export interface ChildHandle {
3
+ proc: ChildProcess;
4
+ stdout: string;
5
+ stderr: string;
6
+ }
7
+ export interface SessionRecord {
8
+ id: string;
9
+ agent: string;
10
+ workdir: string;
11
+ node: string;
12
+ pid: number;
13
+ }
14
+ export interface SessionsResponse {
15
+ sessions: SessionRecord[];
16
+ }
17
+ export declare function waitFor<T>(producer: () => Promise<T | null>, timeoutMs?: number, intervalMs?: number): Promise<T>;
18
+ export declare function stopProcess(handle: ChildHandle | null): Promise<void>;
19
+ export declare class DashboardIntegrationHarness {
20
+ readonly repoDir: string;
21
+ tempRoot: string;
22
+ homeDir: string;
23
+ workdir: string;
24
+ port: number;
25
+ env: NodeJS.ProcessEnv;
26
+ ui: ChildHandle | null;
27
+ accessToken: string;
28
+ writeToken: string;
29
+ private readonly agents;
30
+ constructor(repoDir: string);
31
+ setup(): Promise<void>;
32
+ teardown(): Promise<void>;
33
+ startAgent(agent: 'claude' | 'codex'): Promise<ChildHandle>;
34
+ stopAgent(handle: ChildHandle | null): Promise<void>;
35
+ stopAllAgents(): Promise<void>;
36
+ fetchSessions(): Promise<SessionsResponse>;
37
+ waitForSession(agent: 'claude' | 'codex', timeoutMs?: number): Promise<SessionRecord>;
38
+ waitForNoSessions(timeoutMs?: number): Promise<void>;
39
+ stopSessionViaApi(id: string): Promise<{
40
+ ok: boolean;
41
+ error?: string;
42
+ }>;
43
+ waitForProcessExit(handle: ChildHandle, timeoutMs?: number): Promise<void>;
44
+ }