labgate 0.5.40 → 0.5.42
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/README.md +132 -265
- package/dist/cli.js +9 -33
- package/dist/cli.js.map +1 -1
- package/dist/lib/config.d.ts +18 -3
- package/dist/lib/config.js +151 -80
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/container.d.ts +11 -9
- package/dist/lib/container.js +753 -302
- package/dist/lib/container.js.map +1 -1
- package/dist/lib/dataset-mcp.js +2 -9
- package/dist/lib/dataset-mcp.js.map +1 -1
- package/dist/lib/display-mcp.d.ts +2 -2
- package/dist/lib/display-mcp.js +17 -38
- package/dist/lib/display-mcp.js.map +1 -1
- package/dist/lib/doctor.js +8 -0
- package/dist/lib/doctor.js.map +1 -1
- package/dist/lib/explorer-claude.js +36 -1
- package/dist/lib/explorer-claude.js.map +1 -1
- package/dist/lib/explorer-eval.js +3 -2
- package/dist/lib/explorer-eval.js.map +1 -1
- package/dist/lib/init.js +14 -18
- package/dist/lib/init.js.map +1 -1
- package/dist/lib/slurm-cli-passthrough.d.ts +12 -2
- package/dist/lib/slurm-cli-passthrough.js +401 -143
- package/dist/lib/slurm-cli-passthrough.js.map +1 -1
- package/dist/lib/startup-stage-lock.d.ts +21 -0
- package/dist/lib/startup-stage-lock.js +196 -0
- package/dist/lib/startup-stage-lock.js.map +1 -0
- package/dist/lib/ui.d.ts +40 -0
- package/dist/lib/ui.html +4953 -3366
- package/dist/lib/ui.js +1749 -295
- package/dist/lib/ui.js.map +1 -1
- package/dist/lib/web-terminal-startup-readiness.d.ts +8 -0
- package/dist/lib/web-terminal-startup-readiness.js +29 -0
- package/dist/lib/web-terminal-startup-readiness.js.map +1 -0
- package/dist/lib/web-terminal.d.ts +51 -0
- package/dist/lib/web-terminal.js +171 -1
- package/dist/lib/web-terminal.js.map +1 -1
- package/dist/mcp-bundles/dataset-mcp.bundle.mjs +125 -74
- package/dist/mcp-bundles/display-mcp.bundle.mjs +22 -30
- package/dist/mcp-bundles/explorer-mcp.bundle.mjs +211 -106
- package/dist/mcp-bundles/results-mcp.bundle.mjs +22 -24
- package/dist/mcp-bundles/slurm-mcp.bundle.mjs +6 -8
- package/package.json +1 -1
|
@@ -7209,6 +7209,7 @@ __export(config_exports, {
|
|
|
7209
7209
|
LABGATE_DIR: () => LABGATE_DIR,
|
|
7210
7210
|
PRIVATE_DIR_MODE: () => PRIVATE_DIR_MODE,
|
|
7211
7211
|
PRIVATE_FILE_MODE: () => PRIVATE_FILE_MODE,
|
|
7212
|
+
buildConfigFromRaw: () => buildConfigFromRaw,
|
|
7212
7213
|
ensurePrivateDir: () => ensurePrivateDir,
|
|
7213
7214
|
ensurePrivateFile: () => ensurePrivateFile,
|
|
7214
7215
|
findLockedFieldConflicts: () => findLockedFieldConflicts,
|
|
@@ -7236,11 +7237,15 @@ __export(config_exports, {
|
|
|
7236
7237
|
isKnownPluginId: () => isKnownPluginId,
|
|
7237
7238
|
loadConfig: () => loadConfig,
|
|
7238
7239
|
loadEffectiveConfig: () => loadEffectiveConfig,
|
|
7240
|
+
parseRawConfigText: () => parseRawConfigText,
|
|
7241
|
+
readRawConfigFile: () => readRawConfigFile,
|
|
7239
7242
|
shouldClaudeHeadlessRunWithAllowedPermissions: () => shouldClaudeHeadlessRunWithAllowedPermissions,
|
|
7240
|
-
|
|
7243
|
+
stripJsonComments: () => stripJsonComments,
|
|
7244
|
+
validateConfig: () => validateConfig,
|
|
7245
|
+
writeRawConfigFile: () => writeRawConfigFile
|
|
7241
7246
|
});
|
|
7242
|
-
import { readFileSync as readFileSync3, existsSync as existsSync3, chmodSync, mkdirSync } from "fs";
|
|
7243
|
-
import { join as join3, resolve } from "path";
|
|
7247
|
+
import { readFileSync as readFileSync3, existsSync as existsSync3, chmodSync, mkdirSync, writeFileSync as writeFileSync2 } from "fs";
|
|
7248
|
+
import { dirname as dirname2, join as join3, resolve } from "path";
|
|
7244
7249
|
import { homedir as homedir3 } from "os";
|
|
7245
7250
|
function isKnownPluginId(pluginId) {
|
|
7246
7251
|
return KNOWN_PLUGIN_ID_SET.has(pluginId);
|
|
@@ -7255,6 +7260,12 @@ function sanitizePluginMap(rawPlugins) {
|
|
|
7255
7260
|
}
|
|
7256
7261
|
return merged;
|
|
7257
7262
|
}
|
|
7263
|
+
function resolveImagesDirOverride(raw) {
|
|
7264
|
+
if (typeof raw !== "string") return null;
|
|
7265
|
+
const trimmed = raw.trim();
|
|
7266
|
+
if (!trimmed) return null;
|
|
7267
|
+
return resolve(trimmed.replace(/^~/, homedir3()));
|
|
7268
|
+
}
|
|
7258
7269
|
function ensurePrivateDir(path) {
|
|
7259
7270
|
mkdirSync(path, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
7260
7271
|
try {
|
|
@@ -7278,14 +7289,15 @@ function getSandboxHome() {
|
|
|
7278
7289
|
return join3(LABGATE_DIR, "ai-home");
|
|
7279
7290
|
}
|
|
7280
7291
|
function getImagesDir() {
|
|
7281
|
-
const
|
|
7282
|
-
if (
|
|
7283
|
-
|
|
7284
|
-
|
|
7292
|
+
const envOverride = resolveImagesDirOverride(process.env.LABGATE_IMAGES_DIR);
|
|
7293
|
+
if (envOverride) return envOverride;
|
|
7294
|
+
const configOverride = resolveImagesDirOverride(loadConfig().images_dir);
|
|
7295
|
+
if (configOverride) return configOverride;
|
|
7285
7296
|
return join3(LABGATE_DIR, "images");
|
|
7286
7297
|
}
|
|
7287
7298
|
function isImagesDirOverridden() {
|
|
7288
|
-
|
|
7299
|
+
if (resolveImagesDirOverride(process.env.LABGATE_IMAGES_DIR)) return true;
|
|
7300
|
+
return resolveImagesDirOverride(loadConfig().images_dir) !== null;
|
|
7289
7301
|
}
|
|
7290
7302
|
function getEmptyDir() {
|
|
7291
7303
|
return join3(LABGATE_DIR, "empty");
|
|
@@ -7335,12 +7347,104 @@ function getExplorerLockDir(experimentId) {
|
|
|
7335
7347
|
function getExplorerWorktreesDir(experimentId) {
|
|
7336
7348
|
return join3(getExplorerWorktreesRootDir(), experimentId);
|
|
7337
7349
|
}
|
|
7338
|
-
function shouldClaudeHeadlessRunWithAllowedPermissions(
|
|
7339
|
-
return
|
|
7350
|
+
function shouldClaudeHeadlessRunWithAllowedPermissions(_config) {
|
|
7351
|
+
return false;
|
|
7340
7352
|
}
|
|
7341
7353
|
function cloneConfig(config2) {
|
|
7342
7354
|
return JSON.parse(JSON.stringify(config2));
|
|
7343
7355
|
}
|
|
7356
|
+
function normalizeLegacyRuntime(rawRuntime, warnOnLegacyRuntime) {
|
|
7357
|
+
if (rawRuntime === "docker") {
|
|
7358
|
+
if (warnOnLegacyRuntime) {
|
|
7359
|
+
console.error('Warning: runtime "docker" is deprecated. Using "podman".');
|
|
7360
|
+
}
|
|
7361
|
+
return "podman";
|
|
7362
|
+
}
|
|
7363
|
+
if (rawRuntime === "singularity") {
|
|
7364
|
+
if (warnOnLegacyRuntime) {
|
|
7365
|
+
console.error('Warning: runtime "singularity" is deprecated. Using "apptainer".');
|
|
7366
|
+
}
|
|
7367
|
+
return "apptainer";
|
|
7368
|
+
}
|
|
7369
|
+
return rawRuntime;
|
|
7370
|
+
}
|
|
7371
|
+
function stripJsonComments(rawText) {
|
|
7372
|
+
return rawText.split("\n").filter((line) => !line.trimStart().startsWith("//")).join("\n");
|
|
7373
|
+
}
|
|
7374
|
+
function parseRawConfigText(rawText) {
|
|
7375
|
+
const stripped = stripJsonComments(rawText).trim();
|
|
7376
|
+
if (!stripped) return {};
|
|
7377
|
+
const parsed = JSON.parse(stripped);
|
|
7378
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
7379
|
+
throw new Error("Config root must be a JSON object");
|
|
7380
|
+
}
|
|
7381
|
+
return parsed;
|
|
7382
|
+
}
|
|
7383
|
+
function buildConfigFromRaw(rawInput, options = {}) {
|
|
7384
|
+
const raw = rawInput;
|
|
7385
|
+
const runtime = normalizeLegacyRuntime(
|
|
7386
|
+
raw.runtime,
|
|
7387
|
+
options.warnOnLegacyRuntime ?? false
|
|
7388
|
+
);
|
|
7389
|
+
return {
|
|
7390
|
+
runtime: runtime ?? DEFAULT_CONFIG.runtime,
|
|
7391
|
+
images_dir: raw.images_dir ?? DEFAULT_CONFIG.images_dir,
|
|
7392
|
+
image: raw.image ?? DEFAULT_CONFIG.image,
|
|
7393
|
+
session_timeout_hours: raw.session_timeout_hours ?? DEFAULT_CONFIG.session_timeout_hours,
|
|
7394
|
+
filesystem: {
|
|
7395
|
+
extra_paths: raw.filesystem?.extra_paths ?? [...DEFAULT_CONFIG.filesystem.extra_paths],
|
|
7396
|
+
blocked_patterns: raw.filesystem?.blocked_patterns ?? [...DEFAULT_CONFIG.filesystem.blocked_patterns]
|
|
7397
|
+
},
|
|
7398
|
+
datasets: Array.isArray(raw.datasets) ? raw.datasets : [],
|
|
7399
|
+
commands: {
|
|
7400
|
+
blacklist: raw.commands?.blacklist ?? [...DEFAULT_CONFIG.commands.blacklist],
|
|
7401
|
+
ensure_commands: raw.commands?.ensure_commands ?? [...DEFAULT_CONFIG.commands.ensure_commands ?? []]
|
|
7402
|
+
},
|
|
7403
|
+
network: {
|
|
7404
|
+
mode: raw.network?.mode ?? DEFAULT_CONFIG.network.mode,
|
|
7405
|
+
allowed_domains: raw.network?.allowed_domains ?? [...DEFAULT_CONFIG.network.allowed_domains]
|
|
7406
|
+
},
|
|
7407
|
+
slurm: {
|
|
7408
|
+
enabled: raw.slurm?.enabled ?? DEFAULT_CONFIG.slurm.enabled,
|
|
7409
|
+
poll_interval_seconds: raw.slurm?.poll_interval_seconds ?? DEFAULT_CONFIG.slurm.poll_interval_seconds,
|
|
7410
|
+
sacct_lookback_hours: raw.slurm?.sacct_lookback_hours ?? DEFAULT_CONFIG.slurm.sacct_lookback_hours,
|
|
7411
|
+
mcp_server: raw.slurm?.mcp_server ?? DEFAULT_CONFIG.slurm.mcp_server
|
|
7412
|
+
},
|
|
7413
|
+
audit: {
|
|
7414
|
+
enabled: raw.audit?.enabled ?? DEFAULT_CONFIG.audit.enabled,
|
|
7415
|
+
log_dir: raw.audit?.log_dir ?? DEFAULT_CONFIG.audit.log_dir
|
|
7416
|
+
},
|
|
7417
|
+
automation: {
|
|
7418
|
+
api_key: raw.automation?.api_key ?? DEFAULT_CONFIG.automation?.api_key,
|
|
7419
|
+
model: raw.automation?.model ?? DEFAULT_CONFIG.automation.model,
|
|
7420
|
+
system_prompt: raw.automation?.system_prompt ?? DEFAULT_CONFIG.automation.system_prompt,
|
|
7421
|
+
trigger_patterns: raw.automation?.trigger_patterns ?? [...DEFAULT_CONFIG.automation.trigger_patterns],
|
|
7422
|
+
context_lines: raw.automation?.context_lines ?? DEFAULT_CONFIG.automation.context_lines,
|
|
7423
|
+
delay_ms: raw.automation?.delay_ms ?? DEFAULT_CONFIG.automation.delay_ms,
|
|
7424
|
+
max_turns: raw.automation?.max_turns ?? DEFAULT_CONFIG.automation.max_turns,
|
|
7425
|
+
max_tokens: raw.automation?.max_tokens ?? DEFAULT_CONFIG.automation.max_tokens
|
|
7426
|
+
},
|
|
7427
|
+
headless: {
|
|
7428
|
+
claude_run_with_allowed_permissions: raw.headless?.claude_run_with_allowed_permissions ?? DEFAULT_CONFIG.headless?.claude_run_with_allowed_permissions ?? false,
|
|
7429
|
+
continuation_in_other_terminals: raw.headless?.continuation_in_other_terminals ?? DEFAULT_CONFIG.headless?.continuation_in_other_terminals ?? true,
|
|
7430
|
+
git_integration: raw.headless?.git_integration ?? DEFAULT_CONFIG.headless?.git_integration ?? false
|
|
7431
|
+
},
|
|
7432
|
+
plugins: sanitizePluginMap(raw.plugins)
|
|
7433
|
+
};
|
|
7434
|
+
}
|
|
7435
|
+
function readRawConfigFile(configPath = getConfigPath()) {
|
|
7436
|
+
if (!existsSync3(configPath)) return {};
|
|
7437
|
+
ensurePrivateFile(configPath);
|
|
7438
|
+
return parseRawConfigText(readFileSync3(configPath, "utf-8"));
|
|
7439
|
+
}
|
|
7440
|
+
function writeRawConfigFile(rawConfig, configPath = getConfigPath()) {
|
|
7441
|
+
ensurePrivateDir(dirname2(configPath));
|
|
7442
|
+
writeFileSync2(configPath, JSON.stringify(rawConfig, null, 2) + "\n", {
|
|
7443
|
+
encoding: "utf-8",
|
|
7444
|
+
mode: PRIVATE_FILE_MODE
|
|
7445
|
+
});
|
|
7446
|
+
ensurePrivateFile(configPath);
|
|
7447
|
+
}
|
|
7344
7448
|
function validateConfig(config2) {
|
|
7345
7449
|
const errors = [];
|
|
7346
7450
|
const networkMode = config2.network?.mode;
|
|
@@ -7348,11 +7452,15 @@ function validateConfig(config2) {
|
|
|
7348
7452
|
const blockedPatterns = config2.filesystem?.blocked_patterns;
|
|
7349
7453
|
const extraPaths = config2.filesystem?.extra_paths;
|
|
7350
7454
|
const blacklist = config2.commands?.blacklist;
|
|
7455
|
+
const ensureCommands = config2.commands?.ensure_commands;
|
|
7351
7456
|
const plugins = config2.plugins;
|
|
7352
7457
|
const headless = config2.headless;
|
|
7353
7458
|
if (!VALID_RUNTIMES2.includes(config2.runtime)) {
|
|
7354
7459
|
errors.push(`Invalid runtime: "${config2.runtime}". Must be one of: ${VALID_RUNTIMES2.join(", ")}`);
|
|
7355
7460
|
}
|
|
7461
|
+
if (config2.images_dir !== void 0 && typeof config2.images_dir !== "string") {
|
|
7462
|
+
errors.push("images_dir must be a string");
|
|
7463
|
+
}
|
|
7356
7464
|
if (!config2.image || typeof config2.image !== "string") {
|
|
7357
7465
|
errors.push("image must be a non-empty string");
|
|
7358
7466
|
}
|
|
@@ -7374,6 +7482,22 @@ function validateConfig(config2) {
|
|
|
7374
7482
|
if (!Array.isArray(blacklist)) {
|
|
7375
7483
|
errors.push("commands.blacklist must be an array");
|
|
7376
7484
|
}
|
|
7485
|
+
if (ensureCommands !== void 0) {
|
|
7486
|
+
if (!Array.isArray(ensureCommands)) {
|
|
7487
|
+
errors.push("commands.ensure_commands must be an array");
|
|
7488
|
+
} else {
|
|
7489
|
+
for (let i = 0; i < ensureCommands.length; i++) {
|
|
7490
|
+
const command = ensureCommands[i];
|
|
7491
|
+
if (typeof command !== "string" || !command.trim()) {
|
|
7492
|
+
errors.push(`commands.ensure_commands[${i}] must be a non-empty string`);
|
|
7493
|
+
} else if (!/^[a-zA-Z0-9._+-]+$/.test(command)) {
|
|
7494
|
+
errors.push(
|
|
7495
|
+
`commands.ensure_commands[${i}] contains invalid characters; use letters, digits, ., _, +, - only`
|
|
7496
|
+
);
|
|
7497
|
+
}
|
|
7498
|
+
}
|
|
7499
|
+
}
|
|
7500
|
+
}
|
|
7377
7501
|
if (plugins !== void 0) {
|
|
7378
7502
|
if (!plugins || typeof plugins !== "object" || Array.isArray(plugins)) {
|
|
7379
7503
|
errors.push("plugins must be an object");
|
|
@@ -7500,61 +7624,8 @@ function loadConfig() {
|
|
|
7500
7624
|
}
|
|
7501
7625
|
ensurePrivateFile(configPath);
|
|
7502
7626
|
try {
|
|
7503
|
-
const
|
|
7504
|
-
const
|
|
7505
|
-
const raw = JSON.parse(stripped);
|
|
7506
|
-
const rawRuntime = raw.runtime;
|
|
7507
|
-
let runtime = rawRuntime;
|
|
7508
|
-
if (rawRuntime === "docker") {
|
|
7509
|
-
runtime = "podman";
|
|
7510
|
-
console.error('Warning: runtime "docker" is deprecated. Using "podman".');
|
|
7511
|
-
} else if (rawRuntime === "singularity") {
|
|
7512
|
-
runtime = "apptainer";
|
|
7513
|
-
console.error('Warning: runtime "singularity" is deprecated. Using "apptainer".');
|
|
7514
|
-
}
|
|
7515
|
-
const config2 = {
|
|
7516
|
-
runtime: runtime ?? DEFAULT_CONFIG.runtime,
|
|
7517
|
-
image: raw.image ?? DEFAULT_CONFIG.image,
|
|
7518
|
-
session_timeout_hours: raw.session_timeout_hours ?? DEFAULT_CONFIG.session_timeout_hours,
|
|
7519
|
-
filesystem: {
|
|
7520
|
-
extra_paths: raw.filesystem?.extra_paths ?? [...DEFAULT_CONFIG.filesystem.extra_paths],
|
|
7521
|
-
blocked_patterns: raw.filesystem?.blocked_patterns ?? [...DEFAULT_CONFIG.filesystem.blocked_patterns]
|
|
7522
|
-
},
|
|
7523
|
-
datasets: Array.isArray(raw.datasets) ? raw.datasets : [],
|
|
7524
|
-
commands: {
|
|
7525
|
-
blacklist: raw.commands?.blacklist ?? [...DEFAULT_CONFIG.commands.blacklist]
|
|
7526
|
-
},
|
|
7527
|
-
network: {
|
|
7528
|
-
mode: raw.network?.mode ?? DEFAULT_CONFIG.network.mode,
|
|
7529
|
-
allowed_domains: raw.network?.allowed_domains ?? [...DEFAULT_CONFIG.network.allowed_domains]
|
|
7530
|
-
},
|
|
7531
|
-
slurm: {
|
|
7532
|
-
enabled: raw.slurm?.enabled ?? DEFAULT_CONFIG.slurm.enabled,
|
|
7533
|
-
poll_interval_seconds: raw.slurm?.poll_interval_seconds ?? DEFAULT_CONFIG.slurm.poll_interval_seconds,
|
|
7534
|
-
sacct_lookback_hours: raw.slurm?.sacct_lookback_hours ?? DEFAULT_CONFIG.slurm.sacct_lookback_hours,
|
|
7535
|
-
mcp_server: raw.slurm?.mcp_server ?? DEFAULT_CONFIG.slurm.mcp_server
|
|
7536
|
-
},
|
|
7537
|
-
audit: {
|
|
7538
|
-
enabled: raw.audit?.enabled ?? DEFAULT_CONFIG.audit.enabled,
|
|
7539
|
-
log_dir: raw.audit?.log_dir ?? DEFAULT_CONFIG.audit.log_dir
|
|
7540
|
-
},
|
|
7541
|
-
automation: {
|
|
7542
|
-
api_key: raw.automation?.api_key ?? DEFAULT_CONFIG.automation?.api_key,
|
|
7543
|
-
model: raw.automation?.model ?? DEFAULT_CONFIG.automation.model,
|
|
7544
|
-
system_prompt: raw.automation?.system_prompt ?? DEFAULT_CONFIG.automation.system_prompt,
|
|
7545
|
-
trigger_patterns: raw.automation?.trigger_patterns ?? [...DEFAULT_CONFIG.automation.trigger_patterns],
|
|
7546
|
-
context_lines: raw.automation?.context_lines ?? DEFAULT_CONFIG.automation.context_lines,
|
|
7547
|
-
delay_ms: raw.automation?.delay_ms ?? DEFAULT_CONFIG.automation.delay_ms,
|
|
7548
|
-
max_turns: raw.automation?.max_turns ?? DEFAULT_CONFIG.automation.max_turns,
|
|
7549
|
-
max_tokens: raw.automation?.max_tokens ?? DEFAULT_CONFIG.automation.max_tokens
|
|
7550
|
-
},
|
|
7551
|
-
headless: {
|
|
7552
|
-
claude_run_with_allowed_permissions: raw.headless?.claude_run_with_allowed_permissions ?? DEFAULT_CONFIG.headless?.claude_run_with_allowed_permissions ?? true,
|
|
7553
|
-
continuation_in_other_terminals: raw.headless?.continuation_in_other_terminals ?? DEFAULT_CONFIG.headless?.continuation_in_other_terminals ?? true,
|
|
7554
|
-
git_integration: raw.headless?.git_integration ?? DEFAULT_CONFIG.headless?.git_integration ?? false
|
|
7555
|
-
},
|
|
7556
|
-
plugins: sanitizePluginMap(raw.plugins)
|
|
7557
|
-
};
|
|
7627
|
+
const raw = readRawConfigFile(configPath);
|
|
7628
|
+
const config2 = buildConfigFromRaw(raw, { warnOnLegacyRuntime: true });
|
|
7558
7629
|
const errors = validateConfig(config2);
|
|
7559
7630
|
if (errors.length > 0) {
|
|
7560
7631
|
console.error(`Warning: invalid config in ${configPath}:`);
|
|
@@ -7631,6 +7702,7 @@ var init_config = __esm({
|
|
|
7631
7702
|
"use strict";
|
|
7632
7703
|
DEFAULT_CONFIG = {
|
|
7633
7704
|
runtime: "auto",
|
|
7705
|
+
images_dir: "",
|
|
7634
7706
|
// Default sandbox image: includes python3 + basic build tools (git/make/g++).
|
|
7635
7707
|
// Note: pip/venv are not included by default in Debian; users may still need a
|
|
7636
7708
|
// custom image for richer Python workflows.
|
|
@@ -7663,7 +7735,8 @@ var init_config = __esm({
|
|
|
7663
7735
|
"mkfs",
|
|
7664
7736
|
"reboot",
|
|
7665
7737
|
"shutdown"
|
|
7666
|
-
]
|
|
7738
|
+
],
|
|
7739
|
+
ensure_commands: ["git"]
|
|
7667
7740
|
},
|
|
7668
7741
|
network: {
|
|
7669
7742
|
mode: "host",
|
|
@@ -7689,13 +7762,9 @@ var init_config = __esm({
|
|
|
7689
7762
|
},
|
|
7690
7763
|
plugins: {
|
|
7691
7764
|
files: true,
|
|
7765
|
+
activity: true,
|
|
7692
7766
|
datasets: false,
|
|
7693
7767
|
results: false,
|
|
7694
|
-
charting: true,
|
|
7695
|
-
molecular: true,
|
|
7696
|
-
genomics: true,
|
|
7697
|
-
phylogenetics: true,
|
|
7698
|
-
network: true,
|
|
7699
7768
|
slurm: true,
|
|
7700
7769
|
explorer: true,
|
|
7701
7770
|
automation: false
|
|
@@ -7716,7 +7785,7 @@ var init_config = __esm({
|
|
|
7716
7785
|
max_tokens: 1024
|
|
7717
7786
|
},
|
|
7718
7787
|
headless: {
|
|
7719
|
-
claude_run_with_allowed_permissions:
|
|
7788
|
+
claude_run_with_allowed_permissions: false,
|
|
7720
7789
|
continuation_in_other_terminals: true,
|
|
7721
7790
|
git_integration: false
|
|
7722
7791
|
}
|
|
@@ -36397,14 +36466,14 @@ var StdioServerTransport = class {
|
|
|
36397
36466
|
|
|
36398
36467
|
// src/lib/explorer-mcp.ts
|
|
36399
36468
|
init_config();
|
|
36400
|
-
import { mkdirSync as mkdirSync10, writeFileSync as
|
|
36469
|
+
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9 } from "fs";
|
|
36401
36470
|
import { join as join11 } from "path";
|
|
36402
36471
|
|
|
36403
36472
|
// src/lib/explorer-store.ts
|
|
36404
36473
|
init_config();
|
|
36405
36474
|
import { randomUUID } from "crypto";
|
|
36406
|
-
import { chmodSync as chmodSync2, existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as
|
|
36407
|
-
import { dirname as
|
|
36475
|
+
import { chmodSync as chmodSync2, existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
36476
|
+
import { dirname as dirname3 } from "path";
|
|
36408
36477
|
|
|
36409
36478
|
// src/lib/explorer-retention.ts
|
|
36410
36479
|
var DEFAULT_RETENTION_POLICY = {
|
|
@@ -36642,7 +36711,7 @@ function mapEventRow(row) {
|
|
|
36642
36711
|
var ExplorerStore = class {
|
|
36643
36712
|
constructor(dbPath = getExplorerDbPath()) {
|
|
36644
36713
|
this.dbPath = dbPath;
|
|
36645
|
-
const dir =
|
|
36714
|
+
const dir = dirname3(dbPath);
|
|
36646
36715
|
if (!existsSync4(dir)) {
|
|
36647
36716
|
mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
36648
36717
|
}
|
|
@@ -37293,7 +37362,7 @@ var ExplorerStore = class {
|
|
|
37293
37362
|
flushJson() {
|
|
37294
37363
|
if (!this.jsonPath) return;
|
|
37295
37364
|
try {
|
|
37296
|
-
|
|
37365
|
+
writeFileSync3(this.jsonPath, JSON.stringify(this.jsonStore, null, 2) + "\n", {
|
|
37297
37366
|
encoding: "utf-8",
|
|
37298
37367
|
mode: 384
|
|
37299
37368
|
});
|
|
@@ -37308,7 +37377,7 @@ var ExplorerStore = class {
|
|
|
37308
37377
|
|
|
37309
37378
|
// src/lib/explorer-git.ts
|
|
37310
37379
|
import { existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
37311
|
-
import { dirname as
|
|
37380
|
+
import { dirname as dirname4, resolve as resolve2 } from "path";
|
|
37312
37381
|
import { execFileSync, spawnSync } from "child_process";
|
|
37313
37382
|
function runGit(args, cwd) {
|
|
37314
37383
|
return execFileSync("git", args, {
|
|
@@ -37353,7 +37422,7 @@ function resolveGitSha(repoPath, ref = "HEAD") {
|
|
|
37353
37422
|
function cloneRepository(sourceRepoPath, targetRepoPath) {
|
|
37354
37423
|
const source = resolve2(sourceRepoPath);
|
|
37355
37424
|
const target = resolve2(targetRepoPath);
|
|
37356
|
-
const targetParent =
|
|
37425
|
+
const targetParent = dirname4(target);
|
|
37357
37426
|
if (!existsSync5(targetParent)) {
|
|
37358
37427
|
mkdirSync3(targetParent, { recursive: true, mode: 448 });
|
|
37359
37428
|
}
|
|
@@ -37369,7 +37438,7 @@ function createRunWorkspace(repoPath, worktreePath, parentSha, experimentId, run
|
|
|
37369
37438
|
const expPart = sanitizeBranchPart(experimentId) || "exp";
|
|
37370
37439
|
const runPart = sanitizeBranchPart(runId) || "run";
|
|
37371
37440
|
const branchName = `explorer/${expPart}/${runPart}`;
|
|
37372
|
-
const parentDir =
|
|
37441
|
+
const parentDir = dirname4(fullWorktree);
|
|
37373
37442
|
if (!existsSync5(parentDir)) {
|
|
37374
37443
|
mkdirSync3(parentDir, { recursive: true, mode: 448 });
|
|
37375
37444
|
}
|
|
@@ -37438,7 +37507,7 @@ function cleanupWorkspace(repoPath, worktreePath, branchName) {
|
|
|
37438
37507
|
}
|
|
37439
37508
|
|
|
37440
37509
|
// src/lib/explorer-eval.ts
|
|
37441
|
-
import { mkdirSync as mkdirSync4, writeFileSync as
|
|
37510
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
37442
37511
|
import { join as join4, resolve as resolve3 } from "path";
|
|
37443
37512
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
37444
37513
|
function parseLastNonEmptyLine(text) {
|
|
@@ -37453,13 +37522,13 @@ function shellForCurrentPlatform() {
|
|
|
37453
37522
|
if (process.platform === "win32") {
|
|
37454
37523
|
return process.env.COMSPEC || "cmd.exe";
|
|
37455
37524
|
}
|
|
37456
|
-
return
|
|
37525
|
+
return "/bin/sh";
|
|
37457
37526
|
}
|
|
37458
37527
|
function shellArgsForCommand(command) {
|
|
37459
37528
|
if (process.platform === "win32") {
|
|
37460
37529
|
return ["/d", "/s", "/c", command];
|
|
37461
37530
|
}
|
|
37462
|
-
return ["-
|
|
37531
|
+
return ["-c", command];
|
|
37463
37532
|
}
|
|
37464
37533
|
function runEvaluation(opts) {
|
|
37465
37534
|
const worktreePath = resolve3(opts.worktree_path);
|
|
@@ -37482,8 +37551,8 @@ function runEvaluation(opts) {
|
|
|
37482
37551
|
const finishedAt = new Date(started + runtimeMs).toISOString();
|
|
37483
37552
|
const stdout = String(result.stdout || "");
|
|
37484
37553
|
const stderr = String(result.stderr || "");
|
|
37485
|
-
|
|
37486
|
-
|
|
37554
|
+
writeFileSync4(stdoutPath, stdout, "utf-8");
|
|
37555
|
+
writeFileSync4(stderrPath, stderr, "utf-8");
|
|
37487
37556
|
if (result.error && (result.error.code === "ETIMEDOUT" || result.signal === "SIGTERM")) {
|
|
37488
37557
|
return {
|
|
37489
37558
|
status: "timeout",
|
|
@@ -37597,13 +37666,13 @@ import { join as join10, resolve as resolve7 } from "path";
|
|
|
37597
37666
|
|
|
37598
37667
|
// src/lib/explorer-autopilot.ts
|
|
37599
37668
|
init_config();
|
|
37600
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync7, writeFileSync as
|
|
37669
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
37601
37670
|
import { join as join7, resolve as resolve5 } from "path";
|
|
37602
37671
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
37603
37672
|
|
|
37604
37673
|
// src/lib/explorer-lock.ts
|
|
37605
37674
|
init_config();
|
|
37606
|
-
import { closeSync, mkdirSync as mkdirSync5, openSync, readFileSync as readFileSync5, unlinkSync, writeFileSync as
|
|
37675
|
+
import { closeSync, mkdirSync as mkdirSync5, openSync, readFileSync as readFileSync5, unlinkSync, writeFileSync as writeFileSync5 } from "fs";
|
|
37607
37676
|
import { join as join5 } from "path";
|
|
37608
37677
|
function parseLockPid(raw) {
|
|
37609
37678
|
const firstLine = raw.split(/\r?\n/, 1)[0] || "";
|
|
@@ -37654,7 +37723,7 @@ function acquireExperimentLock(experimentId, lockName = "autopilot.lock") {
|
|
|
37654
37723
|
return null;
|
|
37655
37724
|
}
|
|
37656
37725
|
try {
|
|
37657
|
-
|
|
37726
|
+
writeFileSync5(fd, `${process.pid}
|
|
37658
37727
|
`, { encoding: "utf-8" });
|
|
37659
37728
|
} catch (err) {
|
|
37660
37729
|
try {
|
|
@@ -37684,12 +37753,13 @@ function acquireExperimentLock(experimentId, lockName = "autopilot.lock") {
|
|
|
37684
37753
|
|
|
37685
37754
|
// src/lib/explorer-claude.ts
|
|
37686
37755
|
init_config();
|
|
37687
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync6, writeFileSync as
|
|
37688
|
-
import { basename, dirname as
|
|
37756
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync6, writeFileSync as writeFileSync6 } from "fs";
|
|
37757
|
+
import { basename, dirname as dirname5, join as join6, resolve as resolve4 } from "path";
|
|
37689
37758
|
import { homedir as homedir4 } from "os";
|
|
37690
37759
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
37691
37760
|
|
|
37692
37761
|
// src/lib/container.ts
|
|
37762
|
+
import { randomBytes as randomBytes2, createHash } from "crypto";
|
|
37693
37763
|
var import_fast_glob = __toESM(require_out4());
|
|
37694
37764
|
init_config();
|
|
37695
37765
|
|
|
@@ -37918,9 +37988,16 @@ init_config();
|
|
|
37918
37988
|
// src/lib/slurm-cli-passthrough.ts
|
|
37919
37989
|
init_config();
|
|
37920
37990
|
|
|
37991
|
+
// src/lib/startup-stage-lock.ts
|
|
37992
|
+
var DEFAULT_STAGE_LOCK_WAIT_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
37993
|
+
var DEFAULT_STAGE_LOCK_STALE_AFTER_MS = 15 * 60 * 1e3;
|
|
37994
|
+
|
|
37921
37995
|
// src/lib/container.ts
|
|
37922
37996
|
function imageToSifName(image) {
|
|
37923
|
-
|
|
37997
|
+
const normalized = String(image || "").trim();
|
|
37998
|
+
const readable = normalized.replace(/[^a-zA-Z0-9._-]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 160) || "image";
|
|
37999
|
+
const hash2 = createHash("sha256").update(normalized).digest("hex").slice(0, 12);
|
|
38000
|
+
return `${readable}-${hash2}.sif`;
|
|
37924
38001
|
}
|
|
37925
38002
|
|
|
37926
38003
|
// src/lib/explorer-claude.ts
|
|
@@ -38080,12 +38157,37 @@ function runApptainer(args, cwd, timeoutSec) {
|
|
|
38080
38157
|
function ensureDisplayDbFile() {
|
|
38081
38158
|
const displayDbPath = getDisplayDbPath();
|
|
38082
38159
|
if (existsSync6(displayDbPath)) return;
|
|
38083
|
-
ensurePrivateDir(
|
|
38084
|
-
|
|
38160
|
+
ensurePrivateDir(dirname5(displayDbPath));
|
|
38161
|
+
writeFileSync6(displayDbPath, JSON.stringify({ version: 1, events: [] }, null, 2) + "\n", {
|
|
38085
38162
|
encoding: "utf-8",
|
|
38086
38163
|
mode: PRIVATE_FILE_MODE
|
|
38087
38164
|
});
|
|
38088
38165
|
}
|
|
38166
|
+
function buildClaudeHeadlessAddDirArgs(config2) {
|
|
38167
|
+
const dirs = /* @__PURE__ */ new Set();
|
|
38168
|
+
let hasExtraMounts = false;
|
|
38169
|
+
let hasDatasets = false;
|
|
38170
|
+
for (const mount of config2.filesystem.extra_paths || []) {
|
|
38171
|
+
if (!mount || typeof mount.path !== "string") continue;
|
|
38172
|
+
const resolved = mount.path.replace(/^~/, homedir4());
|
|
38173
|
+
const target = `/mnt/${basename(resolved)}`;
|
|
38174
|
+
hasExtraMounts = true;
|
|
38175
|
+
dirs.add(target);
|
|
38176
|
+
}
|
|
38177
|
+
for (const ds of config2.datasets || []) {
|
|
38178
|
+
if (!ds || typeof ds.name !== "string") continue;
|
|
38179
|
+
const name = ds.name.trim();
|
|
38180
|
+
if (!name) continue;
|
|
38181
|
+
hasDatasets = true;
|
|
38182
|
+
dirs.add(`/datasets/${name}`);
|
|
38183
|
+
}
|
|
38184
|
+
if (hasExtraMounts) dirs.add("/mnt");
|
|
38185
|
+
if (hasDatasets) dirs.add("/datasets");
|
|
38186
|
+
return Array.from(dirs).flatMap((dir) => ["--add-dir", dir]);
|
|
38187
|
+
}
|
|
38188
|
+
function buildClaudeHeadlessAllowedToolsArgs() {
|
|
38189
|
+
return ["--allowed-tools", "Glob,Read,Grep,WebFetch"];
|
|
38190
|
+
}
|
|
38089
38191
|
function buildContainerPrefixArgs(config2, worktreePath, sifPath) {
|
|
38090
38192
|
const sandboxHome = getSandboxHome();
|
|
38091
38193
|
const args = [
|
|
@@ -38181,7 +38283,8 @@ function normalizeTimeout(raw) {
|
|
|
38181
38283
|
return Math.max(30, Math.min(4 * 60 * 60, Math.floor(parsed)));
|
|
38182
38284
|
}
|
|
38183
38285
|
function runClaudeHeadlessInWorktree(input) {
|
|
38184
|
-
const
|
|
38286
|
+
const worktreePathRaw = String(input.worktree_path || "").trim();
|
|
38287
|
+
const worktreePath = worktreePathRaw ? resolve4(worktreePathRaw) : "";
|
|
38185
38288
|
const prompt = String(input.prompt || "").trim();
|
|
38186
38289
|
const resumeSessionId = String(input.resume_session_id || "").trim();
|
|
38187
38290
|
const timeoutSec = normalizeTimeout(input.timeout_sec);
|
|
@@ -38210,6 +38313,8 @@ function runClaudeHeadlessInWorktree(input) {
|
|
|
38210
38313
|
"--output-format",
|
|
38211
38314
|
"stream-json",
|
|
38212
38315
|
"--include-partial-messages",
|
|
38316
|
+
...buildClaudeHeadlessAddDirArgs(config2),
|
|
38317
|
+
...buildClaudeHeadlessAllowedToolsArgs(),
|
|
38213
38318
|
...shouldClaudeHeadlessRunWithAllowedPermissions(config2) ? ["--dangerously-skip-permissions"] : [],
|
|
38214
38319
|
...resumeSessionId ? ["--resume", resumeSessionId] : [],
|
|
38215
38320
|
prompt
|
|
@@ -38517,13 +38622,13 @@ function writeAgentDebugArtifacts(artifactDir, debug) {
|
|
|
38517
38622
|
if (!debug) return;
|
|
38518
38623
|
try {
|
|
38519
38624
|
if (debug.activity_log) {
|
|
38520
|
-
|
|
38625
|
+
writeFileSync7(join7(artifactDir, "agent.log"), debug.activity_log, "utf-8");
|
|
38521
38626
|
}
|
|
38522
38627
|
if (debug.stdout) {
|
|
38523
|
-
|
|
38628
|
+
writeFileSync7(join7(artifactDir, "claude.stdout.log"), debug.stdout, "utf-8");
|
|
38524
38629
|
}
|
|
38525
38630
|
if (debug.stderr) {
|
|
38526
|
-
|
|
38631
|
+
writeFileSync7(join7(artifactDir, "claude.stderr.log"), debug.stderr, "utf-8");
|
|
38527
38632
|
}
|
|
38528
38633
|
} catch {
|
|
38529
38634
|
}
|
|
@@ -38570,7 +38675,7 @@ function recoverStaleActiveRuns(experimentId, store, staleAfterSec) {
|
|
|
38570
38675
|
].join("\n");
|
|
38571
38676
|
try {
|
|
38572
38677
|
mkdirSync7(run.artifact_dir, { recursive: true, mode: 448 });
|
|
38573
|
-
|
|
38678
|
+
writeFileSync7(join7(run.artifact_dir, "summary.md"), summary, "utf-8");
|
|
38574
38679
|
} catch {
|
|
38575
38680
|
}
|
|
38576
38681
|
const updated = store.recordRunResult(run.id, {
|
|
@@ -38694,7 +38799,7 @@ function autopilotTick(input) {
|
|
|
38694
38799
|
writeAgentDebugArtifacts(artifactDir, agentResult.debug);
|
|
38695
38800
|
if (!agentResult.ok) {
|
|
38696
38801
|
const summary2 = buildSummary(run.id, parentScore, "failed_build", null, "", agentResult.error, agentResult.error);
|
|
38697
|
-
|
|
38802
|
+
writeFileSync7(join7(artifactDir, "summary.md"), summary2, "utf-8");
|
|
38698
38803
|
store.recordRunResult(run.id, {
|
|
38699
38804
|
status: "failed_build",
|
|
38700
38805
|
metrics_json: JSON.stringify(agentResult.metrics || {}),
|
|
@@ -38710,7 +38815,7 @@ function autopilotTick(input) {
|
|
|
38710
38815
|
}
|
|
38711
38816
|
store.recordRunCommit(run.id, agentResult.commit_sha);
|
|
38712
38817
|
const diffText = getDiff(experiment.repo_path, parent.parent_commit_sha, agentResult.commit_sha);
|
|
38713
|
-
|
|
38818
|
+
writeFileSync7(join7(artifactDir, "diff.patch"), diffText, "utf-8");
|
|
38714
38819
|
const evalResult = runEvaluation({
|
|
38715
38820
|
worktree_path: workspace.worktree_path,
|
|
38716
38821
|
eval_command: experiment.eval_command,
|
|
@@ -38731,7 +38836,7 @@ function autopilotTick(input) {
|
|
|
38731
38836
|
stderr_path: evalResult.stderr_path,
|
|
38732
38837
|
error: evalResult.error || null
|
|
38733
38838
|
};
|
|
38734
|
-
|
|
38839
|
+
writeFileSync7(join7(artifactDir, "eval.json"), JSON.stringify(evalPayload, null, 2) + "\n", "utf-8");
|
|
38735
38840
|
const runStatus = evalResult.status;
|
|
38736
38841
|
const runScore = Number.isFinite(evalResult.score) ? Number(evalResult.score) : null;
|
|
38737
38842
|
const mergedMetrics = {
|
|
@@ -38747,7 +38852,7 @@ function autopilotTick(input) {
|
|
|
38747
38852
|
evalResult.error,
|
|
38748
38853
|
agentResult.note
|
|
38749
38854
|
);
|
|
38750
|
-
|
|
38855
|
+
writeFileSync7(join7(artifactDir, "summary.md"), summary, "utf-8");
|
|
38751
38856
|
store.recordRunResult(run.id, {
|
|
38752
38857
|
status: runStatus,
|
|
38753
38858
|
score: runScore,
|
|
@@ -38789,7 +38894,7 @@ function autopilotTick(input) {
|
|
|
38789
38894
|
if (inFlightArtifactDir) {
|
|
38790
38895
|
try {
|
|
38791
38896
|
mkdirSync7(inFlightArtifactDir, { recursive: true, mode: 448 });
|
|
38792
|
-
|
|
38897
|
+
writeFileSync7(join7(inFlightArtifactDir, "summary.md"), summary, "utf-8");
|
|
38793
38898
|
} catch {
|
|
38794
38899
|
}
|
|
38795
38900
|
}
|
|
@@ -39090,7 +39195,7 @@ function experimentGc(experimentId, store, options) {
|
|
|
39090
39195
|
// src/lib/explorer-compare.ts
|
|
39091
39196
|
init_config();
|
|
39092
39197
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
39093
|
-
import { mkdirSync as mkdirSync8, writeFileSync as
|
|
39198
|
+
import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
39094
39199
|
import { join as join9 } from "path";
|
|
39095
39200
|
function runGit2(repoPath, args) {
|
|
39096
39201
|
return String(execFileSync3("git", ["-C", repoPath, ...args], {
|
|
@@ -39215,7 +39320,7 @@ function runCompare(input, store) {
|
|
|
39215
39320
|
const safeB = (bRunId || "base").replace(/[^a-zA-Z0-9._-]+/g, "_");
|
|
39216
39321
|
const target = join9(compareDir, `${aRun.id}_vs_${safeB}.patch`);
|
|
39217
39322
|
const patchText = runGit2(experiment.repo_path, ["diff", "--binary", `${bCommitSha}..${aRun.commit_sha}`]);
|
|
39218
|
-
|
|
39323
|
+
writeFileSync8(target, patchText, "utf-8");
|
|
39219
39324
|
patchPath = target;
|
|
39220
39325
|
}
|
|
39221
39326
|
const aMetrics = parseMetrics(aRun.metrics_json);
|
|
@@ -39551,7 +39656,7 @@ function runExperimentBaselineInit(experimentId, store) {
|
|
|
39551
39656
|
error: baseline.error || null
|
|
39552
39657
|
};
|
|
39553
39658
|
mkdirSync10(artifactDir, { recursive: true, mode: 448 });
|
|
39554
|
-
|
|
39659
|
+
writeFileSync9(join11(artifactDir, "eval.json"), JSON.stringify(evalPayload, null, 2) + "\n", "utf-8");
|
|
39555
39660
|
store.createEvent(experiment.id, "note", {
|
|
39556
39661
|
message: "experiment initialized with baseline evaluation",
|
|
39557
39662
|
status: baseline.status,
|