labgate 0.5.39 → 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 -248
- package/dist/cli.js +9 -33
- package/dist/cli.js.map +1 -1
- package/dist/lib/config.d.ts +19 -3
- package/dist/lib/config.js +154 -75
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/container.d.ts +11 -9
- package/dist/lib/container.js +749 -282
- 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/image-pull-lock.d.ts +18 -0
- package/dist/lib/image-pull-lock.js +167 -0
- package/dist/lib/image-pull-lock.js.map +1 -0
- package/dist/lib/init.js +22 -19
- 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 +1771 -297
- 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 +144 -93
- package/dist/mcp-bundles/display-mcp.bundle.mjs +35 -43
- package/dist/mcp-bundles/explorer-mcp.bundle.mjs +263 -146
- package/dist/mcp-bundles/results-mcp.bundle.mjs +39 -41
- package/dist/mcp-bundles/slurm-mcp.bundle.mjs +19 -21
- package/package.json +1 -1
|
@@ -2989,7 +2989,7 @@ var require_compile = __commonJS({
|
|
|
2989
2989
|
const schOrFunc = root.refs[ref];
|
|
2990
2990
|
if (schOrFunc)
|
|
2991
2991
|
return schOrFunc;
|
|
2992
|
-
let _sch =
|
|
2992
|
+
let _sch = resolve8.call(this, root, ref);
|
|
2993
2993
|
if (_sch === void 0) {
|
|
2994
2994
|
const schema = (_a2 = root.localRefs) === null || _a2 === void 0 ? void 0 : _a2[ref];
|
|
2995
2995
|
const { schemaId } = this.opts;
|
|
@@ -3016,7 +3016,7 @@ var require_compile = __commonJS({
|
|
|
3016
3016
|
function sameSchemaEnv(s1, s2) {
|
|
3017
3017
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
3018
3018
|
}
|
|
3019
|
-
function
|
|
3019
|
+
function resolve8(root, ref) {
|
|
3020
3020
|
let sch;
|
|
3021
3021
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
3022
3022
|
ref = sch;
|
|
@@ -3591,7 +3591,7 @@ var require_fast_uri = __commonJS({
|
|
|
3591
3591
|
}
|
|
3592
3592
|
return uri;
|
|
3593
3593
|
}
|
|
3594
|
-
function
|
|
3594
|
+
function resolve8(baseURI, relativeURI, options) {
|
|
3595
3595
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
3596
3596
|
const resolved = resolveComponent(parse3(baseURI, schemelessOptions), parse3(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
3597
3597
|
schemelessOptions.skipEscape = true;
|
|
@@ -3818,7 +3818,7 @@ var require_fast_uri = __commonJS({
|
|
|
3818
3818
|
var fastUri = {
|
|
3819
3819
|
SCHEMES,
|
|
3820
3820
|
normalize,
|
|
3821
|
-
resolve:
|
|
3821
|
+
resolve: resolve8,
|
|
3822
3822
|
resolveComponent,
|
|
3823
3823
|
equal,
|
|
3824
3824
|
serialize,
|
|
@@ -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,
|
|
@@ -7232,14 +7233,19 @@ __export(config_exports, {
|
|
|
7232
7233
|
getSessionsDir: () => getSessionsDir,
|
|
7233
7234
|
getSlurmDbPath: () => getSlurmDbPath,
|
|
7234
7235
|
getUiSocketPath: () => getUiSocketPath,
|
|
7236
|
+
isImagesDirOverridden: () => isImagesDirOverridden,
|
|
7235
7237
|
isKnownPluginId: () => isKnownPluginId,
|
|
7236
7238
|
loadConfig: () => loadConfig,
|
|
7237
7239
|
loadEffectiveConfig: () => loadEffectiveConfig,
|
|
7240
|
+
parseRawConfigText: () => parseRawConfigText,
|
|
7241
|
+
readRawConfigFile: () => readRawConfigFile,
|
|
7238
7242
|
shouldClaudeHeadlessRunWithAllowedPermissions: () => shouldClaudeHeadlessRunWithAllowedPermissions,
|
|
7239
|
-
|
|
7243
|
+
stripJsonComments: () => stripJsonComments,
|
|
7244
|
+
validateConfig: () => validateConfig,
|
|
7245
|
+
writeRawConfigFile: () => writeRawConfigFile
|
|
7240
7246
|
});
|
|
7241
|
-
import { readFileSync as readFileSync3, existsSync as existsSync3, chmodSync, mkdirSync } from "fs";
|
|
7242
|
-
import { join as join3 } 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";
|
|
7243
7249
|
import { homedir as homedir3 } from "os";
|
|
7244
7250
|
function isKnownPluginId(pluginId) {
|
|
7245
7251
|
return KNOWN_PLUGIN_ID_SET.has(pluginId);
|
|
@@ -7254,6 +7260,12 @@ function sanitizePluginMap(rawPlugins) {
|
|
|
7254
7260
|
}
|
|
7255
7261
|
return merged;
|
|
7256
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
|
+
}
|
|
7257
7269
|
function ensurePrivateDir(path) {
|
|
7258
7270
|
mkdirSync(path, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
7259
7271
|
try {
|
|
@@ -7277,8 +7289,16 @@ function getSandboxHome() {
|
|
|
7277
7289
|
return join3(LABGATE_DIR, "ai-home");
|
|
7278
7290
|
}
|
|
7279
7291
|
function getImagesDir() {
|
|
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;
|
|
7280
7296
|
return join3(LABGATE_DIR, "images");
|
|
7281
7297
|
}
|
|
7298
|
+
function isImagesDirOverridden() {
|
|
7299
|
+
if (resolveImagesDirOverride(process.env.LABGATE_IMAGES_DIR)) return true;
|
|
7300
|
+
return resolveImagesDirOverride(loadConfig().images_dir) !== null;
|
|
7301
|
+
}
|
|
7282
7302
|
function getEmptyDir() {
|
|
7283
7303
|
return join3(LABGATE_DIR, "empty");
|
|
7284
7304
|
}
|
|
@@ -7327,12 +7347,104 @@ function getExplorerLockDir(experimentId) {
|
|
|
7327
7347
|
function getExplorerWorktreesDir(experimentId) {
|
|
7328
7348
|
return join3(getExplorerWorktreesRootDir(), experimentId);
|
|
7329
7349
|
}
|
|
7330
|
-
function shouldClaudeHeadlessRunWithAllowedPermissions(
|
|
7331
|
-
return
|
|
7350
|
+
function shouldClaudeHeadlessRunWithAllowedPermissions(_config) {
|
|
7351
|
+
return false;
|
|
7332
7352
|
}
|
|
7333
7353
|
function cloneConfig(config2) {
|
|
7334
7354
|
return JSON.parse(JSON.stringify(config2));
|
|
7335
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
|
+
}
|
|
7336
7448
|
function validateConfig(config2) {
|
|
7337
7449
|
const errors = [];
|
|
7338
7450
|
const networkMode = config2.network?.mode;
|
|
@@ -7340,11 +7452,15 @@ function validateConfig(config2) {
|
|
|
7340
7452
|
const blockedPatterns = config2.filesystem?.blocked_patterns;
|
|
7341
7453
|
const extraPaths = config2.filesystem?.extra_paths;
|
|
7342
7454
|
const blacklist = config2.commands?.blacklist;
|
|
7455
|
+
const ensureCommands = config2.commands?.ensure_commands;
|
|
7343
7456
|
const plugins = config2.plugins;
|
|
7344
7457
|
const headless = config2.headless;
|
|
7345
7458
|
if (!VALID_RUNTIMES2.includes(config2.runtime)) {
|
|
7346
7459
|
errors.push(`Invalid runtime: "${config2.runtime}". Must be one of: ${VALID_RUNTIMES2.join(", ")}`);
|
|
7347
7460
|
}
|
|
7461
|
+
if (config2.images_dir !== void 0 && typeof config2.images_dir !== "string") {
|
|
7462
|
+
errors.push("images_dir must be a string");
|
|
7463
|
+
}
|
|
7348
7464
|
if (!config2.image || typeof config2.image !== "string") {
|
|
7349
7465
|
errors.push("image must be a non-empty string");
|
|
7350
7466
|
}
|
|
@@ -7366,6 +7482,22 @@ function validateConfig(config2) {
|
|
|
7366
7482
|
if (!Array.isArray(blacklist)) {
|
|
7367
7483
|
errors.push("commands.blacklist must be an array");
|
|
7368
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
|
+
}
|
|
7369
7501
|
if (plugins !== void 0) {
|
|
7370
7502
|
if (!plugins || typeof plugins !== "object" || Array.isArray(plugins)) {
|
|
7371
7503
|
errors.push("plugins must be an object");
|
|
@@ -7492,61 +7624,8 @@ function loadConfig() {
|
|
|
7492
7624
|
}
|
|
7493
7625
|
ensurePrivateFile(configPath);
|
|
7494
7626
|
try {
|
|
7495
|
-
const
|
|
7496
|
-
const
|
|
7497
|
-
const raw = JSON.parse(stripped);
|
|
7498
|
-
const rawRuntime = raw.runtime;
|
|
7499
|
-
let runtime = rawRuntime;
|
|
7500
|
-
if (rawRuntime === "docker") {
|
|
7501
|
-
runtime = "podman";
|
|
7502
|
-
console.error('Warning: runtime "docker" is deprecated. Using "podman".');
|
|
7503
|
-
} else if (rawRuntime === "singularity") {
|
|
7504
|
-
runtime = "apptainer";
|
|
7505
|
-
console.error('Warning: runtime "singularity" is deprecated. Using "apptainer".');
|
|
7506
|
-
}
|
|
7507
|
-
const config2 = {
|
|
7508
|
-
runtime: runtime ?? DEFAULT_CONFIG.runtime,
|
|
7509
|
-
image: raw.image ?? DEFAULT_CONFIG.image,
|
|
7510
|
-
session_timeout_hours: raw.session_timeout_hours ?? DEFAULT_CONFIG.session_timeout_hours,
|
|
7511
|
-
filesystem: {
|
|
7512
|
-
extra_paths: raw.filesystem?.extra_paths ?? [...DEFAULT_CONFIG.filesystem.extra_paths],
|
|
7513
|
-
blocked_patterns: raw.filesystem?.blocked_patterns ?? [...DEFAULT_CONFIG.filesystem.blocked_patterns]
|
|
7514
|
-
},
|
|
7515
|
-
datasets: Array.isArray(raw.datasets) ? raw.datasets : [],
|
|
7516
|
-
commands: {
|
|
7517
|
-
blacklist: raw.commands?.blacklist ?? [...DEFAULT_CONFIG.commands.blacklist]
|
|
7518
|
-
},
|
|
7519
|
-
network: {
|
|
7520
|
-
mode: raw.network?.mode ?? DEFAULT_CONFIG.network.mode,
|
|
7521
|
-
allowed_domains: raw.network?.allowed_domains ?? [...DEFAULT_CONFIG.network.allowed_domains]
|
|
7522
|
-
},
|
|
7523
|
-
slurm: {
|
|
7524
|
-
enabled: raw.slurm?.enabled ?? DEFAULT_CONFIG.slurm.enabled,
|
|
7525
|
-
poll_interval_seconds: raw.slurm?.poll_interval_seconds ?? DEFAULT_CONFIG.slurm.poll_interval_seconds,
|
|
7526
|
-
sacct_lookback_hours: raw.slurm?.sacct_lookback_hours ?? DEFAULT_CONFIG.slurm.sacct_lookback_hours,
|
|
7527
|
-
mcp_server: raw.slurm?.mcp_server ?? DEFAULT_CONFIG.slurm.mcp_server
|
|
7528
|
-
},
|
|
7529
|
-
audit: {
|
|
7530
|
-
enabled: raw.audit?.enabled ?? DEFAULT_CONFIG.audit.enabled,
|
|
7531
|
-
log_dir: raw.audit?.log_dir ?? DEFAULT_CONFIG.audit.log_dir
|
|
7532
|
-
},
|
|
7533
|
-
automation: {
|
|
7534
|
-
api_key: raw.automation?.api_key ?? DEFAULT_CONFIG.automation?.api_key,
|
|
7535
|
-
model: raw.automation?.model ?? DEFAULT_CONFIG.automation.model,
|
|
7536
|
-
system_prompt: raw.automation?.system_prompt ?? DEFAULT_CONFIG.automation.system_prompt,
|
|
7537
|
-
trigger_patterns: raw.automation?.trigger_patterns ?? [...DEFAULT_CONFIG.automation.trigger_patterns],
|
|
7538
|
-
context_lines: raw.automation?.context_lines ?? DEFAULT_CONFIG.automation.context_lines,
|
|
7539
|
-
delay_ms: raw.automation?.delay_ms ?? DEFAULT_CONFIG.automation.delay_ms,
|
|
7540
|
-
max_turns: raw.automation?.max_turns ?? DEFAULT_CONFIG.automation.max_turns,
|
|
7541
|
-
max_tokens: raw.automation?.max_tokens ?? DEFAULT_CONFIG.automation.max_tokens
|
|
7542
|
-
},
|
|
7543
|
-
headless: {
|
|
7544
|
-
claude_run_with_allowed_permissions: raw.headless?.claude_run_with_allowed_permissions ?? DEFAULT_CONFIG.headless?.claude_run_with_allowed_permissions ?? true,
|
|
7545
|
-
continuation_in_other_terminals: raw.headless?.continuation_in_other_terminals ?? DEFAULT_CONFIG.headless?.continuation_in_other_terminals ?? true,
|
|
7546
|
-
git_integration: raw.headless?.git_integration ?? DEFAULT_CONFIG.headless?.git_integration ?? false
|
|
7547
|
-
},
|
|
7548
|
-
plugins: sanitizePluginMap(raw.plugins)
|
|
7549
|
-
};
|
|
7627
|
+
const raw = readRawConfigFile(configPath);
|
|
7628
|
+
const config2 = buildConfigFromRaw(raw, { warnOnLegacyRuntime: true });
|
|
7550
7629
|
const errors = validateConfig(config2);
|
|
7551
7630
|
if (errors.length > 0) {
|
|
7552
7631
|
console.error(`Warning: invalid config in ${configPath}:`);
|
|
@@ -7623,6 +7702,7 @@ var init_config = __esm({
|
|
|
7623
7702
|
"use strict";
|
|
7624
7703
|
DEFAULT_CONFIG = {
|
|
7625
7704
|
runtime: "auto",
|
|
7705
|
+
images_dir: "",
|
|
7626
7706
|
// Default sandbox image: includes python3 + basic build tools (git/make/g++).
|
|
7627
7707
|
// Note: pip/venv are not included by default in Debian; users may still need a
|
|
7628
7708
|
// custom image for richer Python workflows.
|
|
@@ -7655,7 +7735,8 @@ var init_config = __esm({
|
|
|
7655
7735
|
"mkfs",
|
|
7656
7736
|
"reboot",
|
|
7657
7737
|
"shutdown"
|
|
7658
|
-
]
|
|
7738
|
+
],
|
|
7739
|
+
ensure_commands: ["git"]
|
|
7659
7740
|
},
|
|
7660
7741
|
network: {
|
|
7661
7742
|
mode: "host",
|
|
@@ -7681,13 +7762,9 @@ var init_config = __esm({
|
|
|
7681
7762
|
},
|
|
7682
7763
|
plugins: {
|
|
7683
7764
|
files: true,
|
|
7765
|
+
activity: true,
|
|
7684
7766
|
datasets: false,
|
|
7685
7767
|
results: false,
|
|
7686
|
-
charting: true,
|
|
7687
|
-
molecular: true,
|
|
7688
|
-
genomics: true,
|
|
7689
|
-
phylogenetics: true,
|
|
7690
|
-
network: true,
|
|
7691
7768
|
slurm: true,
|
|
7692
7769
|
explorer: true,
|
|
7693
7770
|
automation: false
|
|
@@ -7708,7 +7785,7 @@ var init_config = __esm({
|
|
|
7708
7785
|
max_tokens: 1024
|
|
7709
7786
|
},
|
|
7710
7787
|
headless: {
|
|
7711
|
-
claude_run_with_allowed_permissions:
|
|
7788
|
+
claude_run_with_allowed_permissions: false,
|
|
7712
7789
|
continuation_in_other_terminals: true,
|
|
7713
7790
|
git_integration: false
|
|
7714
7791
|
}
|
|
@@ -12018,41 +12095,41 @@ var require_queue = __commonJS({
|
|
|
12018
12095
|
queue.drained = drained;
|
|
12019
12096
|
return queue;
|
|
12020
12097
|
function push(value) {
|
|
12021
|
-
var p = new Promise(function(
|
|
12098
|
+
var p = new Promise(function(resolve8, reject) {
|
|
12022
12099
|
pushCb(value, function(err, result) {
|
|
12023
12100
|
if (err) {
|
|
12024
12101
|
reject(err);
|
|
12025
12102
|
return;
|
|
12026
12103
|
}
|
|
12027
|
-
|
|
12104
|
+
resolve8(result);
|
|
12028
12105
|
});
|
|
12029
12106
|
});
|
|
12030
12107
|
p.catch(noop);
|
|
12031
12108
|
return p;
|
|
12032
12109
|
}
|
|
12033
12110
|
function unshift(value) {
|
|
12034
|
-
var p = new Promise(function(
|
|
12111
|
+
var p = new Promise(function(resolve8, reject) {
|
|
12035
12112
|
unshiftCb(value, function(err, result) {
|
|
12036
12113
|
if (err) {
|
|
12037
12114
|
reject(err);
|
|
12038
12115
|
return;
|
|
12039
12116
|
}
|
|
12040
|
-
|
|
12117
|
+
resolve8(result);
|
|
12041
12118
|
});
|
|
12042
12119
|
});
|
|
12043
12120
|
p.catch(noop);
|
|
12044
12121
|
return p;
|
|
12045
12122
|
}
|
|
12046
12123
|
function drained() {
|
|
12047
|
-
var p = new Promise(function(
|
|
12124
|
+
var p = new Promise(function(resolve8) {
|
|
12048
12125
|
process.nextTick(function() {
|
|
12049
12126
|
if (queue.idle()) {
|
|
12050
|
-
|
|
12127
|
+
resolve8();
|
|
12051
12128
|
} else {
|
|
12052
12129
|
var previousDrain = queue.drain;
|
|
12053
12130
|
queue.drain = function() {
|
|
12054
12131
|
if (typeof previousDrain === "function") previousDrain();
|
|
12055
|
-
|
|
12132
|
+
resolve8();
|
|
12056
12133
|
queue.drain = previousDrain;
|
|
12057
12134
|
};
|
|
12058
12135
|
}
|
|
@@ -12538,9 +12615,9 @@ var require_stream3 = __commonJS({
|
|
|
12538
12615
|
});
|
|
12539
12616
|
}
|
|
12540
12617
|
_getStat(filepath) {
|
|
12541
|
-
return new Promise((
|
|
12618
|
+
return new Promise((resolve8, reject) => {
|
|
12542
12619
|
this._stat(filepath, this._fsStatSettings, (error49, stats) => {
|
|
12543
|
-
return error49 === null ?
|
|
12620
|
+
return error49 === null ? resolve8(stats) : reject(error49);
|
|
12544
12621
|
});
|
|
12545
12622
|
});
|
|
12546
12623
|
}
|
|
@@ -12564,10 +12641,10 @@ var require_async5 = __commonJS({
|
|
|
12564
12641
|
this._readerStream = new stream_1.default(this._settings);
|
|
12565
12642
|
}
|
|
12566
12643
|
dynamic(root, options) {
|
|
12567
|
-
return new Promise((
|
|
12644
|
+
return new Promise((resolve8, reject) => {
|
|
12568
12645
|
this._walkAsync(root, options, (error49, entries) => {
|
|
12569
12646
|
if (error49 === null) {
|
|
12570
|
-
|
|
12647
|
+
resolve8(entries);
|
|
12571
12648
|
} else {
|
|
12572
12649
|
reject(error49);
|
|
12573
12650
|
}
|
|
@@ -12577,10 +12654,10 @@ var require_async5 = __commonJS({
|
|
|
12577
12654
|
async static(patterns, options) {
|
|
12578
12655
|
const entries = [];
|
|
12579
12656
|
const stream = this._readerStream.static(patterns, options);
|
|
12580
|
-
return new Promise((
|
|
12657
|
+
return new Promise((resolve8, reject) => {
|
|
12581
12658
|
stream.once("error", reject);
|
|
12582
12659
|
stream.on("data", (entry) => entries.push(entry));
|
|
12583
|
-
stream.once("end", () =>
|
|
12660
|
+
stream.once("end", () => resolve8(entries));
|
|
12584
12661
|
});
|
|
12585
12662
|
}
|
|
12586
12663
|
};
|
|
@@ -34413,7 +34490,7 @@ var Protocol = class {
|
|
|
34413
34490
|
return;
|
|
34414
34491
|
}
|
|
34415
34492
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
|
|
34416
|
-
await new Promise((
|
|
34493
|
+
await new Promise((resolve8) => setTimeout(resolve8, pollInterval));
|
|
34417
34494
|
options?.signal?.throwIfAborted();
|
|
34418
34495
|
}
|
|
34419
34496
|
} catch (error49) {
|
|
@@ -34430,7 +34507,7 @@ var Protocol = class {
|
|
|
34430
34507
|
*/
|
|
34431
34508
|
request(request, resultSchema, options) {
|
|
34432
34509
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
34433
|
-
return new Promise((
|
|
34510
|
+
return new Promise((resolve8, reject) => {
|
|
34434
34511
|
const earlyReject = (error49) => {
|
|
34435
34512
|
reject(error49);
|
|
34436
34513
|
};
|
|
@@ -34508,7 +34585,7 @@ var Protocol = class {
|
|
|
34508
34585
|
if (!parseResult.success) {
|
|
34509
34586
|
reject(parseResult.error);
|
|
34510
34587
|
} else {
|
|
34511
|
-
|
|
34588
|
+
resolve8(parseResult.data);
|
|
34512
34589
|
}
|
|
34513
34590
|
} catch (error49) {
|
|
34514
34591
|
reject(error49);
|
|
@@ -34769,12 +34846,12 @@ var Protocol = class {
|
|
|
34769
34846
|
}
|
|
34770
34847
|
} catch {
|
|
34771
34848
|
}
|
|
34772
|
-
return new Promise((
|
|
34849
|
+
return new Promise((resolve8, reject) => {
|
|
34773
34850
|
if (signal.aborted) {
|
|
34774
34851
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
34775
34852
|
return;
|
|
34776
34853
|
}
|
|
34777
|
-
const timeoutId = setTimeout(
|
|
34854
|
+
const timeoutId = setTimeout(resolve8, interval);
|
|
34778
34855
|
signal.addEventListener("abort", () => {
|
|
34779
34856
|
clearTimeout(timeoutId);
|
|
34780
34857
|
reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
|
|
@@ -35733,7 +35810,7 @@ var McpServer = class {
|
|
|
35733
35810
|
let task = createTaskResult.task;
|
|
35734
35811
|
const pollInterval = task.pollInterval ?? 5e3;
|
|
35735
35812
|
while (task.status !== "completed" && task.status !== "failed" && task.status !== "cancelled") {
|
|
35736
|
-
await new Promise((
|
|
35813
|
+
await new Promise((resolve8) => setTimeout(resolve8, pollInterval));
|
|
35737
35814
|
const updatedTask = await extra.taskStore.getTask(taskId);
|
|
35738
35815
|
if (!updatedTask) {
|
|
35739
35816
|
throw new McpError(ErrorCode.InternalError, `Task ${taskId} not found during polling`);
|
|
@@ -36376,12 +36453,12 @@ var StdioServerTransport = class {
|
|
|
36376
36453
|
this.onclose?.();
|
|
36377
36454
|
}
|
|
36378
36455
|
send(message) {
|
|
36379
|
-
return new Promise((
|
|
36456
|
+
return new Promise((resolve8) => {
|
|
36380
36457
|
const json2 = serializeMessage(message);
|
|
36381
36458
|
if (this._stdout.write(json2)) {
|
|
36382
|
-
|
|
36459
|
+
resolve8();
|
|
36383
36460
|
} else {
|
|
36384
|
-
this._stdout.once("drain",
|
|
36461
|
+
this._stdout.once("drain", resolve8);
|
|
36385
36462
|
}
|
|
36386
36463
|
});
|
|
36387
36464
|
}
|
|
@@ -36389,14 +36466,14 @@ var StdioServerTransport = class {
|
|
|
36389
36466
|
|
|
36390
36467
|
// src/lib/explorer-mcp.ts
|
|
36391
36468
|
init_config();
|
|
36392
|
-
import { mkdirSync as mkdirSync10, writeFileSync as
|
|
36469
|
+
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9 } from "fs";
|
|
36393
36470
|
import { join as join11 } from "path";
|
|
36394
36471
|
|
|
36395
36472
|
// src/lib/explorer-store.ts
|
|
36396
36473
|
init_config();
|
|
36397
36474
|
import { randomUUID } from "crypto";
|
|
36398
|
-
import { chmodSync as chmodSync2, existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as
|
|
36399
|
-
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";
|
|
36400
36477
|
|
|
36401
36478
|
// src/lib/explorer-retention.ts
|
|
36402
36479
|
var DEFAULT_RETENTION_POLICY = {
|
|
@@ -36634,7 +36711,7 @@ function mapEventRow(row) {
|
|
|
36634
36711
|
var ExplorerStore = class {
|
|
36635
36712
|
constructor(dbPath = getExplorerDbPath()) {
|
|
36636
36713
|
this.dbPath = dbPath;
|
|
36637
|
-
const dir =
|
|
36714
|
+
const dir = dirname3(dbPath);
|
|
36638
36715
|
if (!existsSync4(dir)) {
|
|
36639
36716
|
mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
36640
36717
|
}
|
|
@@ -37285,7 +37362,7 @@ var ExplorerStore = class {
|
|
|
37285
37362
|
flushJson() {
|
|
37286
37363
|
if (!this.jsonPath) return;
|
|
37287
37364
|
try {
|
|
37288
|
-
|
|
37365
|
+
writeFileSync3(this.jsonPath, JSON.stringify(this.jsonStore, null, 2) + "\n", {
|
|
37289
37366
|
encoding: "utf-8",
|
|
37290
37367
|
mode: 384
|
|
37291
37368
|
});
|
|
@@ -37300,7 +37377,7 @@ var ExplorerStore = class {
|
|
|
37300
37377
|
|
|
37301
37378
|
// src/lib/explorer-git.ts
|
|
37302
37379
|
import { existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
37303
|
-
import { dirname as
|
|
37380
|
+
import { dirname as dirname4, resolve as resolve2 } from "path";
|
|
37304
37381
|
import { execFileSync, spawnSync } from "child_process";
|
|
37305
37382
|
function runGit(args, cwd) {
|
|
37306
37383
|
return execFileSync("git", args, {
|
|
@@ -37332,7 +37409,7 @@ function sanitizeBranchPart(value) {
|
|
|
37332
37409
|
return value.toLowerCase().replace(/[^a-z0-9._/-]+/g, "-").replace(/--+/g, "-").replace(/^-+/, "").replace(/-+$/, "").slice(0, 100);
|
|
37333
37410
|
}
|
|
37334
37411
|
function ensureGitRepository(repoPath) {
|
|
37335
|
-
const full =
|
|
37412
|
+
const full = resolve2(repoPath);
|
|
37336
37413
|
const check2 = runGitStatus(["-C", full, "rev-parse", "--git-dir"]);
|
|
37337
37414
|
if (check2.status !== 0) {
|
|
37338
37415
|
throw new Error(`Not a git repository: ${full}`);
|
|
@@ -37340,20 +37417,20 @@ function ensureGitRepository(repoPath) {
|
|
|
37340
37417
|
}
|
|
37341
37418
|
function resolveGitSha(repoPath, ref = "HEAD") {
|
|
37342
37419
|
ensureGitRepository(repoPath);
|
|
37343
|
-
return runGit(["-C",
|
|
37420
|
+
return runGit(["-C", resolve2(repoPath), "rev-parse", ref]);
|
|
37344
37421
|
}
|
|
37345
37422
|
function cloneRepository(sourceRepoPath, targetRepoPath) {
|
|
37346
|
-
const source =
|
|
37347
|
-
const target =
|
|
37348
|
-
const targetParent =
|
|
37423
|
+
const source = resolve2(sourceRepoPath);
|
|
37424
|
+
const target = resolve2(targetRepoPath);
|
|
37425
|
+
const targetParent = dirname4(target);
|
|
37349
37426
|
if (!existsSync5(targetParent)) {
|
|
37350
37427
|
mkdirSync3(targetParent, { recursive: true, mode: 448 });
|
|
37351
37428
|
}
|
|
37352
37429
|
runGit(["clone", "--quiet", source, target]);
|
|
37353
37430
|
}
|
|
37354
37431
|
function createRunWorkspace(repoPath, worktreePath, parentSha, experimentId, runId) {
|
|
37355
|
-
const fullRepo =
|
|
37356
|
-
const fullWorktree =
|
|
37432
|
+
const fullRepo = resolve2(repoPath);
|
|
37433
|
+
const fullWorktree = resolve2(worktreePath);
|
|
37357
37434
|
const parent = sanitizeBranchPart(parentSha);
|
|
37358
37435
|
if (!parent) {
|
|
37359
37436
|
throw new Error("parentSha is required");
|
|
@@ -37361,7 +37438,7 @@ function createRunWorkspace(repoPath, worktreePath, parentSha, experimentId, run
|
|
|
37361
37438
|
const expPart = sanitizeBranchPart(experimentId) || "exp";
|
|
37362
37439
|
const runPart = sanitizeBranchPart(runId) || "run";
|
|
37363
37440
|
const branchName = `explorer/${expPart}/${runPart}`;
|
|
37364
|
-
const parentDir =
|
|
37441
|
+
const parentDir = dirname4(fullWorktree);
|
|
37365
37442
|
if (!existsSync5(parentDir)) {
|
|
37366
37443
|
mkdirSync3(parentDir, { recursive: true, mode: 448 });
|
|
37367
37444
|
}
|
|
@@ -37372,7 +37449,7 @@ function createRunWorkspace(repoPath, worktreePath, parentSha, experimentId, run
|
|
|
37372
37449
|
};
|
|
37373
37450
|
}
|
|
37374
37451
|
function commitAll(worktreePath, message, opts) {
|
|
37375
|
-
const fullWorktree =
|
|
37452
|
+
const fullWorktree = resolve2(worktreePath);
|
|
37376
37453
|
const commitMessage = message.trim() || "explorer run";
|
|
37377
37454
|
const allowEmpty = opts?.allow_empty === true;
|
|
37378
37455
|
runGit(["-C", fullWorktree, "add", "-A"]);
|
|
@@ -37413,12 +37490,12 @@ ${commitResult.stdout || ""}`.trim();
|
|
|
37413
37490
|
return runGit(["-C", fullWorktree, "rev-parse", "HEAD"]);
|
|
37414
37491
|
}
|
|
37415
37492
|
function getDiff(repoPath, parentSha, commitSha) {
|
|
37416
|
-
const fullRepo =
|
|
37493
|
+
const fullRepo = resolve2(repoPath);
|
|
37417
37494
|
return runGitRaw(["-C", fullRepo, "diff", "--binary", `${parentSha}..${commitSha}`]);
|
|
37418
37495
|
}
|
|
37419
37496
|
function cleanupWorkspace(repoPath, worktreePath, branchName) {
|
|
37420
|
-
const fullRepo =
|
|
37421
|
-
const fullWorktree =
|
|
37497
|
+
const fullRepo = resolve2(repoPath);
|
|
37498
|
+
const fullWorktree = resolve2(worktreePath);
|
|
37422
37499
|
runGit(["-C", fullRepo, "worktree", "remove", "--force", fullWorktree]);
|
|
37423
37500
|
if (branchName && branchName.trim()) {
|
|
37424
37501
|
const branch = branchName.trim();
|
|
@@ -37430,8 +37507,8 @@ function cleanupWorkspace(repoPath, worktreePath, branchName) {
|
|
|
37430
37507
|
}
|
|
37431
37508
|
|
|
37432
37509
|
// src/lib/explorer-eval.ts
|
|
37433
|
-
import { mkdirSync as mkdirSync4, writeFileSync as
|
|
37434
|
-
import { join as join4, resolve as
|
|
37510
|
+
import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
37511
|
+
import { join as join4, resolve as resolve3 } from "path";
|
|
37435
37512
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
37436
37513
|
function parseLastNonEmptyLine(text) {
|
|
37437
37514
|
const lines = text.split(/\r?\n/);
|
|
@@ -37445,17 +37522,17 @@ function shellForCurrentPlatform() {
|
|
|
37445
37522
|
if (process.platform === "win32") {
|
|
37446
37523
|
return process.env.COMSPEC || "cmd.exe";
|
|
37447
37524
|
}
|
|
37448
|
-
return
|
|
37525
|
+
return "/bin/sh";
|
|
37449
37526
|
}
|
|
37450
37527
|
function shellArgsForCommand(command) {
|
|
37451
37528
|
if (process.platform === "win32") {
|
|
37452
37529
|
return ["/d", "/s", "/c", command];
|
|
37453
37530
|
}
|
|
37454
|
-
return ["-
|
|
37531
|
+
return ["-c", command];
|
|
37455
37532
|
}
|
|
37456
37533
|
function runEvaluation(opts) {
|
|
37457
|
-
const worktreePath =
|
|
37458
|
-
const artifactDir =
|
|
37534
|
+
const worktreePath = resolve3(opts.worktree_path);
|
|
37535
|
+
const artifactDir = resolve3(opts.artifact_dir);
|
|
37459
37536
|
const timeoutSec = Number.isFinite(opts.timeout_sec) ? Math.min(86400, Math.max(1, Math.floor(opts.timeout_sec))) : 120;
|
|
37460
37537
|
mkdirSync4(artifactDir, { recursive: true, mode: 448 });
|
|
37461
37538
|
const stdoutPath = join4(artifactDir, "stdout.log");
|
|
@@ -37474,8 +37551,8 @@ function runEvaluation(opts) {
|
|
|
37474
37551
|
const finishedAt = new Date(started + runtimeMs).toISOString();
|
|
37475
37552
|
const stdout = String(result.stdout || "");
|
|
37476
37553
|
const stderr = String(result.stderr || "");
|
|
37477
|
-
|
|
37478
|
-
|
|
37554
|
+
writeFileSync4(stdoutPath, stdout, "utf-8");
|
|
37555
|
+
writeFileSync4(stderrPath, stderr, "utf-8");
|
|
37479
37556
|
if (result.error && (result.error.code === "ETIMEDOUT" || result.signal === "SIGTERM")) {
|
|
37480
37557
|
return {
|
|
37481
37558
|
status: "timeout",
|
|
@@ -37585,17 +37662,17 @@ function runEvaluation(opts) {
|
|
|
37585
37662
|
// src/lib/explorer.ts
|
|
37586
37663
|
init_config();
|
|
37587
37664
|
import { existsSync as existsSync9, mkdirSync as mkdirSync9 } from "fs";
|
|
37588
|
-
import { join as join10, resolve as
|
|
37665
|
+
import { join as join10, resolve as resolve7 } from "path";
|
|
37589
37666
|
|
|
37590
37667
|
// src/lib/explorer-autopilot.ts
|
|
37591
37668
|
init_config();
|
|
37592
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync7, writeFileSync as
|
|
37593
|
-
import { join as join7, resolve as
|
|
37669
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
37670
|
+
import { join as join7, resolve as resolve5 } from "path";
|
|
37594
37671
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
37595
37672
|
|
|
37596
37673
|
// src/lib/explorer-lock.ts
|
|
37597
37674
|
init_config();
|
|
37598
|
-
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";
|
|
37599
37676
|
import { join as join5 } from "path";
|
|
37600
37677
|
function parseLockPid(raw) {
|
|
37601
37678
|
const firstLine = raw.split(/\r?\n/, 1)[0] || "";
|
|
@@ -37646,7 +37723,7 @@ function acquireExperimentLock(experimentId, lockName = "autopilot.lock") {
|
|
|
37646
37723
|
return null;
|
|
37647
37724
|
}
|
|
37648
37725
|
try {
|
|
37649
|
-
|
|
37726
|
+
writeFileSync5(fd, `${process.pid}
|
|
37650
37727
|
`, { encoding: "utf-8" });
|
|
37651
37728
|
} catch (err) {
|
|
37652
37729
|
try {
|
|
@@ -37676,12 +37753,13 @@ function acquireExperimentLock(experimentId, lockName = "autopilot.lock") {
|
|
|
37676
37753
|
|
|
37677
37754
|
// src/lib/explorer-claude.ts
|
|
37678
37755
|
init_config();
|
|
37679
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync6, writeFileSync as
|
|
37680
|
-
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";
|
|
37681
37758
|
import { homedir as homedir4 } from "os";
|
|
37682
37759
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
37683
37760
|
|
|
37684
37761
|
// src/lib/container.ts
|
|
37762
|
+
import { randomBytes as randomBytes2, createHash } from "crypto";
|
|
37685
37763
|
var import_fast_glob = __toESM(require_out4());
|
|
37686
37764
|
init_config();
|
|
37687
37765
|
|
|
@@ -37889,6 +37967,10 @@ function hasCommand(cmd) {
|
|
|
37889
37967
|
}
|
|
37890
37968
|
}
|
|
37891
37969
|
|
|
37970
|
+
// src/lib/image-pull-lock.ts
|
|
37971
|
+
var DEFAULT_PULL_LOCK_WAIT_TIMEOUT_MS = 60 * 60 * 1e3;
|
|
37972
|
+
var DEFAULT_PULL_LOCK_STALE_AFTER_MS = 2 * 60 * 60 * 1e3;
|
|
37973
|
+
|
|
37892
37974
|
// src/lib/audit.ts
|
|
37893
37975
|
init_config();
|
|
37894
37976
|
|
|
@@ -37906,9 +37988,16 @@ init_config();
|
|
|
37906
37988
|
// src/lib/slurm-cli-passthrough.ts
|
|
37907
37989
|
init_config();
|
|
37908
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
|
+
|
|
37909
37995
|
// src/lib/container.ts
|
|
37910
37996
|
function imageToSifName(image) {
|
|
37911
|
-
|
|
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`;
|
|
37912
38001
|
}
|
|
37913
38002
|
|
|
37914
38003
|
// src/lib/explorer-claude.ts
|
|
@@ -38068,12 +38157,37 @@ function runApptainer(args, cwd, timeoutSec) {
|
|
|
38068
38157
|
function ensureDisplayDbFile() {
|
|
38069
38158
|
const displayDbPath = getDisplayDbPath();
|
|
38070
38159
|
if (existsSync6(displayDbPath)) return;
|
|
38071
|
-
ensurePrivateDir(
|
|
38072
|
-
|
|
38160
|
+
ensurePrivateDir(dirname5(displayDbPath));
|
|
38161
|
+
writeFileSync6(displayDbPath, JSON.stringify({ version: 1, events: [] }, null, 2) + "\n", {
|
|
38073
38162
|
encoding: "utf-8",
|
|
38074
38163
|
mode: PRIVATE_FILE_MODE
|
|
38075
38164
|
});
|
|
38076
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
|
+
}
|
|
38077
38191
|
function buildContainerPrefixArgs(config2, worktreePath, sifPath) {
|
|
38078
38192
|
const sandboxHome = getSandboxHome();
|
|
38079
38193
|
const args = [
|
|
@@ -38169,7 +38283,8 @@ function normalizeTimeout(raw) {
|
|
|
38169
38283
|
return Math.max(30, Math.min(4 * 60 * 60, Math.floor(parsed)));
|
|
38170
38284
|
}
|
|
38171
38285
|
function runClaudeHeadlessInWorktree(input) {
|
|
38172
|
-
const
|
|
38286
|
+
const worktreePathRaw = String(input.worktree_path || "").trim();
|
|
38287
|
+
const worktreePath = worktreePathRaw ? resolve4(worktreePathRaw) : "";
|
|
38173
38288
|
const prompt = String(input.prompt || "").trim();
|
|
38174
38289
|
const resumeSessionId = String(input.resume_session_id || "").trim();
|
|
38175
38290
|
const timeoutSec = normalizeTimeout(input.timeout_sec);
|
|
@@ -38198,6 +38313,8 @@ function runClaudeHeadlessInWorktree(input) {
|
|
|
38198
38313
|
"--output-format",
|
|
38199
38314
|
"stream-json",
|
|
38200
38315
|
"--include-partial-messages",
|
|
38316
|
+
...buildClaudeHeadlessAddDirArgs(config2),
|
|
38317
|
+
...buildClaudeHeadlessAllowedToolsArgs(),
|
|
38201
38318
|
...shouldClaudeHeadlessRunWithAllowedPermissions(config2) ? ["--dangerously-skip-permissions"] : [],
|
|
38202
38319
|
...resumeSessionId ? ["--resume", resumeSessionId] : [],
|
|
38203
38320
|
prompt
|
|
@@ -38362,7 +38479,7 @@ function runStubAgent(repoPath, worktreePath, runId, policy) {
|
|
|
38362
38479
|
if (!patchRef) {
|
|
38363
38480
|
return { ok: false, error: "stub agent mode requires policy.stub_patch_file" };
|
|
38364
38481
|
}
|
|
38365
|
-
const patchPath = patchRef.startsWith("/") ? patchRef :
|
|
38482
|
+
const patchPath = patchRef.startsWith("/") ? patchRef : resolve5(repoPath, patchRef);
|
|
38366
38483
|
if (!existsSync7(patchPath)) {
|
|
38367
38484
|
return { ok: false, error: `stub patch file not found: ${patchPath}` };
|
|
38368
38485
|
}
|
|
@@ -38505,13 +38622,13 @@ function writeAgentDebugArtifacts(artifactDir, debug) {
|
|
|
38505
38622
|
if (!debug) return;
|
|
38506
38623
|
try {
|
|
38507
38624
|
if (debug.activity_log) {
|
|
38508
|
-
|
|
38625
|
+
writeFileSync7(join7(artifactDir, "agent.log"), debug.activity_log, "utf-8");
|
|
38509
38626
|
}
|
|
38510
38627
|
if (debug.stdout) {
|
|
38511
|
-
|
|
38628
|
+
writeFileSync7(join7(artifactDir, "claude.stdout.log"), debug.stdout, "utf-8");
|
|
38512
38629
|
}
|
|
38513
38630
|
if (debug.stderr) {
|
|
38514
|
-
|
|
38631
|
+
writeFileSync7(join7(artifactDir, "claude.stderr.log"), debug.stderr, "utf-8");
|
|
38515
38632
|
}
|
|
38516
38633
|
} catch {
|
|
38517
38634
|
}
|
|
@@ -38558,7 +38675,7 @@ function recoverStaleActiveRuns(experimentId, store, staleAfterSec) {
|
|
|
38558
38675
|
].join("\n");
|
|
38559
38676
|
try {
|
|
38560
38677
|
mkdirSync7(run.artifact_dir, { recursive: true, mode: 448 });
|
|
38561
|
-
|
|
38678
|
+
writeFileSync7(join7(run.artifact_dir, "summary.md"), summary, "utf-8");
|
|
38562
38679
|
} catch {
|
|
38563
38680
|
}
|
|
38564
38681
|
const updated = store.recordRunResult(run.id, {
|
|
@@ -38682,7 +38799,7 @@ function autopilotTick(input) {
|
|
|
38682
38799
|
writeAgentDebugArtifacts(artifactDir, agentResult.debug);
|
|
38683
38800
|
if (!agentResult.ok) {
|
|
38684
38801
|
const summary2 = buildSummary(run.id, parentScore, "failed_build", null, "", agentResult.error, agentResult.error);
|
|
38685
|
-
|
|
38802
|
+
writeFileSync7(join7(artifactDir, "summary.md"), summary2, "utf-8");
|
|
38686
38803
|
store.recordRunResult(run.id, {
|
|
38687
38804
|
status: "failed_build",
|
|
38688
38805
|
metrics_json: JSON.stringify(agentResult.metrics || {}),
|
|
@@ -38698,7 +38815,7 @@ function autopilotTick(input) {
|
|
|
38698
38815
|
}
|
|
38699
38816
|
store.recordRunCommit(run.id, agentResult.commit_sha);
|
|
38700
38817
|
const diffText = getDiff(experiment.repo_path, parent.parent_commit_sha, agentResult.commit_sha);
|
|
38701
|
-
|
|
38818
|
+
writeFileSync7(join7(artifactDir, "diff.patch"), diffText, "utf-8");
|
|
38702
38819
|
const evalResult = runEvaluation({
|
|
38703
38820
|
worktree_path: workspace.worktree_path,
|
|
38704
38821
|
eval_command: experiment.eval_command,
|
|
@@ -38719,7 +38836,7 @@ function autopilotTick(input) {
|
|
|
38719
38836
|
stderr_path: evalResult.stderr_path,
|
|
38720
38837
|
error: evalResult.error || null
|
|
38721
38838
|
};
|
|
38722
|
-
|
|
38839
|
+
writeFileSync7(join7(artifactDir, "eval.json"), JSON.stringify(evalPayload, null, 2) + "\n", "utf-8");
|
|
38723
38840
|
const runStatus = evalResult.status;
|
|
38724
38841
|
const runScore = Number.isFinite(evalResult.score) ? Number(evalResult.score) : null;
|
|
38725
38842
|
const mergedMetrics = {
|
|
@@ -38735,7 +38852,7 @@ function autopilotTick(input) {
|
|
|
38735
38852
|
evalResult.error,
|
|
38736
38853
|
agentResult.note
|
|
38737
38854
|
);
|
|
38738
|
-
|
|
38855
|
+
writeFileSync7(join7(artifactDir, "summary.md"), summary, "utf-8");
|
|
38739
38856
|
store.recordRunResult(run.id, {
|
|
38740
38857
|
status: runStatus,
|
|
38741
38858
|
score: runScore,
|
|
@@ -38777,7 +38894,7 @@ function autopilotTick(input) {
|
|
|
38777
38894
|
if (inFlightArtifactDir) {
|
|
38778
38895
|
try {
|
|
38779
38896
|
mkdirSync7(inFlightArtifactDir, { recursive: true, mode: 448 });
|
|
38780
|
-
|
|
38897
|
+
writeFileSync7(join7(inFlightArtifactDir, "summary.md"), summary, "utf-8");
|
|
38781
38898
|
} catch {
|
|
38782
38899
|
}
|
|
38783
38900
|
}
|
|
@@ -38818,7 +38935,7 @@ function autopilotTick(input) {
|
|
|
38818
38935
|
|
|
38819
38936
|
// src/lib/explorer-gc.ts
|
|
38820
38937
|
import { existsSync as existsSync8, readdirSync, statSync as statSync3, unlinkSync as unlinkSync2, rmSync } from "fs";
|
|
38821
|
-
import { join as join8, resolve as
|
|
38938
|
+
import { join as join8, resolve as resolve6 } from "path";
|
|
38822
38939
|
var FAILED_STATUSES = /* @__PURE__ */ new Set([
|
|
38823
38940
|
"failed_build",
|
|
38824
38941
|
"failed_eval",
|
|
@@ -38868,7 +38985,7 @@ function safeSize(path) {
|
|
|
38868
38985
|
}
|
|
38869
38986
|
}
|
|
38870
38987
|
function computeArtifactPlan(run, mode) {
|
|
38871
|
-
const artifactDir =
|
|
38988
|
+
const artifactDir = resolve6(run.artifact_dir);
|
|
38872
38989
|
const files = listFilesRecursive(artifactDir);
|
|
38873
38990
|
const keepBasenames = mode === "minimal" ? /* @__PURE__ */ new Set(["eval.json", "summary.md", "diff.patch", "agent.log"]) : mode === "none" ? /* @__PURE__ */ new Set(["eval.json", "summary.md"]) : /* @__PURE__ */ new Set();
|
|
38874
38991
|
const keepPaths = [];
|
|
@@ -39078,7 +39195,7 @@ function experimentGc(experimentId, store, options) {
|
|
|
39078
39195
|
// src/lib/explorer-compare.ts
|
|
39079
39196
|
init_config();
|
|
39080
39197
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
39081
|
-
import { mkdirSync as mkdirSync8, writeFileSync as
|
|
39198
|
+
import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
39082
39199
|
import { join as join9 } from "path";
|
|
39083
39200
|
function runGit2(repoPath, args) {
|
|
39084
39201
|
return String(execFileSync3("git", ["-C", repoPath, ...args], {
|
|
@@ -39203,7 +39320,7 @@ function runCompare(input, store) {
|
|
|
39203
39320
|
const safeB = (bRunId || "base").replace(/[^a-zA-Z0-9._-]+/g, "_");
|
|
39204
39321
|
const target = join9(compareDir, `${aRun.id}_vs_${safeB}.patch`);
|
|
39205
39322
|
const patchText = runGit2(experiment.repo_path, ["diff", "--binary", `${bCommitSha}..${aRun.commit_sha}`]);
|
|
39206
|
-
|
|
39323
|
+
writeFileSync8(target, patchText, "utf-8");
|
|
39207
39324
|
patchPath = target;
|
|
39208
39325
|
}
|
|
39209
39326
|
const aMetrics = parseMetrics(aRun.metrics_json);
|
|
@@ -39275,7 +39392,7 @@ function createExplorerExperiment(options, store) {
|
|
|
39275
39392
|
const db = store || new ExplorerStore();
|
|
39276
39393
|
try {
|
|
39277
39394
|
ensureExplorerDirs();
|
|
39278
|
-
const sourceRepoPath =
|
|
39395
|
+
const sourceRepoPath = resolve7(options.source_repo_path);
|
|
39279
39396
|
ensureGitRepository(sourceRepoPath);
|
|
39280
39397
|
const experimentId = makeExplorerExperimentId();
|
|
39281
39398
|
const repoPath = join10(getExplorerReposDir(), experimentId, "repo");
|
|
@@ -39539,7 +39656,7 @@ function runExperimentBaselineInit(experimentId, store) {
|
|
|
39539
39656
|
error: baseline.error || null
|
|
39540
39657
|
};
|
|
39541
39658
|
mkdirSync10(artifactDir, { recursive: true, mode: 448 });
|
|
39542
|
-
|
|
39659
|
+
writeFileSync9(join11(artifactDir, "eval.json"), JSON.stringify(evalPayload, null, 2) + "\n", "utf-8");
|
|
39543
39660
|
store.createEvent(experiment.id, "note", {
|
|
39544
39661
|
message: "experiment initialized with baseline evaluation",
|
|
39545
39662
|
status: baseline.status,
|