@zixt/host 0.0.119 → 0.0.121
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 +868 -444
- 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.121",
|
|
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];
|
|
@@ -27899,15 +28130,15 @@ async function installRelease(version2, options = {}) {
|
|
|
27899
28130
|
}
|
|
27900
28131
|
const platform = options.platform ?? process.platform;
|
|
27901
28132
|
const root = options.root ?? versionsRoot();
|
|
27902
|
-
const prefix =
|
|
28133
|
+
const prefix = join10(root, version2);
|
|
27903
28134
|
const entry = installedReleaseEntry(version2, root);
|
|
27904
28135
|
if (await validReleaseAtPrefix(prefix, version2)) return entry;
|
|
27905
28136
|
if (options.signal?.aborted)
|
|
27906
28137
|
return fail("cancelled", "this Host was stopping before npm started");
|
|
27907
28138
|
const installerCommand = options.installerCommand ?? await resolveInstallerCommand({ platform });
|
|
27908
|
-
await
|
|
27909
|
-
const staging =
|
|
27910
|
-
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()}`);
|
|
27911
28142
|
const usesWindowsInstallerGuardian = platform === "win32" && options.spawnInstaller === void 0;
|
|
27912
28143
|
const installerGateNonce = usesWindowsInstallerGuardian ? crypto.randomUUID() : null;
|
|
27913
28144
|
const installerArguments = (installPrefix, installVersion) => [
|
|
@@ -27922,14 +28153,14 @@ async function installRelease(version2, options = {}) {
|
|
|
27922
28153
|
const spawnInstaller = options.spawnInstaller ?? ((installPrefix, installVersion) => {
|
|
27923
28154
|
const installerArgs = installerArguments(installPrefix, installVersion);
|
|
27924
28155
|
if (usesWindowsInstallerGuardian) {
|
|
27925
|
-
return
|
|
28156
|
+
return spawn6(process.execPath, ["-e", WINDOWS_INSTALLER_GUARDIAN, installerGateNonce], {
|
|
27926
28157
|
cwd: root,
|
|
27927
28158
|
stdio: ["pipe", "inherit", "inherit", "ipc"],
|
|
27928
28159
|
env: sanitizedInstallerEnv(process.env),
|
|
27929
28160
|
windowsHide: true
|
|
27930
28161
|
});
|
|
27931
28162
|
}
|
|
27932
|
-
return
|
|
28163
|
+
return spawn6(installerCommand, installerArgs, {
|
|
27933
28164
|
// stdin stays closed for the same reason as the Windows guardian
|
|
27934
28165
|
// above: this worker actively reads its own stdin (the supervisor's
|
|
27935
28166
|
// stop pipe), and an unattended npm must not share or depend on it.
|
|
@@ -27942,7 +28173,7 @@ async function installRelease(version2, options = {}) {
|
|
|
27942
28173
|
try {
|
|
27943
28174
|
child = spawnInstaller(staging, version2);
|
|
27944
28175
|
} catch (error52) {
|
|
27945
|
-
await
|
|
28176
|
+
await rm6(staging, { recursive: true, force: true }).catch(() => void 0);
|
|
27946
28177
|
return fail(
|
|
27947
28178
|
"installer_unavailable",
|
|
27948
28179
|
`${installerCommand} could not be started (${error52 instanceof Error ? error52.message : "unknown error"})`
|
|
@@ -27968,7 +28199,7 @@ async function installRelease(version2, options = {}) {
|
|
|
27968
28199
|
installerContainmentSetupError = error52;
|
|
27969
28200
|
return null;
|
|
27970
28201
|
}) : Promise.resolve(null);
|
|
27971
|
-
const timeoutMs = options.timeoutMs ??
|
|
28202
|
+
const timeoutMs = options.timeoutMs ?? INSTALL_TIMEOUT_MS2;
|
|
27972
28203
|
const outcome = { code: null, signal: null, timedOut: false, spawnError: null };
|
|
27973
28204
|
const installed = await new Promise((resolve18, reject3) => {
|
|
27974
28205
|
let finished = false;
|
|
@@ -28139,8 +28370,8 @@ async function installRelease(version2, options = {}) {
|
|
|
28139
28370
|
`${prefix} is not a runnable ${PACKAGE_NAME}@${version2} after installing`
|
|
28140
28371
|
);
|
|
28141
28372
|
} finally {
|
|
28142
|
-
await
|
|
28143
|
-
await
|
|
28373
|
+
await rm6(staging, { recursive: true, force: true }).catch(() => void 0);
|
|
28374
|
+
await rm6(quarantine, { recursive: true, force: true }).catch(() => void 0);
|
|
28144
28375
|
}
|
|
28145
28376
|
}
|
|
28146
28377
|
async function pruneInstalledVersions(keep, root = versionsRoot()) {
|
|
@@ -28155,10 +28386,10 @@ async function pruneInstalledVersions(keep, root = versionsRoot()) {
|
|
|
28155
28386
|
const removed = [];
|
|
28156
28387
|
for (const name of entries) {
|
|
28157
28388
|
if (protectedDirs.has(name) || !VERSION_DIR.test(name)) continue;
|
|
28158
|
-
const dir =
|
|
28389
|
+
const dir = join10(root, name);
|
|
28159
28390
|
if (running && running.startsWith(`${dir}${sep4}`)) continue;
|
|
28160
28391
|
try {
|
|
28161
|
-
await
|
|
28392
|
+
await rm6(dir, { recursive: true, force: true });
|
|
28162
28393
|
removed.push(name);
|
|
28163
28394
|
} catch {
|
|
28164
28395
|
}
|
|
@@ -28169,7 +28400,7 @@ function durableState(phase, candidateVersion, fallbackVersion) {
|
|
|
28169
28400
|
return { schema: 1, phase, candidateVersion, fallbackVersion };
|
|
28170
28401
|
}
|
|
28171
28402
|
async function validInstalledRelease(version2, root = versionsRoot()) {
|
|
28172
|
-
return validReleaseAtPrefix(
|
|
28403
|
+
return validReleaseAtPrefix(join10(root, version2), version2);
|
|
28173
28404
|
}
|
|
28174
28405
|
async function recoverDurableReleaseState(store, runningVersion, activeBootVersion, activate, log2) {
|
|
28175
28406
|
const state = await store.load();
|
|
@@ -28287,7 +28518,7 @@ function defaultSpawn(command, argv, supervisorVersion, watchdog, compatibilityO
|
|
|
28287
28518
|
delete env.ZIXT_HOST_REJECT_VERSION;
|
|
28288
28519
|
if (command.rejectedVersion) env.ZIXT_HOST_REJECT_VERSION = command.rejectedVersion;
|
|
28289
28520
|
const entry = compatibilityProxy ? process.argv[1] ?? "" : command.entry ?? process.argv[1] ?? "";
|
|
28290
|
-
const child =
|
|
28521
|
+
const child = spawn6(process.execPath, [entry, ...argv, ...ownership?.argv ?? []], {
|
|
28291
28522
|
// stdin is a pipe this process owns: closing it is how the worker is
|
|
28292
28523
|
// asked to stop, which works identically on Windows, where there is no
|
|
28293
28524
|
// real SIGINT to send. stdout stays the person's terminal; stderr is teed
|
|
@@ -28295,7 +28526,7 @@ function defaultSpawn(command, argv, supervisorVersion, watchdog, compatibilityO
|
|
|
28295
28526
|
stdio: watchdog ? ["pipe", "inherit", "pipe", "ipc"] : ["pipe", "inherit", "pipe"],
|
|
28296
28527
|
env,
|
|
28297
28528
|
...containmentGateNonce ? {
|
|
28298
|
-
cwd: ownership?.ownershipFile ?
|
|
28529
|
+
cwd: ownership?.ownershipFile ? dirname5(ownership.ownershipFile) : dirname5(entry)
|
|
28299
28530
|
} : {},
|
|
28300
28531
|
// The launch nonce is not a user-facing CLI argument. Keeping it as
|
|
28301
28532
|
// argv[0] gives the stable launcher an exact cross-platform process
|
|
@@ -28324,7 +28555,7 @@ async function runWorkerCompatibilityProxy(env = process.env, argv = process.arg
|
|
|
28324
28555
|
const ownership = consumeWorkerOwnershipArguments(argv, env);
|
|
28325
28556
|
const nonce = env[WORKER_WATCHDOG_NONCE_ENV];
|
|
28326
28557
|
const ownershipFile = env[WORKER_OWNERSHIP_FILE_ENV];
|
|
28327
|
-
if (typeof target !== "string" || !
|
|
28558
|
+
if (typeof target !== "string" || !isAbsolute10(target) || typeof nonce !== "string" || typeof ownershipFile !== "string" || !ownership.requested || !ownership.valid) {
|
|
28328
28559
|
return 1;
|
|
28329
28560
|
}
|
|
28330
28561
|
if (!recordWorkerOwnership(ownershipFile, nonce)) return 1;
|
|
@@ -28341,7 +28572,7 @@ async function runWorkerCompatibilityProxy(env = process.env, argv = process.arg
|
|
|
28341
28572
|
delete workerEnv[SUPERVISOR_OWNERSHIP_FILE_ENV];
|
|
28342
28573
|
delete workerEnv[WINDOWS_CONTAINMENT_GATE_ENV];
|
|
28343
28574
|
delete workerEnv[WINDOWS_POST_CONTAINMENT_CWD_ENV];
|
|
28344
|
-
const child =
|
|
28575
|
+
const child = spawn6(process.execPath, [target, ...ownership.argv], {
|
|
28345
28576
|
stdio: ["pipe", "inherit", "inherit"],
|
|
28346
28577
|
env: workerEnv,
|
|
28347
28578
|
// The proxy is already a detached group/session leader on POSIX. The old
|
|
@@ -28397,7 +28628,7 @@ async function launchHostSupervisor(options = {}) {
|
|
|
28397
28628
|
const generationNonce = ownershipDirectory ? basename3(ownershipDirectory) : null;
|
|
28398
28629
|
if (ownershipDirectory && generationNonce) {
|
|
28399
28630
|
env[LAUNCHER_OWNERSHIP_DIR_ENV] = ownershipDirectory;
|
|
28400
|
-
env[SUPERVISOR_OWNERSHIP_FILE_ENV] =
|
|
28631
|
+
env[SUPERVISOR_OWNERSHIP_FILE_ENV] = join10(ownershipDirectory, `${generationNonce}.json`);
|
|
28401
28632
|
} else {
|
|
28402
28633
|
delete env[LAUNCHER_OWNERSHIP_DIR_ENV];
|
|
28403
28634
|
}
|
|
@@ -28405,10 +28636,10 @@ async function launchHostSupervisor(options = {}) {
|
|
|
28405
28636
|
if (!containmentGateNonce) delete env[WINDOWS_POST_CONTAINMENT_CWD_ENV];
|
|
28406
28637
|
if (version2) env[SUPERVISOR_VERSION_ENV] = version2;
|
|
28407
28638
|
else delete env[SUPERVISOR_VERSION_ENV];
|
|
28408
|
-
const child2 =
|
|
28639
|
+
const child2 = spawn6(process.execPath, [supervisorEntry, ...argv], {
|
|
28409
28640
|
stdio: ["pipe", "inherit", "inherit"],
|
|
28410
28641
|
env,
|
|
28411
|
-
...containmentGateNonce ? { cwd: ownershipDirectory ??
|
|
28642
|
+
...containmentGateNonce ? { cwd: ownershipDirectory ?? dirname5(supervisorEntry) } : {},
|
|
28412
28643
|
detached: platform !== "win32",
|
|
28413
28644
|
// The new launcher can discover the durable PID record and still has
|
|
28414
28645
|
// to bind it to this exact process before signalling a recycled PID.
|
|
@@ -28420,8 +28651,8 @@ async function launchHostSupervisor(options = {}) {
|
|
|
28420
28651
|
});
|
|
28421
28652
|
const customDelay = options.delay;
|
|
28422
28653
|
const ownsWorkerBoundary = options.spawnSupervisor === void 0 || options.ownershipRoot !== void 0;
|
|
28423
|
-
const ownershipRoot = options.ownershipRoot ??
|
|
28424
|
-
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());
|
|
28425
28656
|
const terminateRecordedOwnership = options.terminateRecordedOwnership ?? terminateRecordedProcessTree;
|
|
28426
28657
|
const createSupervisorContainment = options.createSupervisorContainment ?? (platform === "win32" && options.spawnSupervisor === void 0 ? async (target, identityNonce, signal) => {
|
|
28427
28658
|
if (!target.pid) throw new Error("supervisor process id is unavailable");
|
|
@@ -28530,8 +28761,8 @@ async function launchHostSupervisor(options = {}) {
|
|
|
28530
28761
|
let stdinIsPipe = options.parentStdinIsPipe ?? false;
|
|
28531
28762
|
if (options.parentStdinIsPipe === void 0) {
|
|
28532
28763
|
try {
|
|
28533
|
-
const
|
|
28534
|
-
stdinIsPipe = !
|
|
28764
|
+
const stat4 = fstatSync(0);
|
|
28765
|
+
stdinIsPipe = !stat4.isCharacterDevice() && !stat4.isFile() && !process.stdin.isTTY;
|
|
28535
28766
|
} catch {
|
|
28536
28767
|
}
|
|
28537
28768
|
}
|
|
@@ -28688,10 +28919,10 @@ async function superviseHost(options = {}) {
|
|
|
28688
28919
|
const log2 = options.log ?? ((message) => console.error(message));
|
|
28689
28920
|
const signalWorker = options.signalWorker ?? signalWorkerGroup;
|
|
28690
28921
|
const inheritedOwnershipDirectory = process.env[LAUNCHER_OWNERSHIP_DIR_ENV];
|
|
28691
|
-
const launcherOwnershipDirectory = productionLifecycle && typeof inheritedOwnershipDirectory === "string" &&
|
|
28922
|
+
const launcherOwnershipDirectory = productionLifecycle && typeof inheritedOwnershipDirectory === "string" && isAbsolute10(inheritedOwnershipDirectory) ? inheritedOwnershipDirectory : null;
|
|
28692
28923
|
if (productionLifecycle && isSupervisorRole() && launcherOwnershipDirectory) {
|
|
28693
28924
|
const generationNonce = basename3(launcherOwnershipDirectory);
|
|
28694
|
-
const expectedOwnershipFile =
|
|
28925
|
+
const expectedOwnershipFile = join10(launcherOwnershipDirectory, `${generationNonce}.json`);
|
|
28695
28926
|
const configuredOwnershipFile = process.env[SUPERVISOR_OWNERSHIP_FILE_ENV];
|
|
28696
28927
|
if (process.argv0 !== generationNonce || configuredOwnershipFile !== expectedOwnershipFile || !recordWorkerOwnership(expectedOwnershipFile, generationNonce)) {
|
|
28697
28928
|
log2("Zixt Host: supervisor ownership could not be committed; refusing to start a worker");
|
|
@@ -29340,9 +29571,9 @@ function beginWorkerShutdown(options) {
|
|
|
29340
29571
|
// src/parent-pipe.ts
|
|
29341
29572
|
import { fstatSync as fstatSync2 } from "node:fs";
|
|
29342
29573
|
var END_OF_TEXT = 3;
|
|
29343
|
-
function stdinIsParentPipe(
|
|
29574
|
+
function stdinIsParentPipe(stat4 = (fd) => fstatSync2(fd), isTTY = process.stdin.isTTY === true) {
|
|
29344
29575
|
try {
|
|
29345
|
-
const stdin =
|
|
29576
|
+
const stdin = stat4(0);
|
|
29346
29577
|
return !stdin.isCharacterDevice() && !stdin.isFile() && !isTTY;
|
|
29347
29578
|
} catch {
|
|
29348
29579
|
return false;
|
|
@@ -29370,14 +29601,14 @@ function watchParentPipe(pipe2, onStop) {
|
|
|
29370
29601
|
}
|
|
29371
29602
|
|
|
29372
29603
|
// src/index.ts
|
|
29373
|
-
import { homedir as
|
|
29604
|
+
import { homedir as homedir16, hostname as hostname3 } from "node:os";
|
|
29374
29605
|
|
|
29375
29606
|
// src/hardware.ts
|
|
29376
29607
|
import { existsSync } from "node:fs";
|
|
29377
29608
|
import { statfs } from "node:fs/promises";
|
|
29378
|
-
import { cpus, freemem, homedir as
|
|
29379
|
-
import { dirname as
|
|
29380
|
-
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()) {
|
|
29381
29612
|
return {
|
|
29382
29613
|
// A container or cgroup can hide processors from this count; it is what
|
|
29383
29614
|
// this process can see, which is what its Tasks will actually get.
|
|
@@ -29405,7 +29636,7 @@ function nearestExistingPath(start) {
|
|
|
29405
29636
|
let candidate = resolve6(start);
|
|
29406
29637
|
for (let depth = 0; depth < 16; depth++) {
|
|
29407
29638
|
if (existsSync(candidate)) return candidate;
|
|
29408
|
-
const parent =
|
|
29639
|
+
const parent = dirname6(candidate);
|
|
29409
29640
|
if (parent === candidate) return null;
|
|
29410
29641
|
candidate = parent;
|
|
29411
29642
|
}
|
|
@@ -29599,17 +29830,17 @@ function createDemoBrowserAdapterFactory() {
|
|
|
29599
29830
|
}
|
|
29600
29831
|
|
|
29601
29832
|
// src/browser/manager.ts
|
|
29602
|
-
import { lstat as lstat6, mkdir as
|
|
29603
|
-
import { homedir as
|
|
29604
|
-
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";
|
|
29605
29836
|
var SAFE_SEGMENT2 = /^[A-Za-z0-9_-]{1,200}$/;
|
|
29606
29837
|
var FRAME_MIN_INTERVAL_MS = 100;
|
|
29607
29838
|
var IDLE_TIMEOUT_MS = 15 * 6e4;
|
|
29608
29839
|
var BrowserManager = class {
|
|
29609
29840
|
constructor(opts) {
|
|
29610
29841
|
this.opts = opts;
|
|
29611
|
-
this.profileRoot = opts.profileRoot ??
|
|
29612
|
-
this.profileStateRoot =
|
|
29842
|
+
this.profileRoot = opts.profileRoot ?? join11(homedir6(), ".zixt", "browser-profiles");
|
|
29843
|
+
this.profileStateRoot = join11(this.profileRoot, ".profile-state");
|
|
29613
29844
|
this.viewport = opts.viewport ?? BROWSER_DEFAULT_VIEWPORT;
|
|
29614
29845
|
this.idleTimeoutMs = opts.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
|
|
29615
29846
|
this.frameMinIntervalMs = opts.frameMinIntervalMs ?? FRAME_MIN_INTERVAL_MS;
|
|
@@ -29706,15 +29937,15 @@ var BrowserManager = class {
|
|
|
29706
29937
|
exactChild(root, child) {
|
|
29707
29938
|
const canonicalRoot = resolve7(root);
|
|
29708
29939
|
const target = resolve7(canonicalRoot, child);
|
|
29709
|
-
if (
|
|
29940
|
+
if (dirname7(target) !== canonicalRoot) {
|
|
29710
29941
|
throw new Error("browser profile path escaped its owned root");
|
|
29711
29942
|
}
|
|
29712
29943
|
return target;
|
|
29713
29944
|
}
|
|
29714
29945
|
async ensureOwnedDirectory(path) {
|
|
29715
|
-
await
|
|
29716
|
-
const
|
|
29717
|
-
if (!
|
|
29946
|
+
await mkdir7(path, { recursive: true, mode: 448 });
|
|
29947
|
+
const stat4 = await lstat6(path);
|
|
29948
|
+
if (!stat4.isDirectory() || stat4.isSymbolicLink()) {
|
|
29718
29949
|
throw new Error("browser profile root must be an owned directory, not a symbolic link");
|
|
29719
29950
|
}
|
|
29720
29951
|
}
|
|
@@ -29778,7 +30009,7 @@ var BrowserManager = class {
|
|
|
29778
30009
|
await this.syncDirectory(this.profileStateRoot);
|
|
29779
30010
|
await this.syncDirectory(this.profileRoot);
|
|
29780
30011
|
} catch (error52) {
|
|
29781
|
-
await
|
|
30012
|
+
await rm7(temporary, { force: true }).catch(() => {
|
|
29782
30013
|
});
|
|
29783
30014
|
throw error52;
|
|
29784
30015
|
}
|
|
@@ -29858,7 +30089,7 @@ var BrowserManager = class {
|
|
|
29858
30089
|
} catch (error52) {
|
|
29859
30090
|
if (error52.code !== "ENOENT") throw error52;
|
|
29860
30091
|
}
|
|
29861
|
-
await
|
|
30092
|
+
await mkdir7(profileDir, { recursive: true, mode: 448 });
|
|
29862
30093
|
const adapter = await this.opts.factory.open({
|
|
29863
30094
|
taskId,
|
|
29864
30095
|
agentId,
|
|
@@ -29946,7 +30177,7 @@ var BrowserManager = class {
|
|
|
29946
30177
|
});
|
|
29947
30178
|
const sessionTaskIds = [...this.sessions.values()].filter((session) => session.agentId === agentId).map((session) => session.taskId);
|
|
29948
30179
|
for (const taskId of sessionTaskIds) await this.closeLocked(taskId, "stopped");
|
|
29949
|
-
await
|
|
30180
|
+
await rm7(this.profilePath(agentId), { recursive: true, force: true, maxRetries: 3 });
|
|
29950
30181
|
await this.syncDirectory(this.profileRoot);
|
|
29951
30182
|
});
|
|
29952
30183
|
}
|
|
@@ -30117,13 +30348,13 @@ var BrowserManager = class {
|
|
|
30117
30348
|
};
|
|
30118
30349
|
|
|
30119
30350
|
// src/browser/playwright-adapter.ts
|
|
30120
|
-
import { spawn as
|
|
30351
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
30121
30352
|
import { access as access3 } from "node:fs/promises";
|
|
30122
30353
|
import { createRequire } from "node:module";
|
|
30123
|
-
import { dirname as
|
|
30354
|
+
import { dirname as dirname8, join as join12 } from "node:path";
|
|
30124
30355
|
var nodeRequire = createRequire(import.meta.url);
|
|
30125
30356
|
var playwrightCoreManifestPath = nodeRequire.resolve("playwright-core/package.json");
|
|
30126
|
-
var playwrightCoreRoot =
|
|
30357
|
+
var playwrightCoreRoot = dirname8(playwrightCoreManifestPath);
|
|
30127
30358
|
var playwrightCoreVersion = nodeRequire(playwrightCoreManifestPath).version;
|
|
30128
30359
|
if (typeof playwrightCoreVersion !== "string" || !/^\d+\.\d+\.\d+$/.test(playwrightCoreVersion)) {
|
|
30129
30360
|
throw new Error("playwright-core package version is invalid");
|
|
@@ -30140,9 +30371,9 @@ async function loadPlaywright() {
|
|
|
30140
30371
|
return import("playwright-core");
|
|
30141
30372
|
}
|
|
30142
30373
|
async function installChromium() {
|
|
30143
|
-
const cliPath =
|
|
30374
|
+
const cliPath = join12(playwrightCoreRoot, "cli.js");
|
|
30144
30375
|
await new Promise((resolve18, reject3) => {
|
|
30145
|
-
const child =
|
|
30376
|
+
const child = spawn7(process.execPath, [cliPath, "install", "chromium"], {
|
|
30146
30377
|
env: process.env,
|
|
30147
30378
|
stdio: ["ignore", "inherit", "inherit"],
|
|
30148
30379
|
// A service-managed Host has no console; letting Windows allocate one
|
|
@@ -30774,11 +31005,11 @@ function createPlaywrightBrowserAdapterFactory(dependencies = {}) {
|
|
|
30774
31005
|
}
|
|
30775
31006
|
|
|
30776
31007
|
// src/runners/cli-runner.ts
|
|
30777
|
-
import { spawn as
|
|
31008
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
30778
31009
|
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
30779
|
-
import { lstat as lstat11, mkdir as
|
|
30780
|
-
import { homedir as
|
|
30781
|
-
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";
|
|
30782
31013
|
|
|
30783
31014
|
// src/tool-packs/browser/authentication-wall.ts
|
|
30784
31015
|
var AUTH_PATH_SEGMENT = /(?:^|\/)(?:log[-_]?in|sign[-_]?in|sso|saml|auth|authorize|authenticate|oauth2?|session\/new|checkpoint)(?:\/|$)/i;
|
|
@@ -33596,16 +33827,16 @@ function createGithubPushOrchestrator(input) {
|
|
|
33596
33827
|
}
|
|
33597
33828
|
|
|
33598
33829
|
// src/tool-packs/github/git-bridge.ts
|
|
33599
|
-
import { spawn as
|
|
33830
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
33600
33831
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
33601
|
-
import { chmod as chmod4, lstat as lstat8, mkdir as
|
|
33602
|
-
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";
|
|
33603
33834
|
|
|
33604
33835
|
// src/tool-packs/github/git-credential-broker.ts
|
|
33605
33836
|
import { createServer } from "node:http";
|
|
33606
33837
|
import { randomBytes, randomUUID as randomUUID7, timingSafeEqual } from "node:crypto";
|
|
33607
|
-
import { chmod as chmod3, lstat as lstat7, realpath as realpath4, writeFile as
|
|
33608
|
-
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";
|
|
33609
33840
|
var MAX_REQUEST_BYTES = 16 * 1024;
|
|
33610
33841
|
var FILE_MODE2 = 384;
|
|
33611
33842
|
var HELPER_SOURCE = String.raw`'use strict';
|
|
@@ -33719,7 +33950,7 @@ async function readBoundedBody2(request) {
|
|
|
33719
33950
|
}
|
|
33720
33951
|
function assertChildPath(parent, child) {
|
|
33721
33952
|
const path = relative5(parent, child);
|
|
33722
|
-
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") ||
|
|
33953
|
+
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") || isAbsolute11(path)) {
|
|
33723
33954
|
throw new Error("Git credential helper path escaped its private run directory");
|
|
33724
33955
|
}
|
|
33725
33956
|
}
|
|
@@ -33734,9 +33965,9 @@ async function createGithubGitCredentialBroker(input) {
|
|
|
33734
33965
|
throw new Error("Git credential broker requires a private real run directory");
|
|
33735
33966
|
}
|
|
33736
33967
|
const runRoot = await realpath4(input.runArtifactsRoot);
|
|
33737
|
-
const helperPath =
|
|
33968
|
+
const helperPath = join13(runRoot, `git-credential-${randomUUID7()}.cjs`);
|
|
33738
33969
|
assertChildPath(runRoot, helperPath);
|
|
33739
|
-
await
|
|
33970
|
+
await writeFile4(helperPath, HELPER_SOURCE, { flag: "wx", mode: FILE_MODE2 });
|
|
33740
33971
|
await chmod3(helperPath, FILE_MODE2);
|
|
33741
33972
|
const capability2 = randomBytes(32).toString("base64url");
|
|
33742
33973
|
const expectedPath = `${input.repositoryFullName}.git`;
|
|
@@ -33834,7 +34065,7 @@ ${stderr}`;
|
|
|
33834
34065
|
}
|
|
33835
34066
|
function assertBelow2(parent, child, label) {
|
|
33836
34067
|
const path = relative6(parent, child);
|
|
33837
|
-
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") ||
|
|
34068
|
+
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") || isAbsolute12(path)) {
|
|
33838
34069
|
throw new GithubGitProcessError("invalid_input");
|
|
33839
34070
|
}
|
|
33840
34071
|
void label;
|
|
@@ -33849,8 +34080,8 @@ async function requireRealDirectory2(path, label) {
|
|
|
33849
34080
|
}
|
|
33850
34081
|
async function validateTokenlessPaths(command) {
|
|
33851
34082
|
if (command.kind === "clone-from-bridge") {
|
|
33852
|
-
if (!
|
|
33853
|
-
const parent = await requireRealDirectory2(
|
|
34083
|
+
if (!isAbsolute12(command.destination)) throw new GithubGitProcessError("invalid_input");
|
|
34084
|
+
const parent = await requireRealDirectory2(dirname9(command.destination), "clone parent");
|
|
33854
34085
|
assertBelow2(parent, command.destination, "clone destination");
|
|
33855
34086
|
const destination = await lstat8(command.destination).catch((error52) => {
|
|
33856
34087
|
if (error52.code === "ENOENT") return null;
|
|
@@ -33860,7 +34091,7 @@ async function validateTokenlessPaths(command) {
|
|
|
33860
34091
|
return;
|
|
33861
34092
|
}
|
|
33862
34093
|
if ("repositoryPath" in command) {
|
|
33863
|
-
if (!
|
|
34094
|
+
if (!isAbsolute12(command.repositoryPath)) throw new GithubGitProcessError("invalid_input");
|
|
33864
34095
|
const repositoryPath5 = await requireRealDirectory2(command.repositoryPath, "repository path");
|
|
33865
34096
|
if (repositoryPath5 !== command.repositoryPath) throw new GithubGitProcessError("invalid_input");
|
|
33866
34097
|
}
|
|
@@ -33940,13 +34171,13 @@ async function runGit(input, args, env) {
|
|
|
33940
34171
|
if (input.authoritySignal.aborted || input.cancelledNow()) {
|
|
33941
34172
|
throw new GithubGitProcessError("cancelled");
|
|
33942
34173
|
}
|
|
33943
|
-
if (!
|
|
34174
|
+
if (!isAbsolute12(input.executablePath)) throw new GithubGitProcessError("invalid_input");
|
|
33944
34175
|
const timeoutMs = input.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
33945
34176
|
if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > DEFAULT_TIMEOUT_MS2) {
|
|
33946
34177
|
throw new GithubGitProcessError("invalid_input");
|
|
33947
34178
|
}
|
|
33948
34179
|
return new Promise((resolvePromise, rejectPromise) => {
|
|
33949
|
-
const child =
|
|
34180
|
+
const child = spawn8(input.executablePath, [...input.commandPrefixArgs ?? [], ...args], {
|
|
33950
34181
|
cwd: input.trustedCwd,
|
|
33951
34182
|
env,
|
|
33952
34183
|
shell: false,
|
|
@@ -34046,7 +34277,7 @@ function tokenlessArgs(command) {
|
|
|
34046
34277
|
switch (command.kind) {
|
|
34047
34278
|
case "clone-from-bridge":
|
|
34048
34279
|
assertRef(command.branch);
|
|
34049
|
-
if (!
|
|
34280
|
+
if (!isAbsolute12(command.destination)) throw new GithubGitProcessError("invalid_input");
|
|
34050
34281
|
return [
|
|
34051
34282
|
"clone",
|
|
34052
34283
|
"--no-recurse-submodules",
|
|
@@ -34058,7 +34289,7 @@ function tokenlessArgs(command) {
|
|
|
34058
34289
|
];
|
|
34059
34290
|
case "fetch-from-bridge":
|
|
34060
34291
|
assertFetchRefspecs(command.refspecs);
|
|
34061
|
-
if (!
|
|
34292
|
+
if (!isAbsolute12(command.repositoryPath)) throw new GithubGitProcessError("invalid_input");
|
|
34062
34293
|
return [
|
|
34063
34294
|
"-C",
|
|
34064
34295
|
command.repositoryPath,
|
|
@@ -34070,7 +34301,7 @@ function tokenlessArgs(command) {
|
|
|
34070
34301
|
...command.refspecs
|
|
34071
34302
|
];
|
|
34072
34303
|
case "copy-commit-to-bridge":
|
|
34073
|
-
if (!
|
|
34304
|
+
if (!isAbsolute12(command.repositoryPath) || !SHA.test(command.sha)) {
|
|
34074
34305
|
throw new GithubGitProcessError("invalid_input");
|
|
34075
34306
|
}
|
|
34076
34307
|
return [
|
|
@@ -34082,11 +34313,11 @@ function tokenlessArgs(command) {
|
|
|
34082
34313
|
`${command.sha}:refs/zixt/push-source`
|
|
34083
34314
|
];
|
|
34084
34315
|
case "rev-parse":
|
|
34085
|
-
if (!
|
|
34316
|
+
if (!isAbsolute12(command.repositoryPath)) throw new GithubGitProcessError("invalid_input");
|
|
34086
34317
|
assertRef(command.ref);
|
|
34087
34318
|
return ["-C", command.repositoryPath, "rev-parse", "--verify", `${command.ref}^{commit}`];
|
|
34088
34319
|
case "remote-configure":
|
|
34089
|
-
if (!
|
|
34320
|
+
if (!isAbsolute12(command.repositoryPath) || !REPOSITORY.test(command.repositoryFullName)) {
|
|
34090
34321
|
throw new GithubGitProcessError("invalid_input");
|
|
34091
34322
|
}
|
|
34092
34323
|
return [
|
|
@@ -34098,7 +34329,7 @@ function tokenlessArgs(command) {
|
|
|
34098
34329
|
`https://github.com/${command.repositoryFullName}.git`
|
|
34099
34330
|
];
|
|
34100
34331
|
case "status":
|
|
34101
|
-
if (!
|
|
34332
|
+
if (!isAbsolute12(command.repositoryPath)) throw new GithubGitProcessError("invalid_input");
|
|
34102
34333
|
return [
|
|
34103
34334
|
"-C",
|
|
34104
34335
|
command.repositoryPath,
|
|
@@ -34128,7 +34359,7 @@ function createGithubGitBridge(input) {
|
|
|
34128
34359
|
})();
|
|
34129
34360
|
const requireBridge = async (value) => {
|
|
34130
34361
|
const current = await roots();
|
|
34131
|
-
if (!
|
|
34362
|
+
if (!isAbsolute12(value) || !active.has(value)) throw new GithubGitProcessError("invalid_input");
|
|
34132
34363
|
const real = await requireRealDirectory2(value, "git bridge");
|
|
34133
34364
|
assertBelow2(current.bridges, real, "git bridge");
|
|
34134
34365
|
if (real !== value) throw new GithubGitProcessError("invalid_input");
|
|
@@ -34138,9 +34369,9 @@ function createGithubGitBridge(input) {
|
|
|
34138
34369
|
async createPrivateBridge() {
|
|
34139
34370
|
if (closed) throw new GithubGitProcessError("cancelled");
|
|
34140
34371
|
const current = await roots();
|
|
34141
|
-
const path =
|
|
34372
|
+
const path = join14(current.bridges, `${randomUUID8()}.git`);
|
|
34142
34373
|
assertBelow2(current.bridges, path, "git bridge");
|
|
34143
|
-
await
|
|
34374
|
+
await mkdir8(path, { mode: DIRECTORY_MODE2 });
|
|
34144
34375
|
await chmod4(path, DIRECTORY_MODE2);
|
|
34145
34376
|
try {
|
|
34146
34377
|
await runGit(
|
|
@@ -34156,16 +34387,16 @@ function createGithubGitBridge(input) {
|
|
|
34156
34387
|
);
|
|
34157
34388
|
const real = await requireRealDirectory2(path, "git bridge");
|
|
34158
34389
|
assertBelow2(current.bridges, real, "git bridge");
|
|
34159
|
-
const hooks =
|
|
34160
|
-
await
|
|
34161
|
-
await
|
|
34390
|
+
const hooks = join14(real, "hooks");
|
|
34391
|
+
await rm8(hooks, { recursive: true, force: true });
|
|
34392
|
+
await mkdir8(hooks, { mode: DIRECTORY_MODE2 });
|
|
34162
34393
|
await chmod4(hooks, DIRECTORY_MODE2);
|
|
34163
|
-
const config2 =
|
|
34394
|
+
const config2 = join14(real, "config");
|
|
34164
34395
|
await chmod4(config2, 384);
|
|
34165
34396
|
active.add(real);
|
|
34166
34397
|
return real;
|
|
34167
34398
|
} catch (error52) {
|
|
34168
|
-
await
|
|
34399
|
+
await rm8(path, { recursive: true, force: true }).catch(() => {
|
|
34169
34400
|
});
|
|
34170
34401
|
throw error52;
|
|
34171
34402
|
}
|
|
@@ -34259,7 +34490,7 @@ function createGithubGitBridge(input) {
|
|
|
34259
34490
|
},
|
|
34260
34491
|
async destroyPrivateBridge(path) {
|
|
34261
34492
|
const bridge = await requireBridge(path);
|
|
34262
|
-
await
|
|
34493
|
+
await rm8(bridge, { recursive: true, force: true });
|
|
34263
34494
|
active.delete(bridge);
|
|
34264
34495
|
credentialed2.delete(bridge);
|
|
34265
34496
|
},
|
|
@@ -34267,7 +34498,7 @@ function createGithubGitBridge(input) {
|
|
|
34267
34498
|
if (closed) return;
|
|
34268
34499
|
closed = true;
|
|
34269
34500
|
const paths = [...active];
|
|
34270
|
-
await Promise.all(paths.map((path) =>
|
|
34501
|
+
await Promise.all(paths.map((path) => rm8(path, { recursive: true, force: true })));
|
|
34271
34502
|
active.clear();
|
|
34272
34503
|
credentialed2.clear();
|
|
34273
34504
|
}
|
|
@@ -34608,8 +34839,8 @@ function createRepositoryTools(runtime) {
|
|
|
34608
34839
|
|
|
34609
34840
|
// src/tool-packs/github/workspace.ts
|
|
34610
34841
|
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
34611
|
-
import { chmod as chmod5, lstat as lstat9, mkdir as
|
|
34612
|
-
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";
|
|
34613
34844
|
var SAFE_LOCAL_ID = /^[A-Za-z0-9_-]{1,200}$/;
|
|
34614
34845
|
var FULL_NAME2 = /^[A-Za-z0-9_.-]{1,100}\/[A-Za-z0-9_.-]{1,100}$/;
|
|
34615
34846
|
var DIRECTORY_MODE3 = 448;
|
|
@@ -34627,7 +34858,7 @@ function hasControlCharacter2(value) {
|
|
|
34627
34858
|
}
|
|
34628
34859
|
function assertBelow3(parent, child, label) {
|
|
34629
34860
|
const path = relative7(parent, child);
|
|
34630
|
-
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") ||
|
|
34861
|
+
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") || isAbsolute13(path)) {
|
|
34631
34862
|
throw new Error(`${label} escaped the task workspace`);
|
|
34632
34863
|
}
|
|
34633
34864
|
}
|
|
@@ -34646,10 +34877,10 @@ async function requireRealDirectory3(path, label) {
|
|
|
34646
34877
|
return real;
|
|
34647
34878
|
}
|
|
34648
34879
|
async function createOrRequirePrivateDirectory(parent, name, label) {
|
|
34649
|
-
const path =
|
|
34880
|
+
const path = join15(parent, name);
|
|
34650
34881
|
assertBelow3(parent, path, label);
|
|
34651
34882
|
try {
|
|
34652
|
-
await
|
|
34883
|
+
await mkdir9(path, { mode: DIRECTORY_MODE3 });
|
|
34653
34884
|
} catch (error52) {
|
|
34654
34885
|
if (error52.code !== "EEXIST") throw error52;
|
|
34655
34886
|
}
|
|
@@ -34729,8 +34960,8 @@ async function createGithubWorkspaceService(input) {
|
|
|
34729
34960
|
if (expectedFullName !== void 0 && repository.fullName !== expectedFullName) {
|
|
34730
34961
|
throw new Error("GitHub repository name does not match this task grant");
|
|
34731
34962
|
}
|
|
34732
|
-
const destination =
|
|
34733
|
-
const metadataPath =
|
|
34963
|
+
const destination = join15(repositoriesRoot, parsed.data);
|
|
34964
|
+
const metadataPath = join15(metadataRoot, `${parsed.data}.json`);
|
|
34734
34965
|
if (!await pathExists(destination) || !await pathExists(metadataPath)) {
|
|
34735
34966
|
throw new Error("GitHub repository workspace has not been prepared");
|
|
34736
34967
|
}
|
|
@@ -34747,14 +34978,14 @@ async function createGithubWorkspaceService(input) {
|
|
|
34747
34978
|
return real;
|
|
34748
34979
|
};
|
|
34749
34980
|
const cloneRepository = async (clone2) => {
|
|
34750
|
-
const destination =
|
|
34751
|
-
const metadataPath =
|
|
34981
|
+
const destination = join15(repositoriesRoot, clone2.repositoryId);
|
|
34982
|
+
const metadataPath = join15(metadataRoot, `${clone2.repositoryId}.json`);
|
|
34752
34983
|
assertBelow3(repositoriesRoot, destination, "repository path");
|
|
34753
34984
|
assertBelow3(metadataRoot, metadataPath, "repository metadata");
|
|
34754
34985
|
if (await pathExists(destination) || await pathExists(metadataPath)) {
|
|
34755
34986
|
throw new Error("GitHub repository workspace already exists or is inconsistent");
|
|
34756
34987
|
}
|
|
34757
|
-
const temporary =
|
|
34988
|
+
const temporary = join15(repositoriesRoot, `.clone-${randomUUID9()}`);
|
|
34758
34989
|
assertBelow3(repositoriesRoot, temporary, "temporary clone");
|
|
34759
34990
|
try {
|
|
34760
34991
|
await input.git.clone({
|
|
@@ -34779,9 +35010,9 @@ async function createGithubWorkspaceService(input) {
|
|
|
34779
35010
|
path: destination,
|
|
34780
35011
|
...clone2.createIntentId === void 0 ? {} : { createIntentId: clone2.createIntentId }
|
|
34781
35012
|
};
|
|
34782
|
-
const metadataTemporary =
|
|
35013
|
+
const metadataTemporary = join15(metadataRoot, `.${clone2.repositoryId}-${randomUUID9()}.tmp`);
|
|
34783
35014
|
assertBelow3(metadataRoot, metadataTemporary, "temporary repository metadata");
|
|
34784
|
-
await
|
|
35015
|
+
await writeFile5(metadataTemporary, `${JSON.stringify(metadata)}
|
|
34785
35016
|
`, {
|
|
34786
35017
|
flag: "wx",
|
|
34787
35018
|
mode: FILE_MODE3
|
|
@@ -34792,11 +35023,11 @@ async function createGithubWorkspaceService(input) {
|
|
|
34792
35023
|
try {
|
|
34793
35024
|
await rename5(metadataTemporary, metadataPath);
|
|
34794
35025
|
} catch (error52) {
|
|
34795
|
-
await
|
|
35026
|
+
await rm9(destination, { recursive: true, force: true });
|
|
34796
35027
|
throw error52;
|
|
34797
35028
|
}
|
|
34798
35029
|
} finally {
|
|
34799
|
-
await
|
|
35030
|
+
await rm9(metadataTemporary, { force: true }).catch(() => {
|
|
34800
35031
|
});
|
|
34801
35032
|
}
|
|
34802
35033
|
const path = await requireRealDirectory3(destination, "GitHub repository");
|
|
@@ -34808,14 +35039,14 @@ async function createGithubWorkspaceService(input) {
|
|
|
34808
35039
|
headSha
|
|
34809
35040
|
};
|
|
34810
35041
|
} finally {
|
|
34811
|
-
await
|
|
35042
|
+
await rm9(temporary, { recursive: true, force: true }).catch(() => {
|
|
34812
35043
|
});
|
|
34813
35044
|
}
|
|
34814
35045
|
};
|
|
34815
35046
|
const prepareRepository = async (authority) => {
|
|
34816
35047
|
const { repository } = authority;
|
|
34817
|
-
const destination =
|
|
34818
|
-
const metadataPath =
|
|
35048
|
+
const destination = join15(repositoriesRoot, repository.repositoryId);
|
|
35049
|
+
const metadataPath = join15(metadataRoot, `${repository.repositoryId}.json`);
|
|
34819
35050
|
assertBelow3(repositoriesRoot, destination, "repository path");
|
|
34820
35051
|
assertBelow3(metadataRoot, metadataPath, "repository metadata");
|
|
34821
35052
|
return withWorkspaceLock(destination, async () => {
|
|
@@ -34980,7 +35211,7 @@ async function createGithubWorkspaceService(input) {
|
|
|
34980
35211
|
throw new Error("GitHub created repository is outside this installation");
|
|
34981
35212
|
}
|
|
34982
35213
|
parseGitRef(cloneInput.repository.defaultBranch, "default branch");
|
|
34983
|
-
return withWorkspaceLock(
|
|
35214
|
+
return withWorkspaceLock(join15(repositoriesRoot, repositoryId2), async () => {
|
|
34984
35215
|
const prepared = await cloneRepository({
|
|
34985
35216
|
repositoryId: repositoryId2,
|
|
34986
35217
|
fullName: cloneInput.repository.fullName,
|
|
@@ -37104,8 +37335,8 @@ function createCommsToolPacks(grants, context) {
|
|
|
37104
37335
|
}
|
|
37105
37336
|
|
|
37106
37337
|
// src/runners/attachments.ts
|
|
37107
|
-
import { mkdir as
|
|
37108
|
-
import { join as
|
|
37338
|
+
import { mkdir as mkdir10, writeFile as writeFile6 } from "node:fs/promises";
|
|
37339
|
+
import { join as join16 } from "node:path";
|
|
37109
37340
|
var WINDOWS_RESERVED = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\..*)?$/i;
|
|
37110
37341
|
function sanitizeAttachmentFileName(name) {
|
|
37111
37342
|
const base = name.split(/[/\\]/).pop() ?? "";
|
|
@@ -37134,10 +37365,10 @@ async function materializeAttachments(task, taskRoot) {
|
|
|
37134
37365
|
`attached file "${attachment.name}" arrived incomplete (${bytes.byteLength} of ${attachment.size} bytes)`
|
|
37135
37366
|
);
|
|
37136
37367
|
}
|
|
37137
|
-
const directory =
|
|
37138
|
-
await
|
|
37139
|
-
const path =
|
|
37140
|
-
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);
|
|
37141
37372
|
materialized.push({
|
|
37142
37373
|
path,
|
|
37143
37374
|
name: attachment.name,
|
|
@@ -38154,7 +38385,7 @@ function createAskUserServer() {
|
|
|
38154
38385
|
}
|
|
38155
38386
|
|
|
38156
38387
|
// src/runners/runner-env.ts
|
|
38157
|
-
import { delimiter as delimiter2, isAbsolute as
|
|
38388
|
+
import { delimiter as delimiter2, isAbsolute as isAbsolute14 } from "node:path";
|
|
38158
38389
|
var PROVIDER_AUTHORITY_PREFIXES = ["GH_", "GITHUB_", "GIT_", "SSH_"];
|
|
38159
38390
|
var HOST_AUTHORITY_PREFIXES = [
|
|
38160
38391
|
"ZIXT_",
|
|
@@ -38213,7 +38444,7 @@ function inheritedValue(env, name) {
|
|
|
38213
38444
|
}
|
|
38214
38445
|
function sanitizeInheritedSearchPath(path) {
|
|
38215
38446
|
if (!path) return "";
|
|
38216
|
-
return path.split(delimiter2).filter((entry) => entry !== "" &&
|
|
38447
|
+
return path.split(delimiter2).filter((entry) => entry !== "" && isAbsolute14(entry)).join(delimiter2);
|
|
38217
38448
|
}
|
|
38218
38449
|
function buildRunnerEnv(input) {
|
|
38219
38450
|
const env = {};
|
|
@@ -38294,9 +38525,9 @@ function buildRunnerEnv(input) {
|
|
|
38294
38525
|
// src/runners/github-shell-auth.ts
|
|
38295
38526
|
import { execFile } from "node:child_process";
|
|
38296
38527
|
import { randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
38297
|
-
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";
|
|
38298
38529
|
import { createServer as createServer3 } from "node:http";
|
|
38299
|
-
import { isAbsolute as
|
|
38530
|
+
import { isAbsolute as isAbsolute15, join as join17, relative as relative8 } from "node:path";
|
|
38300
38531
|
var MAX_REQUEST_BYTES2 = 16 * 1024;
|
|
38301
38532
|
var DIRECTORY_MODE4 = 448;
|
|
38302
38533
|
var PRIVATE_FILE_MODE = 384;
|
|
@@ -38502,7 +38733,7 @@ function parseGhInvocation(body) {
|
|
|
38502
38733
|
}
|
|
38503
38734
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
38504
38735
|
const { args, cwd } = value;
|
|
38505
|
-
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)) {
|
|
38506
38737
|
return null;
|
|
38507
38738
|
}
|
|
38508
38739
|
return { args, cwd };
|
|
@@ -38661,7 +38892,7 @@ function activationCredential(grant, now = Date.now()) {
|
|
|
38661
38892
|
}
|
|
38662
38893
|
function assertChildPath2(parent, child) {
|
|
38663
38894
|
const path = relative8(parent, child);
|
|
38664
|
-
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") ||
|
|
38895
|
+
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") || isAbsolute15(path)) {
|
|
38665
38896
|
throw new Error("GitHub shell helper path escaped its private run directory");
|
|
38666
38897
|
}
|
|
38667
38898
|
}
|
|
@@ -38672,7 +38903,7 @@ function quoteForPosixShell(value) {
|
|
|
38672
38903
|
return quoteForGitShell2(value);
|
|
38673
38904
|
}
|
|
38674
38905
|
async function writePrivate(path, content, executable = false) {
|
|
38675
|
-
await
|
|
38906
|
+
await writeFile7(path, content, {
|
|
38676
38907
|
flag: "wx",
|
|
38677
38908
|
mode: executable ? EXECUTABLE_FILE_MODE : PRIVATE_FILE_MODE
|
|
38678
38909
|
});
|
|
@@ -38684,7 +38915,7 @@ async function prepareHelpers(input) {
|
|
|
38684
38915
|
throw new Error("GitHub shell authentication requires a private real run directory");
|
|
38685
38916
|
}
|
|
38686
38917
|
const runRoot = await realpath7(input.runRoot);
|
|
38687
|
-
const helperPath =
|
|
38918
|
+
const helperPath = join17(runRoot, "github-shell-git-credential.cjs");
|
|
38688
38919
|
assertChildPath2(runRoot, helperPath);
|
|
38689
38920
|
await writePrivate(helperPath, GIT_HELPER_SOURCE);
|
|
38690
38921
|
if (!input.ghExecutablePath) {
|
|
@@ -38695,14 +38926,14 @@ async function prepareHelpers(input) {
|
|
|
38695
38926
|
wrapperSourcePath: null
|
|
38696
38927
|
};
|
|
38697
38928
|
}
|
|
38698
|
-
const shellToolsDirectory =
|
|
38929
|
+
const shellToolsDirectory = join17(runRoot, "shell-tools");
|
|
38699
38930
|
assertChildPath2(runRoot, shellToolsDirectory);
|
|
38700
|
-
await
|
|
38931
|
+
await mkdir11(shellToolsDirectory, { mode: DIRECTORY_MODE4 });
|
|
38701
38932
|
await chmod6(shellToolsDirectory, DIRECTORY_MODE4);
|
|
38702
|
-
const wrapperSourcePath =
|
|
38933
|
+
const wrapperSourcePath = join17(runRoot, "github-shell-gh-wrapper.cjs");
|
|
38703
38934
|
assertChildPath2(runRoot, wrapperSourcePath);
|
|
38704
38935
|
await writePrivate(wrapperSourcePath, GH_WRAPPER_SOURCE);
|
|
38705
|
-
const wrapperPath =
|
|
38936
|
+
const wrapperPath = join17(shellToolsDirectory, process.platform === "win32" ? "gh.cmd" : "gh");
|
|
38706
38937
|
assertChildPath2(runRoot, wrapperPath);
|
|
38707
38938
|
const launcher = process.platform === "win32" ? `@"${process.execPath.replaceAll('"', '""')}" "${wrapperSourcePath.replaceAll('"', '""')}" %*\r
|
|
38708
38939
|
` : `#!/bin/sh
|
|
@@ -38925,7 +39156,7 @@ password=${credential.accessToken}
|
|
|
38925
39156
|
}
|
|
38926
39157
|
|
|
38927
39158
|
// src/runners/working-context.ts
|
|
38928
|
-
import { spawn as
|
|
39159
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
38929
39160
|
import { resolve as resolve9 } from "node:path";
|
|
38930
39161
|
var COMMAND_TIMEOUT_MS = 5e3;
|
|
38931
39162
|
var OUTPUT_LIMIT_BYTES = 128 * 1024;
|
|
@@ -39056,7 +39287,7 @@ async function stopWorkingContextCommand(child, childExited, options = {}) {
|
|
|
39056
39287
|
function run(command, args, cwd, env, signal) {
|
|
39057
39288
|
if (signal?.aborted) return Promise.resolve(null);
|
|
39058
39289
|
return new Promise((resolvePromise) => {
|
|
39059
|
-
const child =
|
|
39290
|
+
const child = spawn9(command, [...args], {
|
|
39060
39291
|
cwd,
|
|
39061
39292
|
env: { ...env, GIT_OPTIONAL_LOCKS: "0" },
|
|
39062
39293
|
detached: process.platform !== "win32",
|
|
@@ -39496,7 +39727,7 @@ async function settlesWithin(promise2, timeoutMs) {
|
|
|
39496
39727
|
}
|
|
39497
39728
|
}
|
|
39498
39729
|
function defaultRunnerWorkspaceRoot() {
|
|
39499
|
-
return
|
|
39730
|
+
return join18(homedir7(), ".zixt", "workspaces");
|
|
39500
39731
|
}
|
|
39501
39732
|
function defaultRunnerArtifactRoot() {
|
|
39502
39733
|
return defaultRunArtifactRoot();
|
|
@@ -39545,7 +39776,7 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
39545
39776
|
const prefixArgs = opts.commandPrefixArgs ?? [];
|
|
39546
39777
|
const maxWallTimeMs = opts.maxWallTimeMs;
|
|
39547
39778
|
const workspaceRoot = opts.workspaceRoot ?? defaultRunnerWorkspaceRoot();
|
|
39548
|
-
const artifactRoot = opts.artifactRoot ?? (opts.workspaceRoot === void 0 ? defaultRunnerArtifactRoot() :
|
|
39779
|
+
const artifactRoot = opts.artifactRoot ?? (opts.workspaceRoot === void 0 ? defaultRunnerArtifactRoot() : join18(dirname10(workspaceRoot), "run-artifacts"));
|
|
39549
39780
|
const runRegistryRoot2 = opts.runRegistryRoot ?? defaultRunRegistryRoot();
|
|
39550
39781
|
const createArtifacts = opts.createArtifacts ?? createRunArtifacts;
|
|
39551
39782
|
const toolPackRegistry2 = opts.toolPackRegistry ?? createDefaultToolPackRegistry();
|
|
@@ -39563,7 +39794,7 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
39563
39794
|
};
|
|
39564
39795
|
const askUserServer = createAskUserServer();
|
|
39565
39796
|
const windowsRoot = process.env.SystemRoot ?? process.env.WINDIR;
|
|
39566
|
-
const windowsComspecCandidate = process.platform === "win32" && windowsRoot ?
|
|
39797
|
+
const windowsComspecCandidate = process.platform === "win32" && windowsRoot ? join18(windowsRoot, "System32", "cmd.exe") : void 0;
|
|
39567
39798
|
let safetyFailure;
|
|
39568
39799
|
return async (task) => {
|
|
39569
39800
|
if (safetyFailure) {
|
|
@@ -39603,8 +39834,8 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
39603
39834
|
usage: { inputTokens: 0, outputTokens: 0 }
|
|
39604
39835
|
};
|
|
39605
39836
|
}
|
|
39606
|
-
const taskRoot =
|
|
39607
|
-
await
|
|
39837
|
+
const taskRoot = join18(workspaceRoot, task.agentId);
|
|
39838
|
+
await mkdir12(taskRoot, { recursive: true });
|
|
39608
39839
|
if (task.cancelledNow()) return cancelledBeforeRun();
|
|
39609
39840
|
const configuredWorkspace = task.spec.workspace;
|
|
39610
39841
|
let cwd = taskRoot;
|
|
@@ -39670,7 +39901,10 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
39670
39901
|
let terminalOutcomeProducedUnderAuthority = false;
|
|
39671
39902
|
let preparedTerminalOutcome;
|
|
39672
39903
|
try {
|
|
39673
|
-
const resolvedCommand = await
|
|
39904
|
+
const resolvedCommand = await resolveRunnerCommand(command, adapter.type, {
|
|
39905
|
+
resolution: trustedCommandOptions,
|
|
39906
|
+
probe: true
|
|
39907
|
+
});
|
|
39674
39908
|
const resolvedWindowsComspec = windowsComspecCandidate ? await resolveTrustedCliCommand(windowsComspecCandidate, trustedCommandOptions) : null;
|
|
39675
39909
|
const git = await measuredGit();
|
|
39676
39910
|
const githubGrant = providerGrants.find(
|
|
@@ -39940,8 +40174,8 @@ ${attachmentSection}` : prompt;
|
|
|
39940
40174
|
let changed = false;
|
|
39941
40175
|
for (const path of paths) {
|
|
39942
40176
|
if (!path || path.length > 4096) continue;
|
|
39943
|
-
const absolutePath =
|
|
39944
|
-
const directory =
|
|
40177
|
+
const absolutePath = isAbsolute16(path) ? path : resolve10(cwd, path);
|
|
40178
|
+
const directory = dirname10(absolutePath);
|
|
39945
40179
|
observedWorkingDirectories.delete(directory);
|
|
39946
40180
|
observedWorkingDirectories.add(directory);
|
|
39947
40181
|
while (observedWorkingDirectories.size > 19) {
|
|
@@ -40380,7 +40614,7 @@ function runCliProcess(options) {
|
|
|
40380
40614
|
return new Promise((resolve18) => {
|
|
40381
40615
|
const platform = options.platform ?? process.platform;
|
|
40382
40616
|
const containmentGateNonce = options.guardian && platform === "win32" ? randomUUID11() : void 0;
|
|
40383
|
-
const child = options.guardian ?
|
|
40617
|
+
const child = options.guardian ? spawn10(
|
|
40384
40618
|
options.guardian.nodeCommand,
|
|
40385
40619
|
[
|
|
40386
40620
|
options.guardian.scriptPath,
|
|
@@ -40391,7 +40625,7 @@ function runCliProcess(options) {
|
|
|
40391
40625
|
// The idle pre-assignment guardian must never load from or depend
|
|
40392
40626
|
// on an untrusted Task checkout. Only the post-gate target enters
|
|
40393
40627
|
// the requested working directory from its private release frame.
|
|
40394
|
-
cwd:
|
|
40628
|
+
cwd: dirname10(options.guardian.scriptPath),
|
|
40395
40629
|
env: runnerGuardianEnv(process.env, containmentGateNonce),
|
|
40396
40630
|
stdio: ["pipe", "pipe", "pipe"],
|
|
40397
40631
|
windowsHide: true,
|
|
@@ -40672,13 +40906,13 @@ import { randomUUID as randomUUID12 } from "node:crypto";
|
|
|
40672
40906
|
|
|
40673
40907
|
// src/runners/runtime-observation.ts
|
|
40674
40908
|
import { open as open6, readdir as readdir5, realpath as realpath9 } from "node:fs/promises";
|
|
40675
|
-
import { homedir as
|
|
40676
|
-
import { join as
|
|
40909
|
+
import { homedir as homedir8 } from "node:os";
|
|
40910
|
+
import { join as join19 } from "node:path";
|
|
40677
40911
|
var READ_WINDOW_BYTES = 1024 * 1024;
|
|
40678
40912
|
var CATALOG_TIMEOUT_MS = 15e3;
|
|
40679
40913
|
var CATALOG_OUTPUT_LIMIT_BYTES = 4 * 1024 * 1024;
|
|
40680
40914
|
function homeFrom(env) {
|
|
40681
|
-
return env["HOME"] || env["USERPROFILE"] ||
|
|
40915
|
+
return env["HOME"] || env["USERPROFILE"] || homedir8();
|
|
40682
40916
|
}
|
|
40683
40917
|
async function readHead(path) {
|
|
40684
40918
|
let handle;
|
|
@@ -40733,9 +40967,9 @@ function displayValue(value, maxLength) {
|
|
|
40733
40967
|
return trimmed;
|
|
40734
40968
|
}
|
|
40735
40969
|
function claudeTranscriptPath(input) {
|
|
40736
|
-
const configDir = input.env["CLAUDE_CONFIG_DIR"] ||
|
|
40970
|
+
const configDir = input.env["CLAUDE_CONFIG_DIR"] || join19(homeFrom(input.env), ".claude");
|
|
40737
40971
|
const slug = input.resolvedCwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
40738
|
-
return
|
|
40972
|
+
return join19(configDir, "projects", slug, `${input.sessionId}.jsonl`);
|
|
40739
40973
|
}
|
|
40740
40974
|
async function readClaudeSessionEffort(input) {
|
|
40741
40975
|
const resolvedCwd = await realpath9(input.cwd).catch(() => input.cwd);
|
|
@@ -40751,18 +40985,18 @@ async function readClaudeSessionEffort(input) {
|
|
|
40751
40985
|
}
|
|
40752
40986
|
async function newestDirectories(root, limit) {
|
|
40753
40987
|
const entries = await readdir5(root, { withFileTypes: true }).catch(() => []);
|
|
40754
|
-
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));
|
|
40755
40989
|
}
|
|
40756
40990
|
async function findCodexRolloutPath(input) {
|
|
40757
|
-
const codexHome = input.env["CODEX_HOME"] ||
|
|
40758
|
-
const sessions =
|
|
40991
|
+
const codexHome = input.env["CODEX_HOME"] || join19(homeFrom(input.env), ".codex");
|
|
40992
|
+
const sessions = join19(codexHome, "sessions");
|
|
40759
40993
|
const suffix = `-${input.threadId}.jsonl`;
|
|
40760
40994
|
for (const year of await newestDirectories(sessions, 2)) {
|
|
40761
40995
|
for (const month of await newestDirectories(year, 2)) {
|
|
40762
40996
|
for (const day of await newestDirectories(month, 3)) {
|
|
40763
40997
|
const files = await readdir5(day).catch(() => []);
|
|
40764
40998
|
const match = files.find((name) => name.endsWith(suffix));
|
|
40765
|
-
if (match) return
|
|
40999
|
+
if (match) return join19(day, match);
|
|
40766
41000
|
}
|
|
40767
41001
|
}
|
|
40768
41002
|
}
|
|
@@ -41156,18 +41390,18 @@ function improveErrorMessage(error52) {
|
|
|
41156
41390
|
}
|
|
41157
41391
|
|
|
41158
41392
|
// src/runners/codex.ts
|
|
41159
|
-
import { mkdir as
|
|
41393
|
+
import { mkdir as mkdir13, readFile as readFile10, writeFile as writeFile8 } from "node:fs/promises";
|
|
41160
41394
|
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
41161
|
-
import { homedir as
|
|
41162
|
-
import { join as
|
|
41395
|
+
import { homedir as homedir9 } from "node:os";
|
|
41396
|
+
import { join as join20 } from "node:path";
|
|
41163
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.";
|
|
41164
41398
|
function defaultCodexThreadIndexRoot() {
|
|
41165
|
-
return
|
|
41399
|
+
return join20(homedir9(), ".zixt", "codex-threads");
|
|
41166
41400
|
}
|
|
41167
41401
|
var SAFE_SEGMENT3 = /^[A-Za-z0-9_-]{1,200}$/;
|
|
41168
41402
|
function threadIndexPath(root, agentId, sessionKey) {
|
|
41169
41403
|
if (!SAFE_SEGMENT3.test(agentId) || !SAFE_SEGMENT3.test(sessionKey)) return null;
|
|
41170
|
-
return
|
|
41404
|
+
return join20(root, agentId, `${sessionKey}.json`);
|
|
41171
41405
|
}
|
|
41172
41406
|
async function readThreadId(path) {
|
|
41173
41407
|
try {
|
|
@@ -41271,7 +41505,7 @@ ${value}` : value;
|
|
|
41271
41505
|
const recordedThreadId = indexPath ? await readThreadId(indexPath) : null;
|
|
41272
41506
|
const rememberThread = (threadId) => {
|
|
41273
41507
|
if (!indexPath) return;
|
|
41274
|
-
void
|
|
41508
|
+
void mkdir13(join20(threadIndexRoot, task.agentId), { recursive: true }).then(() => writeFile8(indexPath, JSON.stringify({ threadId }), "utf8")).catch(() => {
|
|
41275
41509
|
});
|
|
41276
41510
|
};
|
|
41277
41511
|
const observeRuntime = (threadId) => {
|
|
@@ -41734,9 +41968,9 @@ function improveCodexErrorMessage(error52) {
|
|
|
41734
41968
|
}
|
|
41735
41969
|
|
|
41736
41970
|
// src/runners/git-preflight.ts
|
|
41737
|
-
import { spawn as
|
|
41971
|
+
import { spawn as spawn11 } from "node:child_process";
|
|
41738
41972
|
import { realpath as realpath10 } from "node:fs/promises";
|
|
41739
|
-
import { isAbsolute as
|
|
41973
|
+
import { isAbsolute as isAbsolute17, resolve as resolve11 } from "node:path";
|
|
41740
41974
|
var OUTPUT_LIMIT = 8192;
|
|
41741
41975
|
var DEFAULT_TIMEOUT_MS4 = 1e4;
|
|
41742
41976
|
var VERSION_PATTERN = /^git version [^\r\n]{1,108}$/;
|
|
@@ -41752,7 +41986,7 @@ function unavailable(error52, checkedAt, executablePath = null) {
|
|
|
41752
41986
|
async function preflightGit(options = {}) {
|
|
41753
41987
|
const checkedAt = (options.now?.() ?? /* @__PURE__ */ new Date()).toISOString();
|
|
41754
41988
|
const configured = options.command;
|
|
41755
|
-
if (configured !== void 0 && !
|
|
41989
|
+
if (configured !== void 0 && !isAbsolute17(configured)) {
|
|
41756
41990
|
return unavailable("configured git command must be an absolute file", checkedAt);
|
|
41757
41991
|
}
|
|
41758
41992
|
const trustedCwd = await realpath10(resolve11(options.trustedCwd ?? process.cwd())).catch(() => null);
|
|
@@ -41783,7 +42017,7 @@ async function preflightGit(options = {}) {
|
|
|
41783
42017
|
}
|
|
41784
42018
|
async function runVersionProbe(input) {
|
|
41785
42019
|
return new Promise((resolvePromise) => {
|
|
41786
|
-
const child =
|
|
42020
|
+
const child = spawn11(input.executablePath, input.args, {
|
|
41787
42021
|
cwd: input.cwd,
|
|
41788
42022
|
env: {
|
|
41789
42023
|
...process.env.SystemRoot ? { SystemRoot: process.env.SystemRoot } : {},
|
|
@@ -41852,7 +42086,7 @@ async function preflightClaudeCode(options = {}) {
|
|
|
41852
42086
|
const command = options.command ?? "claude";
|
|
41853
42087
|
const prefixArgs = options.commandPrefixArgs ?? [];
|
|
41854
42088
|
const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
41855
|
-
const trustedCommand = await
|
|
42089
|
+
const trustedCommand = await resolveRunnerCommand(command, "claude-code", { probe: true });
|
|
41856
42090
|
if (!trustedCommand) {
|
|
41857
42091
|
return {
|
|
41858
42092
|
type: "claude-code",
|
|
@@ -41903,7 +42137,7 @@ async function preflightCodex(options = {}) {
|
|
|
41903
42137
|
const command = options.command ?? "codex";
|
|
41904
42138
|
const prefixArgs = options.commandPrefixArgs ?? [];
|
|
41905
42139
|
const checkedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
41906
|
-
const trustedCommand = await
|
|
42140
|
+
const trustedCommand = await resolveRunnerCommand(command, "codex", { probe: true });
|
|
41907
42141
|
if (!trustedCommand) {
|
|
41908
42142
|
return {
|
|
41909
42143
|
type: "codex",
|
|
@@ -42005,11 +42239,11 @@ function run2(command, args) {
|
|
|
42005
42239
|
}
|
|
42006
42240
|
|
|
42007
42241
|
// src/linux-service.ts
|
|
42008
|
-
import { spawn as
|
|
42242
|
+
import { spawn as spawn12 } from "node:child_process";
|
|
42009
42243
|
import { constants as constants2 } from "node:fs";
|
|
42010
|
-
import { access as access4, chmod as chmod7, mkdir as
|
|
42011
|
-
import { homedir as
|
|
42012
|
-
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";
|
|
42013
42247
|
var SERVICE_NAME = "zixt-host.service";
|
|
42014
42248
|
var SYSTEM_SERVICE_COMMAND_TIMEOUT_MS = 7e4;
|
|
42015
42249
|
var SERVICE_STABILITY_DELAY_MS = 2e3;
|
|
@@ -42038,7 +42272,7 @@ function boundedAppend(current, chunk) {
|
|
|
42038
42272
|
async function defaultRunCommand(command, args) {
|
|
42039
42273
|
const commandEnvironment3 = systemServiceCommandEnvironment();
|
|
42040
42274
|
return new Promise((resolve18) => {
|
|
42041
|
-
const child =
|
|
42275
|
+
const child = spawn12(command, [...args], {
|
|
42042
42276
|
stdio: ["ignore", "pipe", "pipe"],
|
|
42043
42277
|
env: commandEnvironment3,
|
|
42044
42278
|
windowsHide: true
|
|
@@ -42110,22 +42344,22 @@ async function defaultSyncDirectory(path) {
|
|
|
42110
42344
|
}
|
|
42111
42345
|
}
|
|
42112
42346
|
async function ensureDirectory(path, mode, syncDirectory8) {
|
|
42113
|
-
const firstCreated = await
|
|
42347
|
+
const firstCreated = await mkdir14(path, { recursive: true, mode });
|
|
42114
42348
|
if (!firstCreated) return;
|
|
42115
42349
|
const first = resolve12(firstCreated);
|
|
42116
42350
|
const target = resolve12(path);
|
|
42117
|
-
await syncDirectory8(
|
|
42351
|
+
await syncDirectory8(dirname11(first));
|
|
42118
42352
|
let current = first;
|
|
42119
42353
|
const descendants = relative9(first, target);
|
|
42120
42354
|
for (const part of descendants ? descendants.split(sep5) : []) {
|
|
42121
42355
|
await syncDirectory8(current);
|
|
42122
|
-
current =
|
|
42356
|
+
current = join21(current, part);
|
|
42123
42357
|
}
|
|
42124
42358
|
}
|
|
42125
42359
|
async function replacePrivateFile(path, contents, mode, syncDirectory8) {
|
|
42126
|
-
const parent =
|
|
42360
|
+
const parent = dirname11(path);
|
|
42127
42361
|
await ensureDirectory(parent, 448, syncDirectory8);
|
|
42128
|
-
const temporary =
|
|
42362
|
+
const temporary = join21(parent, `.${basename4(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
42129
42363
|
const handle = await open7(temporary, "wx", mode);
|
|
42130
42364
|
try {
|
|
42131
42365
|
await handle.writeFile(contents, "utf8");
|
|
@@ -42136,7 +42370,7 @@ async function replacePrivateFile(path, contents, mode, syncDirectory8) {
|
|
|
42136
42370
|
await syncDirectory8(parent);
|
|
42137
42371
|
} catch (error52) {
|
|
42138
42372
|
await handle.close().catch(() => void 0);
|
|
42139
|
-
await
|
|
42373
|
+
await rm10(temporary, { force: true }).catch(() => void 0);
|
|
42140
42374
|
throw error52;
|
|
42141
42375
|
}
|
|
42142
42376
|
}
|
|
@@ -42169,7 +42403,7 @@ async function installLinuxService(options) {
|
|
|
42169
42403
|
throw new Error("Linux automatic startup is available only on Linux.");
|
|
42170
42404
|
}
|
|
42171
42405
|
const env = options.env ?? process.env;
|
|
42172
|
-
const home = options.home ??
|
|
42406
|
+
const home = options.home ?? homedir10();
|
|
42173
42407
|
const username = oneLine(options.username ?? userInfo().username, "user name");
|
|
42174
42408
|
const token2 = oneLine(options.token, "pairing code");
|
|
42175
42409
|
const path = oneLine(
|
|
@@ -42177,11 +42411,11 @@ async function installLinuxService(options) {
|
|
|
42177
42411
|
"command search path"
|
|
42178
42412
|
);
|
|
42179
42413
|
const cloudUrl = options.cloudUrl ? oneLine(options.cloudUrl, "Zixt Cloud address") : void 0;
|
|
42180
|
-
const xdgConfigHome = env.XDG_CONFIG_HOME ? oneLine(env.XDG_CONFIG_HOME, "Linux configuration path") :
|
|
42181
|
-
const configRoot = options.serviceConfigRoot ??
|
|
42182
|
-
const unitRoot = options.userUnitRoot ??
|
|
42183
|
-
const environmentPath =
|
|
42184
|
-
const unitPath =
|
|
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);
|
|
42185
42419
|
const installVersion = options.installVersion ?? ((version2, onFailure) => installRelease(version2, onFailure ? { onFailure } : {}));
|
|
42186
42420
|
const activateVersion = options.activateVersion ?? (options.installVersion ? async (entry) => entry : activateInstalledRelease);
|
|
42187
42421
|
const resolveCommand = options.resolveCommand ?? defaultResolveCommand;
|
|
@@ -42227,6 +42461,7 @@ async function installLinuxService(options) {
|
|
|
42227
42461
|
...cloudUrl ? [`ZIXT_CLOUD_URL=${systemdEnvironmentValue(cloudUrl)}`] : [],
|
|
42228
42462
|
`PATH=${systemdEnvironmentValue(path)}`,
|
|
42229
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)}`] : [],
|
|
42230
42465
|
...env.ZIXT_HOST_UPDATE_URL ? [`ZIXT_HOST_UPDATE_URL=${systemdEnvironmentValue(env.ZIXT_HOST_UPDATE_URL)}`] : [],
|
|
42231
42466
|
...env.ZIXT_HOST_VERSIONS_DIR ? [`ZIXT_HOST_VERSIONS_DIR=${systemdEnvironmentValue(env.ZIXT_HOST_VERSIONS_DIR)}`] : [],
|
|
42232
42467
|
// A Machine on a private registry mirror checks ZIXT_HOST_UPDATE_URL for
|
|
@@ -42307,11 +42542,11 @@ async function installLinuxService(options) {
|
|
|
42307
42542
|
}
|
|
42308
42543
|
|
|
42309
42544
|
// src/macos-service.ts
|
|
42310
|
-
import { spawn as
|
|
42545
|
+
import { spawn as spawn13 } from "node:child_process";
|
|
42311
42546
|
import { constants as constants3 } from "node:fs";
|
|
42312
|
-
import { access as access5, chmod as chmod8, mkdir as
|
|
42313
|
-
import { homedir as
|
|
42314
|
-
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";
|
|
42315
42550
|
var LAUNCH_AGENT_LABEL = "ai.zixt.host";
|
|
42316
42551
|
var SERVICE_STABILITY_DELAY_MS2 = 2e3;
|
|
42317
42552
|
var COMMAND_TIMEOUT_MS2 = 7e4;
|
|
@@ -42335,21 +42570,21 @@ async function syncDirectory4(path) {
|
|
|
42335
42570
|
}
|
|
42336
42571
|
}
|
|
42337
42572
|
async function ensureDirectory2(path, sync) {
|
|
42338
|
-
const firstCreated = await
|
|
42573
|
+
const firstCreated = await mkdir15(path, { recursive: true, mode: 448 });
|
|
42339
42574
|
if (!firstCreated) return;
|
|
42340
42575
|
const first = resolve13(firstCreated);
|
|
42341
42576
|
const target = resolve13(path);
|
|
42342
|
-
await sync(
|
|
42577
|
+
await sync(dirname12(first));
|
|
42343
42578
|
let current = first;
|
|
42344
42579
|
for (const part of relative10(first, target).split(sep6).filter(Boolean)) {
|
|
42345
42580
|
await sync(current);
|
|
42346
|
-
current =
|
|
42581
|
+
current = join22(current, part);
|
|
42347
42582
|
}
|
|
42348
42583
|
}
|
|
42349
42584
|
async function replacePrivateFile2(path, contents, mode, sync) {
|
|
42350
|
-
const parent =
|
|
42585
|
+
const parent = dirname12(path);
|
|
42351
42586
|
await ensureDirectory2(parent, sync);
|
|
42352
|
-
const temporary =
|
|
42587
|
+
const temporary = join22(parent, `.${basename5(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
42353
42588
|
const handle = await open8(temporary, "wx", mode);
|
|
42354
42589
|
try {
|
|
42355
42590
|
await handle.writeFile(contents, "utf8");
|
|
@@ -42360,7 +42595,7 @@ async function replacePrivateFile2(path, contents, mode, sync) {
|
|
|
42360
42595
|
await sync(parent);
|
|
42361
42596
|
} catch (error52) {
|
|
42362
42597
|
await handle.close().catch(() => void 0);
|
|
42363
|
-
await
|
|
42598
|
+
await rm11(temporary, { force: true }).catch(() => void 0);
|
|
42364
42599
|
throw error52;
|
|
42365
42600
|
}
|
|
42366
42601
|
}
|
|
@@ -42374,7 +42609,7 @@ function commandEnvironment(env) {
|
|
|
42374
42609
|
}
|
|
42375
42610
|
async function defaultRunCommand2(command, args, env) {
|
|
42376
42611
|
return new Promise((resolveResult) => {
|
|
42377
|
-
const child =
|
|
42612
|
+
const child = spawn13(command, [...args], {
|
|
42378
42613
|
stdio: ["ignore", "pipe", "pipe"],
|
|
42379
42614
|
env: commandEnvironment(env)
|
|
42380
42615
|
});
|
|
@@ -42437,7 +42672,7 @@ async function installMacosService(options) {
|
|
|
42437
42672
|
throw new Error("macOS automatic startup is available only on macOS.");
|
|
42438
42673
|
}
|
|
42439
42674
|
const env = options.env ?? process.env;
|
|
42440
|
-
const home = options.home ??
|
|
42675
|
+
const home = options.home ?? homedir11();
|
|
42441
42676
|
const uid = options.uid ?? userInfo2().uid;
|
|
42442
42677
|
if (!Number.isSafeInteger(uid) || uid < 0) throw new Error("macOS user id is invalid.");
|
|
42443
42678
|
const token2 = oneLine2(options.token, "pairing code");
|
|
@@ -42446,14 +42681,14 @@ async function installMacosService(options) {
|
|
|
42446
42681
|
options.path ?? env.PATH ?? "/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin",
|
|
42447
42682
|
"command search path"
|
|
42448
42683
|
);
|
|
42449
|
-
const configRoot = options.configRoot ??
|
|
42450
|
-
const launchAgentsRoot = options.launchAgentsRoot ??
|
|
42451
|
-
const logRoot = options.logRoot ??
|
|
42452
|
-
const configPath =
|
|
42453
|
-
const launcherPath =
|
|
42454
|
-
const plistPath =
|
|
42455
|
-
const stdoutPath =
|
|
42456
|
-
const stderrPath =
|
|
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");
|
|
42457
42692
|
const installVersion = options.installVersion ?? ((version2, onFailure) => installRelease(version2, onFailure ? { onFailure } : {}));
|
|
42458
42693
|
const activateVersion = options.activateVersion ?? (options.installVersion ? async (entry) => entry : (entry) => activateInstalledRelease(entry));
|
|
42459
42694
|
const resolveCommand = options.resolveCommand ?? (async () => defaultResolveCommand2());
|
|
@@ -42483,6 +42718,7 @@ async function installMacosService(options) {
|
|
|
42483
42718
|
`PATH=${shellValue(path)}`,
|
|
42484
42719
|
"ZIXT_HOST_SERVICE_MANAGER=launchd",
|
|
42485
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)}`] : [],
|
|
42486
42722
|
...env.ZIXT_HOST_UPDATE_URL ? [`ZIXT_HOST_UPDATE_URL=${shellValue(env.ZIXT_HOST_UPDATE_URL)}`] : [],
|
|
42487
42723
|
...env.ZIXT_HOST_VERSIONS_DIR ? [`ZIXT_HOST_VERSIONS_DIR=${shellValue(env.ZIXT_HOST_VERSIONS_DIR)}`] : [],
|
|
42488
42724
|
// A Machine on a private registry mirror checks ZIXT_HOST_UPDATE_URL for
|
|
@@ -42547,11 +42783,11 @@ async function installMacosService(options) {
|
|
|
42547
42783
|
}
|
|
42548
42784
|
|
|
42549
42785
|
// src/windows-service.ts
|
|
42550
|
-
import { spawn as
|
|
42786
|
+
import { spawn as spawn14 } from "node:child_process";
|
|
42551
42787
|
import { constants as constants4 } from "node:fs";
|
|
42552
|
-
import { access as access6, mkdir as
|
|
42553
|
-
import { homedir as
|
|
42554
|
-
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";
|
|
42555
42791
|
var TASK_NAME = "Zixt Host";
|
|
42556
42792
|
var COMMAND_TIMEOUT_MS3 = 7e4;
|
|
42557
42793
|
var SERVICE_STABILITY_DELAY_MS3 = 2e3;
|
|
@@ -42577,21 +42813,21 @@ async function syncDirectory5(path) {
|
|
|
42577
42813
|
}
|
|
42578
42814
|
}
|
|
42579
42815
|
async function ensureDirectory3(path, sync) {
|
|
42580
|
-
const firstCreated = await
|
|
42816
|
+
const firstCreated = await mkdir16(path, { recursive: true, mode: 448 });
|
|
42581
42817
|
if (!firstCreated) return;
|
|
42582
42818
|
const first = resolve14(firstCreated);
|
|
42583
42819
|
const target = resolve14(path);
|
|
42584
|
-
await sync(
|
|
42820
|
+
await sync(dirname13(first));
|
|
42585
42821
|
let current = first;
|
|
42586
42822
|
for (const part of relative11(first, target).split(sep7).filter(Boolean)) {
|
|
42587
42823
|
await sync(current);
|
|
42588
|
-
current =
|
|
42824
|
+
current = join23(current, part);
|
|
42589
42825
|
}
|
|
42590
42826
|
}
|
|
42591
42827
|
async function replacePrivateFile3(path, contents, sync, encoding = "utf8") {
|
|
42592
|
-
const parent =
|
|
42828
|
+
const parent = dirname13(path);
|
|
42593
42829
|
await ensureDirectory3(parent, sync);
|
|
42594
|
-
const temporary =
|
|
42830
|
+
const temporary = join23(parent, `.${basename6(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
42595
42831
|
const handle = await open9(temporary, "wx", 384);
|
|
42596
42832
|
try {
|
|
42597
42833
|
await handle.writeFile(encoding === "utf16le" ? `\uFEFF${contents}` : contents, encoding);
|
|
@@ -42601,7 +42837,7 @@ async function replacePrivateFile3(path, contents, sync, encoding = "utf8") {
|
|
|
42601
42837
|
await sync(parent);
|
|
42602
42838
|
} catch (error52) {
|
|
42603
42839
|
await handle.close().catch(() => void 0);
|
|
42604
|
-
await
|
|
42840
|
+
await rm12(temporary, { force: true }).catch(() => void 0);
|
|
42605
42841
|
throw error52;
|
|
42606
42842
|
}
|
|
42607
42843
|
}
|
|
@@ -42612,7 +42848,7 @@ function commandEnvironment2(env) {
|
|
|
42612
42848
|
}
|
|
42613
42849
|
async function runChild(command, args, env, input) {
|
|
42614
42850
|
return new Promise((resolveResult) => {
|
|
42615
|
-
const child =
|
|
42851
|
+
const child = spawn14(command, [...args], {
|
|
42616
42852
|
stdio: [input === void 0 ? "ignore" : "pipe", "pipe", "pipe"],
|
|
42617
42853
|
env: commandEnvironment2(env),
|
|
42618
42854
|
windowsHide: true
|
|
@@ -42645,8 +42881,8 @@ async function runChild(command, args, env, input) {
|
|
|
42645
42881
|
}
|
|
42646
42882
|
async function defaultResolveCommand3(name, env) {
|
|
42647
42883
|
const root = env.SYSTEMROOT ?? env.WINDIR;
|
|
42648
|
-
if (!root || !
|
|
42649
|
-
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`);
|
|
42650
42886
|
return access6(candidate, constants4.X_OK).then(
|
|
42651
42887
|
() => candidate,
|
|
42652
42888
|
() => null
|
|
@@ -42696,6 +42932,7 @@ try {
|
|
|
42696
42932
|
if ($config.cloudUrl) { $env:ZIXT_CLOUD_URL = $config.cloudUrl } else { Remove-Item Env:ZIXT_CLOUD_URL -ErrorAction SilentlyContinue }
|
|
42697
42933
|
$env:PATH = $config.path
|
|
42698
42934
|
if ($config.update) { $env:ZIXT_HOST_UPDATE = $config.update }
|
|
42935
|
+
if ($config.runnerAutoinstall) { $env:ZIXT_RUNNER_AUTOINSTALL = $config.runnerAutoinstall }
|
|
42699
42936
|
if ($config.updateUrl) { $env:ZIXT_HOST_UPDATE_URL = $config.updateUrl }
|
|
42700
42937
|
if ($config.versionsRoot) { $env:ZIXT_HOST_VERSIONS_DIR = $config.versionsRoot }
|
|
42701
42938
|
if ($config.npmRegistry) { $env:NPM_CONFIG_REGISTRY = $config.npmRegistry }
|
|
@@ -42746,6 +42983,18 @@ async function defaultObserveStatus(path, generation) {
|
|
|
42746
42983
|
return null;
|
|
42747
42984
|
}
|
|
42748
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
|
+
}
|
|
42749
42998
|
function taskXml(input) {
|
|
42750
42999
|
return `<?xml version="1.0" encoding="UTF-16"?>
|
|
42751
43000
|
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
|
@@ -42760,8 +43009,8 @@ function taskXml(input) {
|
|
|
42760
43009
|
<RestartOnFailure><Interval>PT1M</Interval><Count>999</Count></RestartOnFailure>
|
|
42761
43010
|
</Settings>
|
|
42762
43011
|
<Actions Context="ZixtUser"><Exec>
|
|
42763
|
-
<Command>${xml2(input.
|
|
42764
|
-
<Arguments
|
|
43012
|
+
<Command>${xml2(input.wscript)}</Command>
|
|
43013
|
+
<Arguments>//B //NoLogo "${xml2(input.launchShimPath)}"</Arguments>
|
|
42765
43014
|
<WorkingDirectory>${xml2(input.home)}</WorkingDirectory>
|
|
42766
43015
|
</Exec></Actions>
|
|
42767
43016
|
</Task>
|
|
@@ -42776,19 +43025,20 @@ async function installWindowsService(options) {
|
|
|
42776
43025
|
throw new Error("Windows automatic startup is available only on Windows.");
|
|
42777
43026
|
}
|
|
42778
43027
|
const env = options.env ?? process.env;
|
|
42779
|
-
const home = options.home ??
|
|
43028
|
+
const home = options.home ?? homedir12();
|
|
42780
43029
|
const localAppData = options.localAppData ?? env.LOCALAPPDATA;
|
|
42781
|
-
if (!localAppData || !
|
|
43030
|
+
if (!localAppData || !isAbsolute18(localAppData)) {
|
|
42782
43031
|
throw new Error("Windows local application data path is unavailable.");
|
|
42783
43032
|
}
|
|
42784
43033
|
const token2 = oneLine3(options.token, "pairing code");
|
|
42785
43034
|
const cloudUrl = options.cloudUrl ? oneLine3(options.cloudUrl, "Zixt Cloud address") : void 0;
|
|
42786
43035
|
const path = oneLine3(options.path ?? env.PATH ?? "", "command search path");
|
|
42787
|
-
const configRoot = options.configRoot ??
|
|
42788
|
-
const configPath =
|
|
42789
|
-
const launcherPath =
|
|
42790
|
-
const
|
|
42791
|
-
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");
|
|
42792
43042
|
const installVersion = options.installVersion ?? ((version2, onFailure) => installRelease(version2, onFailure ? { onFailure } : {}));
|
|
42793
43043
|
const activateVersion = options.activateVersion ?? (options.installVersion ? async (entry) => entry : (entry) => activateInstalledRelease(entry));
|
|
42794
43044
|
const resolveCommand = options.resolveCommand ?? ((name) => defaultResolveCommand3(name, env));
|
|
@@ -42796,12 +43046,13 @@ async function installWindowsService(options) {
|
|
|
42796
43046
|
const sync = options.syncDirectory ?? syncDirectory5;
|
|
42797
43047
|
const delay4 = options.delay ?? ((ms) => new Promise((done) => setTimeout(done, ms)));
|
|
42798
43048
|
const observe = options.observeStatus ?? defaultObserveStatus;
|
|
42799
|
-
const [powershell, schtasks, icacls] = await Promise.all([
|
|
43049
|
+
const [powershell, schtasks, icacls, wscript] = await Promise.all([
|
|
42800
43050
|
resolveCommand("powershell"),
|
|
42801
43051
|
resolveCommand("schtasks"),
|
|
42802
|
-
resolveCommand("icacls")
|
|
43052
|
+
resolveCommand("icacls"),
|
|
43053
|
+
resolveCommand("wscript")
|
|
42803
43054
|
]);
|
|
42804
|
-
if (!powershell || !schtasks || !icacls) {
|
|
43055
|
+
if (!powershell || !schtasks || !icacls || !wscript) {
|
|
42805
43056
|
throw new Error("Windows Scheduled Task tools could not be found.");
|
|
42806
43057
|
}
|
|
42807
43058
|
const sid = options.sid ?? await defaultCurrentSid(powershell, env);
|
|
@@ -42835,6 +43086,7 @@ async function installWindowsService(options) {
|
|
|
42835
43086
|
...cloudUrl ? { cloudUrl } : {},
|
|
42836
43087
|
path,
|
|
42837
43088
|
...env.ZIXT_HOST_UPDATE ? { update: env.ZIXT_HOST_UPDATE } : {},
|
|
43089
|
+
...env.ZIXT_RUNNER_AUTOINSTALL ? { runnerAutoinstall: env.ZIXT_RUNNER_AUTOINSTALL } : {},
|
|
42838
43090
|
...env.ZIXT_HOST_UPDATE_URL ? { updateUrl: env.ZIXT_HOST_UPDATE_URL } : {},
|
|
42839
43091
|
...env.ZIXT_HOST_VERSIONS_DIR ? { versionsRoot: env.ZIXT_HOST_VERSIONS_DIR } : {},
|
|
42840
43092
|
// A Machine on a private registry mirror checks updateUrl for releases;
|
|
@@ -42845,13 +43097,14 @@ async function installWindowsService(options) {
|
|
|
42845
43097
|
sync
|
|
42846
43098
|
);
|
|
42847
43099
|
await replacePrivateFile3(launcherPath, launcherSource2(configPath, statusPath), sync);
|
|
43100
|
+
await replacePrivateFile3(launchShimPath, hiddenLaunchSource(powershell, launcherPath), sync);
|
|
42848
43101
|
await replacePrivateFile3(
|
|
42849
43102
|
taskXmlPath,
|
|
42850
|
-
taskXml({ sid,
|
|
43103
|
+
taskXml({ sid, wscript, launchShimPath, home }),
|
|
42851
43104
|
sync,
|
|
42852
43105
|
"utf16le"
|
|
42853
43106
|
);
|
|
42854
|
-
await
|
|
43107
|
+
await rm12(statusPath, { force: true });
|
|
42855
43108
|
const acl = await run3(icacls, [
|
|
42856
43109
|
configRoot,
|
|
42857
43110
|
"/inheritance:r",
|
|
@@ -42861,6 +43114,13 @@ async function installWindowsService(options) {
|
|
|
42861
43114
|
"*S-1-5-18:(OI)(CI)F"
|
|
42862
43115
|
]);
|
|
42863
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);
|
|
42864
43124
|
await run3(schtasks, ["/End", "/TN", TASK_NAME]);
|
|
42865
43125
|
const create = await run3(schtasks, ["/Create", "/TN", TASK_NAME, "/XML", taskXmlPath, "/F"]);
|
|
42866
43126
|
if (create.code !== 0) throw commandFailure3("Installing Zixt at sign-in", create);
|
|
@@ -42884,6 +43144,7 @@ async function installWindowsService(options) {
|
|
|
42884
43144
|
taskXmlPath,
|
|
42885
43145
|
configPath,
|
|
42886
43146
|
launcherPath,
|
|
43147
|
+
launchShimPath,
|
|
42887
43148
|
statusPath,
|
|
42888
43149
|
releaseEntry,
|
|
42889
43150
|
currentEntry,
|
|
@@ -42903,23 +43164,23 @@ async function installSystemService(options) {
|
|
|
42903
43164
|
}
|
|
42904
43165
|
|
|
42905
43166
|
// src/terminal-outcomes.ts
|
|
42906
|
-
import { chmod as chmod9, lstat as lstat12, mkdir as
|
|
42907
|
-
import { homedir as
|
|
42908
|
-
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";
|
|
42909
43170
|
var DIRECTORY_MODE5 = 448;
|
|
42910
43171
|
var FILE_MODE4 = 384;
|
|
42911
43172
|
var MAX_OUTCOME_BYTES = 4 * 1024 * 1024;
|
|
42912
43173
|
var HOST_DIRECTORY = /^hst_[0-9a-f]{32}$/;
|
|
42913
43174
|
var OUTCOME_FILE = /^(tsk_[0-9a-f]{32})\.([1-9][0-9]*)\.json$/;
|
|
42914
43175
|
function defaultTerminalOutcomeRoot() {
|
|
42915
|
-
return
|
|
43176
|
+
return join24(homedir13(), ".zixt", "terminal-outcomes");
|
|
42916
43177
|
}
|
|
42917
43178
|
function hostOutcomeRoot(root, hostId) {
|
|
42918
43179
|
if (!HOST_DIRECTORY.test(hostId)) throw new Error("terminal outcome Host identity is malformed");
|
|
42919
|
-
return
|
|
43180
|
+
return join24(root, hostId);
|
|
42920
43181
|
}
|
|
42921
43182
|
function outcomePath(root, hostId, taskId, epoch) {
|
|
42922
|
-
return
|
|
43183
|
+
return join24(hostOutcomeRoot(root, hostId), `${taskId}.${epoch}.json`);
|
|
42923
43184
|
}
|
|
42924
43185
|
async function syncDirectory6(root) {
|
|
42925
43186
|
if (process.platform === "win32") return;
|
|
@@ -42931,19 +43192,19 @@ async function syncDirectory6(root) {
|
|
|
42931
43192
|
}
|
|
42932
43193
|
}
|
|
42933
43194
|
async function requirePrivateRoot(root, sync = syncDirectory6) {
|
|
42934
|
-
const firstCreated = await
|
|
43195
|
+
const firstCreated = await mkdir17(root, { recursive: true, mode: DIRECTORY_MODE5 });
|
|
42935
43196
|
if (firstCreated) {
|
|
42936
43197
|
const first = resolve15(firstCreated);
|
|
42937
43198
|
const target = resolve15(root);
|
|
42938
|
-
await sync(
|
|
43199
|
+
await sync(dirname14(first));
|
|
42939
43200
|
let current = first;
|
|
42940
43201
|
for (const part of relative12(first, target).split(sep8).filter(Boolean)) {
|
|
42941
43202
|
await sync(current);
|
|
42942
|
-
current =
|
|
43203
|
+
current = join24(current, part);
|
|
42943
43204
|
}
|
|
42944
43205
|
}
|
|
42945
|
-
const
|
|
42946
|
-
if (
|
|
43206
|
+
const stat4 = await lstat12(root);
|
|
43207
|
+
if (stat4.isSymbolicLink() || !stat4.isDirectory()) {
|
|
42947
43208
|
throw new Error("terminal outcome journal root is not a trusted directory");
|
|
42948
43209
|
}
|
|
42949
43210
|
await chmod9(root, DIRECTORY_MODE5);
|
|
@@ -42979,7 +43240,7 @@ async function recordTerminalOutcome(hostId, input, root = defaultTerminalOutcom
|
|
|
42979
43240
|
} catch (error52) {
|
|
42980
43241
|
if (error52.code !== "ENOENT") throw error52;
|
|
42981
43242
|
}
|
|
42982
|
-
const temporary =
|
|
43243
|
+
const temporary = join24(
|
|
42983
43244
|
scopedRoot,
|
|
42984
43245
|
`.${outcome.taskId}.${outcome.epoch}.${process.pid}.${Date.now()}.${outcome.resultId}.tmp`
|
|
42985
43246
|
);
|
|
@@ -42996,7 +43257,7 @@ async function recordTerminalOutcome(hostId, input, root = defaultTerminalOutcom
|
|
|
42996
43257
|
} finally {
|
|
42997
43258
|
await handle?.close().catch(() => {
|
|
42998
43259
|
});
|
|
42999
|
-
await
|
|
43260
|
+
await rm13(temporary, { force: true }).catch(() => {
|
|
43000
43261
|
});
|
|
43001
43262
|
}
|
|
43002
43263
|
}
|
|
@@ -43032,9 +43293,9 @@ async function readTerminalOutcomesStrict(root = defaultTerminalOutcomeRoot()) {
|
|
|
43032
43293
|
if (!match || !entry.isFile() || entry.isSymbolicLink()) {
|
|
43033
43294
|
throw new Error("committed terminal outcome is not a trusted regular file");
|
|
43034
43295
|
}
|
|
43035
|
-
const path =
|
|
43036
|
-
const
|
|
43037
|
-
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) {
|
|
43038
43299
|
throw new Error("committed terminal outcome is not a trusted regular file");
|
|
43039
43300
|
}
|
|
43040
43301
|
const outcome = parseCommittedOutcome(
|
|
@@ -43065,7 +43326,7 @@ async function forgetAcknowledgedTerminalOutcomes(refs, root = defaultTerminalOu
|
|
|
43065
43326
|
if (acknowledged.get(`${hostId}:${outcome.taskId}:${outcome.epoch}`) !== outcome.resultId) {
|
|
43066
43327
|
continue;
|
|
43067
43328
|
}
|
|
43068
|
-
await
|
|
43329
|
+
await rm13(outcomePath(root, hostId, outcome.taskId, outcome.epoch), { force: true });
|
|
43069
43330
|
changedHostRoots.add(hostOutcomeRoot(root, hostId));
|
|
43070
43331
|
}
|
|
43071
43332
|
for (const scopedRoot of changedHostRoots) await syncDirectory6(scopedRoot);
|
|
@@ -43077,22 +43338,22 @@ async function forgetSupersededTerminalOutcomes(hostId, taskId, epoch, root = de
|
|
|
43077
43338
|
if (scoped.hostId !== hostId) continue;
|
|
43078
43339
|
const { outcome } = scoped;
|
|
43079
43340
|
if (outcome.taskId !== taskId || outcome.epoch >= epoch) continue;
|
|
43080
|
-
await
|
|
43341
|
+
await rm13(outcomePath(root, hostId, outcome.taskId, outcome.epoch), { force: true });
|
|
43081
43342
|
removed = true;
|
|
43082
43343
|
}
|
|
43083
43344
|
if (removed) await syncDirectory6(hostOutcomeRoot(root, hostId));
|
|
43084
43345
|
}
|
|
43085
43346
|
|
|
43086
43347
|
// src/accepted-assignments.ts
|
|
43087
|
-
import { chmod as chmod10, lstat as lstat13, mkdir as
|
|
43088
|
-
import { homedir as
|
|
43089
|
-
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";
|
|
43090
43351
|
var DIRECTORY_MODE6 = 448;
|
|
43091
43352
|
var FILE_MODE5 = 384;
|
|
43092
43353
|
var CLAIM_FILE = /^(tsk_[0-9a-f]{32})\.([1-9][0-9]*)\.json$/;
|
|
43093
43354
|
var TASK_ID = /^tsk_[0-9a-f]{32}$/;
|
|
43094
43355
|
function defaultAcceptedAssignmentRoot() {
|
|
43095
|
-
return
|
|
43356
|
+
return join25(homedir14(), ".zixt", "accepted-assignments");
|
|
43096
43357
|
}
|
|
43097
43358
|
async function syncDirectory7(root) {
|
|
43098
43359
|
if (process.platform === "win32") return;
|
|
@@ -43104,19 +43365,19 @@ async function syncDirectory7(root) {
|
|
|
43104
43365
|
}
|
|
43105
43366
|
}
|
|
43106
43367
|
async function requirePrivateRoot2(root, sync = syncDirectory7) {
|
|
43107
|
-
const firstCreated = await
|
|
43368
|
+
const firstCreated = await mkdir18(root, { recursive: true, mode: DIRECTORY_MODE6 });
|
|
43108
43369
|
if (firstCreated) {
|
|
43109
43370
|
const first = resolve16(firstCreated);
|
|
43110
43371
|
const target = resolve16(root);
|
|
43111
|
-
await sync(
|
|
43372
|
+
await sync(dirname15(first));
|
|
43112
43373
|
let current = first;
|
|
43113
43374
|
for (const part of relative13(first, target).split(sep9).filter(Boolean)) {
|
|
43114
43375
|
await sync(current);
|
|
43115
|
-
current =
|
|
43376
|
+
current = join25(current, part);
|
|
43116
43377
|
}
|
|
43117
43378
|
}
|
|
43118
|
-
const
|
|
43119
|
-
if (
|
|
43379
|
+
const stat4 = await lstat13(root);
|
|
43380
|
+
if (stat4.isSymbolicLink() || !stat4.isDirectory()) {
|
|
43120
43381
|
throw new Error("accepted assignment journal root is not a trusted directory");
|
|
43121
43382
|
}
|
|
43122
43383
|
await chmod10(root, DIRECTORY_MODE6);
|
|
@@ -43126,7 +43387,7 @@ function claimPath(root, taskId, epoch) {
|
|
|
43126
43387
|
if (!Number.isSafeInteger(epoch) || epoch < 1) {
|
|
43127
43388
|
throw new Error("accepted assignment epoch is malformed");
|
|
43128
43389
|
}
|
|
43129
|
-
return
|
|
43390
|
+
return join25(root, `${taskId}.${epoch}.json`);
|
|
43130
43391
|
}
|
|
43131
43392
|
async function recordAcceptedAssignment(assignment, root = defaultAcceptedAssignmentRoot(), options = {}) {
|
|
43132
43393
|
const sync = options.syncDirectory ?? syncDirectory7;
|
|
@@ -43136,7 +43397,7 @@ async function recordAcceptedAssignment(assignment, root = defaultAcceptedAssign
|
|
|
43136
43397
|
} catch {
|
|
43137
43398
|
return false;
|
|
43138
43399
|
}
|
|
43139
|
-
const temporary =
|
|
43400
|
+
const temporary = join25(
|
|
43140
43401
|
root,
|
|
43141
43402
|
`.${assignment.taskId}.${assignment.epoch}.${process.pid}.${Date.now()}.tmp`
|
|
43142
43403
|
);
|
|
@@ -43156,7 +43417,7 @@ async function recordAcceptedAssignment(assignment, root = defaultAcceptedAssign
|
|
|
43156
43417
|
} finally {
|
|
43157
43418
|
await handle?.close().catch(() => {
|
|
43158
43419
|
});
|
|
43159
|
-
await
|
|
43420
|
+
await rm14(temporary, { force: true }).catch(() => {
|
|
43160
43421
|
});
|
|
43161
43422
|
}
|
|
43162
43423
|
}
|
|
@@ -43190,13 +43451,18 @@ async function forgetAcceptedAssignment(assignment, root = defaultAcceptedAssign
|
|
|
43190
43451
|
} catch {
|
|
43191
43452
|
return;
|
|
43192
43453
|
}
|
|
43193
|
-
await
|
|
43454
|
+
await rm14(path, { force: true }).catch(() => {
|
|
43194
43455
|
});
|
|
43195
43456
|
}
|
|
43196
43457
|
async function forgetAcknowledgedAcceptedAssignments(assignments, root = defaultAcceptedAssignmentRoot()) {
|
|
43197
43458
|
for (const assignment of assignments) await forgetAcceptedAssignment(assignment, root);
|
|
43198
43459
|
}
|
|
43199
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
|
+
|
|
43200
43466
|
// src/logger.ts
|
|
43201
43467
|
var ANSI = {
|
|
43202
43468
|
reset: "\x1B[0m",
|
|
@@ -43288,7 +43554,9 @@ function createHostLogger(options = {}) {
|
|
|
43288
43554
|
const color = options.color ?? (process.stderr.isTTY === true && process.env.NO_COLOR === void 0);
|
|
43289
43555
|
const write = options.write ?? ((line) => console.error(line));
|
|
43290
43556
|
const log2 = (level, message, context) => {
|
|
43291
|
-
|
|
43557
|
+
const at = now();
|
|
43558
|
+
write(formatHostLogLine(level, message, context, { at, color }));
|
|
43559
|
+
options.onEntry?.({ at, level, message, context: context ?? {} });
|
|
43292
43560
|
};
|
|
43293
43561
|
return {
|
|
43294
43562
|
info: (message, context) => log2("info", message, context),
|
|
@@ -43298,24 +43566,105 @@ function createHostLogger(options = {}) {
|
|
|
43298
43566
|
};
|
|
43299
43567
|
}
|
|
43300
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
|
+
|
|
43301
43649
|
// src/demo-state.ts
|
|
43302
|
-
import { isAbsolute as
|
|
43650
|
+
import { isAbsolute as isAbsolute19, join as join27, parse as parse3, resolve as resolve17 } from "node:path";
|
|
43303
43651
|
var DEMO_STATE_ROOT_ENV = "ZIXT_DEMO_STATE_ROOT";
|
|
43304
43652
|
function resolveDemoHostStatePaths(env = process.env) {
|
|
43305
43653
|
const configured = env.ZIXT_RUNNER === "demo" ? env[DEMO_STATE_ROOT_ENV] : void 0;
|
|
43306
43654
|
if (!configured) return null;
|
|
43307
43655
|
const root = resolve17(configured);
|
|
43308
|
-
if (!
|
|
43656
|
+
if (!isAbsolute19(configured) || root === parse3(root).root) {
|
|
43309
43657
|
throw new Error(`${DEMO_STATE_ROOT_ENV} must be a dedicated absolute directory`);
|
|
43310
43658
|
}
|
|
43311
43659
|
return {
|
|
43312
|
-
runRegistryRoot:
|
|
43313
|
-
terminalOutcomeRoot:
|
|
43314
|
-
acceptedAssignmentRoot:
|
|
43315
|
-
runArtifactRoot:
|
|
43316
|
-
browserProfileRoot:
|
|
43317
|
-
runnerWorkspaceRoot:
|
|
43318
|
-
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")
|
|
43319
43668
|
};
|
|
43320
43669
|
}
|
|
43321
43670
|
|
|
@@ -43492,12 +43841,14 @@ function recordConsoleLine(line) {
|
|
|
43492
43841
|
if (hostConsoleTail.length > 200) hostConsoleTail.shift();
|
|
43493
43842
|
clientForConsole.current?.hostConsoleLine(entry);
|
|
43494
43843
|
}
|
|
43844
|
+
var localConsoleSink = { current: null };
|
|
43495
43845
|
var log = createHostLogger({
|
|
43496
43846
|
...colorOverride === void 0 ? {} : { color: colorOverride },
|
|
43497
43847
|
write: (line) => {
|
|
43498
43848
|
console.error(line);
|
|
43499
43849
|
recordConsoleLine(line);
|
|
43500
|
-
}
|
|
43850
|
+
},
|
|
43851
|
+
onEntry: (entry) => localConsoleSink.current?.entry(entry)
|
|
43501
43852
|
});
|
|
43502
43853
|
function replayConsoleLine(level, message, context) {
|
|
43503
43854
|
recordConsoleLine(
|
|
@@ -43505,6 +43856,7 @@ function replayConsoleLine(level, message, context) {
|
|
|
43505
43856
|
...colorOverride === void 0 ? {} : { color: colorOverride }
|
|
43506
43857
|
})
|
|
43507
43858
|
);
|
|
43859
|
+
localConsoleSink.current?.entry({ at: /* @__PURE__ */ new Date(), level, message, context: context ?? {} });
|
|
43508
43860
|
}
|
|
43509
43861
|
if (cliOptions.help) {
|
|
43510
43862
|
process.stdout.write(`${hostHelpText()}
|
|
@@ -43568,8 +43920,20 @@ var {
|
|
|
43568
43920
|
runArtifactRoot,
|
|
43569
43921
|
browserProfileRoot,
|
|
43570
43922
|
runnerWorkspaceRoot,
|
|
43571
|
-
codexThreadIndexRoot
|
|
43923
|
+
codexThreadIndexRoot,
|
|
43924
|
+
localObservabilityRoot
|
|
43572
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
|
+
});
|
|
43573
43937
|
var disclaimableAssignments;
|
|
43574
43938
|
var acceptedAssignments;
|
|
43575
43939
|
var terminalOutcomes;
|
|
@@ -43611,6 +43975,23 @@ if (!token) {
|
|
|
43611
43975
|
process.exit(DO_NOT_RESTART_EXIT_CODE);
|
|
43612
43976
|
}
|
|
43613
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
|
+
});
|
|
43614
43995
|
var gitPreflight = await preflightGit();
|
|
43615
43996
|
var gitRefresh = null;
|
|
43616
43997
|
var GIT_PREFLIGHT_REFRESH_MS = 4 * 6e4;
|
|
@@ -43754,12 +44135,18 @@ async function telemetry() {
|
|
|
43754
44135
|
preflightCodex()
|
|
43755
44136
|
]);
|
|
43756
44137
|
cachedRunnersAt = Date.now();
|
|
43757
|
-
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
|
+
}
|
|
43758
44144
|
}
|
|
43759
44145
|
const providerToolPacks = toolPackRegistry.capabilities({
|
|
43760
44146
|
now: /* @__PURE__ */ new Date(),
|
|
43761
44147
|
git: await currentGitPreflight()
|
|
43762
44148
|
});
|
|
44149
|
+
publishLocalStatus();
|
|
43763
44150
|
providerToolPacks.push({
|
|
43764
44151
|
provider: "email",
|
|
43765
44152
|
version: 1,
|
|
@@ -43786,7 +44173,7 @@ async function telemetry() {
|
|
|
43786
44173
|
// Measured per heartbeat: free memory and free disk are only useful while
|
|
43787
44174
|
// they are current, and a demo Host reports its own private root so the
|
|
43788
44175
|
// number describes the filesystem its Tasks would really write to.
|
|
43789
|
-
hardware: await machineHardware(runnerWorkspaceRoot ??
|
|
44176
|
+
hardware: await machineHardware(runnerWorkspaceRoot ?? homedir16()),
|
|
43790
44177
|
capabilities: {
|
|
43791
44178
|
linearToolPack: providerToolPacks.some(
|
|
43792
44179
|
(pack) => pack.provider === "linear" && pack.health === "ready"
|
|
@@ -43843,6 +44230,36 @@ var connectionContext = connectionLogContext({
|
|
|
43843
44230
|
cloud: cloudTarget,
|
|
43844
44231
|
version: HOST_VERSION
|
|
43845
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
|
+
}
|
|
43846
44263
|
var stopUpdateWatch = () => {
|
|
43847
44264
|
};
|
|
43848
44265
|
var releaseParentPipeWatch = () => {
|
|
@@ -43967,6 +44384,9 @@ var client = new HostClient({
|
|
|
43967
44384
|
switch (status) {
|
|
43968
44385
|
case "connected":
|
|
43969
44386
|
log.success("Connected to Zixt Cloud", connectionContext);
|
|
44387
|
+
localCloudState = "connected";
|
|
44388
|
+
localCloudConnectedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
44389
|
+
publishLocalStatus();
|
|
43970
44390
|
if (reportedWorkerExits.length > 0) {
|
|
43971
44391
|
void forgetWorkerExits(reportedWorkerExits.map(({ file: file2 }) => file2));
|
|
43972
44392
|
}
|
|
@@ -43976,12 +44396,16 @@ var client = new HostClient({
|
|
|
43976
44396
|
...connectionContext,
|
|
43977
44397
|
next: "Check the cloud and Machine pairing if this continues"
|
|
43978
44398
|
});
|
|
44399
|
+
localCloudState = "connecting";
|
|
44400
|
+
publishLocalStatus();
|
|
43979
44401
|
break;
|
|
43980
44402
|
case "unresponsive":
|
|
43981
44403
|
log.warn("Zixt Cloud stopped answering; Tasks unwound before reconnecting", {
|
|
43982
44404
|
...connectionContext,
|
|
43983
44405
|
next: "Check this Machine's network path and Zixt Cloud health if this repeats"
|
|
43984
44406
|
});
|
|
44407
|
+
localCloudState = "connecting";
|
|
44408
|
+
publishLocalStatus();
|
|
43985
44409
|
break;
|
|
43986
44410
|
case "replaced":
|
|
43987
44411
|
log.warn("Another Host process took over this Machine", connectionContext);
|