@zixt/host 0.0.118 → 0.0.120
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/dist/index.js +937 -461
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8,27 +8,27 @@ var __export = (target, all) => {
|
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
// src/supervisor.ts
|
|
11
|
-
import { spawn as
|
|
11
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
12
12
|
import { fstatSync } from "node:fs";
|
|
13
13
|
import {
|
|
14
14
|
access as access2,
|
|
15
15
|
lstat as lstat5,
|
|
16
|
-
mkdir as
|
|
16
|
+
mkdir as mkdir6,
|
|
17
17
|
open as open4,
|
|
18
18
|
readFile as readFile7,
|
|
19
19
|
readlink,
|
|
20
20
|
readdir as readdir4,
|
|
21
21
|
rename as rename3,
|
|
22
|
-
rm as
|
|
22
|
+
rm as rm6,
|
|
23
23
|
symlink
|
|
24
24
|
} from "node:fs/promises";
|
|
25
|
-
import { basename as basename3, dirname as
|
|
26
|
-
import { homedir as
|
|
25
|
+
import { basename as basename3, dirname as dirname5, isAbsolute as isAbsolute10, join as join10, relative as relative4, resolve as resolve5, sep as sep4 } from "node:path";
|
|
26
|
+
import { homedir as homedir4 } from "node:os";
|
|
27
27
|
|
|
28
28
|
// package.json
|
|
29
29
|
var package_default = {
|
|
30
30
|
name: "@zixt/host",
|
|
31
|
-
version: "0.0.
|
|
31
|
+
version: "0.0.120",
|
|
32
32
|
type: "module",
|
|
33
33
|
exports: {
|
|
34
34
|
".": "./src/client.ts",
|
|
@@ -22148,10 +22148,10 @@ async function publishTaskFile(input) {
|
|
|
22148
22148
|
if (!roots.some((root) => isWithin(file2, root))) {
|
|
22149
22149
|
return { ok: false, error: "the file is outside this task workspace" };
|
|
22150
22150
|
}
|
|
22151
|
-
const
|
|
22152
|
-
if (!
|
|
22153
|
-
if (
|
|
22154
|
-
if (
|
|
22151
|
+
const stat4 = await lstat(file2);
|
|
22152
|
+
if (!stat4.isFile()) return { ok: false, error: "only regular files can be published" };
|
|
22153
|
+
if (stat4.size < 1) return { ok: false, error: "empty files cannot be published" };
|
|
22154
|
+
if (stat4.size > TASK_ARTIFACT_MAX_BYTES) {
|
|
22155
22155
|
return {
|
|
22156
22156
|
ok: false,
|
|
22157
22157
|
error: `the file is larger than Zixt's ${TASK_ARTIFACT_MAX_BYTES / 1024 / 1024} MB limit`
|
|
@@ -22364,13 +22364,299 @@ function isCommandNotFound(text) {
|
|
|
22364
22364
|
return /\bENOENT\b|is not recognized|command not found|no such file/i.test(text);
|
|
22365
22365
|
}
|
|
22366
22366
|
|
|
22367
|
+
// src/runners/runner-install.ts
|
|
22368
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
22369
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
22370
|
+
import { homedir, tmpdir } from "node:os";
|
|
22371
|
+
import { isAbsolute as isAbsolute3, join as join3 } from "node:path";
|
|
22372
|
+
|
|
22373
|
+
// src/runners/installer-env.ts
|
|
22374
|
+
import { dirname, join as join2 } from "node:path";
|
|
22375
|
+
function npmCommand(platform = process.platform) {
|
|
22376
|
+
return platform === "win32" ? "npm.cmd" : "npm";
|
|
22377
|
+
}
|
|
22378
|
+
async function resolveInstallerCommand(options = {}) {
|
|
22379
|
+
const platform = options.platform ?? process.platform;
|
|
22380
|
+
const command = npmCommand(platform);
|
|
22381
|
+
if (platform !== "win32") return command;
|
|
22382
|
+
const execPath = options.execPath ?? process.execPath;
|
|
22383
|
+
const resolution = {
|
|
22384
|
+
platform,
|
|
22385
|
+
...options.searchPath !== void 0 ? { searchPath: options.searchPath } : {}
|
|
22386
|
+
};
|
|
22387
|
+
return (
|
|
22388
|
+
// npm ships beside the `node` running this process, and that copy is the
|
|
22389
|
+
// one matching it. A per-user Scheduled Task may carry no npm on PATH.
|
|
22390
|
+
await resolveTrustedCliCommand(join2(dirname(execPath), command), resolution) ?? await resolveTrustedCliCommand(command, resolution) ?? // Nothing resolved: keep the previous behaviour, so a Machine without npm
|
|
22391
|
+
// fails one install rather than changing how failure is handled.
|
|
22392
|
+
command
|
|
22393
|
+
);
|
|
22394
|
+
}
|
|
22395
|
+
function windowsInstallerCommandLine(command, args) {
|
|
22396
|
+
return [command, ...args].map(quoteForCmd).join(" ");
|
|
22397
|
+
}
|
|
22398
|
+
function sanitizedInstallerEnv(inherited) {
|
|
22399
|
+
const allowed = /* @__PURE__ */ new Set([
|
|
22400
|
+
"PATH",
|
|
22401
|
+
"HOME",
|
|
22402
|
+
"USERPROFILE",
|
|
22403
|
+
"SYSTEMROOT",
|
|
22404
|
+
"WINDIR",
|
|
22405
|
+
"TEMP",
|
|
22406
|
+
"TMP",
|
|
22407
|
+
"TMPDIR",
|
|
22408
|
+
"LOCALAPPDATA",
|
|
22409
|
+
"APPDATA",
|
|
22410
|
+
"XDG_CONFIG_HOME",
|
|
22411
|
+
"XDG_CACHE_HOME",
|
|
22412
|
+
"HTTP_PROXY",
|
|
22413
|
+
"HTTPS_PROXY",
|
|
22414
|
+
"NO_PROXY",
|
|
22415
|
+
"ALL_PROXY",
|
|
22416
|
+
"NODE_EXTRA_CA_CERTS",
|
|
22417
|
+
"SSL_CERT_FILE",
|
|
22418
|
+
"SSL_CERT_DIR",
|
|
22419
|
+
"NPM_CONFIG_REGISTRY",
|
|
22420
|
+
"NPM_CONFIG_CACHE",
|
|
22421
|
+
"NPM_CONFIG_USERCONFIG",
|
|
22422
|
+
"NPM_CONFIG_STRICT_SSL"
|
|
22423
|
+
]);
|
|
22424
|
+
return Object.fromEntries(
|
|
22425
|
+
Object.entries(inherited).filter(
|
|
22426
|
+
([name, value]) => value !== void 0 && allowed.has(name.toUpperCase())
|
|
22427
|
+
)
|
|
22428
|
+
);
|
|
22429
|
+
}
|
|
22430
|
+
|
|
22431
|
+
// src/runners/runner-install.ts
|
|
22432
|
+
var CLAUDE_INSTALLER_URL_POSIX = "https://claude.ai/install.sh";
|
|
22433
|
+
var CLAUDE_INSTALLER_URL_WINDOWS = "https://claude.ai/install.ps1";
|
|
22434
|
+
var CODEX_PACKAGE = "@openai/codex";
|
|
22435
|
+
var INSTALL_TIMEOUT_MS = 10 * 6e4;
|
|
22436
|
+
var FAILURE_COOLDOWN_MS = 10 * 6e4;
|
|
22437
|
+
function defaultRunnerToolsRoot() {
|
|
22438
|
+
return join3(homedir(), ".zixt", "tools");
|
|
22439
|
+
}
|
|
22440
|
+
function runnerCommandCandidates(type, options = {}) {
|
|
22441
|
+
const platform = options.platform ?? process.platform;
|
|
22442
|
+
const home = options.home ?? homedir();
|
|
22443
|
+
const toolsRoot = options.toolsRoot ?? defaultRunnerToolsRoot();
|
|
22444
|
+
if (type === "claude-code") return [join3(home, ".local", "bin", "claude")];
|
|
22445
|
+
return platform === "win32" ? [join3(toolsRoot, "codex")] : [join3(toolsRoot, "bin", "codex")];
|
|
22446
|
+
}
|
|
22447
|
+
async function commandRuns(path) {
|
|
22448
|
+
return new Promise((resolve18) => {
|
|
22449
|
+
let child;
|
|
22450
|
+
try {
|
|
22451
|
+
child = spawnCli(path, ["--version"], {
|
|
22452
|
+
stdio: "ignore",
|
|
22453
|
+
windowsHide: true
|
|
22454
|
+
});
|
|
22455
|
+
} catch {
|
|
22456
|
+
resolve18(false);
|
|
22457
|
+
return;
|
|
22458
|
+
}
|
|
22459
|
+
const timer = setTimeout(() => {
|
|
22460
|
+
child.kill();
|
|
22461
|
+
resolve18(false);
|
|
22462
|
+
}, 1e4);
|
|
22463
|
+
timer.unref?.();
|
|
22464
|
+
child.once("error", () => {
|
|
22465
|
+
clearTimeout(timer);
|
|
22466
|
+
resolve18(false);
|
|
22467
|
+
});
|
|
22468
|
+
child.once("exit", (code) => {
|
|
22469
|
+
clearTimeout(timer);
|
|
22470
|
+
resolve18(code === 0);
|
|
22471
|
+
});
|
|
22472
|
+
});
|
|
22473
|
+
}
|
|
22474
|
+
async function resolveRunnerCommand(command, type, options = {}) {
|
|
22475
|
+
const candidates = [];
|
|
22476
|
+
if (!options.managedOnly) {
|
|
22477
|
+
const fromPath = await resolveTrustedCliCommand(command, options.resolution ?? {});
|
|
22478
|
+
if (fromPath) candidates.push(fromPath);
|
|
22479
|
+
}
|
|
22480
|
+
if (!command.includes("/") && !command.includes("\\")) {
|
|
22481
|
+
for (const candidate of runnerCommandCandidates(type, options)) {
|
|
22482
|
+
const resolved = await resolveTrustedCliCommand(candidate, options.resolution ?? {});
|
|
22483
|
+
if (resolved && !candidates.includes(resolved)) candidates.push(resolved);
|
|
22484
|
+
}
|
|
22485
|
+
}
|
|
22486
|
+
if (!options.probe) return candidates[0] ?? null;
|
|
22487
|
+
for (const candidate of candidates) {
|
|
22488
|
+
if (await commandRuns(candidate)) return candidate;
|
|
22489
|
+
}
|
|
22490
|
+
return null;
|
|
22491
|
+
}
|
|
22492
|
+
function windowsPowershell(env) {
|
|
22493
|
+
const root = env.SYSTEMROOT ?? env.WINDIR;
|
|
22494
|
+
if (!root || !isAbsolute3(root)) return null;
|
|
22495
|
+
return join3(root, "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
|
|
22496
|
+
}
|
|
22497
|
+
async function runInstaller(plan, env) {
|
|
22498
|
+
await new Promise((resolveRun, rejectRun) => {
|
|
22499
|
+
const child = plan.shellLine !== void 0 ? spawn2(plan.shellLine, {
|
|
22500
|
+
...plan.cwd ? { cwd: plan.cwd } : {},
|
|
22501
|
+
env,
|
|
22502
|
+
// stdin stays closed: see the module comment. Output flows to the
|
|
22503
|
+
// ordinary worker console so progress reaches the cloud and the
|
|
22504
|
+
// local console file.
|
|
22505
|
+
stdio: ["ignore", "inherit", "inherit"],
|
|
22506
|
+
windowsHide: true,
|
|
22507
|
+
shell: true
|
|
22508
|
+
}) : spawn2(plan.command, plan.args, {
|
|
22509
|
+
...plan.cwd ? { cwd: plan.cwd } : {},
|
|
22510
|
+
env,
|
|
22511
|
+
stdio: ["ignore", "inherit", "inherit"],
|
|
22512
|
+
windowsHide: true
|
|
22513
|
+
});
|
|
22514
|
+
let settled = false;
|
|
22515
|
+
const finish = (error52) => {
|
|
22516
|
+
if (settled) return;
|
|
22517
|
+
settled = true;
|
|
22518
|
+
clearTimeout(timer);
|
|
22519
|
+
if (error52) rejectRun(error52);
|
|
22520
|
+
else resolveRun();
|
|
22521
|
+
};
|
|
22522
|
+
const timer = setTimeout(() => {
|
|
22523
|
+
child.kill();
|
|
22524
|
+
finish(new Error("the runner installer did not finish within 10 minutes"));
|
|
22525
|
+
}, INSTALL_TIMEOUT_MS);
|
|
22526
|
+
timer.unref?.();
|
|
22527
|
+
child.once("error", (error52) => finish(error52));
|
|
22528
|
+
child.once("exit", (code, signal) => {
|
|
22529
|
+
if (code === 0) finish();
|
|
22530
|
+
else {
|
|
22531
|
+
finish(
|
|
22532
|
+
new Error(
|
|
22533
|
+
signal ? `the runner installer stopped with ${signal}` : `the runner installer exited with code ${code ?? "unknown"}`
|
|
22534
|
+
)
|
|
22535
|
+
);
|
|
22536
|
+
}
|
|
22537
|
+
});
|
|
22538
|
+
});
|
|
22539
|
+
}
|
|
22540
|
+
async function downloadInstallerScript(url3, destination) {
|
|
22541
|
+
const response = await fetch(url3, { signal: AbortSignal.timeout(6e4) });
|
|
22542
|
+
if (!response.ok) {
|
|
22543
|
+
throw new Error(`the installer download answered HTTP ${response.status}`);
|
|
22544
|
+
}
|
|
22545
|
+
const body = await response.text();
|
|
22546
|
+
if (!body || body.length > 5 * 1024 * 1024) {
|
|
22547
|
+
throw new Error("the installer download looked wrong and was not run");
|
|
22548
|
+
}
|
|
22549
|
+
await writeFile(destination, body, { encoding: "utf8", mode: 448 });
|
|
22550
|
+
}
|
|
22551
|
+
function createRunnerAutoInstaller(options) {
|
|
22552
|
+
const platform = options.platform ?? process.platform;
|
|
22553
|
+
const home = options.home ?? homedir();
|
|
22554
|
+
const toolsRoot = options.toolsRoot ?? defaultRunnerToolsRoot();
|
|
22555
|
+
const now = options.now ?? Date.now;
|
|
22556
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
22557
|
+
const failedAt = /* @__PURE__ */ new Map();
|
|
22558
|
+
const installClaude = async () => {
|
|
22559
|
+
const script = join3(
|
|
22560
|
+
tmpdir(),
|
|
22561
|
+
`zixt-claude-install-${process.pid}-${crypto.randomUUID()}.${platform === "win32" ? "ps1" : "sh"}`
|
|
22562
|
+
);
|
|
22563
|
+
try {
|
|
22564
|
+
if (platform === "win32") {
|
|
22565
|
+
await downloadInstallerScript(CLAUDE_INSTALLER_URL_WINDOWS, script);
|
|
22566
|
+
const powershell = windowsPowershell(process.env);
|
|
22567
|
+
if (!powershell) throw new Error("Windows PowerShell could not be found");
|
|
22568
|
+
await runInstaller(
|
|
22569
|
+
{
|
|
22570
|
+
command: powershell,
|
|
22571
|
+
args: ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-File", script]
|
|
22572
|
+
},
|
|
22573
|
+
sanitizedInstallerEnv(process.env)
|
|
22574
|
+
);
|
|
22575
|
+
} else {
|
|
22576
|
+
await downloadInstallerScript(CLAUDE_INSTALLER_URL_POSIX, script);
|
|
22577
|
+
await runInstaller({ command: "bash", args: [script] }, sanitizedInstallerEnv(process.env));
|
|
22578
|
+
}
|
|
22579
|
+
} finally {
|
|
22580
|
+
await rm(script, { force: true }).catch(() => void 0);
|
|
22581
|
+
}
|
|
22582
|
+
};
|
|
22583
|
+
const installCodex = async () => {
|
|
22584
|
+
await mkdir(toolsRoot, { recursive: true, mode: 448 });
|
|
22585
|
+
const npm = await resolveInstallerCommand({ platform });
|
|
22586
|
+
const args = [
|
|
22587
|
+
"install",
|
|
22588
|
+
"-g",
|
|
22589
|
+
"--prefix",
|
|
22590
|
+
toolsRoot,
|
|
22591
|
+
"--no-audit",
|
|
22592
|
+
"--no-fund",
|
|
22593
|
+
"--ignore-scripts",
|
|
22594
|
+
CODEX_PACKAGE
|
|
22595
|
+
];
|
|
22596
|
+
if (platform === "win32") {
|
|
22597
|
+
await runInstaller(
|
|
22598
|
+
{ shellLine: windowsInstallerCommandLine(npm, args), cwd: toolsRoot },
|
|
22599
|
+
sanitizedInstallerEnv(process.env)
|
|
22600
|
+
);
|
|
22601
|
+
} else {
|
|
22602
|
+
await runInstaller(
|
|
22603
|
+
{ command: npm, args, cwd: toolsRoot },
|
|
22604
|
+
sanitizedInstallerEnv(process.env)
|
|
22605
|
+
);
|
|
22606
|
+
}
|
|
22607
|
+
};
|
|
22608
|
+
const install = options.install ?? ((type) => type === "claude-code" ? installClaude() : installCodex());
|
|
22609
|
+
return {
|
|
22610
|
+
ensureInstalled(type) {
|
|
22611
|
+
if (inFlight.has(type)) return;
|
|
22612
|
+
const lastFailure = failedAt.get(type);
|
|
22613
|
+
if (lastFailure !== void 0 && now() - lastFailure < FAILURE_COOLDOWN_MS) return;
|
|
22614
|
+
options.onEvent({ runner: type, state: "started" });
|
|
22615
|
+
const attempt = (async () => {
|
|
22616
|
+
try {
|
|
22617
|
+
await install(type);
|
|
22618
|
+
const resolved = await resolveRunnerCommand(
|
|
22619
|
+
type === "claude-code" ? "claude" : "codex",
|
|
22620
|
+
type,
|
|
22621
|
+
{
|
|
22622
|
+
home,
|
|
22623
|
+
toolsRoot,
|
|
22624
|
+
probe: true,
|
|
22625
|
+
managedOnly: true,
|
|
22626
|
+
...options.resolution ? { resolution: options.resolution } : {}
|
|
22627
|
+
}
|
|
22628
|
+
);
|
|
22629
|
+
if (!resolved) {
|
|
22630
|
+
throw new Error("the installer finished but the runner is still not on this Machine");
|
|
22631
|
+
}
|
|
22632
|
+
failedAt.delete(type);
|
|
22633
|
+
options.onEvent({ runner: type, state: "completed" });
|
|
22634
|
+
} catch (error52) {
|
|
22635
|
+
failedAt.set(type, now());
|
|
22636
|
+
options.onEvent({
|
|
22637
|
+
runner: type,
|
|
22638
|
+
state: "failed",
|
|
22639
|
+
error: error52 instanceof Error ? error52.message : "unknown runner install error"
|
|
22640
|
+
});
|
|
22641
|
+
} finally {
|
|
22642
|
+
inFlight.delete(type);
|
|
22643
|
+
}
|
|
22644
|
+
})();
|
|
22645
|
+
inFlight.set(type, attempt);
|
|
22646
|
+
},
|
|
22647
|
+
async settled() {
|
|
22648
|
+
while (inFlight.size > 0) await Promise.allSettled([...inFlight.values()]);
|
|
22649
|
+
}
|
|
22650
|
+
};
|
|
22651
|
+
}
|
|
22652
|
+
|
|
22367
22653
|
// src/runners/title.ts
|
|
22368
22654
|
var TITLE_TIMEOUT_MS = 45e3;
|
|
22369
22655
|
var INSTRUCTIONS_BUDGET = 4e3;
|
|
22370
22656
|
var CLAUDE_TITLE_MODEL = "haiku";
|
|
22371
22657
|
async function generateTaskTitle(instructions, runner) {
|
|
22372
22658
|
if (runner && runner.type !== "claude-code") return null;
|
|
22373
|
-
const command = await
|
|
22659
|
+
const command = await resolveRunnerCommand("claude", "claude-code");
|
|
22374
22660
|
if (!command) return null;
|
|
22375
22661
|
const prompt = [
|
|
22376
22662
|
"Name this task for a task list. Reply with ONLY the name: at most eight",
|
|
@@ -22443,7 +22729,7 @@ function isPlausibleTaskTitle(title) {
|
|
|
22443
22729
|
// src/worker-watchdog.ts
|
|
22444
22730
|
import { randomUUID } from "node:crypto";
|
|
22445
22731
|
import { writeFileSync as writeFileSync2 } from "node:fs";
|
|
22446
|
-
import { isAbsolute as
|
|
22732
|
+
import { isAbsolute as isAbsolute5 } from "node:path";
|
|
22447
22733
|
|
|
22448
22734
|
// src/worker-ownership.ts
|
|
22449
22735
|
import {
|
|
@@ -22456,8 +22742,8 @@ import {
|
|
|
22456
22742
|
rmSync,
|
|
22457
22743
|
writeFileSync
|
|
22458
22744
|
} from "node:fs";
|
|
22459
|
-
import { chmod, lstat as lstat2, mkdir, open, readFile as readFile2, readdir, rm, rmdir } from "node:fs/promises";
|
|
22460
|
-
import { basename as basename2, dirname, isAbsolute as
|
|
22745
|
+
import { chmod, lstat as lstat2, mkdir as mkdir2, open, readFile as readFile2, readdir, rm as rm2, rmdir } from "node:fs/promises";
|
|
22746
|
+
import { basename as basename2, dirname as dirname2, isAbsolute as isAbsolute4, join as join4, relative as relative2, resolve as resolve3, sep as sep2 } from "node:path";
|
|
22461
22747
|
var LAUNCHER_OWNERSHIP_DIR_ENV = "ZIXT_HOST_LAUNCHER_OWNERSHIP_DIR";
|
|
22462
22748
|
var WORKER_OWNERSHIP_FILE_ENV = "ZIXT_HOST_WORKER_OWNERSHIP_FILE";
|
|
22463
22749
|
var SUPERVISOR_OWNERSHIP_FILE_ENV = "ZIXT_HOST_SUPERVISOR_OWNERSHIP_FILE";
|
|
@@ -22467,8 +22753,8 @@ var MAX_OWNERSHIP_RECORD_BYTES = 4 * 1024;
|
|
|
22467
22753
|
var MAX_OWNERSHIP_RECORDS = 32;
|
|
22468
22754
|
var MAX_OWNERSHIP_GENERATIONS = 32;
|
|
22469
22755
|
function workerOwnershipFile(directory, nonce) {
|
|
22470
|
-
if (!
|
|
22471
|
-
return
|
|
22756
|
+
if (!isAbsolute4(directory) || !SAFE_WORKER_OWNERSHIP_NONCE.test(nonce)) return null;
|
|
22757
|
+
return join4(directory, `${nonce}.json`);
|
|
22472
22758
|
}
|
|
22473
22759
|
function workerOwnershipArguments(nonce) {
|
|
22474
22760
|
return [WORKER_OWNERSHIP_ARGUMENT, nonce];
|
|
@@ -22477,7 +22763,7 @@ function consumeWorkerOwnershipArguments(argv, env) {
|
|
|
22477
22763
|
const file2 = env[WORKER_OWNERSHIP_FILE_ENV];
|
|
22478
22764
|
const nonce = env.ZIXT_HOST_WORKER_WATCHDOG_NONCE;
|
|
22479
22765
|
if (typeof file2 !== "string") return { argv: [...argv], requested: false, valid: true };
|
|
22480
|
-
if (typeof nonce !== "string" || !SAFE_WORKER_OWNERSHIP_NONCE.test(nonce) || !
|
|
22766
|
+
if (typeof nonce !== "string" || !SAFE_WORKER_OWNERSHIP_NONCE.test(nonce) || !isAbsolute4(file2) || basename2(file2) !== `${nonce}.json`) {
|
|
22481
22767
|
return { argv: [...argv], requested: true, valid: false };
|
|
22482
22768
|
}
|
|
22483
22769
|
const result = [];
|
|
@@ -22504,11 +22790,11 @@ function syncDirectorySync(path) {
|
|
|
22504
22790
|
}
|
|
22505
22791
|
}
|
|
22506
22792
|
function recordWorkerOwnership(path, nonce, pid = process.pid) {
|
|
22507
|
-
if (!
|
|
22793
|
+
if (!isAbsolute4(path) || !SAFE_WORKER_OWNERSHIP_NONCE.test(nonce) || basename2(path) !== `${nonce}.json` || !Number.isSafeInteger(pid) || pid <= 1) {
|
|
22508
22794
|
return false;
|
|
22509
22795
|
}
|
|
22510
|
-
const directory =
|
|
22511
|
-
const temporary =
|
|
22796
|
+
const directory = dirname2(path);
|
|
22797
|
+
const temporary = join4(directory, `.pending-${crypto.randomUUID()}`);
|
|
22512
22798
|
const existingMatches = () => {
|
|
22513
22799
|
try {
|
|
22514
22800
|
const metadata = lstatSync(path);
|
|
@@ -22562,16 +22848,16 @@ async function syncDirectory(path) {
|
|
|
22562
22848
|
}
|
|
22563
22849
|
}
|
|
22564
22850
|
async function ensurePrivateOwnershipRoot(root) {
|
|
22565
|
-
if (!
|
|
22566
|
-
const firstCreated = await
|
|
22851
|
+
if (!isAbsolute4(root)) throw new Error("launcher ownership root is invalid");
|
|
22852
|
+
const firstCreated = await mkdir2(root, { recursive: true, mode: 448 });
|
|
22567
22853
|
if (firstCreated && process.platform !== "win32") {
|
|
22568
22854
|
const first = resolve3(firstCreated);
|
|
22569
22855
|
const target = resolve3(root);
|
|
22570
|
-
await syncDirectory(
|
|
22856
|
+
await syncDirectory(dirname2(first));
|
|
22571
22857
|
let current = first;
|
|
22572
22858
|
for (const part of relative2(first, target).split(sep2).filter(Boolean)) {
|
|
22573
22859
|
await syncDirectory(current);
|
|
22574
|
-
current =
|
|
22860
|
+
current = join4(current, part);
|
|
22575
22861
|
}
|
|
22576
22862
|
}
|
|
22577
22863
|
const metadata = await lstat2(root);
|
|
@@ -22584,14 +22870,14 @@ async function createLauncherOwnershipGeneration(root) {
|
|
|
22584
22870
|
await ensurePrivateOwnershipRoot(root);
|
|
22585
22871
|
for (let attempt = 0; attempt < 8; attempt++) {
|
|
22586
22872
|
const nonce = crypto.randomUUID();
|
|
22587
|
-
const directory =
|
|
22873
|
+
const directory = join4(root, nonce);
|
|
22588
22874
|
try {
|
|
22589
|
-
await
|
|
22875
|
+
await mkdir2(directory, { mode: 448 });
|
|
22590
22876
|
await syncDirectory(root);
|
|
22591
22877
|
return {
|
|
22592
22878
|
nonce,
|
|
22593
22879
|
directory,
|
|
22594
|
-
supervisorOwnershipFile:
|
|
22880
|
+
supervisorOwnershipFile: join4(directory, `${nonce}.json`)
|
|
22595
22881
|
};
|
|
22596
22882
|
} catch (error52) {
|
|
22597
22883
|
if (error52.code !== "EEXIST") throw error52;
|
|
@@ -22610,7 +22896,7 @@ async function readLauncherOwnershipGenerations(root) {
|
|
|
22610
22896
|
if (!entry.isDirectory() || entry.isSymbolicLink() || !SAFE_WORKER_OWNERSHIP_NONCE.test(entry.name)) {
|
|
22611
22897
|
throw new Error("launcher ownership root is malformed");
|
|
22612
22898
|
}
|
|
22613
|
-
const directory =
|
|
22899
|
+
const directory = join4(root, entry.name);
|
|
22614
22900
|
const metadata = await lstat2(directory);
|
|
22615
22901
|
if (metadata.isSymbolicLink() || !metadata.isDirectory()) {
|
|
22616
22902
|
throw new Error("launcher ownership generation is not a trusted directory");
|
|
@@ -22619,7 +22905,7 @@ async function readLauncherOwnershipGenerations(root) {
|
|
|
22619
22905
|
generations.push({
|
|
22620
22906
|
nonce: entry.name,
|
|
22621
22907
|
directory,
|
|
22622
|
-
supervisorOwnershipFile:
|
|
22908
|
+
supervisorOwnershipFile: join4(directory, `${entry.name}.json`)
|
|
22623
22909
|
});
|
|
22624
22910
|
}
|
|
22625
22911
|
return generations.sort((left, right) => left.nonce.localeCompare(right.nonce));
|
|
@@ -22633,7 +22919,7 @@ function parseRecord(value, path, expectedNonce) {
|
|
|
22633
22919
|
return { schema: 1, nonce: expectedNonce, pid: record2.pid, path };
|
|
22634
22920
|
}
|
|
22635
22921
|
async function readWorkerOwnershipRecords(directory) {
|
|
22636
|
-
if (!
|
|
22922
|
+
if (!isAbsolute4(directory)) throw new Error("worker ownership directory is invalid");
|
|
22637
22923
|
const entries = await readdir(directory, { withFileTypes: true }).catch(
|
|
22638
22924
|
(error52) => {
|
|
22639
22925
|
if (error52.code === "ENOENT") return [];
|
|
@@ -22645,9 +22931,9 @@ async function readWorkerOwnershipRecords(directory) {
|
|
|
22645
22931
|
}
|
|
22646
22932
|
const records = [];
|
|
22647
22933
|
for (const entry of entries) {
|
|
22648
|
-
const path =
|
|
22934
|
+
const path = join4(directory, entry.name);
|
|
22649
22935
|
if (entry.name.startsWith(".pending-")) {
|
|
22650
|
-
await
|
|
22936
|
+
await rm2(path, { force: true });
|
|
22651
22937
|
continue;
|
|
22652
22938
|
}
|
|
22653
22939
|
const match = /^([A-Za-z0-9_-]{16,200})\.json$/.exec(entry.name);
|
|
@@ -22667,15 +22953,15 @@ async function readWorkerOwnershipRecords(directory) {
|
|
|
22667
22953
|
return records;
|
|
22668
22954
|
}
|
|
22669
22955
|
async function forgetWorkerOwnership(path) {
|
|
22670
|
-
if (!
|
|
22671
|
-
const directory =
|
|
22672
|
-
await
|
|
22956
|
+
if (!isAbsolute4(path)) throw new Error("worker ownership path is invalid");
|
|
22957
|
+
const directory = dirname2(path);
|
|
22958
|
+
await rm2(path, { force: true });
|
|
22673
22959
|
await syncDirectory(directory);
|
|
22674
22960
|
}
|
|
22675
22961
|
async function removeWorkerOwnershipDirectory(directory) {
|
|
22676
22962
|
try {
|
|
22677
22963
|
await rmdir(directory);
|
|
22678
|
-
await syncDirectory(
|
|
22964
|
+
await syncDirectory(dirname2(directory));
|
|
22679
22965
|
} catch (error52) {
|
|
22680
22966
|
if (error52.code !== "ENOENT") throw error52;
|
|
22681
22967
|
}
|
|
@@ -22765,7 +23051,7 @@ function startWorkerWatchdogHeartbeat(env = process.env, argv = process.argv.sli
|
|
|
22765
23051
|
}
|
|
22766
23052
|
const heartbeatFile = env[WORKER_WATCHDOG_FILE_ENV];
|
|
22767
23053
|
const ipc = typeof process.send === "function" && process.connected;
|
|
22768
|
-
const file2 = !ipc && typeof heartbeatFile === "string" &&
|
|
23054
|
+
const file2 = !ipc && typeof heartbeatFile === "string" && isAbsolute5(heartbeatFile) ? heartbeatFile : null;
|
|
22769
23055
|
if (!ipc && !file2) {
|
|
22770
23056
|
heartbeatActive = false;
|
|
22771
23057
|
heartbeatUsesIpc = false;
|
|
@@ -22928,7 +23214,7 @@ function workerWatchdogIsActive() {
|
|
|
22928
23214
|
// src/workspaces.ts
|
|
22929
23215
|
import { access, stat as stat2 } from "node:fs/promises";
|
|
22930
23216
|
import { constants } from "node:fs";
|
|
22931
|
-
import { join as
|
|
23217
|
+
import { join as join5 } from "node:path";
|
|
22932
23218
|
var PROBE_TIMEOUT_MS = 2e3;
|
|
22933
23219
|
async function withinBudget(work) {
|
|
22934
23220
|
let timer;
|
|
@@ -22967,7 +23253,7 @@ async function probeWorkspace(workspace) {
|
|
|
22967
23253
|
await withinBudget(access(workspace, constants.R_OK | constants.X_OK));
|
|
22968
23254
|
let error52 = null;
|
|
22969
23255
|
try {
|
|
22970
|
-
await withinBudget(stat2(
|
|
23256
|
+
await withinBudget(stat2(join5(workspace, ".git")));
|
|
22971
23257
|
} catch {
|
|
22972
23258
|
error52 = "Usable, but not a git repository";
|
|
22973
23259
|
}
|
|
@@ -25264,9 +25550,9 @@ function watchForUpdates(options) {
|
|
|
25264
25550
|
}
|
|
25265
25551
|
|
|
25266
25552
|
// src/runners/process-tree.ts
|
|
25267
|
-
import { spawn as
|
|
25553
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
25268
25554
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
25269
|
-
import { isAbsolute as
|
|
25555
|
+
import { isAbsolute as isAbsolute6, join as join6 } from "node:path";
|
|
25270
25556
|
var windowsProcessTreeModule = process.platform === "win32" ? import("@vscode/windows-process-tree").catch(() => null) : null;
|
|
25271
25557
|
var PROCESS_TERM_GRACE_MS = 500;
|
|
25272
25558
|
var PROCESS_EXIT_POLL_MS = 20;
|
|
@@ -25351,7 +25637,7 @@ async function observePosixGuardianNonce(pid, nonce) {
|
|
|
25351
25637
|
}
|
|
25352
25638
|
}
|
|
25353
25639
|
return new Promise((resolve18, reject3) => {
|
|
25354
|
-
const observer =
|
|
25640
|
+
const observer = spawn3("/bin/ps", ["-ww", "-o", "command=", "-p", String(pid)], {
|
|
25355
25641
|
stdio: ["ignore", "pipe", "ignore"]
|
|
25356
25642
|
});
|
|
25357
25643
|
let output = "";
|
|
@@ -25442,7 +25728,7 @@ function posixProcessRecordsFromPs(output) {
|
|
|
25442
25728
|
}
|
|
25443
25729
|
async function snapshotPosixProcesses() {
|
|
25444
25730
|
return new Promise((resolve18, reject3) => {
|
|
25445
|
-
const observer =
|
|
25731
|
+
const observer = spawn3("/bin/ps", ["-axo", "uid=,pid=,ppid=,pgid=,stat="], {
|
|
25446
25732
|
stdio: ["ignore", "pipe", "ignore"]
|
|
25447
25733
|
});
|
|
25448
25734
|
let output = "";
|
|
@@ -25722,13 +26008,13 @@ async function observePosixGroupIdentity(records, pgid, identity) {
|
|
|
25722
26008
|
}
|
|
25723
26009
|
function defaultTaskkillCommand() {
|
|
25724
26010
|
const windowsRoot = process.env.SystemRoot ?? process.env.WINDIR;
|
|
25725
|
-
if (!windowsRoot || !
|
|
26011
|
+
if (!windowsRoot || !isAbsolute6(windowsRoot)) {
|
|
25726
26012
|
throw new ProcessTreeTerminationError(
|
|
25727
26013
|
"termination_failed",
|
|
25728
26014
|
"Windows runner tree termination authority is unavailable"
|
|
25729
26015
|
);
|
|
25730
26016
|
}
|
|
25731
|
-
return
|
|
26017
|
+
return join6(windowsRoot, "System32", "taskkill.exe");
|
|
25732
26018
|
}
|
|
25733
26019
|
function validWindowsPid(value) {
|
|
25734
26020
|
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 && value <= 4294967295;
|
|
@@ -25864,7 +26150,7 @@ async function waitForProcessesExit(pids, timeoutMs) {
|
|
|
25864
26150
|
async function runTaskkill(pid, command, timeoutMs = TASKKILL_TIMEOUT_MS, independentlyTrackedPids = []) {
|
|
25865
26151
|
const trustedCommand = command ?? defaultTaskkillCommand();
|
|
25866
26152
|
const result = await new Promise((resolve18, reject3) => {
|
|
25867
|
-
const killer =
|
|
26153
|
+
const killer = spawn3(trustedCommand, ["/PID", String(pid), "/T", "/F"], {
|
|
25868
26154
|
stdio: ["ignore", "pipe", "pipe"],
|
|
25869
26155
|
windowsHide: true
|
|
25870
26156
|
});
|
|
@@ -26110,14 +26396,14 @@ async function terminateProcessTree(child, childExited, options = {}) {
|
|
|
26110
26396
|
}
|
|
26111
26397
|
|
|
26112
26398
|
// src/release-state.ts
|
|
26113
|
-
import { lstat as lstat3, mkdir as
|
|
26114
|
-
import { dirname as
|
|
26399
|
+
import { lstat as lstat3, mkdir as mkdir3, open as open2, readFile as readFile4, rename, rm as rm3 } from "node:fs/promises";
|
|
26400
|
+
import { dirname as dirname3, join as join7 } from "node:path";
|
|
26115
26401
|
var STATE_FILE = "release-state.json";
|
|
26116
26402
|
var STATE_SCHEMA = 1;
|
|
26117
26403
|
var MAX_STATE_BYTES = 4 * 1024;
|
|
26118
26404
|
var VERSION = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/;
|
|
26119
26405
|
function releaseStatePath(root) {
|
|
26120
|
-
return
|
|
26406
|
+
return join7(root, STATE_FILE);
|
|
26121
26407
|
}
|
|
26122
26408
|
function parseState(value) {
|
|
26123
26409
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
@@ -26168,8 +26454,8 @@ function createReleaseStateStore(root) {
|
|
|
26168
26454
|
},
|
|
26169
26455
|
async save(state) {
|
|
26170
26456
|
const normalized = parseState(state);
|
|
26171
|
-
await
|
|
26172
|
-
const temporary =
|
|
26457
|
+
await mkdir3(root, { recursive: true, mode: 448 });
|
|
26458
|
+
const temporary = join7(root, `.${STATE_FILE}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
26173
26459
|
const handle = await open2(temporary, "wx", 384);
|
|
26174
26460
|
try {
|
|
26175
26461
|
await handle.writeFile(`${JSON.stringify(normalized)}
|
|
@@ -26180,7 +26466,7 @@ function createReleaseStateStore(root) {
|
|
|
26180
26466
|
await syncDirectory2(root);
|
|
26181
26467
|
} catch (error52) {
|
|
26182
26468
|
await handle.close().catch(() => void 0);
|
|
26183
|
-
await
|
|
26469
|
+
await rm3(temporary, { force: true }).catch(() => void 0);
|
|
26184
26470
|
throw error52;
|
|
26185
26471
|
}
|
|
26186
26472
|
},
|
|
@@ -26193,17 +26479,17 @@ function createReleaseStateStore(root) {
|
|
|
26193
26479
|
}
|
|
26194
26480
|
);
|
|
26195
26481
|
if (!present) return;
|
|
26196
|
-
await
|
|
26197
|
-
await syncDirectory2(
|
|
26482
|
+
await rm3(path);
|
|
26483
|
+
await syncDirectory2(dirname3(path));
|
|
26198
26484
|
}
|
|
26199
26485
|
};
|
|
26200
26486
|
}
|
|
26201
26487
|
|
|
26202
26488
|
// src/worker-diagnostics.ts
|
|
26203
26489
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
26204
|
-
import { mkdir as
|
|
26205
|
-
import { homedir } from "node:os";
|
|
26206
|
-
import { isAbsolute as
|
|
26490
|
+
import { mkdir as mkdir4, readdir as readdir2, readFile as readFile5, rm as rm4, writeFile as writeFile2 } from "node:fs/promises";
|
|
26491
|
+
import { homedir as homedir2 } from "node:os";
|
|
26492
|
+
import { isAbsolute as isAbsolute7, join as join8 } from "node:path";
|
|
26207
26493
|
var WORKER_DIAGNOSTICS_DIR_ENV = "ZIXT_HOST_DIAGNOSTICS_DIR";
|
|
26208
26494
|
var RETAINED_RECORDS = 20;
|
|
26209
26495
|
var STDERR_TAIL_LINES = 40;
|
|
@@ -26211,11 +26497,11 @@ var STDERR_LINE_LIMIT = 800;
|
|
|
26211
26497
|
var RECORD_TTL_MS = 7 * 24 * 60 * 6e4;
|
|
26212
26498
|
var RECORD_FILE = /^[0-9a-f-]{36}\.json$/;
|
|
26213
26499
|
function defaultWorkerDiagnosticsRoot() {
|
|
26214
|
-
return
|
|
26500
|
+
return join8(homedir2(), ".zixt", "host-diagnostics");
|
|
26215
26501
|
}
|
|
26216
26502
|
function configuredWorkerDiagnosticsRoot(env = process.env) {
|
|
26217
26503
|
const configured = env[WORKER_DIAGNOSTICS_DIR_ENV];
|
|
26218
|
-
return typeof configured === "string" &&
|
|
26504
|
+
return typeof configured === "string" && isAbsolute7(configured) ? configured : null;
|
|
26219
26505
|
}
|
|
26220
26506
|
function boundedStderr(lines) {
|
|
26221
26507
|
return lines.slice(-STDERR_TAIL_LINES).map(
|
|
@@ -26224,13 +26510,13 @@ function boundedStderr(lines) {
|
|
|
26224
26510
|
}
|
|
26225
26511
|
async function recordWorkerExit(root, record2) {
|
|
26226
26512
|
try {
|
|
26227
|
-
await
|
|
26513
|
+
await mkdir4(root, { recursive: true, mode: 448 });
|
|
26228
26514
|
const stored = {
|
|
26229
26515
|
...record2,
|
|
26230
26516
|
schema: 1,
|
|
26231
26517
|
stderr: boundedStderr(record2.stderr)
|
|
26232
26518
|
};
|
|
26233
|
-
await
|
|
26519
|
+
await writeFile2(join8(root, `${randomUUID2()}.json`), JSON.stringify(stored), {
|
|
26234
26520
|
encoding: "utf8",
|
|
26235
26521
|
mode: 384
|
|
26236
26522
|
});
|
|
@@ -26266,7 +26552,7 @@ async function readWorkerExits(root) {
|
|
|
26266
26552
|
const stored = [];
|
|
26267
26553
|
for (const name of names) {
|
|
26268
26554
|
if (!RECORD_FILE.test(name)) continue;
|
|
26269
|
-
const file2 =
|
|
26555
|
+
const file2 = join8(root, name);
|
|
26270
26556
|
try {
|
|
26271
26557
|
const record2 = parseRecord2(await readFile5(file2, "utf8"));
|
|
26272
26558
|
if (record2) stored.push({ file: file2, record: record2 });
|
|
@@ -26276,7 +26562,7 @@ async function readWorkerExits(root) {
|
|
|
26276
26562
|
return stored.sort((a, b) => Date.parse(a.record.at) - Date.parse(b.record.at));
|
|
26277
26563
|
}
|
|
26278
26564
|
async function forgetWorkerExits(files) {
|
|
26279
|
-
await Promise.all(files.map((file2) =>
|
|
26565
|
+
await Promise.all(files.map((file2) => rm4(file2, { force: true }).catch(() => {
|
|
26280
26566
|
})));
|
|
26281
26567
|
}
|
|
26282
26568
|
async function pruneWorkerExits(root, nowMs) {
|
|
@@ -26308,26 +26594,26 @@ function describeWorkerExit(record2) {
|
|
|
26308
26594
|
}
|
|
26309
26595
|
|
|
26310
26596
|
// src/runners/run-artifacts.ts
|
|
26311
|
-
import { spawn as
|
|
26597
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
26312
26598
|
import {
|
|
26313
26599
|
chmod as chmod2,
|
|
26314
26600
|
lstat as lstat4,
|
|
26315
|
-
mkdir as
|
|
26601
|
+
mkdir as mkdir5,
|
|
26316
26602
|
open as open3,
|
|
26317
26603
|
readdir as readdir3,
|
|
26318
26604
|
readFile as readFile6,
|
|
26319
26605
|
realpath as realpath3,
|
|
26320
26606
|
rename as rename2,
|
|
26321
|
-
rm as
|
|
26322
|
-
writeFile as
|
|
26607
|
+
rm as rm5,
|
|
26608
|
+
writeFile as writeFile3
|
|
26323
26609
|
} from "node:fs/promises";
|
|
26324
|
-
import { homedir as
|
|
26325
|
-
import { dirname as
|
|
26610
|
+
import { homedir as homedir3 } from "node:os";
|
|
26611
|
+
import { dirname as dirname4, isAbsolute as isAbsolute9, join as join9, relative as relative3, resolve as resolve4, sep as sep3, win32 as win322 } from "node:path";
|
|
26326
26612
|
|
|
26327
26613
|
// src/windows-job.ts
|
|
26328
|
-
import { spawn as
|
|
26614
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
26329
26615
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
26330
|
-
import { isAbsolute as
|
|
26616
|
+
import { isAbsolute as isAbsolute8, win32 } from "node:path";
|
|
26331
26617
|
var WINDOWS_CONTAINMENT_GATE_ENV = "ZIXT_WINDOWS_CONTAINMENT_GATE";
|
|
26332
26618
|
var WINDOWS_CONTAINMENT_GATE_PREFIX = "__ZIXT_WINDOWS_CONTAINMENT_READY__";
|
|
26333
26619
|
var WINDOWS_POST_CONTAINMENT_CWD_ENV = "ZIXT_WINDOWS_POST_CONTAINMENT_CWD";
|
|
@@ -26640,7 +26926,7 @@ async function createWindowsJobContainment(pid, options) {
|
|
|
26640
26926
|
const env = options.env ?? process.env;
|
|
26641
26927
|
const nonce = randomUUID3();
|
|
26642
26928
|
const encodedSource = encodedPowershellSource(WINDOWS_JOB_HELPER_SOURCE);
|
|
26643
|
-
const helper = options.spawnHelper ? options.spawnHelper(nonce, encodedSource) :
|
|
26929
|
+
const helper = options.spawnHelper ? options.spawnHelper(nonce, encodedSource) : spawn4(
|
|
26644
26930
|
options.powershellCommand ?? defaultPowershellCommand(env),
|
|
26645
26931
|
[
|
|
26646
26932
|
"-NoLogo",
|
|
@@ -26823,7 +27109,7 @@ async function awaitWindowsContainmentGate(env = process.env, input = process.st
|
|
|
26823
27109
|
const postContainmentCwd = env[WINDOWS_POST_CONTAINMENT_CWD_ENV];
|
|
26824
27110
|
delete env[WINDOWS_POST_CONTAINMENT_CWD_ENV];
|
|
26825
27111
|
if (postContainmentCwd !== void 0) {
|
|
26826
|
-
if (!
|
|
27112
|
+
if (!isAbsolute8(postContainmentCwd)) return finish(false);
|
|
26827
27113
|
try {
|
|
26828
27114
|
process.chdir(postContainmentCwd);
|
|
26829
27115
|
} catch {
|
|
@@ -27061,7 +27347,7 @@ foreach ($path in $paths) {
|
|
|
27061
27347
|
}
|
|
27062
27348
|
`;
|
|
27063
27349
|
function defaultRunArtifactRoot() {
|
|
27064
|
-
return
|
|
27350
|
+
return join9(homedir3(), ".zixt", "run-artifacts");
|
|
27065
27351
|
}
|
|
27066
27352
|
function requireSafeSegment(value, field) {
|
|
27067
27353
|
if (!SAFE_SEGMENT.test(value)) {
|
|
@@ -27073,7 +27359,7 @@ function isMissing(error52) {
|
|
|
27073
27359
|
}
|
|
27074
27360
|
function assertBelow(parent, child) {
|
|
27075
27361
|
const path = relative3(parent, child);
|
|
27076
|
-
const escapes = path === "" || path === ".." || path.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ||
|
|
27362
|
+
const escapes = path === "" || path === ".." || path.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || isAbsolute9(path);
|
|
27077
27363
|
if (escapes) throw new Error("run artifact path escapes its private root");
|
|
27078
27364
|
}
|
|
27079
27365
|
async function requireRealDirectory(path, label) {
|
|
@@ -27108,7 +27394,7 @@ async function prepareRoot(root) {
|
|
|
27108
27394
|
const absolute = resolve4(root);
|
|
27109
27395
|
let realProfile;
|
|
27110
27396
|
if (process.platform === "win32") {
|
|
27111
|
-
const profile = resolve4(
|
|
27397
|
+
const profile = resolve4(homedir3());
|
|
27112
27398
|
assertWindowsProfileBoundary(profile, absolute);
|
|
27113
27399
|
await rejectWindowsSymlinkAncestors(profile, absolute);
|
|
27114
27400
|
realProfile = await realpath3(profile);
|
|
@@ -27117,7 +27403,7 @@ async function prepareRoot(root) {
|
|
|
27117
27403
|
await lstat4(absolute);
|
|
27118
27404
|
} catch (error52) {
|
|
27119
27405
|
if (!isMissing(error52)) throw error52;
|
|
27120
|
-
await
|
|
27406
|
+
await mkdir5(absolute, { recursive: true, mode: DIRECTORY_MODE });
|
|
27121
27407
|
}
|
|
27122
27408
|
const real = await requireRealDirectory(absolute, "run artifact root");
|
|
27123
27409
|
if (realProfile) assertWindowsProfileBoundary(realProfile, real);
|
|
@@ -27125,14 +27411,14 @@ async function prepareRoot(root) {
|
|
|
27125
27411
|
return real;
|
|
27126
27412
|
}
|
|
27127
27413
|
async function prepareAgentRoot(root, agentId) {
|
|
27128
|
-
const path =
|
|
27414
|
+
const path = join9(root, agentId);
|
|
27129
27415
|
assertBelow(root, path);
|
|
27130
27416
|
try {
|
|
27131
27417
|
await lstat4(path);
|
|
27132
27418
|
} catch (error52) {
|
|
27133
27419
|
if (!isMissing(error52)) throw error52;
|
|
27134
27420
|
try {
|
|
27135
|
-
await
|
|
27421
|
+
await mkdir5(path, { mode: DIRECTORY_MODE });
|
|
27136
27422
|
} catch (mkdirError) {
|
|
27137
27423
|
if (mkdirError.code !== "EEXIST") throw mkdirError;
|
|
27138
27424
|
}
|
|
@@ -27148,10 +27434,10 @@ async function lockDownWindowsDirectories(paths) {
|
|
|
27148
27434
|
if (!windowsRoot || !win322.isAbsolute(windowsRoot)) {
|
|
27149
27435
|
throw new Error("private Windows run-artifact ACL authority is unavailable");
|
|
27150
27436
|
}
|
|
27151
|
-
const powershell =
|
|
27437
|
+
const powershell = join9(windowsRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
|
|
27152
27438
|
const encoded = Buffer.from(WINDOWS_PRIVATE_DACL_SCRIPT, "utf16le").toString("base64");
|
|
27153
27439
|
await new Promise((resolvePromise, reject3) => {
|
|
27154
|
-
const helper =
|
|
27440
|
+
const helper = spawn5(
|
|
27155
27441
|
powershell,
|
|
27156
27442
|
["-NoLogo", "-NoProfile", "-NonInteractive", "-EncodedCommand", encoded],
|
|
27157
27443
|
{
|
|
@@ -27190,16 +27476,16 @@ async function lockDownWindowsDirectories(paths) {
|
|
|
27190
27476
|
});
|
|
27191
27477
|
}
|
|
27192
27478
|
async function createPrivateDirectory(parent, name) {
|
|
27193
|
-
const path =
|
|
27479
|
+
const path = join9(parent, name);
|
|
27194
27480
|
assertBelow(parent, path);
|
|
27195
|
-
await
|
|
27481
|
+
await mkdir5(path, { mode: DIRECTORY_MODE });
|
|
27196
27482
|
await chmod2(path, DIRECTORY_MODE);
|
|
27197
27483
|
const real = await realpath3(path);
|
|
27198
27484
|
assertBelow(parent, real);
|
|
27199
27485
|
return real;
|
|
27200
27486
|
}
|
|
27201
27487
|
async function writePrivateFile(path, content) {
|
|
27202
|
-
await
|
|
27488
|
+
await writeFile3(path, content, { flag: "wx", mode: FILE_MODE });
|
|
27203
27489
|
await chmod2(path, FILE_MODE);
|
|
27204
27490
|
}
|
|
27205
27491
|
function quotePosix(value) {
|
|
@@ -27219,24 +27505,24 @@ async function createRunArtifacts(input) {
|
|
|
27219
27505
|
requireSafeSegment(input.agentId, "agentId");
|
|
27220
27506
|
requireSafeSegment(input.runToken, "runToken");
|
|
27221
27507
|
const root = await prepareRoot(input.root);
|
|
27222
|
-
const removeTree = input.removeTree ?? ((path) =>
|
|
27508
|
+
const removeTree = input.removeTree ?? ((path) => rm5(path, { recursive: true, force: true }));
|
|
27223
27509
|
const cleanupRetryDelayMs = input.cleanupRetryDelayMs ?? CLEANUP_RETRY_DELAY_MS;
|
|
27224
27510
|
const agentRoot = await prepareAgentRoot(root, input.agentId);
|
|
27225
27511
|
await lockDownWindowsDirectories([root, agentRoot]);
|
|
27226
|
-
const runRoot =
|
|
27512
|
+
const runRoot = join9(agentRoot, input.runToken);
|
|
27227
27513
|
assertBelow(agentRoot, runRoot);
|
|
27228
27514
|
try {
|
|
27229
|
-
await
|
|
27515
|
+
await mkdir5(runRoot, { mode: DIRECTORY_MODE });
|
|
27230
27516
|
await chmod2(runRoot, DIRECTORY_MODE);
|
|
27231
27517
|
const realRunRoot = await realpath3(runRoot);
|
|
27232
27518
|
assertBelow(agentRoot, realRunRoot);
|
|
27233
27519
|
const emptyGithubConfigDirectory = await createPrivateDirectory(realRunRoot, "gh-config");
|
|
27234
27520
|
const emptyGitHooksDirectory = await createPrivateDirectory(realRunRoot, "git-hooks");
|
|
27235
27521
|
const gitBridgesDirectory = await createPrivateDirectory(realRunRoot, "git-bridges");
|
|
27236
|
-
const denySshScript =
|
|
27237
|
-
const runnerWrapperScript =
|
|
27238
|
-
const systemPromptPath =
|
|
27239
|
-
const mcpConfigPath =
|
|
27522
|
+
const denySshScript = join9(realRunRoot, "deny-ssh.cjs");
|
|
27523
|
+
const runnerWrapperScript = join9(realRunRoot, "runner-wrapper.cjs");
|
|
27524
|
+
const systemPromptPath = join9(realRunRoot, "system-prompt.txt");
|
|
27525
|
+
const mcpConfigPath = join9(realRunRoot, "mcp.json");
|
|
27240
27526
|
await writePrivateFile(denySshScript, "process.exitCode = 127;");
|
|
27241
27527
|
await writePrivateFile(runnerWrapperScript, RUNNER_GUARDIAN);
|
|
27242
27528
|
return {
|
|
@@ -27258,9 +27544,9 @@ async function createRunArtifacts(input) {
|
|
|
27258
27544
|
},
|
|
27259
27545
|
async writePrivateDataFile(name, content) {
|
|
27260
27546
|
requireSafeSegment(name, "private file name");
|
|
27261
|
-
const path =
|
|
27547
|
+
const path = join9(realRunRoot, name);
|
|
27262
27548
|
assertBelow(realRunRoot, path);
|
|
27263
|
-
await
|
|
27549
|
+
await writeFile3(path, content, { flag: "wx", mode: FILE_MODE });
|
|
27264
27550
|
await chmod2(path, FILE_MODE);
|
|
27265
27551
|
return path;
|
|
27266
27552
|
},
|
|
@@ -27289,7 +27575,7 @@ async function sweepOrphanedRunArtifacts(root) {
|
|
|
27289
27575
|
const absolute = resolve4(root);
|
|
27290
27576
|
let realProfile;
|
|
27291
27577
|
if (process.platform === "win32") {
|
|
27292
|
-
const profile = resolve4(
|
|
27578
|
+
const profile = resolve4(homedir3());
|
|
27293
27579
|
assertWindowsProfileBoundary(profile, absolute);
|
|
27294
27580
|
await rejectWindowsSymlinkAncestors(profile, absolute);
|
|
27295
27581
|
realProfile = await realpath3(profile);
|
|
@@ -27308,20 +27594,20 @@ async function sweepOrphanedRunArtifacts(root) {
|
|
|
27308
27594
|
let removed = 0;
|
|
27309
27595
|
for (const agent of agents) {
|
|
27310
27596
|
if (!SAFE_SEGMENT.test(agent.name) || !agent.isDirectory() || agent.isSymbolicLink()) continue;
|
|
27311
|
-
const agentPath =
|
|
27597
|
+
const agentPath = join9(realRoot, agent.name);
|
|
27312
27598
|
const runs = await readdir3(agentPath, { withFileTypes: true });
|
|
27313
27599
|
for (const run3 of runs) {
|
|
27314
27600
|
if (!SAFE_SEGMENT.test(run3.name) || !run3.isDirectory() || run3.isSymbolicLink()) continue;
|
|
27315
|
-
const runPath =
|
|
27601
|
+
const runPath = join9(agentPath, run3.name);
|
|
27316
27602
|
assertBelow(agentPath, runPath);
|
|
27317
|
-
await
|
|
27603
|
+
await rm5(runPath, { recursive: true, force: true });
|
|
27318
27604
|
removed++;
|
|
27319
27605
|
}
|
|
27320
27606
|
}
|
|
27321
27607
|
return removed;
|
|
27322
27608
|
}
|
|
27323
27609
|
function defaultRunRegistryRoot() {
|
|
27324
|
-
return
|
|
27610
|
+
return join9(homedir3(), ".zixt", "run-registry");
|
|
27325
27611
|
}
|
|
27326
27612
|
async function terminateRecordedRunProcesses(registryRoot = defaultRunRegistryRoot(), terminate = terminateRecordedProcessTree) {
|
|
27327
27613
|
const entries = await readRecordedRunAssignmentEntriesStrict(registryRoot);
|
|
@@ -27347,23 +27633,23 @@ async function syncRunRegistryDirectory(path) {
|
|
|
27347
27633
|
}
|
|
27348
27634
|
}
|
|
27349
27635
|
async function ensureDurableRunRegistryRoot(registryRoot, syncDirectory8) {
|
|
27350
|
-
const firstCreated = await
|
|
27636
|
+
const firstCreated = await mkdir5(registryRoot, { recursive: true, mode: DIRECTORY_MODE });
|
|
27351
27637
|
if (firstCreated && process.platform !== "win32") {
|
|
27352
27638
|
const first = resolve4(firstCreated);
|
|
27353
27639
|
const target = resolve4(registryRoot);
|
|
27354
|
-
await syncDirectory8(
|
|
27640
|
+
await syncDirectory8(dirname4(first));
|
|
27355
27641
|
let current = first;
|
|
27356
27642
|
for (const part of relative3(first, target).split(sep3).filter(Boolean)) {
|
|
27357
27643
|
await syncDirectory8(current);
|
|
27358
|
-
current =
|
|
27644
|
+
current = join9(current, part);
|
|
27359
27645
|
}
|
|
27360
27646
|
}
|
|
27361
27647
|
await chmod2(registryRoot, DIRECTORY_MODE);
|
|
27362
27648
|
}
|
|
27363
27649
|
async function recordRunAssignment(runToken, record2, registryRoot = defaultRunRegistryRoot(), options = {}) {
|
|
27364
27650
|
if (!SAFE_SEGMENT.test(runToken)) return false;
|
|
27365
|
-
const destination =
|
|
27366
|
-
const temporary =
|
|
27651
|
+
const destination = join9(registryRoot, `${runToken}.json`);
|
|
27652
|
+
const temporary = join9(registryRoot, `.${runToken}.${process.pid}.${Date.now()}.tmp`);
|
|
27367
27653
|
let handle;
|
|
27368
27654
|
try {
|
|
27369
27655
|
const syncDirectory8 = options.syncDirectory ?? syncRunRegistryDirectory;
|
|
@@ -27383,7 +27669,7 @@ async function recordRunAssignment(runToken, record2, registryRoot = defaultRunR
|
|
|
27383
27669
|
} finally {
|
|
27384
27670
|
await handle?.close().catch(() => {
|
|
27385
27671
|
});
|
|
27386
|
-
await
|
|
27672
|
+
await rm5(temporary, { force: true }).catch(() => {
|
|
27387
27673
|
});
|
|
27388
27674
|
}
|
|
27389
27675
|
}
|
|
@@ -27395,7 +27681,7 @@ async function forgetRunAssignment(runToken, registryRoot = defaultRunRegistryRo
|
|
|
27395
27681
|
if (retainingAssignments) return;
|
|
27396
27682
|
if (!SAFE_SEGMENT.test(runToken)) return;
|
|
27397
27683
|
try {
|
|
27398
|
-
await
|
|
27684
|
+
await rm5(join9(registryRoot, `${runToken}.json`), { force: true });
|
|
27399
27685
|
} catch {
|
|
27400
27686
|
}
|
|
27401
27687
|
}
|
|
@@ -27440,7 +27726,7 @@ async function readRecordedRunAssignmentEntries(registryRoot = defaultRunRegistr
|
|
|
27440
27726
|
if (!SAFE_SEGMENT.test(runToken)) continue;
|
|
27441
27727
|
let text;
|
|
27442
27728
|
try {
|
|
27443
|
-
text = await readFile6(
|
|
27729
|
+
text = await readFile6(join9(registryRoot, entry.name), "utf8");
|
|
27444
27730
|
} catch {
|
|
27445
27731
|
continue;
|
|
27446
27732
|
}
|
|
@@ -27476,7 +27762,7 @@ async function readRecordedRunAssignmentEntriesStrict(registryRoot = defaultRunR
|
|
|
27476
27762
|
}
|
|
27477
27763
|
let text;
|
|
27478
27764
|
try {
|
|
27479
|
-
text = await readFile6(
|
|
27765
|
+
text = await readFile6(join9(registryRoot, entry.name), "utf8");
|
|
27480
27766
|
} catch {
|
|
27481
27767
|
throw new Error("committed run registry witness could not be read");
|
|
27482
27768
|
}
|
|
@@ -27493,13 +27779,13 @@ async function forgetAcknowledgedRunAssignments(assignments, registryRoot = defa
|
|
|
27493
27779
|
);
|
|
27494
27780
|
const entries = await readRecordedRunAssignmentEntries(registryRoot);
|
|
27495
27781
|
await Promise.all(
|
|
27496
|
-
entries.filter(({ record: record2 }) => acknowledged.has(`${record2.taskId}:${record2.epoch}`)).map(({ runToken }) =>
|
|
27782
|
+
entries.filter(({ record: record2 }) => acknowledged.has(`${record2.taskId}:${record2.epoch}`)).map(({ runToken }) => rm5(join9(registryRoot, `${runToken}.json`), { force: true }))
|
|
27497
27783
|
);
|
|
27498
27784
|
}
|
|
27499
27785
|
async function forgetSupersededRunAssignments(taskId, epoch, registryRoot = defaultRunRegistryRoot()) {
|
|
27500
27786
|
const entries = await readRecordedRunAssignmentEntries(registryRoot);
|
|
27501
27787
|
await Promise.all(
|
|
27502
|
-
entries.filter(({ record: record2 }) => record2.taskId === taskId && record2.epoch < epoch).map(({ runToken }) =>
|
|
27788
|
+
entries.filter(({ record: record2 }) => record2.taskId === taskId && record2.epoch < epoch).map(({ runToken }) => rm5(join9(registryRoot, `${runToken}.json`), { force: true }))
|
|
27503
27789
|
);
|
|
27504
27790
|
}
|
|
27505
27791
|
|
|
@@ -27525,7 +27811,7 @@ function streakBackoffMs(streak) {
|
|
|
27525
27811
|
var RELEASE_PROBATION_MS = 5 * 6e4;
|
|
27526
27812
|
var FAST_UPDATE_EXIT_MS = 1e4;
|
|
27527
27813
|
var STOP_GRACE_MS = 3e4;
|
|
27528
|
-
var
|
|
27814
|
+
var INSTALL_TIMEOUT_MS2 = 5 * 6e4;
|
|
27529
27815
|
var WORKER_WATCHDOG_CHECK_MS = 1e3;
|
|
27530
27816
|
var WORKER_WATCHDOG_TIMEOUT_MS = 15e3;
|
|
27531
27817
|
var WORKER_WATCHDOG_STARTUP_MS = 6e4;
|
|
@@ -27567,39 +27853,16 @@ function captureWorkerStderr(child) {
|
|
|
27567
27853
|
return () => (partial2 ? [...lines, partial2] : [...lines]).slice(-WORKER_STDERR_TAIL_LINES);
|
|
27568
27854
|
}
|
|
27569
27855
|
function versionsRoot() {
|
|
27570
|
-
return process.env.ZIXT_HOST_VERSIONS_DIR ??
|
|
27571
|
-
}
|
|
27572
|
-
function npmCommand(platform = process.platform) {
|
|
27573
|
-
return platform === "win32" ? "npm.cmd" : "npm";
|
|
27574
|
-
}
|
|
27575
|
-
async function resolveInstallerCommand(options = {}) {
|
|
27576
|
-
const platform = options.platform ?? process.platform;
|
|
27577
|
-
const command = npmCommand(platform);
|
|
27578
|
-
if (platform !== "win32") return command;
|
|
27579
|
-
const execPath = options.execPath ?? process.execPath;
|
|
27580
|
-
const resolution = {
|
|
27581
|
-
platform,
|
|
27582
|
-
...options.searchPath !== void 0 ? { searchPath: options.searchPath } : {}
|
|
27583
|
-
};
|
|
27584
|
-
return (
|
|
27585
|
-
// npm ships beside the `node` running this process, and that copy is the
|
|
27586
|
-
// one matching it. A per-user Scheduled Task may carry no npm on PATH.
|
|
27587
|
-
await resolveTrustedCliCommand(join8(dirname4(execPath), command), resolution) ?? await resolveTrustedCliCommand(command, resolution) ?? // Nothing resolved: keep the previous behaviour, so a Machine without npm
|
|
27588
|
-
// fails one install rather than changing how failure is handled.
|
|
27589
|
-
command
|
|
27590
|
-
);
|
|
27591
|
-
}
|
|
27592
|
-
function windowsInstallerCommandLine(command, args) {
|
|
27593
|
-
return [command, ...args].map(quoteForCmd).join(" ");
|
|
27856
|
+
return process.env.ZIXT_HOST_VERSIONS_DIR ?? join10(homedir4(), ".zixt", "host-versions");
|
|
27594
27857
|
}
|
|
27595
27858
|
function installedReleaseEntry(version2, root = versionsRoot()) {
|
|
27596
|
-
return
|
|
27859
|
+
return join10(root, version2, "node_modules", PACKAGE_NAME, "dist", "index.js");
|
|
27597
27860
|
}
|
|
27598
27861
|
function releaseEntryAtPrefix(prefix) {
|
|
27599
|
-
return
|
|
27862
|
+
return join10(prefix, "node_modules", PACKAGE_NAME, "dist", "index.js");
|
|
27600
27863
|
}
|
|
27601
27864
|
function releaseManifestAtPrefix(prefix) {
|
|
27602
|
-
return
|
|
27865
|
+
return join10(prefix, "node_modules", PACKAGE_NAME, "package.json");
|
|
27603
27866
|
}
|
|
27604
27867
|
async function validReleaseAtPrefix(prefix, version2) {
|
|
27605
27868
|
try {
|
|
@@ -27624,9 +27887,9 @@ async function syncDirectory3(path) {
|
|
|
27624
27887
|
}
|
|
27625
27888
|
}
|
|
27626
27889
|
function installedReleaseVersion(entry, root = versionsRoot()) {
|
|
27627
|
-
if (!
|
|
27890
|
+
if (!isAbsolute10(entry)) return null;
|
|
27628
27891
|
const relativeEntry = relative4(resolve5(root), resolve5(entry));
|
|
27629
|
-
if (!relativeEntry || relativeEntry.startsWith(`..${sep4}`) ||
|
|
27892
|
+
if (!relativeEntry || relativeEntry.startsWith(`..${sep4}`) || isAbsolute10(relativeEntry)) {
|
|
27630
27893
|
return null;
|
|
27631
27894
|
}
|
|
27632
27895
|
const version2 = relativeEntry.split(sep4)[0];
|
|
@@ -27634,10 +27897,10 @@ function installedReleaseVersion(entry, root = versionsRoot()) {
|
|
|
27634
27897
|
return resolve5(entry) === resolve5(installedReleaseEntry(version2, root)) ? version2 : null;
|
|
27635
27898
|
}
|
|
27636
27899
|
function currentReleaseEntry(root = versionsRoot(), platform = process.platform) {
|
|
27637
|
-
return
|
|
27900
|
+
return join10(root, platform === "win32" ? "current-launcher.cjs" : CURRENT_RELEASE_ENTRY);
|
|
27638
27901
|
}
|
|
27639
27902
|
function windowsReleasePointer(root = versionsRoot()) {
|
|
27640
|
-
return
|
|
27903
|
+
return join10(root, WINDOWS_RELEASE_POINTER);
|
|
27641
27904
|
}
|
|
27642
27905
|
var WINDOWS_STABLE_LAUNCHER = `${WINDOWS_LAUNCHER_MARKER}
|
|
27643
27906
|
'use strict';
|
|
@@ -27672,9 +27935,9 @@ child.once('error', () => process.exit(1));
|
|
|
27672
27935
|
child.once('exit', (code) => process.exit(code == null ? 1 : code));
|
|
27673
27936
|
`;
|
|
27674
27937
|
async function replaceDurableFile(path, contents, sync = syncDirectory3) {
|
|
27675
|
-
const parent =
|
|
27676
|
-
await
|
|
27677
|
-
const temporary =
|
|
27938
|
+
const parent = dirname5(path);
|
|
27939
|
+
await mkdir6(parent, { recursive: true, mode: 448 });
|
|
27940
|
+
const temporary = join10(parent, `.${CURRENT_RELEASE_ENTRY}.${process.pid}.${crypto.randomUUID()}`);
|
|
27678
27941
|
const handle = await open4(temporary, "wx", 384);
|
|
27679
27942
|
try {
|
|
27680
27943
|
await handle.writeFile(contents, "utf8");
|
|
@@ -27684,7 +27947,7 @@ async function replaceDurableFile(path, contents, sync = syncDirectory3) {
|
|
|
27684
27947
|
await sync(parent);
|
|
27685
27948
|
} catch (error52) {
|
|
27686
27949
|
await handle.close().catch(() => void 0);
|
|
27687
|
-
await
|
|
27950
|
+
await rm6(temporary, { force: true }).catch(() => void 0);
|
|
27688
27951
|
throw error52;
|
|
27689
27952
|
}
|
|
27690
27953
|
}
|
|
@@ -27694,7 +27957,7 @@ async function activateInstalledRelease(entry, root = versionsRoot(), platform =
|
|
|
27694
27957
|
}
|
|
27695
27958
|
await access2(entry);
|
|
27696
27959
|
if (platform === "win32") {
|
|
27697
|
-
await
|
|
27960
|
+
await mkdir6(root, { recursive: true, mode: 448 });
|
|
27698
27961
|
const launcher = currentReleaseEntry(root, platform);
|
|
27699
27962
|
const existingLauncher = await lstat5(launcher).catch((error52) => {
|
|
27700
27963
|
if (error52.code === "ENOENT") return null;
|
|
@@ -27743,7 +28006,7 @@ async function activateInstalledRelease(entry, root = versionsRoot(), platform =
|
|
|
27743
28006
|
return launcher;
|
|
27744
28007
|
}
|
|
27745
28008
|
if (platform !== "linux" && platform !== "darwin") return entry;
|
|
27746
|
-
await
|
|
28009
|
+
await mkdir6(root, { recursive: true, mode: 448 });
|
|
27747
28010
|
const current = currentReleaseEntry(root, platform);
|
|
27748
28011
|
const existing = await lstat5(current).catch((error52) => {
|
|
27749
28012
|
if (error52.code === "ENOENT") return null;
|
|
@@ -27752,13 +28015,13 @@ async function activateInstalledRelease(entry, root = versionsRoot(), platform =
|
|
|
27752
28015
|
if (existing && !existing.isSymbolicLink()) {
|
|
27753
28016
|
throw new Error("the Zixt Host current-release entry is not a symbolic link");
|
|
27754
28017
|
}
|
|
27755
|
-
const temporary =
|
|
28018
|
+
const temporary = join10(root, `.${CURRENT_RELEASE_ENTRY}.${process.pid}.${crypto.randomUUID()}`);
|
|
27756
28019
|
try {
|
|
27757
28020
|
await symlink(entry, temporary, "file");
|
|
27758
28021
|
await rename3(temporary, current);
|
|
27759
28022
|
await sync(root);
|
|
27760
28023
|
} catch (error52) {
|
|
27761
|
-
await
|
|
28024
|
+
await rm6(temporary, { force: true }).catch(() => void 0);
|
|
27762
28025
|
throw error52;
|
|
27763
28026
|
}
|
|
27764
28027
|
return current;
|
|
@@ -27779,43 +28042,11 @@ async function activatedReleaseVersion(root = versionsRoot(), platform = process
|
|
|
27779
28042
|
try {
|
|
27780
28043
|
const current = currentReleaseEntry(root, platform);
|
|
27781
28044
|
const target = await readlink(current);
|
|
27782
|
-
return installedReleaseVersion(resolve5(
|
|
28045
|
+
return installedReleaseVersion(resolve5(dirname5(current), target), root);
|
|
27783
28046
|
} catch {
|
|
27784
28047
|
return null;
|
|
27785
28048
|
}
|
|
27786
28049
|
}
|
|
27787
|
-
function sanitizedInstallerEnv(inherited) {
|
|
27788
|
-
const allowed = /* @__PURE__ */ new Set([
|
|
27789
|
-
"PATH",
|
|
27790
|
-
"HOME",
|
|
27791
|
-
"USERPROFILE",
|
|
27792
|
-
"SYSTEMROOT",
|
|
27793
|
-
"WINDIR",
|
|
27794
|
-
"TEMP",
|
|
27795
|
-
"TMP",
|
|
27796
|
-
"TMPDIR",
|
|
27797
|
-
"LOCALAPPDATA",
|
|
27798
|
-
"APPDATA",
|
|
27799
|
-
"XDG_CONFIG_HOME",
|
|
27800
|
-
"XDG_CACHE_HOME",
|
|
27801
|
-
"HTTP_PROXY",
|
|
27802
|
-
"HTTPS_PROXY",
|
|
27803
|
-
"NO_PROXY",
|
|
27804
|
-
"ALL_PROXY",
|
|
27805
|
-
"NODE_EXTRA_CA_CERTS",
|
|
27806
|
-
"SSL_CERT_FILE",
|
|
27807
|
-
"SSL_CERT_DIR",
|
|
27808
|
-
"NPM_CONFIG_REGISTRY",
|
|
27809
|
-
"NPM_CONFIG_CACHE",
|
|
27810
|
-
"NPM_CONFIG_USERCONFIG",
|
|
27811
|
-
"NPM_CONFIG_STRICT_SSL"
|
|
27812
|
-
]);
|
|
27813
|
-
return Object.fromEntries(
|
|
27814
|
-
Object.entries(inherited).filter(
|
|
27815
|
-
([name, value]) => value !== void 0 && allowed.has(name.toUpperCase())
|
|
27816
|
-
)
|
|
27817
|
-
);
|
|
27818
|
-
}
|
|
27819
28050
|
var WINDOWS_INSTALLER_GUARDIAN = String.raw`
|
|
27820
28051
|
const { spawn } = require('node:child_process');
|
|
27821
28052
|
const nonce = process.argv[1];
|
|
@@ -27860,7 +28091,13 @@ process.stdin.on('data', (chunk) => {
|
|
|
27860
28091
|
const target = spawn(config.commandLine, {
|
|
27861
28092
|
cwd: config.cwd,
|
|
27862
28093
|
env: process.env,
|
|
27863
|
-
|
|
28094
|
+
// Never share this guardian's stdin with npm. The guardian keeps an
|
|
28095
|
+
// active read pending on that pipe (the config protocol above), and a
|
|
28096
|
+
// Windows child whose inherited stdin pipe has a concurrent reader wedges
|
|
28097
|
+
// inside Node startup until the reader dies - npm sat at zero CPU for the
|
|
28098
|
+
// whole install timeout on a real Machine (live, 2026-08-18). An
|
|
28099
|
+
// unattended install may never depend on stdin anyway.
|
|
28100
|
+
stdio: ['ignore', 'inherit', 'inherit'],
|
|
27864
28101
|
windowsHide: true,
|
|
27865
28102
|
// cmd.exe has to resolve npm.cmd, so the shell stays - but the whole line
|
|
27866
28103
|
// arrives pre-quoted as one string. Node's (command, args, shell) shape is
|
|
@@ -27893,15 +28130,15 @@ async function installRelease(version2, options = {}) {
|
|
|
27893
28130
|
}
|
|
27894
28131
|
const platform = options.platform ?? process.platform;
|
|
27895
28132
|
const root = options.root ?? versionsRoot();
|
|
27896
|
-
const prefix =
|
|
28133
|
+
const prefix = join10(root, version2);
|
|
27897
28134
|
const entry = installedReleaseEntry(version2, root);
|
|
27898
28135
|
if (await validReleaseAtPrefix(prefix, version2)) return entry;
|
|
27899
28136
|
if (options.signal?.aborted)
|
|
27900
28137
|
return fail("cancelled", "this Host was stopping before npm started");
|
|
27901
28138
|
const installerCommand = options.installerCommand ?? await resolveInstallerCommand({ platform });
|
|
27902
|
-
await
|
|
27903
|
-
const staging =
|
|
27904
|
-
const quarantine =
|
|
28139
|
+
await mkdir6(root, { recursive: true, mode: 448 });
|
|
28140
|
+
const staging = join10(root, `.install-${version2}-${process.pid}-${crypto.randomUUID()}`);
|
|
28141
|
+
const quarantine = join10(root, `.invalid-${version2}-${process.pid}-${crypto.randomUUID()}`);
|
|
27905
28142
|
const usesWindowsInstallerGuardian = platform === "win32" && options.spawnInstaller === void 0;
|
|
27906
28143
|
const installerGateNonce = usesWindowsInstallerGuardian ? crypto.randomUUID() : null;
|
|
27907
28144
|
const installerArguments = (installPrefix, installVersion) => [
|
|
@@ -27916,15 +28153,18 @@ async function installRelease(version2, options = {}) {
|
|
|
27916
28153
|
const spawnInstaller = options.spawnInstaller ?? ((installPrefix, installVersion) => {
|
|
27917
28154
|
const installerArgs = installerArguments(installPrefix, installVersion);
|
|
27918
28155
|
if (usesWindowsInstallerGuardian) {
|
|
27919
|
-
return
|
|
28156
|
+
return spawn6(process.execPath, ["-e", WINDOWS_INSTALLER_GUARDIAN, installerGateNonce], {
|
|
27920
28157
|
cwd: root,
|
|
27921
28158
|
stdio: ["pipe", "inherit", "inherit", "ipc"],
|
|
27922
28159
|
env: sanitizedInstallerEnv(process.env),
|
|
27923
28160
|
windowsHide: true
|
|
27924
28161
|
});
|
|
27925
28162
|
}
|
|
27926
|
-
return
|
|
27927
|
-
|
|
28163
|
+
return spawn6(installerCommand, installerArgs, {
|
|
28164
|
+
// stdin stays closed for the same reason as the Windows guardian
|
|
28165
|
+
// above: this worker actively reads its own stdin (the supervisor's
|
|
28166
|
+
// stop pipe), and an unattended npm must not share or depend on it.
|
|
28167
|
+
stdio: ["ignore", "inherit", "inherit"],
|
|
27928
28168
|
env: sanitizedInstallerEnv(process.env),
|
|
27929
28169
|
detached: true
|
|
27930
28170
|
});
|
|
@@ -27933,7 +28173,7 @@ async function installRelease(version2, options = {}) {
|
|
|
27933
28173
|
try {
|
|
27934
28174
|
child = spawnInstaller(staging, version2);
|
|
27935
28175
|
} catch (error52) {
|
|
27936
|
-
await
|
|
28176
|
+
await rm6(staging, { recursive: true, force: true }).catch(() => void 0);
|
|
27937
28177
|
return fail(
|
|
27938
28178
|
"installer_unavailable",
|
|
27939
28179
|
`${installerCommand} could not be started (${error52 instanceof Error ? error52.message : "unknown error"})`
|
|
@@ -27959,7 +28199,7 @@ async function installRelease(version2, options = {}) {
|
|
|
27959
28199
|
installerContainmentSetupError = error52;
|
|
27960
28200
|
return null;
|
|
27961
28201
|
}) : Promise.resolve(null);
|
|
27962
|
-
const timeoutMs = options.timeoutMs ??
|
|
28202
|
+
const timeoutMs = options.timeoutMs ?? INSTALL_TIMEOUT_MS2;
|
|
27963
28203
|
const outcome = { code: null, signal: null, timedOut: false, spawnError: null };
|
|
27964
28204
|
const installed = await new Promise((resolve18, reject3) => {
|
|
27965
28205
|
let finished = false;
|
|
@@ -28130,8 +28370,8 @@ async function installRelease(version2, options = {}) {
|
|
|
28130
28370
|
`${prefix} is not a runnable ${PACKAGE_NAME}@${version2} after installing`
|
|
28131
28371
|
);
|
|
28132
28372
|
} finally {
|
|
28133
|
-
await
|
|
28134
|
-
await
|
|
28373
|
+
await rm6(staging, { recursive: true, force: true }).catch(() => void 0);
|
|
28374
|
+
await rm6(quarantine, { recursive: true, force: true }).catch(() => void 0);
|
|
28135
28375
|
}
|
|
28136
28376
|
}
|
|
28137
28377
|
async function pruneInstalledVersions(keep, root = versionsRoot()) {
|
|
@@ -28146,10 +28386,10 @@ async function pruneInstalledVersions(keep, root = versionsRoot()) {
|
|
|
28146
28386
|
const removed = [];
|
|
28147
28387
|
for (const name of entries) {
|
|
28148
28388
|
if (protectedDirs.has(name) || !VERSION_DIR.test(name)) continue;
|
|
28149
|
-
const dir =
|
|
28389
|
+
const dir = join10(root, name);
|
|
28150
28390
|
if (running && running.startsWith(`${dir}${sep4}`)) continue;
|
|
28151
28391
|
try {
|
|
28152
|
-
await
|
|
28392
|
+
await rm6(dir, { recursive: true, force: true });
|
|
28153
28393
|
removed.push(name);
|
|
28154
28394
|
} catch {
|
|
28155
28395
|
}
|
|
@@ -28160,7 +28400,7 @@ function durableState(phase, candidateVersion, fallbackVersion) {
|
|
|
28160
28400
|
return { schema: 1, phase, candidateVersion, fallbackVersion };
|
|
28161
28401
|
}
|
|
28162
28402
|
async function validInstalledRelease(version2, root = versionsRoot()) {
|
|
28163
|
-
return validReleaseAtPrefix(
|
|
28403
|
+
return validReleaseAtPrefix(join10(root, version2), version2);
|
|
28164
28404
|
}
|
|
28165
28405
|
async function recoverDurableReleaseState(store, runningVersion, activeBootVersion, activate, log2) {
|
|
28166
28406
|
const state = await store.load();
|
|
@@ -28278,7 +28518,7 @@ function defaultSpawn(command, argv, supervisorVersion, watchdog, compatibilityO
|
|
|
28278
28518
|
delete env.ZIXT_HOST_REJECT_VERSION;
|
|
28279
28519
|
if (command.rejectedVersion) env.ZIXT_HOST_REJECT_VERSION = command.rejectedVersion;
|
|
28280
28520
|
const entry = compatibilityProxy ? process.argv[1] ?? "" : command.entry ?? process.argv[1] ?? "";
|
|
28281
|
-
const child =
|
|
28521
|
+
const child = spawn6(process.execPath, [entry, ...argv, ...ownership?.argv ?? []], {
|
|
28282
28522
|
// stdin is a pipe this process owns: closing it is how the worker is
|
|
28283
28523
|
// asked to stop, which works identically on Windows, where there is no
|
|
28284
28524
|
// real SIGINT to send. stdout stays the person's terminal; stderr is teed
|
|
@@ -28286,7 +28526,7 @@ function defaultSpawn(command, argv, supervisorVersion, watchdog, compatibilityO
|
|
|
28286
28526
|
stdio: watchdog ? ["pipe", "inherit", "pipe", "ipc"] : ["pipe", "inherit", "pipe"],
|
|
28287
28527
|
env,
|
|
28288
28528
|
...containmentGateNonce ? {
|
|
28289
|
-
cwd: ownership?.ownershipFile ?
|
|
28529
|
+
cwd: ownership?.ownershipFile ? dirname5(ownership.ownershipFile) : dirname5(entry)
|
|
28290
28530
|
} : {},
|
|
28291
28531
|
// The launch nonce is not a user-facing CLI argument. Keeping it as
|
|
28292
28532
|
// argv[0] gives the stable launcher an exact cross-platform process
|
|
@@ -28315,7 +28555,7 @@ async function runWorkerCompatibilityProxy(env = process.env, argv = process.arg
|
|
|
28315
28555
|
const ownership = consumeWorkerOwnershipArguments(argv, env);
|
|
28316
28556
|
const nonce = env[WORKER_WATCHDOG_NONCE_ENV];
|
|
28317
28557
|
const ownershipFile = env[WORKER_OWNERSHIP_FILE_ENV];
|
|
28318
|
-
if (typeof target !== "string" || !
|
|
28558
|
+
if (typeof target !== "string" || !isAbsolute10(target) || typeof nonce !== "string" || typeof ownershipFile !== "string" || !ownership.requested || !ownership.valid) {
|
|
28319
28559
|
return 1;
|
|
28320
28560
|
}
|
|
28321
28561
|
if (!recordWorkerOwnership(ownershipFile, nonce)) return 1;
|
|
@@ -28330,7 +28570,9 @@ async function runWorkerCompatibilityProxy(env = process.env, argv = process.arg
|
|
|
28330
28570
|
delete workerEnv[WORKER_OWNERSHIP_FILE_ENV];
|
|
28331
28571
|
delete workerEnv[LAUNCHER_OWNERSHIP_DIR_ENV];
|
|
28332
28572
|
delete workerEnv[SUPERVISOR_OWNERSHIP_FILE_ENV];
|
|
28333
|
-
|
|
28573
|
+
delete workerEnv[WINDOWS_CONTAINMENT_GATE_ENV];
|
|
28574
|
+
delete workerEnv[WINDOWS_POST_CONTAINMENT_CWD_ENV];
|
|
28575
|
+
const child = spawn6(process.execPath, [target, ...ownership.argv], {
|
|
28334
28576
|
stdio: ["pipe", "inherit", "inherit"],
|
|
28335
28577
|
env: workerEnv,
|
|
28336
28578
|
// The proxy is already a detached group/session leader on POSIX. The old
|
|
@@ -28386,7 +28628,7 @@ async function launchHostSupervisor(options = {}) {
|
|
|
28386
28628
|
const generationNonce = ownershipDirectory ? basename3(ownershipDirectory) : null;
|
|
28387
28629
|
if (ownershipDirectory && generationNonce) {
|
|
28388
28630
|
env[LAUNCHER_OWNERSHIP_DIR_ENV] = ownershipDirectory;
|
|
28389
|
-
env[SUPERVISOR_OWNERSHIP_FILE_ENV] =
|
|
28631
|
+
env[SUPERVISOR_OWNERSHIP_FILE_ENV] = join10(ownershipDirectory, `${generationNonce}.json`);
|
|
28390
28632
|
} else {
|
|
28391
28633
|
delete env[LAUNCHER_OWNERSHIP_DIR_ENV];
|
|
28392
28634
|
}
|
|
@@ -28394,10 +28636,10 @@ async function launchHostSupervisor(options = {}) {
|
|
|
28394
28636
|
if (!containmentGateNonce) delete env[WINDOWS_POST_CONTAINMENT_CWD_ENV];
|
|
28395
28637
|
if (version2) env[SUPERVISOR_VERSION_ENV] = version2;
|
|
28396
28638
|
else delete env[SUPERVISOR_VERSION_ENV];
|
|
28397
|
-
const child2 =
|
|
28639
|
+
const child2 = spawn6(process.execPath, [supervisorEntry, ...argv], {
|
|
28398
28640
|
stdio: ["pipe", "inherit", "inherit"],
|
|
28399
28641
|
env,
|
|
28400
|
-
...containmentGateNonce ? { cwd: ownershipDirectory ??
|
|
28642
|
+
...containmentGateNonce ? { cwd: ownershipDirectory ?? dirname5(supervisorEntry) } : {},
|
|
28401
28643
|
detached: platform !== "win32",
|
|
28402
28644
|
// The new launcher can discover the durable PID record and still has
|
|
28403
28645
|
// to bind it to this exact process before signalling a recycled PID.
|
|
@@ -28409,8 +28651,8 @@ async function launchHostSupervisor(options = {}) {
|
|
|
28409
28651
|
});
|
|
28410
28652
|
const customDelay = options.delay;
|
|
28411
28653
|
const ownsWorkerBoundary = options.spawnSupervisor === void 0 || options.ownershipRoot !== void 0;
|
|
28412
|
-
const ownershipRoot = options.ownershipRoot ??
|
|
28413
|
-
const runRegistryRoot2 = options.runRegistryRoot ?? (options.ownershipRoot ?
|
|
28654
|
+
const ownershipRoot = options.ownershipRoot ?? join10(versionsRoot(), "launcher-ownership");
|
|
28655
|
+
const runRegistryRoot2 = options.runRegistryRoot ?? (options.ownershipRoot ? join10(dirname5(options.ownershipRoot), "run-registry") : defaultRunRegistryRoot());
|
|
28414
28656
|
const terminateRecordedOwnership = options.terminateRecordedOwnership ?? terminateRecordedProcessTree;
|
|
28415
28657
|
const createSupervisorContainment = options.createSupervisorContainment ?? (platform === "win32" && options.spawnSupervisor === void 0 ? async (target, identityNonce, signal) => {
|
|
28416
28658
|
if (!target.pid) throw new Error("supervisor process id is unavailable");
|
|
@@ -28519,8 +28761,8 @@ async function launchHostSupervisor(options = {}) {
|
|
|
28519
28761
|
let stdinIsPipe = options.parentStdinIsPipe ?? false;
|
|
28520
28762
|
if (options.parentStdinIsPipe === void 0) {
|
|
28521
28763
|
try {
|
|
28522
|
-
const
|
|
28523
|
-
stdinIsPipe = !
|
|
28764
|
+
const stat4 = fstatSync(0);
|
|
28765
|
+
stdinIsPipe = !stat4.isCharacterDevice() && !stat4.isFile() && !process.stdin.isTTY;
|
|
28524
28766
|
} catch {
|
|
28525
28767
|
}
|
|
28526
28768
|
}
|
|
@@ -28677,10 +28919,10 @@ async function superviseHost(options = {}) {
|
|
|
28677
28919
|
const log2 = options.log ?? ((message) => console.error(message));
|
|
28678
28920
|
const signalWorker = options.signalWorker ?? signalWorkerGroup;
|
|
28679
28921
|
const inheritedOwnershipDirectory = process.env[LAUNCHER_OWNERSHIP_DIR_ENV];
|
|
28680
|
-
const launcherOwnershipDirectory = productionLifecycle && typeof inheritedOwnershipDirectory === "string" &&
|
|
28922
|
+
const launcherOwnershipDirectory = productionLifecycle && typeof inheritedOwnershipDirectory === "string" && isAbsolute10(inheritedOwnershipDirectory) ? inheritedOwnershipDirectory : null;
|
|
28681
28923
|
if (productionLifecycle && isSupervisorRole() && launcherOwnershipDirectory) {
|
|
28682
28924
|
const generationNonce = basename3(launcherOwnershipDirectory);
|
|
28683
|
-
const expectedOwnershipFile =
|
|
28925
|
+
const expectedOwnershipFile = join10(launcherOwnershipDirectory, `${generationNonce}.json`);
|
|
28684
28926
|
const configuredOwnershipFile = process.env[SUPERVISOR_OWNERSHIP_FILE_ENV];
|
|
28685
28927
|
if (process.argv0 !== generationNonce || configuredOwnershipFile !== expectedOwnershipFile || !recordWorkerOwnership(expectedOwnershipFile, generationNonce)) {
|
|
28686
28928
|
log2("Zixt Host: supervisor ownership could not be committed; refusing to start a worker");
|
|
@@ -29329,9 +29571,9 @@ function beginWorkerShutdown(options) {
|
|
|
29329
29571
|
// src/parent-pipe.ts
|
|
29330
29572
|
import { fstatSync as fstatSync2 } from "node:fs";
|
|
29331
29573
|
var END_OF_TEXT = 3;
|
|
29332
|
-
function stdinIsParentPipe(
|
|
29574
|
+
function stdinIsParentPipe(stat4 = (fd) => fstatSync2(fd), isTTY = process.stdin.isTTY === true) {
|
|
29333
29575
|
try {
|
|
29334
|
-
const stdin =
|
|
29576
|
+
const stdin = stat4(0);
|
|
29335
29577
|
return !stdin.isCharacterDevice() && !stdin.isFile() && !isTTY;
|
|
29336
29578
|
} catch {
|
|
29337
29579
|
return false;
|
|
@@ -29359,14 +29601,14 @@ function watchParentPipe(pipe2, onStop) {
|
|
|
29359
29601
|
}
|
|
29360
29602
|
|
|
29361
29603
|
// src/index.ts
|
|
29362
|
-
import { homedir as
|
|
29604
|
+
import { homedir as homedir16, hostname as hostname3 } from "node:os";
|
|
29363
29605
|
|
|
29364
29606
|
// src/hardware.ts
|
|
29365
29607
|
import { existsSync } from "node:fs";
|
|
29366
29608
|
import { statfs } from "node:fs/promises";
|
|
29367
|
-
import { cpus, freemem, homedir as
|
|
29368
|
-
import { dirname as
|
|
29369
|
-
async function machineHardware(workRoot =
|
|
29609
|
+
import { cpus, freemem, homedir as homedir5, totalmem } from "node:os";
|
|
29610
|
+
import { dirname as dirname6, resolve as resolve6 } from "node:path";
|
|
29611
|
+
async function machineHardware(workRoot = homedir5()) {
|
|
29370
29612
|
return {
|
|
29371
29613
|
// A container or cgroup can hide processors from this count; it is what
|
|
29372
29614
|
// this process can see, which is what its Tasks will actually get.
|
|
@@ -29394,7 +29636,7 @@ function nearestExistingPath(start) {
|
|
|
29394
29636
|
let candidate = resolve6(start);
|
|
29395
29637
|
for (let depth = 0; depth < 16; depth++) {
|
|
29396
29638
|
if (existsSync(candidate)) return candidate;
|
|
29397
|
-
const parent =
|
|
29639
|
+
const parent = dirname6(candidate);
|
|
29398
29640
|
if (parent === candidate) return null;
|
|
29399
29641
|
candidate = parent;
|
|
29400
29642
|
}
|
|
@@ -29588,17 +29830,17 @@ function createDemoBrowserAdapterFactory() {
|
|
|
29588
29830
|
}
|
|
29589
29831
|
|
|
29590
29832
|
// src/browser/manager.ts
|
|
29591
|
-
import { lstat as lstat6, mkdir as
|
|
29592
|
-
import { homedir as
|
|
29593
|
-
import { dirname as
|
|
29833
|
+
import { lstat as lstat6, mkdir as mkdir7, open as open5, opendir, readFile as readFile8, rename as rename4, rm as rm7 } from "node:fs/promises";
|
|
29834
|
+
import { homedir as homedir6 } from "node:os";
|
|
29835
|
+
import { dirname as dirname7, join as join11, resolve as resolve7 } from "node:path";
|
|
29594
29836
|
var SAFE_SEGMENT2 = /^[A-Za-z0-9_-]{1,200}$/;
|
|
29595
29837
|
var FRAME_MIN_INTERVAL_MS = 100;
|
|
29596
29838
|
var IDLE_TIMEOUT_MS = 15 * 6e4;
|
|
29597
29839
|
var BrowserManager = class {
|
|
29598
29840
|
constructor(opts) {
|
|
29599
29841
|
this.opts = opts;
|
|
29600
|
-
this.profileRoot = opts.profileRoot ??
|
|
29601
|
-
this.profileStateRoot =
|
|
29842
|
+
this.profileRoot = opts.profileRoot ?? join11(homedir6(), ".zixt", "browser-profiles");
|
|
29843
|
+
this.profileStateRoot = join11(this.profileRoot, ".profile-state");
|
|
29602
29844
|
this.viewport = opts.viewport ?? BROWSER_DEFAULT_VIEWPORT;
|
|
29603
29845
|
this.idleTimeoutMs = opts.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
|
|
29604
29846
|
this.frameMinIntervalMs = opts.frameMinIntervalMs ?? FRAME_MIN_INTERVAL_MS;
|
|
@@ -29695,15 +29937,15 @@ var BrowserManager = class {
|
|
|
29695
29937
|
exactChild(root, child) {
|
|
29696
29938
|
const canonicalRoot = resolve7(root);
|
|
29697
29939
|
const target = resolve7(canonicalRoot, child);
|
|
29698
|
-
if (
|
|
29940
|
+
if (dirname7(target) !== canonicalRoot) {
|
|
29699
29941
|
throw new Error("browser profile path escaped its owned root");
|
|
29700
29942
|
}
|
|
29701
29943
|
return target;
|
|
29702
29944
|
}
|
|
29703
29945
|
async ensureOwnedDirectory(path) {
|
|
29704
|
-
await
|
|
29705
|
-
const
|
|
29706
|
-
if (!
|
|
29946
|
+
await mkdir7(path, { recursive: true, mode: 448 });
|
|
29947
|
+
const stat4 = await lstat6(path);
|
|
29948
|
+
if (!stat4.isDirectory() || stat4.isSymbolicLink()) {
|
|
29707
29949
|
throw new Error("browser profile root must be an owned directory, not a symbolic link");
|
|
29708
29950
|
}
|
|
29709
29951
|
}
|
|
@@ -29767,7 +30009,7 @@ var BrowserManager = class {
|
|
|
29767
30009
|
await this.syncDirectory(this.profileStateRoot);
|
|
29768
30010
|
await this.syncDirectory(this.profileRoot);
|
|
29769
30011
|
} catch (error52) {
|
|
29770
|
-
await
|
|
30012
|
+
await rm7(temporary, { force: true }).catch(() => {
|
|
29771
30013
|
});
|
|
29772
30014
|
throw error52;
|
|
29773
30015
|
}
|
|
@@ -29847,7 +30089,7 @@ var BrowserManager = class {
|
|
|
29847
30089
|
} catch (error52) {
|
|
29848
30090
|
if (error52.code !== "ENOENT") throw error52;
|
|
29849
30091
|
}
|
|
29850
|
-
await
|
|
30092
|
+
await mkdir7(profileDir, { recursive: true, mode: 448 });
|
|
29851
30093
|
const adapter = await this.opts.factory.open({
|
|
29852
30094
|
taskId,
|
|
29853
30095
|
agentId,
|
|
@@ -29935,7 +30177,7 @@ var BrowserManager = class {
|
|
|
29935
30177
|
});
|
|
29936
30178
|
const sessionTaskIds = [...this.sessions.values()].filter((session) => session.agentId === agentId).map((session) => session.taskId);
|
|
29937
30179
|
for (const taskId of sessionTaskIds) await this.closeLocked(taskId, "stopped");
|
|
29938
|
-
await
|
|
30180
|
+
await rm7(this.profilePath(agentId), { recursive: true, force: true, maxRetries: 3 });
|
|
29939
30181
|
await this.syncDirectory(this.profileRoot);
|
|
29940
30182
|
});
|
|
29941
30183
|
}
|
|
@@ -30106,13 +30348,13 @@ var BrowserManager = class {
|
|
|
30106
30348
|
};
|
|
30107
30349
|
|
|
30108
30350
|
// src/browser/playwright-adapter.ts
|
|
30109
|
-
import { spawn as
|
|
30351
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
30110
30352
|
import { access as access3 } from "node:fs/promises";
|
|
30111
30353
|
import { createRequire } from "node:module";
|
|
30112
|
-
import { dirname as
|
|
30354
|
+
import { dirname as dirname8, join as join12 } from "node:path";
|
|
30113
30355
|
var nodeRequire = createRequire(import.meta.url);
|
|
30114
30356
|
var playwrightCoreManifestPath = nodeRequire.resolve("playwright-core/package.json");
|
|
30115
|
-
var playwrightCoreRoot =
|
|
30357
|
+
var playwrightCoreRoot = dirname8(playwrightCoreManifestPath);
|
|
30116
30358
|
var playwrightCoreVersion = nodeRequire(playwrightCoreManifestPath).version;
|
|
30117
30359
|
if (typeof playwrightCoreVersion !== "string" || !/^\d+\.\d+\.\d+$/.test(playwrightCoreVersion)) {
|
|
30118
30360
|
throw new Error("playwright-core package version is invalid");
|
|
@@ -30129,12 +30371,15 @@ async function loadPlaywright() {
|
|
|
30129
30371
|
return import("playwright-core");
|
|
30130
30372
|
}
|
|
30131
30373
|
async function installChromium() {
|
|
30132
|
-
const cliPath =
|
|
30374
|
+
const cliPath = join12(playwrightCoreRoot, "cli.js");
|
|
30133
30375
|
await new Promise((resolve18, reject3) => {
|
|
30134
|
-
const child =
|
|
30376
|
+
const child = spawn7(process.execPath, [cliPath, "install", "chromium"], {
|
|
30135
30377
|
env: process.env,
|
|
30136
30378
|
stdio: ["ignore", "inherit", "inherit"],
|
|
30137
|
-
|
|
30379
|
+
// A service-managed Host has no console; letting Windows allocate one
|
|
30380
|
+
// here would flash a visible window on the signed-in desktop for the
|
|
30381
|
+
// whole download. Progress still flows through the inherited pipes.
|
|
30382
|
+
windowsHide: true
|
|
30138
30383
|
});
|
|
30139
30384
|
let settled = false;
|
|
30140
30385
|
const finish = (error52) => {
|
|
@@ -30760,11 +31005,11 @@ function createPlaywrightBrowserAdapterFactory(dependencies = {}) {
|
|
|
30760
31005
|
}
|
|
30761
31006
|
|
|
30762
31007
|
// src/runners/cli-runner.ts
|
|
30763
|
-
import { spawn as
|
|
31008
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
30764
31009
|
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
30765
|
-
import { lstat as lstat11, mkdir as
|
|
30766
|
-
import { homedir as
|
|
30767
|
-
import { dirname as
|
|
31010
|
+
import { lstat as lstat11, mkdir as mkdir12, realpath as realpath8 } from "node:fs/promises";
|
|
31011
|
+
import { homedir as homedir7 } from "node:os";
|
|
31012
|
+
import { dirname as dirname10, isAbsolute as isAbsolute16, join as join18, resolve as resolve10 } from "node:path";
|
|
30768
31013
|
|
|
30769
31014
|
// src/tool-packs/browser/authentication-wall.ts
|
|
30770
31015
|
var AUTH_PATH_SEGMENT = /(?:^|\/)(?:log[-_]?in|sign[-_]?in|sso|saml|auth|authorize|authenticate|oauth2?|session\/new|checkpoint)(?:\/|$)/i;
|
|
@@ -33582,16 +33827,16 @@ function createGithubPushOrchestrator(input) {
|
|
|
33582
33827
|
}
|
|
33583
33828
|
|
|
33584
33829
|
// src/tool-packs/github/git-bridge.ts
|
|
33585
|
-
import { spawn as
|
|
33830
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
33586
33831
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
33587
|
-
import { chmod as chmod4, lstat as lstat8, mkdir as
|
|
33588
|
-
import { dirname as
|
|
33832
|
+
import { chmod as chmod4, lstat as lstat8, mkdir as mkdir8, realpath as realpath5, rm as rm8 } from "node:fs/promises";
|
|
33833
|
+
import { dirname as dirname9, isAbsolute as isAbsolute12, join as join14, relative as relative6 } from "node:path";
|
|
33589
33834
|
|
|
33590
33835
|
// src/tool-packs/github/git-credential-broker.ts
|
|
33591
33836
|
import { createServer } from "node:http";
|
|
33592
33837
|
import { randomBytes, randomUUID as randomUUID7, timingSafeEqual } from "node:crypto";
|
|
33593
|
-
import { chmod as chmod3, lstat as lstat7, realpath as realpath4, writeFile as
|
|
33594
|
-
import { isAbsolute as
|
|
33838
|
+
import { chmod as chmod3, lstat as lstat7, realpath as realpath4, writeFile as writeFile4 } from "node:fs/promises";
|
|
33839
|
+
import { isAbsolute as isAbsolute11, join as join13, relative as relative5 } from "node:path";
|
|
33595
33840
|
var MAX_REQUEST_BYTES = 16 * 1024;
|
|
33596
33841
|
var FILE_MODE2 = 384;
|
|
33597
33842
|
var HELPER_SOURCE = String.raw`'use strict';
|
|
@@ -33705,7 +33950,7 @@ async function readBoundedBody2(request) {
|
|
|
33705
33950
|
}
|
|
33706
33951
|
function assertChildPath(parent, child) {
|
|
33707
33952
|
const path = relative5(parent, child);
|
|
33708
|
-
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") ||
|
|
33953
|
+
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") || isAbsolute11(path)) {
|
|
33709
33954
|
throw new Error("Git credential helper path escaped its private run directory");
|
|
33710
33955
|
}
|
|
33711
33956
|
}
|
|
@@ -33720,9 +33965,9 @@ async function createGithubGitCredentialBroker(input) {
|
|
|
33720
33965
|
throw new Error("Git credential broker requires a private real run directory");
|
|
33721
33966
|
}
|
|
33722
33967
|
const runRoot = await realpath4(input.runArtifactsRoot);
|
|
33723
|
-
const helperPath =
|
|
33968
|
+
const helperPath = join13(runRoot, `git-credential-${randomUUID7()}.cjs`);
|
|
33724
33969
|
assertChildPath(runRoot, helperPath);
|
|
33725
|
-
await
|
|
33970
|
+
await writeFile4(helperPath, HELPER_SOURCE, { flag: "wx", mode: FILE_MODE2 });
|
|
33726
33971
|
await chmod3(helperPath, FILE_MODE2);
|
|
33727
33972
|
const capability2 = randomBytes(32).toString("base64url");
|
|
33728
33973
|
const expectedPath = `${input.repositoryFullName}.git`;
|
|
@@ -33820,7 +34065,7 @@ ${stderr}`;
|
|
|
33820
34065
|
}
|
|
33821
34066
|
function assertBelow2(parent, child, label) {
|
|
33822
34067
|
const path = relative6(parent, child);
|
|
33823
|
-
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") ||
|
|
34068
|
+
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") || isAbsolute12(path)) {
|
|
33824
34069
|
throw new GithubGitProcessError("invalid_input");
|
|
33825
34070
|
}
|
|
33826
34071
|
void label;
|
|
@@ -33835,8 +34080,8 @@ async function requireRealDirectory2(path, label) {
|
|
|
33835
34080
|
}
|
|
33836
34081
|
async function validateTokenlessPaths(command) {
|
|
33837
34082
|
if (command.kind === "clone-from-bridge") {
|
|
33838
|
-
if (!
|
|
33839
|
-
const parent = await requireRealDirectory2(
|
|
34083
|
+
if (!isAbsolute12(command.destination)) throw new GithubGitProcessError("invalid_input");
|
|
34084
|
+
const parent = await requireRealDirectory2(dirname9(command.destination), "clone parent");
|
|
33840
34085
|
assertBelow2(parent, command.destination, "clone destination");
|
|
33841
34086
|
const destination = await lstat8(command.destination).catch((error52) => {
|
|
33842
34087
|
if (error52.code === "ENOENT") return null;
|
|
@@ -33846,7 +34091,7 @@ async function validateTokenlessPaths(command) {
|
|
|
33846
34091
|
return;
|
|
33847
34092
|
}
|
|
33848
34093
|
if ("repositoryPath" in command) {
|
|
33849
|
-
if (!
|
|
34094
|
+
if (!isAbsolute12(command.repositoryPath)) throw new GithubGitProcessError("invalid_input");
|
|
33850
34095
|
const repositoryPath5 = await requireRealDirectory2(command.repositoryPath, "repository path");
|
|
33851
34096
|
if (repositoryPath5 !== command.repositoryPath) throw new GithubGitProcessError("invalid_input");
|
|
33852
34097
|
}
|
|
@@ -33926,13 +34171,13 @@ async function runGit(input, args, env) {
|
|
|
33926
34171
|
if (input.authoritySignal.aborted || input.cancelledNow()) {
|
|
33927
34172
|
throw new GithubGitProcessError("cancelled");
|
|
33928
34173
|
}
|
|
33929
|
-
if (!
|
|
34174
|
+
if (!isAbsolute12(input.executablePath)) throw new GithubGitProcessError("invalid_input");
|
|
33930
34175
|
const timeoutMs = input.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
33931
34176
|
if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > DEFAULT_TIMEOUT_MS2) {
|
|
33932
34177
|
throw new GithubGitProcessError("invalid_input");
|
|
33933
34178
|
}
|
|
33934
34179
|
return new Promise((resolvePromise, rejectPromise) => {
|
|
33935
|
-
const child =
|
|
34180
|
+
const child = spawn8(input.executablePath, [...input.commandPrefixArgs ?? [], ...args], {
|
|
33936
34181
|
cwd: input.trustedCwd,
|
|
33937
34182
|
env,
|
|
33938
34183
|
shell: false,
|
|
@@ -34032,7 +34277,7 @@ function tokenlessArgs(command) {
|
|
|
34032
34277
|
switch (command.kind) {
|
|
34033
34278
|
case "clone-from-bridge":
|
|
34034
34279
|
assertRef(command.branch);
|
|
34035
|
-
if (!
|
|
34280
|
+
if (!isAbsolute12(command.destination)) throw new GithubGitProcessError("invalid_input");
|
|
34036
34281
|
return [
|
|
34037
34282
|
"clone",
|
|
34038
34283
|
"--no-recurse-submodules",
|
|
@@ -34044,7 +34289,7 @@ function tokenlessArgs(command) {
|
|
|
34044
34289
|
];
|
|
34045
34290
|
case "fetch-from-bridge":
|
|
34046
34291
|
assertFetchRefspecs(command.refspecs);
|
|
34047
|
-
if (!
|
|
34292
|
+
if (!isAbsolute12(command.repositoryPath)) throw new GithubGitProcessError("invalid_input");
|
|
34048
34293
|
return [
|
|
34049
34294
|
"-C",
|
|
34050
34295
|
command.repositoryPath,
|
|
@@ -34056,7 +34301,7 @@ function tokenlessArgs(command) {
|
|
|
34056
34301
|
...command.refspecs
|
|
34057
34302
|
];
|
|
34058
34303
|
case "copy-commit-to-bridge":
|
|
34059
|
-
if (!
|
|
34304
|
+
if (!isAbsolute12(command.repositoryPath) || !SHA.test(command.sha)) {
|
|
34060
34305
|
throw new GithubGitProcessError("invalid_input");
|
|
34061
34306
|
}
|
|
34062
34307
|
return [
|
|
@@ -34068,11 +34313,11 @@ function tokenlessArgs(command) {
|
|
|
34068
34313
|
`${command.sha}:refs/zixt/push-source`
|
|
34069
34314
|
];
|
|
34070
34315
|
case "rev-parse":
|
|
34071
|
-
if (!
|
|
34316
|
+
if (!isAbsolute12(command.repositoryPath)) throw new GithubGitProcessError("invalid_input");
|
|
34072
34317
|
assertRef(command.ref);
|
|
34073
34318
|
return ["-C", command.repositoryPath, "rev-parse", "--verify", `${command.ref}^{commit}`];
|
|
34074
34319
|
case "remote-configure":
|
|
34075
|
-
if (!
|
|
34320
|
+
if (!isAbsolute12(command.repositoryPath) || !REPOSITORY.test(command.repositoryFullName)) {
|
|
34076
34321
|
throw new GithubGitProcessError("invalid_input");
|
|
34077
34322
|
}
|
|
34078
34323
|
return [
|
|
@@ -34084,7 +34329,7 @@ function tokenlessArgs(command) {
|
|
|
34084
34329
|
`https://github.com/${command.repositoryFullName}.git`
|
|
34085
34330
|
];
|
|
34086
34331
|
case "status":
|
|
34087
|
-
if (!
|
|
34332
|
+
if (!isAbsolute12(command.repositoryPath)) throw new GithubGitProcessError("invalid_input");
|
|
34088
34333
|
return [
|
|
34089
34334
|
"-C",
|
|
34090
34335
|
command.repositoryPath,
|
|
@@ -34114,7 +34359,7 @@ function createGithubGitBridge(input) {
|
|
|
34114
34359
|
})();
|
|
34115
34360
|
const requireBridge = async (value) => {
|
|
34116
34361
|
const current = await roots();
|
|
34117
|
-
if (!
|
|
34362
|
+
if (!isAbsolute12(value) || !active.has(value)) throw new GithubGitProcessError("invalid_input");
|
|
34118
34363
|
const real = await requireRealDirectory2(value, "git bridge");
|
|
34119
34364
|
assertBelow2(current.bridges, real, "git bridge");
|
|
34120
34365
|
if (real !== value) throw new GithubGitProcessError("invalid_input");
|
|
@@ -34124,9 +34369,9 @@ function createGithubGitBridge(input) {
|
|
|
34124
34369
|
async createPrivateBridge() {
|
|
34125
34370
|
if (closed) throw new GithubGitProcessError("cancelled");
|
|
34126
34371
|
const current = await roots();
|
|
34127
|
-
const path =
|
|
34372
|
+
const path = join14(current.bridges, `${randomUUID8()}.git`);
|
|
34128
34373
|
assertBelow2(current.bridges, path, "git bridge");
|
|
34129
|
-
await
|
|
34374
|
+
await mkdir8(path, { mode: DIRECTORY_MODE2 });
|
|
34130
34375
|
await chmod4(path, DIRECTORY_MODE2);
|
|
34131
34376
|
try {
|
|
34132
34377
|
await runGit(
|
|
@@ -34142,16 +34387,16 @@ function createGithubGitBridge(input) {
|
|
|
34142
34387
|
);
|
|
34143
34388
|
const real = await requireRealDirectory2(path, "git bridge");
|
|
34144
34389
|
assertBelow2(current.bridges, real, "git bridge");
|
|
34145
|
-
const hooks =
|
|
34146
|
-
await
|
|
34147
|
-
await
|
|
34390
|
+
const hooks = join14(real, "hooks");
|
|
34391
|
+
await rm8(hooks, { recursive: true, force: true });
|
|
34392
|
+
await mkdir8(hooks, { mode: DIRECTORY_MODE2 });
|
|
34148
34393
|
await chmod4(hooks, DIRECTORY_MODE2);
|
|
34149
|
-
const config2 =
|
|
34394
|
+
const config2 = join14(real, "config");
|
|
34150
34395
|
await chmod4(config2, 384);
|
|
34151
34396
|
active.add(real);
|
|
34152
34397
|
return real;
|
|
34153
34398
|
} catch (error52) {
|
|
34154
|
-
await
|
|
34399
|
+
await rm8(path, { recursive: true, force: true }).catch(() => {
|
|
34155
34400
|
});
|
|
34156
34401
|
throw error52;
|
|
34157
34402
|
}
|
|
@@ -34245,7 +34490,7 @@ function createGithubGitBridge(input) {
|
|
|
34245
34490
|
},
|
|
34246
34491
|
async destroyPrivateBridge(path) {
|
|
34247
34492
|
const bridge = await requireBridge(path);
|
|
34248
|
-
await
|
|
34493
|
+
await rm8(bridge, { recursive: true, force: true });
|
|
34249
34494
|
active.delete(bridge);
|
|
34250
34495
|
credentialed2.delete(bridge);
|
|
34251
34496
|
},
|
|
@@ -34253,7 +34498,7 @@ function createGithubGitBridge(input) {
|
|
|
34253
34498
|
if (closed) return;
|
|
34254
34499
|
closed = true;
|
|
34255
34500
|
const paths = [...active];
|
|
34256
|
-
await Promise.all(paths.map((path) =>
|
|
34501
|
+
await Promise.all(paths.map((path) => rm8(path, { recursive: true, force: true })));
|
|
34257
34502
|
active.clear();
|
|
34258
34503
|
credentialed2.clear();
|
|
34259
34504
|
}
|
|
@@ -34594,8 +34839,8 @@ function createRepositoryTools(runtime) {
|
|
|
34594
34839
|
|
|
34595
34840
|
// src/tool-packs/github/workspace.ts
|
|
34596
34841
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
34597
|
-
import { chmod as chmod5, lstat as lstat9, mkdir as
|
|
34598
|
-
import { isAbsolute as
|
|
34842
|
+
import { chmod as chmod5, lstat as lstat9, mkdir as mkdir9, readFile as readFile9, realpath as realpath6, rename as rename5, rm as rm9, writeFile as writeFile5 } from "node:fs/promises";
|
|
34843
|
+
import { isAbsolute as isAbsolute13, join as join15, relative as relative7, resolve as resolve8 } from "node:path";
|
|
34599
34844
|
var SAFE_LOCAL_ID = /^[A-Za-z0-9_-]{1,200}$/;
|
|
34600
34845
|
var FULL_NAME2 = /^[A-Za-z0-9_.-]{1,100}\/[A-Za-z0-9_.-]{1,100}$/;
|
|
34601
34846
|
var DIRECTORY_MODE3 = 448;
|
|
@@ -34613,7 +34858,7 @@ function hasControlCharacter2(value) {
|
|
|
34613
34858
|
}
|
|
34614
34859
|
function assertBelow3(parent, child, label) {
|
|
34615
34860
|
const path = relative7(parent, child);
|
|
34616
|
-
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") ||
|
|
34861
|
+
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") || isAbsolute13(path)) {
|
|
34617
34862
|
throw new Error(`${label} escaped the task workspace`);
|
|
34618
34863
|
}
|
|
34619
34864
|
}
|
|
@@ -34632,10 +34877,10 @@ async function requireRealDirectory3(path, label) {
|
|
|
34632
34877
|
return real;
|
|
34633
34878
|
}
|
|
34634
34879
|
async function createOrRequirePrivateDirectory(parent, name, label) {
|
|
34635
|
-
const path =
|
|
34880
|
+
const path = join15(parent, name);
|
|
34636
34881
|
assertBelow3(parent, path, label);
|
|
34637
34882
|
try {
|
|
34638
|
-
await
|
|
34883
|
+
await mkdir9(path, { mode: DIRECTORY_MODE3 });
|
|
34639
34884
|
} catch (error52) {
|
|
34640
34885
|
if (error52.code !== "EEXIST") throw error52;
|
|
34641
34886
|
}
|
|
@@ -34715,8 +34960,8 @@ async function createGithubWorkspaceService(input) {
|
|
|
34715
34960
|
if (expectedFullName !== void 0 && repository.fullName !== expectedFullName) {
|
|
34716
34961
|
throw new Error("GitHub repository name does not match this task grant");
|
|
34717
34962
|
}
|
|
34718
|
-
const destination =
|
|
34719
|
-
const metadataPath =
|
|
34963
|
+
const destination = join15(repositoriesRoot, parsed.data);
|
|
34964
|
+
const metadataPath = join15(metadataRoot, `${parsed.data}.json`);
|
|
34720
34965
|
if (!await pathExists(destination) || !await pathExists(metadataPath)) {
|
|
34721
34966
|
throw new Error("GitHub repository workspace has not been prepared");
|
|
34722
34967
|
}
|
|
@@ -34733,14 +34978,14 @@ async function createGithubWorkspaceService(input) {
|
|
|
34733
34978
|
return real;
|
|
34734
34979
|
};
|
|
34735
34980
|
const cloneRepository = async (clone2) => {
|
|
34736
|
-
const destination =
|
|
34737
|
-
const metadataPath =
|
|
34981
|
+
const destination = join15(repositoriesRoot, clone2.repositoryId);
|
|
34982
|
+
const metadataPath = join15(metadataRoot, `${clone2.repositoryId}.json`);
|
|
34738
34983
|
assertBelow3(repositoriesRoot, destination, "repository path");
|
|
34739
34984
|
assertBelow3(metadataRoot, metadataPath, "repository metadata");
|
|
34740
34985
|
if (await pathExists(destination) || await pathExists(metadataPath)) {
|
|
34741
34986
|
throw new Error("GitHub repository workspace already exists or is inconsistent");
|
|
34742
34987
|
}
|
|
34743
|
-
const temporary =
|
|
34988
|
+
const temporary = join15(repositoriesRoot, `.clone-${randomUUID9()}`);
|
|
34744
34989
|
assertBelow3(repositoriesRoot, temporary, "temporary clone");
|
|
34745
34990
|
try {
|
|
34746
34991
|
await input.git.clone({
|
|
@@ -34765,9 +35010,9 @@ async function createGithubWorkspaceService(input) {
|
|
|
34765
35010
|
path: destination,
|
|
34766
35011
|
...clone2.createIntentId === void 0 ? {} : { createIntentId: clone2.createIntentId }
|
|
34767
35012
|
};
|
|
34768
|
-
const metadataTemporary =
|
|
35013
|
+
const metadataTemporary = join15(metadataRoot, `.${clone2.repositoryId}-${randomUUID9()}.tmp`);
|
|
34769
35014
|
assertBelow3(metadataRoot, metadataTemporary, "temporary repository metadata");
|
|
34770
|
-
await
|
|
35015
|
+
await writeFile5(metadataTemporary, `${JSON.stringify(metadata)}
|
|
34771
35016
|
`, {
|
|
34772
35017
|
flag: "wx",
|
|
34773
35018
|
mode: FILE_MODE3
|
|
@@ -34778,11 +35023,11 @@ async function createGithubWorkspaceService(input) {
|
|
|
34778
35023
|
try {
|
|
34779
35024
|
await rename5(metadataTemporary, metadataPath);
|
|
34780
35025
|
} catch (error52) {
|
|
34781
|
-
await
|
|
35026
|
+
await rm9(destination, { recursive: true, force: true });
|
|
34782
35027
|
throw error52;
|
|
34783
35028
|
}
|
|
34784
35029
|
} finally {
|
|
34785
|
-
await
|
|
35030
|
+
await rm9(metadataTemporary, { force: true }).catch(() => {
|
|
34786
35031
|
});
|
|
34787
35032
|
}
|
|
34788
35033
|
const path = await requireRealDirectory3(destination, "GitHub repository");
|
|
@@ -34794,14 +35039,14 @@ async function createGithubWorkspaceService(input) {
|
|
|
34794
35039
|
headSha
|
|
34795
35040
|
};
|
|
34796
35041
|
} finally {
|
|
34797
|
-
await
|
|
35042
|
+
await rm9(temporary, { recursive: true, force: true }).catch(() => {
|
|
34798
35043
|
});
|
|
34799
35044
|
}
|
|
34800
35045
|
};
|
|
34801
35046
|
const prepareRepository = async (authority) => {
|
|
34802
35047
|
const { repository } = authority;
|
|
34803
|
-
const destination =
|
|
34804
|
-
const metadataPath =
|
|
35048
|
+
const destination = join15(repositoriesRoot, repository.repositoryId);
|
|
35049
|
+
const metadataPath = join15(metadataRoot, `${repository.repositoryId}.json`);
|
|
34805
35050
|
assertBelow3(repositoriesRoot, destination, "repository path");
|
|
34806
35051
|
assertBelow3(metadataRoot, metadataPath, "repository metadata");
|
|
34807
35052
|
return withWorkspaceLock(destination, async () => {
|
|
@@ -34966,7 +35211,7 @@ async function createGithubWorkspaceService(input) {
|
|
|
34966
35211
|
throw new Error("GitHub created repository is outside this installation");
|
|
34967
35212
|
}
|
|
34968
35213
|
parseGitRef(cloneInput.repository.defaultBranch, "default branch");
|
|
34969
|
-
return withWorkspaceLock(
|
|
35214
|
+
return withWorkspaceLock(join15(repositoriesRoot, repositoryId2), async () => {
|
|
34970
35215
|
const prepared = await cloneRepository({
|
|
34971
35216
|
repositoryId: repositoryId2,
|
|
34972
35217
|
fullName: cloneInput.repository.fullName,
|
|
@@ -37090,8 +37335,8 @@ function createCommsToolPacks(grants, context) {
|
|
|
37090
37335
|
}
|
|
37091
37336
|
|
|
37092
37337
|
// src/runners/attachments.ts
|
|
37093
|
-
import { mkdir as
|
|
37094
|
-
import { join as
|
|
37338
|
+
import { mkdir as mkdir10, writeFile as writeFile6 } from "node:fs/promises";
|
|
37339
|
+
import { join as join16 } from "node:path";
|
|
37095
37340
|
var WINDOWS_RESERVED = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\..*)?$/i;
|
|
37096
37341
|
function sanitizeAttachmentFileName(name) {
|
|
37097
37342
|
const base = name.split(/[/\\]/).pop() ?? "";
|
|
@@ -37120,10 +37365,10 @@ async function materializeAttachments(task, taskRoot) {
|
|
|
37120
37365
|
`attached file "${attachment.name}" arrived incomplete (${bytes.byteLength} of ${attachment.size} bytes)`
|
|
37121
37366
|
);
|
|
37122
37367
|
}
|
|
37123
|
-
const directory =
|
|
37124
|
-
await
|
|
37125
|
-
const path =
|
|
37126
|
-
await
|
|
37368
|
+
const directory = join16(taskRoot, ".zixt-attachments", task.taskId, attachment.id);
|
|
37369
|
+
await mkdir10(directory, { recursive: true });
|
|
37370
|
+
const path = join16(directory, sanitizeAttachmentFileName(attachment.name));
|
|
37371
|
+
await writeFile6(path, bytes);
|
|
37127
37372
|
materialized.push({
|
|
37128
37373
|
path,
|
|
37129
37374
|
name: attachment.name,
|
|
@@ -38140,7 +38385,7 @@ function createAskUserServer() {
|
|
|
38140
38385
|
}
|
|
38141
38386
|
|
|
38142
38387
|
// src/runners/runner-env.ts
|
|
38143
|
-
import { delimiter as delimiter2, isAbsolute as
|
|
38388
|
+
import { delimiter as delimiter2, isAbsolute as isAbsolute14 } from "node:path";
|
|
38144
38389
|
var PROVIDER_AUTHORITY_PREFIXES = ["GH_", "GITHUB_", "GIT_", "SSH_"];
|
|
38145
38390
|
var HOST_AUTHORITY_PREFIXES = [
|
|
38146
38391
|
"ZIXT_",
|
|
@@ -38199,7 +38444,7 @@ function inheritedValue(env, name) {
|
|
|
38199
38444
|
}
|
|
38200
38445
|
function sanitizeInheritedSearchPath(path) {
|
|
38201
38446
|
if (!path) return "";
|
|
38202
|
-
return path.split(delimiter2).filter((entry) => entry !== "" &&
|
|
38447
|
+
return path.split(delimiter2).filter((entry) => entry !== "" && isAbsolute14(entry)).join(delimiter2);
|
|
38203
38448
|
}
|
|
38204
38449
|
function buildRunnerEnv(input) {
|
|
38205
38450
|
const env = {};
|
|
@@ -38280,9 +38525,9 @@ function buildRunnerEnv(input) {
|
|
|
38280
38525
|
// src/runners/github-shell-auth.ts
|
|
38281
38526
|
import { execFile } from "node:child_process";
|
|
38282
38527
|
import { randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
38283
|
-
import { chmod as chmod6, lstat as lstat10, mkdir as
|
|
38528
|
+
import { chmod as chmod6, lstat as lstat10, mkdir as mkdir11, realpath as realpath7, writeFile as writeFile7 } from "node:fs/promises";
|
|
38284
38529
|
import { createServer as createServer3 } from "node:http";
|
|
38285
|
-
import { isAbsolute as
|
|
38530
|
+
import { isAbsolute as isAbsolute15, join as join17, relative as relative8 } from "node:path";
|
|
38286
38531
|
var MAX_REQUEST_BYTES2 = 16 * 1024;
|
|
38287
38532
|
var DIRECTORY_MODE4 = 448;
|
|
38288
38533
|
var PRIVATE_FILE_MODE = 384;
|
|
@@ -38488,7 +38733,7 @@ function parseGhInvocation(body) {
|
|
|
38488
38733
|
}
|
|
38489
38734
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
38490
38735
|
const { args, cwd } = value;
|
|
38491
|
-
if (!Array.isArray(args) || args.length > 256 || args.some((argument) => typeof argument !== "string" || argument.length > 4096) || typeof cwd !== "string" || cwd.length === 0 || cwd.length > 4096 || !
|
|
38736
|
+
if (!Array.isArray(args) || args.length > 256 || args.some((argument) => typeof argument !== "string" || argument.length > 4096) || typeof cwd !== "string" || cwd.length === 0 || cwd.length > 4096 || !isAbsolute15(cwd)) {
|
|
38492
38737
|
return null;
|
|
38493
38738
|
}
|
|
38494
38739
|
return { args, cwd };
|
|
@@ -38647,7 +38892,7 @@ function activationCredential(grant, now = Date.now()) {
|
|
|
38647
38892
|
}
|
|
38648
38893
|
function assertChildPath2(parent, child) {
|
|
38649
38894
|
const path = relative8(parent, child);
|
|
38650
|
-
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") ||
|
|
38895
|
+
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") || isAbsolute15(path)) {
|
|
38651
38896
|
throw new Error("GitHub shell helper path escaped its private run directory");
|
|
38652
38897
|
}
|
|
38653
38898
|
}
|
|
@@ -38658,7 +38903,7 @@ function quoteForPosixShell(value) {
|
|
|
38658
38903
|
return quoteForGitShell2(value);
|
|
38659
38904
|
}
|
|
38660
38905
|
async function writePrivate(path, content, executable = false) {
|
|
38661
|
-
await
|
|
38906
|
+
await writeFile7(path, content, {
|
|
38662
38907
|
flag: "wx",
|
|
38663
38908
|
mode: executable ? EXECUTABLE_FILE_MODE : PRIVATE_FILE_MODE
|
|
38664
38909
|
});
|
|
@@ -38670,7 +38915,7 @@ async function prepareHelpers(input) {
|
|
|
38670
38915
|
throw new Error("GitHub shell authentication requires a private real run directory");
|
|
38671
38916
|
}
|
|
38672
38917
|
const runRoot = await realpath7(input.runRoot);
|
|
38673
|
-
const helperPath =
|
|
38918
|
+
const helperPath = join17(runRoot, "github-shell-git-credential.cjs");
|
|
38674
38919
|
assertChildPath2(runRoot, helperPath);
|
|
38675
38920
|
await writePrivate(helperPath, GIT_HELPER_SOURCE);
|
|
38676
38921
|
if (!input.ghExecutablePath) {
|
|
@@ -38681,14 +38926,14 @@ async function prepareHelpers(input) {
|
|
|
38681
38926
|
wrapperSourcePath: null
|
|
38682
38927
|
};
|
|
38683
38928
|
}
|
|
38684
|
-
const shellToolsDirectory =
|
|
38929
|
+
const shellToolsDirectory = join17(runRoot, "shell-tools");
|
|
38685
38930
|
assertChildPath2(runRoot, shellToolsDirectory);
|
|
38686
|
-
await
|
|
38931
|
+
await mkdir11(shellToolsDirectory, { mode: DIRECTORY_MODE4 });
|
|
38687
38932
|
await chmod6(shellToolsDirectory, DIRECTORY_MODE4);
|
|
38688
|
-
const wrapperSourcePath =
|
|
38933
|
+
const wrapperSourcePath = join17(runRoot, "github-shell-gh-wrapper.cjs");
|
|
38689
38934
|
assertChildPath2(runRoot, wrapperSourcePath);
|
|
38690
38935
|
await writePrivate(wrapperSourcePath, GH_WRAPPER_SOURCE);
|
|
38691
|
-
const wrapperPath =
|
|
38936
|
+
const wrapperPath = join17(shellToolsDirectory, process.platform === "win32" ? "gh.cmd" : "gh");
|
|
38692
38937
|
assertChildPath2(runRoot, wrapperPath);
|
|
38693
38938
|
const launcher = process.platform === "win32" ? `@"${process.execPath.replaceAll('"', '""')}" "${wrapperSourcePath.replaceAll('"', '""')}" %*\r
|
|
38694
38939
|
` : `#!/bin/sh
|
|
@@ -38911,7 +39156,7 @@ password=${credential.accessToken}
|
|
|
38911
39156
|
}
|
|
38912
39157
|
|
|
38913
39158
|
// src/runners/working-context.ts
|
|
38914
|
-
import { spawn as
|
|
39159
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
38915
39160
|
import { resolve as resolve9 } from "node:path";
|
|
38916
39161
|
var COMMAND_TIMEOUT_MS = 5e3;
|
|
38917
39162
|
var OUTPUT_LIMIT_BYTES = 128 * 1024;
|
|
@@ -39042,7 +39287,7 @@ async function stopWorkingContextCommand(child, childExited, options = {}) {
|
|
|
39042
39287
|
function run(command, args, cwd, env, signal) {
|
|
39043
39288
|
if (signal?.aborted) return Promise.resolve(null);
|
|
39044
39289
|
return new Promise((resolvePromise) => {
|
|
39045
|
-
const child =
|
|
39290
|
+
const child = spawn9(command, [...args], {
|
|
39046
39291
|
cwd,
|
|
39047
39292
|
env: { ...env, GIT_OPTIONAL_LOCKS: "0" },
|
|
39048
39293
|
detached: process.platform !== "win32",
|
|
@@ -39482,7 +39727,7 @@ async function settlesWithin(promise2, timeoutMs) {
|
|
|
39482
39727
|
}
|
|
39483
39728
|
}
|
|
39484
39729
|
function defaultRunnerWorkspaceRoot() {
|
|
39485
|
-
return
|
|
39730
|
+
return join18(homedir7(), ".zixt", "workspaces");
|
|
39486
39731
|
}
|
|
39487
39732
|
function defaultRunnerArtifactRoot() {
|
|
39488
39733
|
return defaultRunArtifactRoot();
|
|
@@ -39531,7 +39776,7 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
39531
39776
|
const prefixArgs = opts.commandPrefixArgs ?? [];
|
|
39532
39777
|
const maxWallTimeMs = opts.maxWallTimeMs;
|
|
39533
39778
|
const workspaceRoot = opts.workspaceRoot ?? defaultRunnerWorkspaceRoot();
|
|
39534
|
-
const artifactRoot = opts.artifactRoot ?? (opts.workspaceRoot === void 0 ? defaultRunnerArtifactRoot() :
|
|
39779
|
+
const artifactRoot = opts.artifactRoot ?? (opts.workspaceRoot === void 0 ? defaultRunnerArtifactRoot() : join18(dirname10(workspaceRoot), "run-artifacts"));
|
|
39535
39780
|
const runRegistryRoot2 = opts.runRegistryRoot ?? defaultRunRegistryRoot();
|
|
39536
39781
|
const createArtifacts = opts.createArtifacts ?? createRunArtifacts;
|
|
39537
39782
|
const toolPackRegistry2 = opts.toolPackRegistry ?? createDefaultToolPackRegistry();
|
|
@@ -39549,7 +39794,7 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
39549
39794
|
};
|
|
39550
39795
|
const askUserServer = createAskUserServer();
|
|
39551
39796
|
const windowsRoot = process.env.SystemRoot ?? process.env.WINDIR;
|
|
39552
|
-
const windowsComspecCandidate = process.platform === "win32" && windowsRoot ?
|
|
39797
|
+
const windowsComspecCandidate = process.platform === "win32" && windowsRoot ? join18(windowsRoot, "System32", "cmd.exe") : void 0;
|
|
39553
39798
|
let safetyFailure;
|
|
39554
39799
|
return async (task) => {
|
|
39555
39800
|
if (safetyFailure) {
|
|
@@ -39589,8 +39834,8 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
39589
39834
|
usage: { inputTokens: 0, outputTokens: 0 }
|
|
39590
39835
|
};
|
|
39591
39836
|
}
|
|
39592
|
-
const taskRoot =
|
|
39593
|
-
await
|
|
39837
|
+
const taskRoot = join18(workspaceRoot, task.agentId);
|
|
39838
|
+
await mkdir12(taskRoot, { recursive: true });
|
|
39594
39839
|
if (task.cancelledNow()) return cancelledBeforeRun();
|
|
39595
39840
|
const configuredWorkspace = task.spec.workspace;
|
|
39596
39841
|
let cwd = taskRoot;
|
|
@@ -39656,7 +39901,10 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
39656
39901
|
let terminalOutcomeProducedUnderAuthority = false;
|
|
39657
39902
|
let preparedTerminalOutcome;
|
|
39658
39903
|
try {
|
|
39659
|
-
const resolvedCommand = await
|
|
39904
|
+
const resolvedCommand = await resolveRunnerCommand(command, adapter.type, {
|
|
39905
|
+
resolution: trustedCommandOptions,
|
|
39906
|
+
probe: true
|
|
39907
|
+
});
|
|
39660
39908
|
const resolvedWindowsComspec = windowsComspecCandidate ? await resolveTrustedCliCommand(windowsComspecCandidate, trustedCommandOptions) : null;
|
|
39661
39909
|
const git = await measuredGit();
|
|
39662
39910
|
const githubGrant = providerGrants.find(
|
|
@@ -39926,8 +40174,8 @@ ${attachmentSection}` : prompt;
|
|
|
39926
40174
|
let changed = false;
|
|
39927
40175
|
for (const path of paths) {
|
|
39928
40176
|
if (!path || path.length > 4096) continue;
|
|
39929
|
-
const absolutePath =
|
|
39930
|
-
const directory =
|
|
40177
|
+
const absolutePath = isAbsolute16(path) ? path : resolve10(cwd, path);
|
|
40178
|
+
const directory = dirname10(absolutePath);
|
|
39931
40179
|
observedWorkingDirectories.delete(directory);
|
|
39932
40180
|
observedWorkingDirectories.add(directory);
|
|
39933
40181
|
while (observedWorkingDirectories.size > 19) {
|
|
@@ -40366,7 +40614,7 @@ function runCliProcess(options) {
|
|
|
40366
40614
|
return new Promise((resolve18) => {
|
|
40367
40615
|
const platform = options.platform ?? process.platform;
|
|
40368
40616
|
const containmentGateNonce = options.guardian && platform === "win32" ? randomUUID11() : void 0;
|
|
40369
|
-
const child = options.guardian ?
|
|
40617
|
+
const child = options.guardian ? spawn10(
|
|
40370
40618
|
options.guardian.nodeCommand,
|
|
40371
40619
|
[
|
|
40372
40620
|
options.guardian.scriptPath,
|
|
@@ -40377,7 +40625,7 @@ function runCliProcess(options) {
|
|
|
40377
40625
|
// The idle pre-assignment guardian must never load from or depend
|
|
40378
40626
|
// on an untrusted Task checkout. Only the post-gate target enters
|
|
40379
40627
|
// the requested working directory from its private release frame.
|
|
40380
|
-
cwd:
|
|
40628
|
+
cwd: dirname10(options.guardian.scriptPath),
|
|
40381
40629
|
env: runnerGuardianEnv(process.env, containmentGateNonce),
|
|
40382
40630
|
stdio: ["pipe", "pipe", "pipe"],
|
|
40383
40631
|
windowsHide: true,
|
|
@@ -40658,13 +40906,13 @@ import { randomUUID as randomUUID12 } from "node:crypto";
|
|
|
40658
40906
|
|
|
40659
40907
|
// src/runners/runtime-observation.ts
|
|
40660
40908
|
import { open as open6, readdir as readdir5, realpath as realpath9 } from "node:fs/promises";
|
|
40661
|
-
import { homedir as
|
|
40662
|
-
import { join as
|
|
40909
|
+
import { homedir as homedir8 } from "node:os";
|
|
40910
|
+
import { join as join19 } from "node:path";
|
|
40663
40911
|
var READ_WINDOW_BYTES = 1024 * 1024;
|
|
40664
40912
|
var CATALOG_TIMEOUT_MS = 15e3;
|
|
40665
40913
|
var CATALOG_OUTPUT_LIMIT_BYTES = 4 * 1024 * 1024;
|
|
40666
40914
|
function homeFrom(env) {
|
|
40667
|
-
return env["HOME"] || env["USERPROFILE"] ||
|
|
40915
|
+
return env["HOME"] || env["USERPROFILE"] || homedir8();
|
|
40668
40916
|
}
|
|
40669
40917
|
async function readHead(path) {
|
|
40670
40918
|
let handle;
|
|
@@ -40719,9 +40967,9 @@ function displayValue(value, maxLength) {
|
|
|
40719
40967
|
return trimmed;
|
|
40720
40968
|
}
|
|
40721
40969
|
function claudeTranscriptPath(input) {
|
|
40722
|
-
const configDir = input.env["CLAUDE_CONFIG_DIR"] ||
|
|
40970
|
+
const configDir = input.env["CLAUDE_CONFIG_DIR"] || join19(homeFrom(input.env), ".claude");
|
|
40723
40971
|
const slug = input.resolvedCwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
40724
|
-
return
|
|
40972
|
+
return join19(configDir, "projects", slug, `${input.sessionId}.jsonl`);
|
|
40725
40973
|
}
|
|
40726
40974
|
async function readClaudeSessionEffort(input) {
|
|
40727
40975
|
const resolvedCwd = await realpath9(input.cwd).catch(() => input.cwd);
|
|
@@ -40737,18 +40985,18 @@ async function readClaudeSessionEffort(input) {
|
|
|
40737
40985
|
}
|
|
40738
40986
|
async function newestDirectories(root, limit) {
|
|
40739
40987
|
const entries = await readdir5(root, { withFileTypes: true }).catch(() => []);
|
|
40740
|
-
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort((left, right) => right.localeCompare(left)).slice(0, limit).map((name) =>
|
|
40988
|
+
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort((left, right) => right.localeCompare(left)).slice(0, limit).map((name) => join19(root, name));
|
|
40741
40989
|
}
|
|
40742
40990
|
async function findCodexRolloutPath(input) {
|
|
40743
|
-
const codexHome = input.env["CODEX_HOME"] ||
|
|
40744
|
-
const sessions =
|
|
40991
|
+
const codexHome = input.env["CODEX_HOME"] || join19(homeFrom(input.env), ".codex");
|
|
40992
|
+
const sessions = join19(codexHome, "sessions");
|
|
40745
40993
|
const suffix = `-${input.threadId}.jsonl`;
|
|
40746
40994
|
for (const year of await newestDirectories(sessions, 2)) {
|
|
40747
40995
|
for (const month of await newestDirectories(year, 2)) {
|
|
40748
40996
|
for (const day of await newestDirectories(month, 3)) {
|
|
40749
40997
|
const files = await readdir5(day).catch(() => []);
|
|
40750
40998
|
const match = files.find((name) => name.endsWith(suffix));
|
|
40751
|
-
if (match) return
|
|
40999
|
+
if (match) return join19(day, match);
|
|
40752
41000
|
}
|
|
40753
41001
|
}
|
|
40754
41002
|
}
|
|
@@ -41142,18 +41390,18 @@ function improveErrorMessage(error52) {
|
|
|
41142
41390
|
}
|
|
41143
41391
|
|
|
41144
41392
|
// src/runners/codex.ts
|
|
41145
|
-
import { mkdir as
|
|
41393
|
+
import { mkdir as mkdir13, readFile as readFile10, writeFile as writeFile8 } from "node:fs/promises";
|
|
41146
41394
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
41147
|
-
import { homedir as
|
|
41148
|
-
import { join as
|
|
41395
|
+
import { homedir as homedir9 } from "node:os";
|
|
41396
|
+
import { join as join20 } from "node:path";
|
|
41149
41397
|
var CODEX_NOT_FOUND_MESSAGE = "The `codex` CLI was not found on this Machine. Install it (npm install -g @openai/codex) and sign in with `codex login`, or switch the agent to API-key auth.";
|
|
41150
41398
|
function defaultCodexThreadIndexRoot() {
|
|
41151
|
-
return
|
|
41399
|
+
return join20(homedir9(), ".zixt", "codex-threads");
|
|
41152
41400
|
}
|
|
41153
41401
|
var SAFE_SEGMENT3 = /^[A-Za-z0-9_-]{1,200}$/;
|
|
41154
41402
|
function threadIndexPath(root, agentId, sessionKey) {
|
|
41155
41403
|
if (!SAFE_SEGMENT3.test(agentId) || !SAFE_SEGMENT3.test(sessionKey)) return null;
|
|
41156
|
-
return
|
|
41404
|
+
return join20(root, agentId, `${sessionKey}.json`);
|
|
41157
41405
|
}
|
|
41158
41406
|
async function readThreadId(path) {
|
|
41159
41407
|
try {
|
|
@@ -41257,7 +41505,7 @@ ${value}` : value;
|
|
|
41257
41505
|
const recordedThreadId = indexPath ? await readThreadId(indexPath) : null;
|
|
41258
41506
|
const rememberThread = (threadId) => {
|
|
41259
41507
|
if (!indexPath) return;
|
|
41260
|
-
void
|
|
41508
|
+
void mkdir13(join20(threadIndexRoot, task.agentId), { recursive: true }).then(() => writeFile8(indexPath, JSON.stringify({ threadId }), "utf8")).catch(() => {
|
|
41261
41509
|
});
|
|
41262
41510
|
};
|
|
41263
41511
|
const observeRuntime = (threadId) => {
|
|
@@ -41720,9 +41968,9 @@ function improveCodexErrorMessage(error52) {
|
|
|
41720
41968
|
}
|
|
41721
41969
|
|
|
41722
41970
|
// src/runners/git-preflight.ts
|
|
41723
|
-
import { spawn as
|
|
41971
|
+
import { spawn as spawn11 } from "node:child_process";
|
|
41724
41972
|
import { realpath as realpath10 } from "node:fs/promises";
|
|
41725
|
-
import { isAbsolute as
|
|
41973
|
+
import { isAbsolute as isAbsolute17, resolve as resolve11 } from "node:path";
|
|
41726
41974
|
var OUTPUT_LIMIT = 8192;
|
|
41727
41975
|
var DEFAULT_TIMEOUT_MS4 = 1e4;
|
|
41728
41976
|
var VERSION_PATTERN = /^git version [^\r\n]{1,108}$/;
|
|
@@ -41738,7 +41986,7 @@ function unavailable(error52, checkedAt, executablePath = null) {
|
|
|
41738
41986
|
async function preflightGit(options = {}) {
|
|
41739
41987
|
const checkedAt = (options.now?.() ?? /* @__PURE__ */ new Date()).toISOString();
|
|
41740
41988
|
const configured = options.command;
|
|
41741
|
-
if (configured !== void 0 && !
|
|
41989
|
+
if (configured !== void 0 && !isAbsolute17(configured)) {
|
|
41742
41990
|
return unavailable("configured git command must be an absolute file", checkedAt);
|
|
41743
41991
|
}
|
|
41744
41992
|
const trustedCwd = await realpath10(resolve11(options.trustedCwd ?? process.cwd())).catch(() => null);
|
|
@@ -41769,7 +42017,7 @@ async function preflightGit(options = {}) {
|
|
|
41769
42017
|
}
|
|
41770
42018
|
async function runVersionProbe(input) {
|
|
41771
42019
|
return new Promise((resolvePromise) => {
|
|
41772
|
-
const child =
|
|
42020
|
+
const child = spawn11(input.executablePath, input.args, {
|
|
41773
42021
|
cwd: input.cwd,
|
|
41774
42022
|
env: {
|
|
41775
42023
|
...process.env.SystemRoot ? { SystemRoot: process.env.SystemRoot } : {},
|
|
@@ -41838,7 +42086,7 @@ async function preflightClaudeCode(options = {}) {
|
|
|
41838
42086
|
const command = options.command ?? "claude";
|
|
41839
42087
|
const prefixArgs = options.commandPrefixArgs ?? [];
|
|
41840
42088
|
const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
41841
|
-
const trustedCommand = await
|
|
42089
|
+
const trustedCommand = await resolveRunnerCommand(command, "claude-code", { probe: true });
|
|
41842
42090
|
if (!trustedCommand) {
|
|
41843
42091
|
return {
|
|
41844
42092
|
type: "claude-code",
|
|
@@ -41889,7 +42137,7 @@ async function preflightCodex(options = {}) {
|
|
|
41889
42137
|
const command = options.command ?? "codex";
|
|
41890
42138
|
const prefixArgs = options.commandPrefixArgs ?? [];
|
|
41891
42139
|
const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
41892
|
-
const trustedCommand = await
|
|
42140
|
+
const trustedCommand = await resolveRunnerCommand(command, "codex", { probe: true });
|
|
41893
42141
|
if (!trustedCommand) {
|
|
41894
42142
|
return {
|
|
41895
42143
|
type: "codex",
|
|
@@ -41991,11 +42239,11 @@ function run2(command, args) {
|
|
|
41991
42239
|
}
|
|
41992
42240
|
|
|
41993
42241
|
// src/linux-service.ts
|
|
41994
|
-
import { spawn as
|
|
42242
|
+
import { spawn as spawn12 } from "node:child_process";
|
|
41995
42243
|
import { constants as constants2 } from "node:fs";
|
|
41996
|
-
import { access as access4, chmod as chmod7, mkdir as
|
|
41997
|
-
import { homedir as
|
|
41998
|
-
import { basename as basename4, dirname as
|
|
42244
|
+
import { access as access4, chmod as chmod7, mkdir as mkdir14, open as open7, rename as rename6, rm as rm10 } from "node:fs/promises";
|
|
42245
|
+
import { homedir as homedir10, userInfo } from "node:os";
|
|
42246
|
+
import { basename as basename4, dirname as dirname11, join as join21, relative as relative9, resolve as resolve12, sep as sep5 } from "node:path";
|
|
41999
42247
|
var SERVICE_NAME = "zixt-host.service";
|
|
42000
42248
|
var SYSTEM_SERVICE_COMMAND_TIMEOUT_MS = 7e4;
|
|
42001
42249
|
var SERVICE_STABILITY_DELAY_MS = 2e3;
|
|
@@ -42024,7 +42272,7 @@ function boundedAppend(current, chunk) {
|
|
|
42024
42272
|
async function defaultRunCommand(command, args) {
|
|
42025
42273
|
const commandEnvironment3 = systemServiceCommandEnvironment();
|
|
42026
42274
|
return new Promise((resolve18) => {
|
|
42027
|
-
const child =
|
|
42275
|
+
const child = spawn12(command, [...args], {
|
|
42028
42276
|
stdio: ["ignore", "pipe", "pipe"],
|
|
42029
42277
|
env: commandEnvironment3,
|
|
42030
42278
|
windowsHide: true
|
|
@@ -42096,22 +42344,22 @@ async function defaultSyncDirectory(path) {
|
|
|
42096
42344
|
}
|
|
42097
42345
|
}
|
|
42098
42346
|
async function ensureDirectory(path, mode, syncDirectory8) {
|
|
42099
|
-
const firstCreated = await
|
|
42347
|
+
const firstCreated = await mkdir14(path, { recursive: true, mode });
|
|
42100
42348
|
if (!firstCreated) return;
|
|
42101
42349
|
const first = resolve12(firstCreated);
|
|
42102
42350
|
const target = resolve12(path);
|
|
42103
|
-
await syncDirectory8(
|
|
42351
|
+
await syncDirectory8(dirname11(first));
|
|
42104
42352
|
let current = first;
|
|
42105
42353
|
const descendants = relative9(first, target);
|
|
42106
42354
|
for (const part of descendants ? descendants.split(sep5) : []) {
|
|
42107
42355
|
await syncDirectory8(current);
|
|
42108
|
-
current =
|
|
42356
|
+
current = join21(current, part);
|
|
42109
42357
|
}
|
|
42110
42358
|
}
|
|
42111
42359
|
async function replacePrivateFile(path, contents, mode, syncDirectory8) {
|
|
42112
|
-
const parent =
|
|
42360
|
+
const parent = dirname11(path);
|
|
42113
42361
|
await ensureDirectory(parent, 448, syncDirectory8);
|
|
42114
|
-
const temporary =
|
|
42362
|
+
const temporary = join21(parent, `.${basename4(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
42115
42363
|
const handle = await open7(temporary, "wx", mode);
|
|
42116
42364
|
try {
|
|
42117
42365
|
await handle.writeFile(contents, "utf8");
|
|
@@ -42122,7 +42370,7 @@ async function replacePrivateFile(path, contents, mode, syncDirectory8) {
|
|
|
42122
42370
|
await syncDirectory8(parent);
|
|
42123
42371
|
} catch (error52) {
|
|
42124
42372
|
await handle.close().catch(() => void 0);
|
|
42125
|
-
await
|
|
42373
|
+
await rm10(temporary, { force: true }).catch(() => void 0);
|
|
42126
42374
|
throw error52;
|
|
42127
42375
|
}
|
|
42128
42376
|
}
|
|
@@ -42155,7 +42403,7 @@ async function installLinuxService(options) {
|
|
|
42155
42403
|
throw new Error("Linux automatic startup is available only on Linux.");
|
|
42156
42404
|
}
|
|
42157
42405
|
const env = options.env ?? process.env;
|
|
42158
|
-
const home = options.home ??
|
|
42406
|
+
const home = options.home ?? homedir10();
|
|
42159
42407
|
const username = oneLine(options.username ?? userInfo().username, "user name");
|
|
42160
42408
|
const token2 = oneLine(options.token, "pairing code");
|
|
42161
42409
|
const path = oneLine(
|
|
@@ -42163,12 +42411,12 @@ async function installLinuxService(options) {
|
|
|
42163
42411
|
"command search path"
|
|
42164
42412
|
);
|
|
42165
42413
|
const cloudUrl = options.cloudUrl ? oneLine(options.cloudUrl, "Zixt Cloud address") : void 0;
|
|
42166
|
-
const xdgConfigHome = env.XDG_CONFIG_HOME ? oneLine(env.XDG_CONFIG_HOME, "Linux configuration path") :
|
|
42167
|
-
const configRoot = options.serviceConfigRoot ??
|
|
42168
|
-
const unitRoot = options.userUnitRoot ??
|
|
42169
|
-
const environmentPath =
|
|
42170
|
-
const unitPath =
|
|
42171
|
-
const installVersion = options.installVersion ?? installRelease;
|
|
42414
|
+
const xdgConfigHome = env.XDG_CONFIG_HOME ? oneLine(env.XDG_CONFIG_HOME, "Linux configuration path") : join21(home, ".config");
|
|
42415
|
+
const configRoot = options.serviceConfigRoot ?? join21(xdgConfigHome, "zixt");
|
|
42416
|
+
const unitRoot = options.userUnitRoot ?? join21(xdgConfigHome, "systemd", "user");
|
|
42417
|
+
const environmentPath = join21(configRoot, "host.env");
|
|
42418
|
+
const unitPath = join21(unitRoot, SERVICE_NAME);
|
|
42419
|
+
const installVersion = options.installVersion ?? ((version2, onFailure) => installRelease(version2, onFailure ? { onFailure } : {}));
|
|
42172
42420
|
const activateVersion = options.activateVersion ?? (options.installVersion ? async (entry) => entry : activateInstalledRelease);
|
|
42173
42421
|
const resolveCommand = options.resolveCommand ?? defaultResolveCommand;
|
|
42174
42422
|
const run3 = options.runCommand ?? defaultRunCommand;
|
|
@@ -42183,9 +42431,15 @@ async function installLinuxService(options) {
|
|
|
42183
42431
|
"This Linux computer does not have the systemd tools Zixt needs to start itself."
|
|
42184
42432
|
);
|
|
42185
42433
|
}
|
|
42186
|
-
const
|
|
42434
|
+
const attempt = { failure: null };
|
|
42435
|
+
const releaseEntry = await installVersion(options.hostVersion, (failure2) => {
|
|
42436
|
+
attempt.failure = failure2;
|
|
42437
|
+
});
|
|
42187
42438
|
if (!releaseEntry) {
|
|
42188
|
-
|
|
42439
|
+
const failed = attempt.failure;
|
|
42440
|
+
throw new Error(
|
|
42441
|
+
`Zixt Host ${options.hostVersion} could not be installed for automatic start${failed ? ` (${failed.reason}: ${failed.detail})` : ""}.`
|
|
42442
|
+
);
|
|
42189
42443
|
}
|
|
42190
42444
|
const currentEntry = await activateVersion(releaseEntry);
|
|
42191
42445
|
const linger = async () => {
|
|
@@ -42207,8 +42461,12 @@ async function installLinuxService(options) {
|
|
|
42207
42461
|
...cloudUrl ? [`ZIXT_CLOUD_URL=${systemdEnvironmentValue(cloudUrl)}`] : [],
|
|
42208
42462
|
`PATH=${systemdEnvironmentValue(path)}`,
|
|
42209
42463
|
...env.ZIXT_HOST_UPDATE ? [`ZIXT_HOST_UPDATE=${systemdEnvironmentValue(env.ZIXT_HOST_UPDATE)}`] : [],
|
|
42464
|
+
...env.ZIXT_RUNNER_AUTOINSTALL ? [`ZIXT_RUNNER_AUTOINSTALL=${systemdEnvironmentValue(env.ZIXT_RUNNER_AUTOINSTALL)}`] : [],
|
|
42210
42465
|
...env.ZIXT_HOST_UPDATE_URL ? [`ZIXT_HOST_UPDATE_URL=${systemdEnvironmentValue(env.ZIXT_HOST_UPDATE_URL)}`] : [],
|
|
42211
42466
|
...env.ZIXT_HOST_VERSIONS_DIR ? [`ZIXT_HOST_VERSIONS_DIR=${systemdEnvironmentValue(env.ZIXT_HOST_VERSIONS_DIR)}`] : [],
|
|
42467
|
+
// A Machine on a private registry mirror checks ZIXT_HOST_UPDATE_URL for
|
|
42468
|
+
// releases; its unattended npm installs must follow the same mirror.
|
|
42469
|
+
...env.NPM_CONFIG_REGISTRY ? [`NPM_CONFIG_REGISTRY=${systemdEnvironmentValue(env.NPM_CONFIG_REGISTRY)}`] : [],
|
|
42212
42470
|
""
|
|
42213
42471
|
].join("\n");
|
|
42214
42472
|
await replacePrivateFile(environmentPath, serviceEnvironment, 384, syncDirectory8);
|
|
@@ -42284,11 +42542,11 @@ async function installLinuxService(options) {
|
|
|
42284
42542
|
}
|
|
42285
42543
|
|
|
42286
42544
|
// src/macos-service.ts
|
|
42287
|
-
import { spawn as
|
|
42545
|
+
import { spawn as spawn13 } from "node:child_process";
|
|
42288
42546
|
import { constants as constants3 } from "node:fs";
|
|
42289
|
-
import { access as access5, chmod as chmod8, mkdir as
|
|
42290
|
-
import { homedir as
|
|
42291
|
-
import { basename as basename5, dirname as
|
|
42547
|
+
import { access as access5, chmod as chmod8, mkdir as mkdir15, open as open8, rename as rename7, rm as rm11 } from "node:fs/promises";
|
|
42548
|
+
import { homedir as homedir11, userInfo as userInfo2 } from "node:os";
|
|
42549
|
+
import { basename as basename5, dirname as dirname12, join as join22, relative as relative10, resolve as resolve13, sep as sep6 } from "node:path";
|
|
42292
42550
|
var LAUNCH_AGENT_LABEL = "ai.zixt.host";
|
|
42293
42551
|
var SERVICE_STABILITY_DELAY_MS2 = 2e3;
|
|
42294
42552
|
var COMMAND_TIMEOUT_MS2 = 7e4;
|
|
@@ -42312,21 +42570,21 @@ async function syncDirectory4(path) {
|
|
|
42312
42570
|
}
|
|
42313
42571
|
}
|
|
42314
42572
|
async function ensureDirectory2(path, sync) {
|
|
42315
|
-
const firstCreated = await
|
|
42573
|
+
const firstCreated = await mkdir15(path, { recursive: true, mode: 448 });
|
|
42316
42574
|
if (!firstCreated) return;
|
|
42317
42575
|
const first = resolve13(firstCreated);
|
|
42318
42576
|
const target = resolve13(path);
|
|
42319
|
-
await sync(
|
|
42577
|
+
await sync(dirname12(first));
|
|
42320
42578
|
let current = first;
|
|
42321
42579
|
for (const part of relative10(first, target).split(sep6).filter(Boolean)) {
|
|
42322
42580
|
await sync(current);
|
|
42323
|
-
current =
|
|
42581
|
+
current = join22(current, part);
|
|
42324
42582
|
}
|
|
42325
42583
|
}
|
|
42326
42584
|
async function replacePrivateFile2(path, contents, mode, sync) {
|
|
42327
|
-
const parent =
|
|
42585
|
+
const parent = dirname12(path);
|
|
42328
42586
|
await ensureDirectory2(parent, sync);
|
|
42329
|
-
const temporary =
|
|
42587
|
+
const temporary = join22(parent, `.${basename5(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
42330
42588
|
const handle = await open8(temporary, "wx", mode);
|
|
42331
42589
|
try {
|
|
42332
42590
|
await handle.writeFile(contents, "utf8");
|
|
@@ -42337,7 +42595,7 @@ async function replacePrivateFile2(path, contents, mode, sync) {
|
|
|
42337
42595
|
await sync(parent);
|
|
42338
42596
|
} catch (error52) {
|
|
42339
42597
|
await handle.close().catch(() => void 0);
|
|
42340
|
-
await
|
|
42598
|
+
await rm11(temporary, { force: true }).catch(() => void 0);
|
|
42341
42599
|
throw error52;
|
|
42342
42600
|
}
|
|
42343
42601
|
}
|
|
@@ -42351,7 +42609,7 @@ function commandEnvironment(env) {
|
|
|
42351
42609
|
}
|
|
42352
42610
|
async function defaultRunCommand2(command, args, env) {
|
|
42353
42611
|
return new Promise((resolveResult) => {
|
|
42354
|
-
const child =
|
|
42612
|
+
const child = spawn13(command, [...args], {
|
|
42355
42613
|
stdio: ["ignore", "pipe", "pipe"],
|
|
42356
42614
|
env: commandEnvironment(env)
|
|
42357
42615
|
});
|
|
@@ -42414,7 +42672,7 @@ async function installMacosService(options) {
|
|
|
42414
42672
|
throw new Error("macOS automatic startup is available only on macOS.");
|
|
42415
42673
|
}
|
|
42416
42674
|
const env = options.env ?? process.env;
|
|
42417
|
-
const home = options.home ??
|
|
42675
|
+
const home = options.home ?? homedir11();
|
|
42418
42676
|
const uid = options.uid ?? userInfo2().uid;
|
|
42419
42677
|
if (!Number.isSafeInteger(uid) || uid < 0) throw new Error("macOS user id is invalid.");
|
|
42420
42678
|
const token2 = oneLine2(options.token, "pairing code");
|
|
@@ -42423,15 +42681,15 @@ async function installMacosService(options) {
|
|
|
42423
42681
|
options.path ?? env.PATH ?? "/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin",
|
|
42424
42682
|
"command search path"
|
|
42425
42683
|
);
|
|
42426
|
-
const configRoot = options.configRoot ??
|
|
42427
|
-
const launchAgentsRoot = options.launchAgentsRoot ??
|
|
42428
|
-
const logRoot = options.logRoot ??
|
|
42429
|
-
const configPath =
|
|
42430
|
-
const launcherPath =
|
|
42431
|
-
const plistPath =
|
|
42432
|
-
const stdoutPath =
|
|
42433
|
-
const stderrPath =
|
|
42434
|
-
const installVersion = options.installVersion ?? installRelease;
|
|
42684
|
+
const configRoot = options.configRoot ?? join22(home, "Library", "Application Support", "Zixt");
|
|
42685
|
+
const launchAgentsRoot = options.launchAgentsRoot ?? join22(home, "Library", "LaunchAgents");
|
|
42686
|
+
const logRoot = options.logRoot ?? join22(home, "Library", "Logs", "Zixt");
|
|
42687
|
+
const configPath = join22(configRoot, "host.env");
|
|
42688
|
+
const launcherPath = join22(configRoot, "host-launcher.sh");
|
|
42689
|
+
const plistPath = join22(launchAgentsRoot, `${LAUNCH_AGENT_LABEL}.plist`);
|
|
42690
|
+
const stdoutPath = join22(logRoot, "host.log");
|
|
42691
|
+
const stderrPath = join22(logRoot, "host-error.log");
|
|
42692
|
+
const installVersion = options.installVersion ?? ((version2, onFailure) => installRelease(version2, onFailure ? { onFailure } : {}));
|
|
42435
42693
|
const activateVersion = options.activateVersion ?? (options.installVersion ? async (entry) => entry : (entry) => activateInstalledRelease(entry));
|
|
42436
42694
|
const resolveCommand = options.resolveCommand ?? (async () => defaultResolveCommand2());
|
|
42437
42695
|
const run3 = options.runCommand ?? ((command, args) => defaultRunCommand2(command, args, env));
|
|
@@ -42439,9 +42697,15 @@ async function installMacosService(options) {
|
|
|
42439
42697
|
const delay4 = options.delay ?? ((ms) => new Promise((done) => setTimeout(done, ms)));
|
|
42440
42698
|
const launchctl = await resolveCommand("launchctl");
|
|
42441
42699
|
if (!launchctl) throw new Error("macOS launchctl could not be found.");
|
|
42442
|
-
const
|
|
42700
|
+
const attempt = { failure: null };
|
|
42701
|
+
const releaseEntry = await installVersion(options.hostVersion, (failure2) => {
|
|
42702
|
+
attempt.failure = failure2;
|
|
42703
|
+
});
|
|
42443
42704
|
if (!releaseEntry) {
|
|
42444
|
-
|
|
42705
|
+
const failed = attempt.failure;
|
|
42706
|
+
throw new Error(
|
|
42707
|
+
`Zixt Host ${options.hostVersion} could not be installed for automatic start${failed ? ` (${failed.reason}: ${failed.detail})` : ""}.`
|
|
42708
|
+
);
|
|
42445
42709
|
}
|
|
42446
42710
|
const currentEntry = await activateVersion(releaseEntry);
|
|
42447
42711
|
await ensureDirectory2(configRoot, sync);
|
|
@@ -42454,8 +42718,12 @@ async function installMacosService(options) {
|
|
|
42454
42718
|
`PATH=${shellValue(path)}`,
|
|
42455
42719
|
"ZIXT_HOST_SERVICE_MANAGER=launchd",
|
|
42456
42720
|
...env.ZIXT_HOST_UPDATE ? [`ZIXT_HOST_UPDATE=${shellValue(env.ZIXT_HOST_UPDATE)}`] : [],
|
|
42721
|
+
...env.ZIXT_RUNNER_AUTOINSTALL ? [`ZIXT_RUNNER_AUTOINSTALL=${shellValue(env.ZIXT_RUNNER_AUTOINSTALL)}`] : [],
|
|
42457
42722
|
...env.ZIXT_HOST_UPDATE_URL ? [`ZIXT_HOST_UPDATE_URL=${shellValue(env.ZIXT_HOST_UPDATE_URL)}`] : [],
|
|
42458
42723
|
...env.ZIXT_HOST_VERSIONS_DIR ? [`ZIXT_HOST_VERSIONS_DIR=${shellValue(env.ZIXT_HOST_VERSIONS_DIR)}`] : [],
|
|
42724
|
+
// A Machine on a private registry mirror checks ZIXT_HOST_UPDATE_URL for
|
|
42725
|
+
// releases; its unattended npm installs must follow the same mirror.
|
|
42726
|
+
...env.NPM_CONFIG_REGISTRY ? [`NPM_CONFIG_REGISTRY=${shellValue(env.NPM_CONFIG_REGISTRY)}`] : [],
|
|
42459
42727
|
""
|
|
42460
42728
|
].join("\n");
|
|
42461
42729
|
await replacePrivateFile2(configPath, serviceEnvironment, 384, sync);
|
|
@@ -42515,11 +42783,11 @@ async function installMacosService(options) {
|
|
|
42515
42783
|
}
|
|
42516
42784
|
|
|
42517
42785
|
// src/windows-service.ts
|
|
42518
|
-
import { spawn as
|
|
42786
|
+
import { spawn as spawn14 } from "node:child_process";
|
|
42519
42787
|
import { constants as constants4 } from "node:fs";
|
|
42520
|
-
import { access as access6, mkdir as
|
|
42521
|
-
import { homedir as
|
|
42522
|
-
import { basename as basename6, dirname as
|
|
42788
|
+
import { access as access6, mkdir as mkdir16, open as open9, readFile as readFile11, rename as rename8, rm as rm12 } from "node:fs/promises";
|
|
42789
|
+
import { homedir as homedir12 } from "node:os";
|
|
42790
|
+
import { basename as basename6, dirname as dirname13, isAbsolute as isAbsolute18, join as join23, relative as relative11, resolve as resolve14, sep as sep7 } from "node:path";
|
|
42523
42791
|
var TASK_NAME = "Zixt Host";
|
|
42524
42792
|
var COMMAND_TIMEOUT_MS3 = 7e4;
|
|
42525
42793
|
var SERVICE_STABILITY_DELAY_MS3 = 2e3;
|
|
@@ -42545,31 +42813,31 @@ async function syncDirectory5(path) {
|
|
|
42545
42813
|
}
|
|
42546
42814
|
}
|
|
42547
42815
|
async function ensureDirectory3(path, sync) {
|
|
42548
|
-
const firstCreated = await
|
|
42816
|
+
const firstCreated = await mkdir16(path, { recursive: true, mode: 448 });
|
|
42549
42817
|
if (!firstCreated) return;
|
|
42550
42818
|
const first = resolve14(firstCreated);
|
|
42551
42819
|
const target = resolve14(path);
|
|
42552
|
-
await sync(
|
|
42820
|
+
await sync(dirname13(first));
|
|
42553
42821
|
let current = first;
|
|
42554
42822
|
for (const part of relative11(first, target).split(sep7).filter(Boolean)) {
|
|
42555
42823
|
await sync(current);
|
|
42556
|
-
current =
|
|
42824
|
+
current = join23(current, part);
|
|
42557
42825
|
}
|
|
42558
42826
|
}
|
|
42559
|
-
async function replacePrivateFile3(path, contents, sync) {
|
|
42560
|
-
const parent =
|
|
42827
|
+
async function replacePrivateFile3(path, contents, sync, encoding = "utf8") {
|
|
42828
|
+
const parent = dirname13(path);
|
|
42561
42829
|
await ensureDirectory3(parent, sync);
|
|
42562
|
-
const temporary =
|
|
42830
|
+
const temporary = join23(parent, `.${basename6(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
42563
42831
|
const handle = await open9(temporary, "wx", 384);
|
|
42564
42832
|
try {
|
|
42565
|
-
await handle.writeFile(contents,
|
|
42833
|
+
await handle.writeFile(encoding === "utf16le" ? `\uFEFF${contents}` : contents, encoding);
|
|
42566
42834
|
await handle.sync();
|
|
42567
42835
|
await handle.close();
|
|
42568
42836
|
await rename8(temporary, path);
|
|
42569
42837
|
await sync(parent);
|
|
42570
42838
|
} catch (error52) {
|
|
42571
42839
|
await handle.close().catch(() => void 0);
|
|
42572
|
-
await
|
|
42840
|
+
await rm12(temporary, { force: true }).catch(() => void 0);
|
|
42573
42841
|
throw error52;
|
|
42574
42842
|
}
|
|
42575
42843
|
}
|
|
@@ -42580,7 +42848,7 @@ function commandEnvironment2(env) {
|
|
|
42580
42848
|
}
|
|
42581
42849
|
async function runChild(command, args, env, input) {
|
|
42582
42850
|
return new Promise((resolveResult) => {
|
|
42583
|
-
const child =
|
|
42851
|
+
const child = spawn14(command, [...args], {
|
|
42584
42852
|
stdio: [input === void 0 ? "ignore" : "pipe", "pipe", "pipe"],
|
|
42585
42853
|
env: commandEnvironment2(env),
|
|
42586
42854
|
windowsHide: true
|
|
@@ -42613,8 +42881,8 @@ async function runChild(command, args, env, input) {
|
|
|
42613
42881
|
}
|
|
42614
42882
|
async function defaultResolveCommand3(name, env) {
|
|
42615
42883
|
const root = env.SYSTEMROOT ?? env.WINDIR;
|
|
42616
|
-
if (!root || !
|
|
42617
|
-
const candidate = name === "powershell" ?
|
|
42884
|
+
if (!root || !isAbsolute18(root)) return null;
|
|
42885
|
+
const candidate = name === "powershell" ? join23(root, "System32", "WindowsPowerShell", "v1.0", "powershell.exe") : join23(root, "System32", `${name}.exe`);
|
|
42618
42886
|
return access6(candidate, constants4.X_OK).then(
|
|
42619
42887
|
() => candidate,
|
|
42620
42888
|
() => null
|
|
@@ -42664,8 +42932,10 @@ try {
|
|
|
42664
42932
|
if ($config.cloudUrl) { $env:ZIXT_CLOUD_URL = $config.cloudUrl } else { Remove-Item Env:ZIXT_CLOUD_URL -ErrorAction SilentlyContinue }
|
|
42665
42933
|
$env:PATH = $config.path
|
|
42666
42934
|
if ($config.update) { $env:ZIXT_HOST_UPDATE = $config.update }
|
|
42935
|
+
if ($config.runnerAutoinstall) { $env:ZIXT_RUNNER_AUTOINSTALL = $config.runnerAutoinstall }
|
|
42667
42936
|
if ($config.updateUrl) { $env:ZIXT_HOST_UPDATE_URL = $config.updateUrl }
|
|
42668
42937
|
if ($config.versionsRoot) { $env:ZIXT_HOST_VERSIONS_DIR = $config.versionsRoot }
|
|
42938
|
+
if ($config.npmRegistry) { $env:NPM_CONFIG_REGISTRY = $config.npmRegistry }
|
|
42669
42939
|
Set-Location -LiteralPath $config.cwd
|
|
42670
42940
|
|
|
42671
42941
|
# Task Scheduler does not provide a durable stdin lifetime boundary. Give
|
|
@@ -42713,8 +42983,20 @@ async function defaultObserveStatus(path, generation) {
|
|
|
42713
42983
|
return null;
|
|
42714
42984
|
}
|
|
42715
42985
|
}
|
|
42986
|
+
function hiddenLaunchSource(powershell, launcherPath) {
|
|
42987
|
+
const vbsPath = (value) => {
|
|
42988
|
+
if (/[\0\r\n"]/.test(value)) throw new Error("launch path is not a valid one-line value");
|
|
42989
|
+
return value;
|
|
42990
|
+
};
|
|
42991
|
+
return [
|
|
42992
|
+
"Dim q : q = Chr(34)",
|
|
42993
|
+
'Dim shell : Set shell = CreateObject("WScript.Shell")',
|
|
42994
|
+
`WScript.Quit shell.Run(q & "${vbsPath(powershell)}" & q & " -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File " & q & "${vbsPath(launcherPath)}" & q, 0, True)`,
|
|
42995
|
+
""
|
|
42996
|
+
].join("\r\n");
|
|
42997
|
+
}
|
|
42716
42998
|
function taskXml(input) {
|
|
42717
|
-
return `<?xml version="1.0" encoding="UTF-
|
|
42999
|
+
return `<?xml version="1.0" encoding="UTF-16"?>
|
|
42718
43000
|
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
|
42719
43001
|
<Triggers><LogonTrigger><Enabled>true</Enabled><UserId>${xml2(input.sid)}</UserId></LogonTrigger></Triggers>
|
|
42720
43002
|
<Principals><Principal id="ZixtUser"><UserId>${xml2(input.sid)}</UserId><LogonType>InteractiveToken</LogonType><RunLevel>LeastPrivilege</RunLevel></Principal></Principals>
|
|
@@ -42727,8 +43009,8 @@ function taskXml(input) {
|
|
|
42727
43009
|
<RestartOnFailure><Interval>PT1M</Interval><Count>999</Count></RestartOnFailure>
|
|
42728
43010
|
</Settings>
|
|
42729
43011
|
<Actions Context="ZixtUser"><Exec>
|
|
42730
|
-
<Command>${xml2(input.
|
|
42731
|
-
<Arguments
|
|
43012
|
+
<Command>${xml2(input.wscript)}</Command>
|
|
43013
|
+
<Arguments>//B //NoLogo "${xml2(input.launchShimPath)}"</Arguments>
|
|
42732
43014
|
<WorkingDirectory>${xml2(input.home)}</WorkingDirectory>
|
|
42733
43015
|
</Exec></Actions>
|
|
42734
43016
|
</Task>
|
|
@@ -42743,39 +43025,47 @@ async function installWindowsService(options) {
|
|
|
42743
43025
|
throw new Error("Windows automatic startup is available only on Windows.");
|
|
42744
43026
|
}
|
|
42745
43027
|
const env = options.env ?? process.env;
|
|
42746
|
-
const home = options.home ??
|
|
43028
|
+
const home = options.home ?? homedir12();
|
|
42747
43029
|
const localAppData = options.localAppData ?? env.LOCALAPPDATA;
|
|
42748
|
-
if (!localAppData || !
|
|
43030
|
+
if (!localAppData || !isAbsolute18(localAppData)) {
|
|
42749
43031
|
throw new Error("Windows local application data path is unavailable.");
|
|
42750
43032
|
}
|
|
42751
43033
|
const token2 = oneLine3(options.token, "pairing code");
|
|
42752
43034
|
const cloudUrl = options.cloudUrl ? oneLine3(options.cloudUrl, "Zixt Cloud address") : void 0;
|
|
42753
43035
|
const path = oneLine3(options.path ?? env.PATH ?? "", "command search path");
|
|
42754
|
-
const configRoot = options.configRoot ??
|
|
42755
|
-
const configPath =
|
|
42756
|
-
const launcherPath =
|
|
42757
|
-
const
|
|
42758
|
-
const
|
|
42759
|
-
const
|
|
43036
|
+
const configRoot = options.configRoot ?? join23(localAppData, "Zixt", "Host");
|
|
43037
|
+
const configPath = join23(configRoot, "host.json");
|
|
43038
|
+
const launcherPath = join23(configRoot, "host-launcher.ps1");
|
|
43039
|
+
const launchShimPath = join23(configRoot, "host-launch.vbs");
|
|
43040
|
+
const taskXmlPath = join23(configRoot, "host-task.xml");
|
|
43041
|
+
const statusPath = join23(configRoot, "host-status.json");
|
|
43042
|
+
const installVersion = options.installVersion ?? ((version2, onFailure) => installRelease(version2, onFailure ? { onFailure } : {}));
|
|
42760
43043
|
const activateVersion = options.activateVersion ?? (options.installVersion ? async (entry) => entry : (entry) => activateInstalledRelease(entry));
|
|
42761
43044
|
const resolveCommand = options.resolveCommand ?? ((name) => defaultResolveCommand3(name, env));
|
|
42762
43045
|
const run3 = options.runCommand ?? ((command, args) => runChild(command, args, env));
|
|
42763
43046
|
const sync = options.syncDirectory ?? syncDirectory5;
|
|
42764
43047
|
const delay4 = options.delay ?? ((ms) => new Promise((done) => setTimeout(done, ms)));
|
|
42765
43048
|
const observe = options.observeStatus ?? defaultObserveStatus;
|
|
42766
|
-
const [powershell, schtasks, icacls] = await Promise.all([
|
|
43049
|
+
const [powershell, schtasks, icacls, wscript] = await Promise.all([
|
|
42767
43050
|
resolveCommand("powershell"),
|
|
42768
43051
|
resolveCommand("schtasks"),
|
|
42769
|
-
resolveCommand("icacls")
|
|
43052
|
+
resolveCommand("icacls"),
|
|
43053
|
+
resolveCommand("wscript")
|
|
42770
43054
|
]);
|
|
42771
|
-
if (!powershell || !schtasks || !icacls) {
|
|
43055
|
+
if (!powershell || !schtasks || !icacls || !wscript) {
|
|
42772
43056
|
throw new Error("Windows Scheduled Task tools could not be found.");
|
|
42773
43057
|
}
|
|
42774
43058
|
const sid = options.sid ?? await defaultCurrentSid(powershell, env);
|
|
42775
43059
|
if (!sid || !SAFE_SID.test(sid)) throw new Error("Windows user identity could not be confirmed.");
|
|
42776
|
-
const
|
|
43060
|
+
const attempt = { failure: null };
|
|
43061
|
+
const releaseEntry = await installVersion(options.hostVersion, (failure2) => {
|
|
43062
|
+
attempt.failure = failure2;
|
|
43063
|
+
});
|
|
42777
43064
|
if (!releaseEntry) {
|
|
42778
|
-
|
|
43065
|
+
const failed = attempt.failure;
|
|
43066
|
+
throw new Error(
|
|
43067
|
+
`Zixt Host ${options.hostVersion} could not be installed for automatic start${failed ? ` (${failed.reason}: ${failed.detail})` : ""}.`
|
|
43068
|
+
);
|
|
42779
43069
|
}
|
|
42780
43070
|
const currentEntry = await activateVersion(releaseEntry);
|
|
42781
43071
|
const protectedToken = await (options.protectToken ?? ((value, shell) => defaultProtectToken(value, shell, env)))(token2, powershell);
|
|
@@ -42796,15 +43086,25 @@ async function installWindowsService(options) {
|
|
|
42796
43086
|
...cloudUrl ? { cloudUrl } : {},
|
|
42797
43087
|
path,
|
|
42798
43088
|
...env.ZIXT_HOST_UPDATE ? { update: env.ZIXT_HOST_UPDATE } : {},
|
|
43089
|
+
...env.ZIXT_RUNNER_AUTOINSTALL ? { runnerAutoinstall: env.ZIXT_RUNNER_AUTOINSTALL } : {},
|
|
42799
43090
|
...env.ZIXT_HOST_UPDATE_URL ? { updateUrl: env.ZIXT_HOST_UPDATE_URL } : {},
|
|
42800
|
-
...env.ZIXT_HOST_VERSIONS_DIR ? { versionsRoot: env.ZIXT_HOST_VERSIONS_DIR } : {}
|
|
43091
|
+
...env.ZIXT_HOST_VERSIONS_DIR ? { versionsRoot: env.ZIXT_HOST_VERSIONS_DIR } : {},
|
|
43092
|
+
// A Machine on a private registry mirror checks updateUrl for releases;
|
|
43093
|
+
// its unattended npm installs must follow the same mirror.
|
|
43094
|
+
...env.NPM_CONFIG_REGISTRY ? { npmRegistry: env.NPM_CONFIG_REGISTRY } : {}
|
|
42801
43095
|
})}
|
|
42802
43096
|
`,
|
|
42803
43097
|
sync
|
|
42804
43098
|
);
|
|
42805
43099
|
await replacePrivateFile3(launcherPath, launcherSource2(configPath, statusPath), sync);
|
|
42806
|
-
await replacePrivateFile3(
|
|
42807
|
-
await
|
|
43100
|
+
await replacePrivateFile3(launchShimPath, hiddenLaunchSource(powershell, launcherPath), sync);
|
|
43101
|
+
await replacePrivateFile3(
|
|
43102
|
+
taskXmlPath,
|
|
43103
|
+
taskXml({ sid, wscript, launchShimPath, home }),
|
|
43104
|
+
sync,
|
|
43105
|
+
"utf16le"
|
|
43106
|
+
);
|
|
43107
|
+
await rm12(statusPath, { force: true });
|
|
42808
43108
|
const acl = await run3(icacls, [
|
|
42809
43109
|
configRoot,
|
|
42810
43110
|
"/inheritance:r",
|
|
@@ -42814,6 +43114,13 @@ async function installWindowsService(options) {
|
|
|
42814
43114
|
"*S-1-5-18:(OI)(CI)F"
|
|
42815
43115
|
]);
|
|
42816
43116
|
if (acl.code !== 0) throw commandFailure3("Protecting Zixt startup files", acl);
|
|
43117
|
+
const sweep = await run3(powershell, [
|
|
43118
|
+
"-NoProfile",
|
|
43119
|
+
"-NonInteractive",
|
|
43120
|
+
"-Command",
|
|
43121
|
+
`$stopped = 0; Get-CimInstance Win32_Process -Filter "Name='powershell.exe'" | Where-Object { $_.ProcessId -ne $PID -and $_.CommandLine -and $_.CommandLine.Contains(${psLiteral(launcherPath)}) } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue; $stopped++ }; Write-Output $stopped`
|
|
43122
|
+
]);
|
|
43123
|
+
if (Number.parseInt(sweep.stdout.trim(), 10) > 0) await delay4(1500);
|
|
42817
43124
|
await run3(schtasks, ["/End", "/TN", TASK_NAME]);
|
|
42818
43125
|
const create = await run3(schtasks, ["/Create", "/TN", TASK_NAME, "/XML", taskXmlPath, "/F"]);
|
|
42819
43126
|
if (create.code !== 0) throw commandFailure3("Installing Zixt at sign-in", create);
|
|
@@ -42837,6 +43144,7 @@ async function installWindowsService(options) {
|
|
|
42837
43144
|
taskXmlPath,
|
|
42838
43145
|
configPath,
|
|
42839
43146
|
launcherPath,
|
|
43147
|
+
launchShimPath,
|
|
42840
43148
|
statusPath,
|
|
42841
43149
|
releaseEntry,
|
|
42842
43150
|
currentEntry,
|
|
@@ -42856,23 +43164,23 @@ async function installSystemService(options) {
|
|
|
42856
43164
|
}
|
|
42857
43165
|
|
|
42858
43166
|
// src/terminal-outcomes.ts
|
|
42859
|
-
import { chmod as chmod9, lstat as lstat12, mkdir as
|
|
42860
|
-
import { homedir as
|
|
42861
|
-
import { dirname as
|
|
43167
|
+
import { chmod as chmod9, lstat as lstat12, mkdir as mkdir17, open as open10, readdir as readdir6, readFile as readFile12, rename as rename9, rm as rm13 } from "node:fs/promises";
|
|
43168
|
+
import { homedir as homedir13 } from "node:os";
|
|
43169
|
+
import { dirname as dirname14, join as join24, relative as relative12, resolve as resolve15, sep as sep8 } from "node:path";
|
|
42862
43170
|
var DIRECTORY_MODE5 = 448;
|
|
42863
43171
|
var FILE_MODE4 = 384;
|
|
42864
43172
|
var MAX_OUTCOME_BYTES = 4 * 1024 * 1024;
|
|
42865
43173
|
var HOST_DIRECTORY = /^hst_[0-9a-f]{32}$/;
|
|
42866
43174
|
var OUTCOME_FILE = /^(tsk_[0-9a-f]{32})\.([1-9][0-9]*)\.json$/;
|
|
42867
43175
|
function defaultTerminalOutcomeRoot() {
|
|
42868
|
-
return
|
|
43176
|
+
return join24(homedir13(), ".zixt", "terminal-outcomes");
|
|
42869
43177
|
}
|
|
42870
43178
|
function hostOutcomeRoot(root, hostId) {
|
|
42871
43179
|
if (!HOST_DIRECTORY.test(hostId)) throw new Error("terminal outcome Host identity is malformed");
|
|
42872
|
-
return
|
|
43180
|
+
return join24(root, hostId);
|
|
42873
43181
|
}
|
|
42874
43182
|
function outcomePath(root, hostId, taskId, epoch) {
|
|
42875
|
-
return
|
|
43183
|
+
return join24(hostOutcomeRoot(root, hostId), `${taskId}.${epoch}.json`);
|
|
42876
43184
|
}
|
|
42877
43185
|
async function syncDirectory6(root) {
|
|
42878
43186
|
if (process.platform === "win32") return;
|
|
@@ -42884,19 +43192,19 @@ async function syncDirectory6(root) {
|
|
|
42884
43192
|
}
|
|
42885
43193
|
}
|
|
42886
43194
|
async function requirePrivateRoot(root, sync = syncDirectory6) {
|
|
42887
|
-
const firstCreated = await
|
|
43195
|
+
const firstCreated = await mkdir17(root, { recursive: true, mode: DIRECTORY_MODE5 });
|
|
42888
43196
|
if (firstCreated) {
|
|
42889
43197
|
const first = resolve15(firstCreated);
|
|
42890
43198
|
const target = resolve15(root);
|
|
42891
|
-
await sync(
|
|
43199
|
+
await sync(dirname14(first));
|
|
42892
43200
|
let current = first;
|
|
42893
43201
|
for (const part of relative12(first, target).split(sep8).filter(Boolean)) {
|
|
42894
43202
|
await sync(current);
|
|
42895
|
-
current =
|
|
43203
|
+
current = join24(current, part);
|
|
42896
43204
|
}
|
|
42897
43205
|
}
|
|
42898
|
-
const
|
|
42899
|
-
if (
|
|
43206
|
+
const stat4 = await lstat12(root);
|
|
43207
|
+
if (stat4.isSymbolicLink() || !stat4.isDirectory()) {
|
|
42900
43208
|
throw new Error("terminal outcome journal root is not a trusted directory");
|
|
42901
43209
|
}
|
|
42902
43210
|
await chmod9(root, DIRECTORY_MODE5);
|
|
@@ -42932,7 +43240,7 @@ async function recordTerminalOutcome(hostId, input, root = defaultTerminalOutcom
|
|
|
42932
43240
|
} catch (error52) {
|
|
42933
43241
|
if (error52.code !== "ENOENT") throw error52;
|
|
42934
43242
|
}
|
|
42935
|
-
const temporary =
|
|
43243
|
+
const temporary = join24(
|
|
42936
43244
|
scopedRoot,
|
|
42937
43245
|
`.${outcome.taskId}.${outcome.epoch}.${process.pid}.${Date.now()}.${outcome.resultId}.tmp`
|
|
42938
43246
|
);
|
|
@@ -42949,7 +43257,7 @@ async function recordTerminalOutcome(hostId, input, root = defaultTerminalOutcom
|
|
|
42949
43257
|
} finally {
|
|
42950
43258
|
await handle?.close().catch(() => {
|
|
42951
43259
|
});
|
|
42952
|
-
await
|
|
43260
|
+
await rm13(temporary, { force: true }).catch(() => {
|
|
42953
43261
|
});
|
|
42954
43262
|
}
|
|
42955
43263
|
}
|
|
@@ -42985,9 +43293,9 @@ async function readTerminalOutcomesStrict(root = defaultTerminalOutcomeRoot()) {
|
|
|
42985
43293
|
if (!match || !entry.isFile() || entry.isSymbolicLink()) {
|
|
42986
43294
|
throw new Error("committed terminal outcome is not a trusted regular file");
|
|
42987
43295
|
}
|
|
42988
|
-
const path =
|
|
42989
|
-
const
|
|
42990
|
-
if (!
|
|
43296
|
+
const path = join24(scopedRoot, entry.name);
|
|
43297
|
+
const stat4 = await lstat12(path);
|
|
43298
|
+
if (!stat4.isFile() || stat4.isSymbolicLink() || stat4.size > MAX_OUTCOME_BYTES) {
|
|
42991
43299
|
throw new Error("committed terminal outcome is not a trusted regular file");
|
|
42992
43300
|
}
|
|
42993
43301
|
const outcome = parseCommittedOutcome(
|
|
@@ -43018,7 +43326,7 @@ async function forgetAcknowledgedTerminalOutcomes(refs, root = defaultTerminalOu
|
|
|
43018
43326
|
if (acknowledged.get(`${hostId}:${outcome.taskId}:${outcome.epoch}`) !== outcome.resultId) {
|
|
43019
43327
|
continue;
|
|
43020
43328
|
}
|
|
43021
|
-
await
|
|
43329
|
+
await rm13(outcomePath(root, hostId, outcome.taskId, outcome.epoch), { force: true });
|
|
43022
43330
|
changedHostRoots.add(hostOutcomeRoot(root, hostId));
|
|
43023
43331
|
}
|
|
43024
43332
|
for (const scopedRoot of changedHostRoots) await syncDirectory6(scopedRoot);
|
|
@@ -43030,22 +43338,22 @@ async function forgetSupersededTerminalOutcomes(hostId, taskId, epoch, root = de
|
|
|
43030
43338
|
if (scoped.hostId !== hostId) continue;
|
|
43031
43339
|
const { outcome } = scoped;
|
|
43032
43340
|
if (outcome.taskId !== taskId || outcome.epoch >= epoch) continue;
|
|
43033
|
-
await
|
|
43341
|
+
await rm13(outcomePath(root, hostId, outcome.taskId, outcome.epoch), { force: true });
|
|
43034
43342
|
removed = true;
|
|
43035
43343
|
}
|
|
43036
43344
|
if (removed) await syncDirectory6(hostOutcomeRoot(root, hostId));
|
|
43037
43345
|
}
|
|
43038
43346
|
|
|
43039
43347
|
// src/accepted-assignments.ts
|
|
43040
|
-
import { chmod as chmod10, lstat as lstat13, mkdir as
|
|
43041
|
-
import { homedir as
|
|
43042
|
-
import { dirname as
|
|
43348
|
+
import { chmod as chmod10, lstat as lstat13, mkdir as mkdir18, open as open11, readdir as readdir7, rename as rename10, rm as rm14 } from "node:fs/promises";
|
|
43349
|
+
import { homedir as homedir14 } from "node:os";
|
|
43350
|
+
import { dirname as dirname15, join as join25, relative as relative13, resolve as resolve16, sep as sep9 } from "node:path";
|
|
43043
43351
|
var DIRECTORY_MODE6 = 448;
|
|
43044
43352
|
var FILE_MODE5 = 384;
|
|
43045
43353
|
var CLAIM_FILE = /^(tsk_[0-9a-f]{32})\.([1-9][0-9]*)\.json$/;
|
|
43046
43354
|
var TASK_ID = /^tsk_[0-9a-f]{32}$/;
|
|
43047
43355
|
function defaultAcceptedAssignmentRoot() {
|
|
43048
|
-
return
|
|
43356
|
+
return join25(homedir14(), ".zixt", "accepted-assignments");
|
|
43049
43357
|
}
|
|
43050
43358
|
async function syncDirectory7(root) {
|
|
43051
43359
|
if (process.platform === "win32") return;
|
|
@@ -43057,19 +43365,19 @@ async function syncDirectory7(root) {
|
|
|
43057
43365
|
}
|
|
43058
43366
|
}
|
|
43059
43367
|
async function requirePrivateRoot2(root, sync = syncDirectory7) {
|
|
43060
|
-
const firstCreated = await
|
|
43368
|
+
const firstCreated = await mkdir18(root, { recursive: true, mode: DIRECTORY_MODE6 });
|
|
43061
43369
|
if (firstCreated) {
|
|
43062
43370
|
const first = resolve16(firstCreated);
|
|
43063
43371
|
const target = resolve16(root);
|
|
43064
|
-
await sync(
|
|
43372
|
+
await sync(dirname15(first));
|
|
43065
43373
|
let current = first;
|
|
43066
43374
|
for (const part of relative13(first, target).split(sep9).filter(Boolean)) {
|
|
43067
43375
|
await sync(current);
|
|
43068
|
-
current =
|
|
43376
|
+
current = join25(current, part);
|
|
43069
43377
|
}
|
|
43070
43378
|
}
|
|
43071
|
-
const
|
|
43072
|
-
if (
|
|
43379
|
+
const stat4 = await lstat13(root);
|
|
43380
|
+
if (stat4.isSymbolicLink() || !stat4.isDirectory()) {
|
|
43073
43381
|
throw new Error("accepted assignment journal root is not a trusted directory");
|
|
43074
43382
|
}
|
|
43075
43383
|
await chmod10(root, DIRECTORY_MODE6);
|
|
@@ -43079,7 +43387,7 @@ function claimPath(root, taskId, epoch) {
|
|
|
43079
43387
|
if (!Number.isSafeInteger(epoch) || epoch < 1) {
|
|
43080
43388
|
throw new Error("accepted assignment epoch is malformed");
|
|
43081
43389
|
}
|
|
43082
|
-
return
|
|
43390
|
+
return join25(root, `${taskId}.${epoch}.json`);
|
|
43083
43391
|
}
|
|
43084
43392
|
async function recordAcceptedAssignment(assignment, root = defaultAcceptedAssignmentRoot(), options = {}) {
|
|
43085
43393
|
const sync = options.syncDirectory ?? syncDirectory7;
|
|
@@ -43089,7 +43397,7 @@ async function recordAcceptedAssignment(assignment, root = defaultAcceptedAssign
|
|
|
43089
43397
|
} catch {
|
|
43090
43398
|
return false;
|
|
43091
43399
|
}
|
|
43092
|
-
const temporary =
|
|
43400
|
+
const temporary = join25(
|
|
43093
43401
|
root,
|
|
43094
43402
|
`.${assignment.taskId}.${assignment.epoch}.${process.pid}.${Date.now()}.tmp`
|
|
43095
43403
|
);
|
|
@@ -43109,7 +43417,7 @@ async function recordAcceptedAssignment(assignment, root = defaultAcceptedAssign
|
|
|
43109
43417
|
} finally {
|
|
43110
43418
|
await handle?.close().catch(() => {
|
|
43111
43419
|
});
|
|
43112
|
-
await
|
|
43420
|
+
await rm14(temporary, { force: true }).catch(() => {
|
|
43113
43421
|
});
|
|
43114
43422
|
}
|
|
43115
43423
|
}
|
|
@@ -43143,13 +43451,18 @@ async function forgetAcceptedAssignment(assignment, root = defaultAcceptedAssign
|
|
|
43143
43451
|
} catch {
|
|
43144
43452
|
return;
|
|
43145
43453
|
}
|
|
43146
|
-
await
|
|
43454
|
+
await rm14(path, { force: true }).catch(() => {
|
|
43147
43455
|
});
|
|
43148
43456
|
}
|
|
43149
43457
|
async function forgetAcknowledgedAcceptedAssignments(assignments, root = defaultAcceptedAssignmentRoot()) {
|
|
43150
43458
|
for (const assignment of assignments) await forgetAcceptedAssignment(assignment, root);
|
|
43151
43459
|
}
|
|
43152
43460
|
|
|
43461
|
+
// src/local-observability.ts
|
|
43462
|
+
import { appendFile, mkdir as mkdir19, open as open12, rename as rename11, rm as rm15, stat as stat3 } from "node:fs/promises";
|
|
43463
|
+
import { homedir as homedir15 } from "node:os";
|
|
43464
|
+
import { basename as basename7, dirname as dirname16, join as join26 } from "node:path";
|
|
43465
|
+
|
|
43153
43466
|
// src/logger.ts
|
|
43154
43467
|
var ANSI = {
|
|
43155
43468
|
reset: "\x1B[0m",
|
|
@@ -43241,7 +43554,9 @@ function createHostLogger(options = {}) {
|
|
|
43241
43554
|
const color = options.color ?? (process.stderr.isTTY === true && process.env.NO_COLOR === void 0);
|
|
43242
43555
|
const write = options.write ?? ((line) => console.error(line));
|
|
43243
43556
|
const log2 = (level, message, context) => {
|
|
43244
|
-
|
|
43557
|
+
const at = now();
|
|
43558
|
+
write(formatHostLogLine(level, message, context, { at, color }));
|
|
43559
|
+
options.onEntry?.({ at, level, message, context: context ?? {} });
|
|
43245
43560
|
};
|
|
43246
43561
|
return {
|
|
43247
43562
|
info: (message, context) => log2("info", message, context),
|
|
@@ -43251,24 +43566,105 @@ function createHostLogger(options = {}) {
|
|
|
43251
43566
|
};
|
|
43252
43567
|
}
|
|
43253
43568
|
|
|
43569
|
+
// src/local-observability.ts
|
|
43570
|
+
var LOCAL_CONSOLE_FILE = "console.jsonl";
|
|
43571
|
+
var LOCAL_CONSOLE_PREVIOUS_FILE = "console.prev.jsonl";
|
|
43572
|
+
var LOCAL_STATUS_FILE = "status.json";
|
|
43573
|
+
var DEFAULT_CONSOLE_ROTATE_BYTES = 2 * 1024 * 1024;
|
|
43574
|
+
function defaultLocalObservabilityRoot() {
|
|
43575
|
+
return join26(homedir15(), ".zixt", "observability");
|
|
43576
|
+
}
|
|
43577
|
+
function createLocalConsoleSink(options = {}) {
|
|
43578
|
+
const root = options.root ?? defaultLocalObservabilityRoot();
|
|
43579
|
+
const consolePath = join26(root, LOCAL_CONSOLE_FILE);
|
|
43580
|
+
const rotateBytes = options.rotateBytes ?? DEFAULT_CONSOLE_ROTATE_BYTES;
|
|
43581
|
+
let disabled = false;
|
|
43582
|
+
let prepared = false;
|
|
43583
|
+
let approximateBytes = 0;
|
|
43584
|
+
let queue = Promise.resolve();
|
|
43585
|
+
const write = async (entry) => {
|
|
43586
|
+
if (disabled) return;
|
|
43587
|
+
try {
|
|
43588
|
+
if (!prepared) {
|
|
43589
|
+
await mkdir19(root, { recursive: true, mode: 448 });
|
|
43590
|
+
approximateBytes = await stat3(consolePath).then(
|
|
43591
|
+
(existing) => existing.size,
|
|
43592
|
+
() => 0
|
|
43593
|
+
);
|
|
43594
|
+
prepared = true;
|
|
43595
|
+
}
|
|
43596
|
+
if (approximateBytes >= rotateBytes) {
|
|
43597
|
+
await rm15(join26(root, LOCAL_CONSOLE_PREVIOUS_FILE), { force: true });
|
|
43598
|
+
await rename11(consolePath, join26(root, LOCAL_CONSOLE_PREVIOUS_FILE)).catch(
|
|
43599
|
+
(error52) => {
|
|
43600
|
+
if (error52.code !== "ENOENT") throw error52;
|
|
43601
|
+
}
|
|
43602
|
+
);
|
|
43603
|
+
approximateBytes = 0;
|
|
43604
|
+
}
|
|
43605
|
+
const line = `${JSON.stringify({
|
|
43606
|
+
at: entry.at.toISOString(),
|
|
43607
|
+
level: entry.level,
|
|
43608
|
+
line: formatHostLogLine(entry.level, entry.message, entry.context, {
|
|
43609
|
+
at: entry.at,
|
|
43610
|
+
color: false
|
|
43611
|
+
})
|
|
43612
|
+
})}
|
|
43613
|
+
`;
|
|
43614
|
+
await appendFile(consolePath, line, { encoding: "utf8", mode: 384 });
|
|
43615
|
+
approximateBytes += Buffer.byteLength(line);
|
|
43616
|
+
} catch (error52) {
|
|
43617
|
+
disabled = true;
|
|
43618
|
+
options.onDisabled?.(error52);
|
|
43619
|
+
}
|
|
43620
|
+
};
|
|
43621
|
+
return {
|
|
43622
|
+
entry(entry) {
|
|
43623
|
+
queue = queue.then(() => write(entry));
|
|
43624
|
+
},
|
|
43625
|
+
settled: () => queue
|
|
43626
|
+
};
|
|
43627
|
+
}
|
|
43628
|
+
async function writeLocalStatus(status, root = defaultLocalObservabilityRoot()) {
|
|
43629
|
+
const destination = join26(root, LOCAL_STATUS_FILE);
|
|
43630
|
+
const temporary = join26(
|
|
43631
|
+
dirname16(destination),
|
|
43632
|
+
`.${basename7(destination)}.${process.pid}.${crypto.randomUUID()}.tmp`
|
|
43633
|
+
);
|
|
43634
|
+
try {
|
|
43635
|
+
await mkdir19(root, { recursive: true, mode: 448 });
|
|
43636
|
+
const handle = await open12(temporary, "wx", 384);
|
|
43637
|
+
try {
|
|
43638
|
+
await handle.writeFile(`${JSON.stringify(status)}
|
|
43639
|
+
`, "utf8");
|
|
43640
|
+
} finally {
|
|
43641
|
+
await handle.close();
|
|
43642
|
+
}
|
|
43643
|
+
await rename11(temporary, destination);
|
|
43644
|
+
} catch {
|
|
43645
|
+
await rm15(temporary, { force: true }).catch(() => void 0);
|
|
43646
|
+
}
|
|
43647
|
+
}
|
|
43648
|
+
|
|
43254
43649
|
// src/demo-state.ts
|
|
43255
|
-
import { isAbsolute as
|
|
43650
|
+
import { isAbsolute as isAbsolute19, join as join27, parse as parse3, resolve as resolve17 } from "node:path";
|
|
43256
43651
|
var DEMO_STATE_ROOT_ENV = "ZIXT_DEMO_STATE_ROOT";
|
|
43257
43652
|
function resolveDemoHostStatePaths(env = process.env) {
|
|
43258
43653
|
const configured = env.ZIXT_RUNNER === "demo" ? env[DEMO_STATE_ROOT_ENV] : void 0;
|
|
43259
43654
|
if (!configured) return null;
|
|
43260
43655
|
const root = resolve17(configured);
|
|
43261
|
-
if (!
|
|
43656
|
+
if (!isAbsolute19(configured) || root === parse3(root).root) {
|
|
43262
43657
|
throw new Error(`${DEMO_STATE_ROOT_ENV} must be a dedicated absolute directory`);
|
|
43263
43658
|
}
|
|
43264
43659
|
return {
|
|
43265
|
-
runRegistryRoot:
|
|
43266
|
-
terminalOutcomeRoot:
|
|
43267
|
-
acceptedAssignmentRoot:
|
|
43268
|
-
runArtifactRoot:
|
|
43269
|
-
browserProfileRoot:
|
|
43270
|
-
runnerWorkspaceRoot:
|
|
43271
|
-
codexThreadIndexRoot:
|
|
43660
|
+
runRegistryRoot: join27(root, "run-registry"),
|
|
43661
|
+
terminalOutcomeRoot: join27(root, "terminal-outcomes"),
|
|
43662
|
+
acceptedAssignmentRoot: join27(root, "accepted-assignments"),
|
|
43663
|
+
runArtifactRoot: join27(root, "run-artifacts"),
|
|
43664
|
+
browserProfileRoot: join27(root, "browser-profiles"),
|
|
43665
|
+
runnerWorkspaceRoot: join27(root, "workspaces"),
|
|
43666
|
+
codexThreadIndexRoot: join27(root, "codex-threads"),
|
|
43667
|
+
localObservabilityRoot: join27(root, "local-observability")
|
|
43272
43668
|
};
|
|
43273
43669
|
}
|
|
43274
43670
|
|
|
@@ -43330,6 +43726,9 @@ function parseHostCliOptions(argv) {
|
|
|
43330
43726
|
}
|
|
43331
43727
|
return options;
|
|
43332
43728
|
}
|
|
43729
|
+
function isServiceSetupInvocation(argv) {
|
|
43730
|
+
return argv.includes("--install-service");
|
|
43731
|
+
}
|
|
43333
43732
|
function forcedColor(mode) {
|
|
43334
43733
|
if (mode === "always") return true;
|
|
43335
43734
|
if (mode === "never") return false;
|
|
@@ -43412,7 +43811,9 @@ if (packagedBuild) {
|
|
|
43412
43811
|
if (isWorkerProxyRole()) process.exit(managedExit(await runWorkerCompatibilityProxy()));
|
|
43413
43812
|
if (needsLegacySupervisorHandoff()) process.exit(managedExit(await launchHostSupervisor()));
|
|
43414
43813
|
if (isSupervisorRole()) process.exit(managedExit(await superviseHost()));
|
|
43415
|
-
if (!isWorkerRole()
|
|
43814
|
+
if (!isWorkerRole() && !isServiceSetupInvocation(process.argv.slice(2))) {
|
|
43815
|
+
process.exit(managedExit(await launchHostSupervisor()));
|
|
43816
|
+
}
|
|
43416
43817
|
}
|
|
43417
43818
|
var workerWatchdog = startWorkerWatchdogHeartbeat();
|
|
43418
43819
|
if (packagedBuild && isWorkerRole() && process.env[WORKER_WATCHDOG_NONCE_ENV] !== void 0 && !workerWatchdog.active) {
|
|
@@ -43440,12 +43841,14 @@ function recordConsoleLine(line) {
|
|
|
43440
43841
|
if (hostConsoleTail.length > 200) hostConsoleTail.shift();
|
|
43441
43842
|
clientForConsole.current?.hostConsoleLine(entry);
|
|
43442
43843
|
}
|
|
43844
|
+
var localConsoleSink = { current: null };
|
|
43443
43845
|
var log = createHostLogger({
|
|
43444
43846
|
...colorOverride === void 0 ? {} : { color: colorOverride },
|
|
43445
43847
|
write: (line) => {
|
|
43446
43848
|
console.error(line);
|
|
43447
43849
|
recordConsoleLine(line);
|
|
43448
|
-
}
|
|
43850
|
+
},
|
|
43851
|
+
onEntry: (entry) => localConsoleSink.current?.entry(entry)
|
|
43449
43852
|
});
|
|
43450
43853
|
function replayConsoleLine(level, message, context) {
|
|
43451
43854
|
recordConsoleLine(
|
|
@@ -43453,6 +43856,7 @@ function replayConsoleLine(level, message, context) {
|
|
|
43453
43856
|
...colorOverride === void 0 ? {} : { color: colorOverride }
|
|
43454
43857
|
})
|
|
43455
43858
|
);
|
|
43859
|
+
localConsoleSink.current?.entry({ at: /* @__PURE__ */ new Date(), level, message, context: context ?? {} });
|
|
43456
43860
|
}
|
|
43457
43861
|
if (cliOptions.help) {
|
|
43458
43862
|
process.stdout.write(`${hostHelpText()}
|
|
@@ -43516,8 +43920,20 @@ var {
|
|
|
43516
43920
|
runArtifactRoot,
|
|
43517
43921
|
browserProfileRoot,
|
|
43518
43922
|
runnerWorkspaceRoot,
|
|
43519
|
-
codexThreadIndexRoot
|
|
43923
|
+
codexThreadIndexRoot,
|
|
43924
|
+
localObservabilityRoot
|
|
43520
43925
|
} = demoState ?? {};
|
|
43926
|
+
localConsoleSink.current = createLocalConsoleSink({
|
|
43927
|
+
...localObservabilityRoot ? { root: localObservabilityRoot } : {},
|
|
43928
|
+
onDisabled: (error52) => {
|
|
43929
|
+
console.error(
|
|
43930
|
+
formatHostLogLine("warn", "The local console file was disabled after a write failure", {
|
|
43931
|
+
machine,
|
|
43932
|
+
error: error52 instanceof Error ? error52.message : "unknown error"
|
|
43933
|
+
})
|
|
43934
|
+
);
|
|
43935
|
+
}
|
|
43936
|
+
});
|
|
43521
43937
|
var disclaimableAssignments;
|
|
43522
43938
|
var acceptedAssignments;
|
|
43523
43939
|
var terminalOutcomes;
|
|
@@ -43559,6 +43975,23 @@ if (!token) {
|
|
|
43559
43975
|
process.exit(DO_NOT_RESTART_EXIT_CODE);
|
|
43560
43976
|
}
|
|
43561
43977
|
var demoPreflightScript = forceDemo ? process.env.ZIXT_DEMO_PREFLIGHT_SCRIPT : void 0;
|
|
43978
|
+
var runnerAutoInstaller = forceDemo || process.env.ZIXT_RUNNER_AUTOINSTALL === "off" ? null : createRunnerAutoInstaller({
|
|
43979
|
+
onEvent: (event) => {
|
|
43980
|
+
const name = event.runner === "claude-code" ? "Claude Code" : "Codex";
|
|
43981
|
+
if (event.state === "started") {
|
|
43982
|
+
log.info(`${name} not found; installing it for this Machine`, { machine });
|
|
43983
|
+
} else if (event.state === "completed") {
|
|
43984
|
+
log.success(`${name} installed`, { machine });
|
|
43985
|
+
cachedRunners = null;
|
|
43986
|
+
} else {
|
|
43987
|
+
log.warn(`${name} installation failed`, {
|
|
43988
|
+
machine,
|
|
43989
|
+
...event.error ? { error: event.error } : {},
|
|
43990
|
+
next: `Install the ${event.runner === "claude-code" ? "claude" : "codex"} CLI manually; the Host retries later`
|
|
43991
|
+
});
|
|
43992
|
+
}
|
|
43993
|
+
}
|
|
43994
|
+
});
|
|
43562
43995
|
var gitPreflight = await preflightGit();
|
|
43563
43996
|
var gitRefresh = null;
|
|
43564
43997
|
var GIT_PREFLIGHT_REFRESH_MS = 4 * 6e4;
|
|
@@ -43702,12 +44135,18 @@ async function telemetry() {
|
|
|
43702
44135
|
preflightCodex()
|
|
43703
44136
|
]);
|
|
43704
44137
|
cachedRunnersAt = Date.now();
|
|
43705
|
-
for (const runner of cachedRunners)
|
|
44138
|
+
for (const runner of cachedRunners) {
|
|
44139
|
+
reportRunnerReadiness(runner);
|
|
44140
|
+
if (!runner.installed && (runner.type === "claude-code" || runner.type === "codex") && runnerAutoInstaller) {
|
|
44141
|
+
runnerAutoInstaller.ensureInstalled(runner.type);
|
|
44142
|
+
}
|
|
44143
|
+
}
|
|
43706
44144
|
}
|
|
43707
44145
|
const providerToolPacks = toolPackRegistry.capabilities({
|
|
43708
44146
|
now: /* @__PURE__ */ new Date(),
|
|
43709
44147
|
git: await currentGitPreflight()
|
|
43710
44148
|
});
|
|
44149
|
+
publishLocalStatus();
|
|
43711
44150
|
providerToolPacks.push({
|
|
43712
44151
|
provider: "email",
|
|
43713
44152
|
version: 1,
|
|
@@ -43734,7 +44173,7 @@ async function telemetry() {
|
|
|
43734
44173
|
// Measured per heartbeat: free memory and free disk are only useful while
|
|
43735
44174
|
// they are current, and a demo Host reports its own private root so the
|
|
43736
44175
|
// number describes the filesystem its Tasks would really write to.
|
|
43737
|
-
hardware: await machineHardware(runnerWorkspaceRoot ??
|
|
44176
|
+
hardware: await machineHardware(runnerWorkspaceRoot ?? homedir16()),
|
|
43738
44177
|
capabilities: {
|
|
43739
44178
|
linearToolPack: providerToolPacks.some(
|
|
43740
44179
|
(pack) => pack.provider === "linear" && pack.health === "ready"
|
|
@@ -43791,6 +44230,36 @@ var connectionContext = connectionLogContext({
|
|
|
43791
44230
|
cloud: cloudTarget,
|
|
43792
44231
|
version: HOST_VERSION
|
|
43793
44232
|
});
|
|
44233
|
+
var hostStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
44234
|
+
var localCloudState = "connecting";
|
|
44235
|
+
var localCloudConnectedAt;
|
|
44236
|
+
var localStatusQueued = false;
|
|
44237
|
+
function publishLocalStatus() {
|
|
44238
|
+
if (localStatusQueued) return;
|
|
44239
|
+
localStatusQueued = true;
|
|
44240
|
+
queueMicrotask(() => {
|
|
44241
|
+
localStatusQueued = false;
|
|
44242
|
+
void writeLocalStatus(
|
|
44243
|
+
{
|
|
44244
|
+
schema: 1,
|
|
44245
|
+
version: HOST_VERSION,
|
|
44246
|
+
pid: process.pid,
|
|
44247
|
+
machine,
|
|
44248
|
+
startedAt: hostStartedAt,
|
|
44249
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
44250
|
+
cloud: {
|
|
44251
|
+
target: cloudTarget,
|
|
44252
|
+
state: localCloudState,
|
|
44253
|
+
...localCloudConnectedAt ? { connectedAt: localCloudConnectedAt } : {}
|
|
44254
|
+
},
|
|
44255
|
+
activeSessions,
|
|
44256
|
+
runners: cachedRunners ?? [],
|
|
44257
|
+
browser: cachedBrowserCapability ?? { status: "unavailable" }
|
|
44258
|
+
},
|
|
44259
|
+
...localObservabilityRoot ? [localObservabilityRoot] : []
|
|
44260
|
+
);
|
|
44261
|
+
});
|
|
44262
|
+
}
|
|
43794
44263
|
var stopUpdateWatch = () => {
|
|
43795
44264
|
};
|
|
43796
44265
|
var releaseParentPipeWatch = () => {
|
|
@@ -43915,6 +44384,9 @@ var client = new HostClient({
|
|
|
43915
44384
|
switch (status) {
|
|
43916
44385
|
case "connected":
|
|
43917
44386
|
log.success("Connected to Zixt Cloud", connectionContext);
|
|
44387
|
+
localCloudState = "connected";
|
|
44388
|
+
localCloudConnectedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
44389
|
+
publishLocalStatus();
|
|
43918
44390
|
if (reportedWorkerExits.length > 0) {
|
|
43919
44391
|
void forgetWorkerExits(reportedWorkerExits.map(({ file: file2 }) => file2));
|
|
43920
44392
|
}
|
|
@@ -43924,12 +44396,16 @@ var client = new HostClient({
|
|
|
43924
44396
|
...connectionContext,
|
|
43925
44397
|
next: "Check the cloud and Machine pairing if this continues"
|
|
43926
44398
|
});
|
|
44399
|
+
localCloudState = "connecting";
|
|
44400
|
+
publishLocalStatus();
|
|
43927
44401
|
break;
|
|
43928
44402
|
case "unresponsive":
|
|
43929
44403
|
log.warn("Zixt Cloud stopped answering; Tasks unwound before reconnecting", {
|
|
43930
44404
|
...connectionContext,
|
|
43931
44405
|
next: "Check this Machine's network path and Zixt Cloud health if this repeats"
|
|
43932
44406
|
});
|
|
44407
|
+
localCloudState = "connecting";
|
|
44408
|
+
publishLocalStatus();
|
|
43933
44409
|
break;
|
|
43934
44410
|
case "replaced":
|
|
43935
44411
|
log.warn("Another Host process took over this Machine", connectionContext);
|