@zixt/host 0.0.136 → 0.0.137
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 +750 -179
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28,7 +28,7 @@ import { homedir as homedir4 } from "node:os";
|
|
|
28
28
|
// package.json
|
|
29
29
|
var package_default = {
|
|
30
30
|
name: "@zixt/host",
|
|
31
|
-
version: "0.0.
|
|
31
|
+
version: "0.0.137",
|
|
32
32
|
type: "module",
|
|
33
33
|
exports: {
|
|
34
34
|
".": "./src/client.ts",
|
|
@@ -22562,6 +22562,12 @@ var CompanySetupProgress = external_exports.object({
|
|
|
22562
22562
|
/** Every recommended step is done or skipped. */
|
|
22563
22563
|
recommendedSettled: external_exports.boolean()
|
|
22564
22564
|
});
|
|
22565
|
+
var COMPANY_SETUP_PLANNING_NOTE_MAX = 200;
|
|
22566
|
+
var COMPANY_SETUP_PLANNING_NOTES_MAX = 20;
|
|
22567
|
+
var CompanySetupPlanningNote = external_exports.object({
|
|
22568
|
+
at: IsoDate,
|
|
22569
|
+
text: external_exports.string().trim().min(1).max(COMPANY_SETUP_PLANNING_NOTE_MAX)
|
|
22570
|
+
});
|
|
22565
22571
|
var CompanySetupApproval = external_exports.object({
|
|
22566
22572
|
at: IsoDate,
|
|
22567
22573
|
by: MemberId.nullable(),
|
|
@@ -22614,7 +22620,12 @@ var CompanySetupView = external_exports.object({
|
|
|
22614
22620
|
* The plan is being proposed in the background (a planner call can take a
|
|
22615
22621
|
* minute); the page polls until the plan lands or an error is recorded.
|
|
22616
22622
|
*/
|
|
22617
|
-
planning: external_exports.object({
|
|
22623
|
+
planning: external_exports.object({
|
|
22624
|
+
startedAt: IsoDate,
|
|
22625
|
+
error: external_exports.string().max(500).nullable(),
|
|
22626
|
+
/** Oldest first; the planner's visible decisions so far. */
|
|
22627
|
+
notes: external_exports.array(CompanySetupPlanningNote).max(COMPANY_SETUP_PLANNING_NOTES_MAX).default([])
|
|
22628
|
+
}).nullable(),
|
|
22618
22629
|
approval: CompanySetupApproval.nullable(),
|
|
22619
22630
|
steps: external_exports.array(CompanySetupStep),
|
|
22620
22631
|
progress: CompanySetupProgress,
|
|
@@ -31705,11 +31716,11 @@ function createPlaywrightBrowserAdapterFactory(dependencies = {}) {
|
|
|
31705
31716
|
}
|
|
31706
31717
|
|
|
31707
31718
|
// src/runners/cli-runner.ts
|
|
31708
|
-
import { spawn as
|
|
31709
|
-
import { randomUUID as
|
|
31710
|
-
import { lstat as lstat11, mkdir as
|
|
31719
|
+
import { spawn as spawn11 } from "node:child_process";
|
|
31720
|
+
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
31721
|
+
import { lstat as lstat11, mkdir as mkdir13, realpath as realpath8 } from "node:fs/promises";
|
|
31711
31722
|
import { homedir as homedir7 } from "node:os";
|
|
31712
|
-
import { dirname as dirname10, isAbsolute as isAbsolute16, join as
|
|
31723
|
+
import { dirname as dirname10, isAbsolute as isAbsolute16, join as join19, resolve as resolve10 } from "node:path";
|
|
31713
31724
|
|
|
31714
31725
|
// src/tool-packs/browser/authentication-wall.ts
|
|
31715
31726
|
var AUTH_PATH_SEGMENT = /(?:^|\/)(?:log[-_]?in|sign[-_]?in|sso|saml|auth|authorize|authenticate|oauth2?|session\/new|checkpoint)(?:\/|$)/i;
|
|
@@ -38096,6 +38107,415 @@ function renderAttachmentSection(files) {
|
|
|
38096
38107
|
|
|
38097
38108
|
// src/runners/ask-user-server.ts
|
|
38098
38109
|
import { createServer as createServer2 } from "node:http";
|
|
38110
|
+
|
|
38111
|
+
// src/runners/software-install.ts
|
|
38112
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
38113
|
+
import { createHash as createHash6, randomUUID as randomUUID11 } from "node:crypto";
|
|
38114
|
+
import { chmod as chmod6, mkdir as mkdir11, readFile as readFile10, readdir as readdir5, rename as rename6, rm as rm10, symlink as symlink2, writeFile as writeFile7 } from "node:fs/promises";
|
|
38115
|
+
import { join as join17, relative as relative8, resolve as resolvePath, sep as sep5 } from "node:path";
|
|
38116
|
+
var SOFTWARE_INSTALL_METHODS = ["npm", "download"];
|
|
38117
|
+
var SOFTWARE_INSTALL_REFUSAL = "Zixt installs software only into its own folder on this Machine, using npm or a direct download. It never runs a system package manager, never asks for elevation, and never builds from source. Tell the person plainly what is missing, why this work needs it, and the exact command they would run themselves.";
|
|
38118
|
+
var MAX_DOWNLOAD_BYTES = 512 * 1024 * 1024;
|
|
38119
|
+
var PROCESS_TIMEOUT_MS = 10 * 6e4;
|
|
38120
|
+
var DOWNLOAD_TIMEOUT_MS = 10 * 6e4;
|
|
38121
|
+
var FAILURE_COOLDOWN_MS2 = 10 * 6e4;
|
|
38122
|
+
var MAX_ARCHIVE_SEARCH_DEPTH = 5;
|
|
38123
|
+
var MANIFEST_NAME = "installed.json";
|
|
38124
|
+
var COMMAND_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,63}$/;
|
|
38125
|
+
var NPM_SPEC_PATTERN = /^(?:@[a-z0-9~][a-z0-9._~-]*\/)?[a-z0-9~][a-z0-9._~-]*(?:@\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?)?$/;
|
|
38126
|
+
function defaultSoftwareToolsRoot() {
|
|
38127
|
+
return defaultRunnerToolsRoot();
|
|
38128
|
+
}
|
|
38129
|
+
function softwareSearchPathEntries(toolsRoot = defaultSoftwareToolsRoot()) {
|
|
38130
|
+
return [toolsRoot, join17(toolsRoot, "bin")];
|
|
38131
|
+
}
|
|
38132
|
+
function refuseSoftwareRequest(request) {
|
|
38133
|
+
if (!COMMAND_PATTERN.test(request.command)) {
|
|
38134
|
+
return "The command name must be a plain executable name with no path, spaces, or shell characters.";
|
|
38135
|
+
}
|
|
38136
|
+
if (!SOFTWARE_INSTALL_METHODS.includes(request.method)) {
|
|
38137
|
+
return SOFTWARE_INSTALL_REFUSAL;
|
|
38138
|
+
}
|
|
38139
|
+
if (request.method === "npm") {
|
|
38140
|
+
if (!NPM_SPEC_PATTERN.test(request.source)) {
|
|
38141
|
+
return "The npm source must be a package name, optionally with one exact version as name@1.2.3. Ranges, tags, git specs, URLs, and local paths are not installed.";
|
|
38142
|
+
}
|
|
38143
|
+
if (request.sha256 !== void 0) {
|
|
38144
|
+
return "An expected sha256 applies only to downloads; the npm registry names versions, not file digests.";
|
|
38145
|
+
}
|
|
38146
|
+
return null;
|
|
38147
|
+
}
|
|
38148
|
+
let url3;
|
|
38149
|
+
try {
|
|
38150
|
+
url3 = new URL(request.source);
|
|
38151
|
+
} catch {
|
|
38152
|
+
return "The download source must be an absolute HTTPS URL.";
|
|
38153
|
+
}
|
|
38154
|
+
if (url3.protocol !== "https:") return "The download source must use HTTPS.";
|
|
38155
|
+
if (url3.username || url3.password) {
|
|
38156
|
+
return "The download source must not carry credentials in the URL.";
|
|
38157
|
+
}
|
|
38158
|
+
if (request.sha256 !== void 0 && !/^[a-f0-9]{64}$/i.test(request.sha256)) {
|
|
38159
|
+
return "The expected sha256 must be 64 hexadecimal characters.";
|
|
38160
|
+
}
|
|
38161
|
+
return null;
|
|
38162
|
+
}
|
|
38163
|
+
async function runProcess(plan, label) {
|
|
38164
|
+
const env = sanitizedInstallerEnv(process.env);
|
|
38165
|
+
await new Promise((resolveRun, rejectRun) => {
|
|
38166
|
+
const child = plan.shellLine !== void 0 ? spawn9(plan.shellLine, {
|
|
38167
|
+
...plan.cwd ? { cwd: plan.cwd } : {},
|
|
38168
|
+
env,
|
|
38169
|
+
// stdin stays closed; output reaches the ordinary worker console, so
|
|
38170
|
+
// progress and failure land on the Host console like a runner install.
|
|
38171
|
+
stdio: ["ignore", "inherit", "inherit"],
|
|
38172
|
+
windowsHide: true,
|
|
38173
|
+
shell: true
|
|
38174
|
+
}) : spawn9(plan.command, plan.args, {
|
|
38175
|
+
...plan.cwd ? { cwd: plan.cwd } : {},
|
|
38176
|
+
env,
|
|
38177
|
+
stdio: ["ignore", "inherit", "inherit"],
|
|
38178
|
+
windowsHide: true
|
|
38179
|
+
});
|
|
38180
|
+
let settled = false;
|
|
38181
|
+
const finish = (error52) => {
|
|
38182
|
+
if (settled) return;
|
|
38183
|
+
settled = true;
|
|
38184
|
+
clearTimeout(timer);
|
|
38185
|
+
if (error52) rejectRun(error52);
|
|
38186
|
+
else resolveRun();
|
|
38187
|
+
};
|
|
38188
|
+
const timer = setTimeout(() => {
|
|
38189
|
+
child.kill();
|
|
38190
|
+
finish(new Error(`${label} did not finish within 10 minutes`));
|
|
38191
|
+
}, PROCESS_TIMEOUT_MS);
|
|
38192
|
+
timer.unref?.();
|
|
38193
|
+
child.once("error", (error52) => finish(error52));
|
|
38194
|
+
child.once("exit", (code, signal) => {
|
|
38195
|
+
if (code === 0) finish();
|
|
38196
|
+
else if (signal) finish(new Error(`${label} stopped with ${signal}`));
|
|
38197
|
+
else finish(new Error(`${label} exited with code ${code ?? "unknown"}`));
|
|
38198
|
+
});
|
|
38199
|
+
});
|
|
38200
|
+
}
|
|
38201
|
+
async function resolveTarCommand(platform) {
|
|
38202
|
+
if (platform !== "win32") return "tar";
|
|
38203
|
+
const root = process.env["SYSTEMROOT"] ?? process.env["WINDIR"];
|
|
38204
|
+
if (!root) return "tar";
|
|
38205
|
+
return await resolveTrustedCliCommand(join17(root, "System32", "tar.exe"), { platform }) ?? "tar";
|
|
38206
|
+
}
|
|
38207
|
+
function archiveKindFor(url3) {
|
|
38208
|
+
let path;
|
|
38209
|
+
try {
|
|
38210
|
+
path = new URL(url3).pathname.toLowerCase();
|
|
38211
|
+
} catch {
|
|
38212
|
+
return "binary";
|
|
38213
|
+
}
|
|
38214
|
+
if (/\.(?:tar\.(?:gz|xz|bz2)|tgz|tbz2|txz|tar)$/.test(path)) return "tar";
|
|
38215
|
+
if (path.endsWith(".zip")) return "zip";
|
|
38216
|
+
return "binary";
|
|
38217
|
+
}
|
|
38218
|
+
async function findExtractedExecutable(root, command, platform = process.platform) {
|
|
38219
|
+
const names = platform === "win32" ? [`${command}.exe`, `${command}.cmd`, `${command}.bat`, command] : [command];
|
|
38220
|
+
let frontier = [root];
|
|
38221
|
+
for (let depth = 0; depth <= MAX_ARCHIVE_SEARCH_DEPTH && frontier.length > 0; depth += 1) {
|
|
38222
|
+
const next = [];
|
|
38223
|
+
for (const directory of frontier) {
|
|
38224
|
+
let entries;
|
|
38225
|
+
try {
|
|
38226
|
+
entries = await readdir5(directory, { withFileTypes: true });
|
|
38227
|
+
} catch {
|
|
38228
|
+
continue;
|
|
38229
|
+
}
|
|
38230
|
+
for (const name of names) {
|
|
38231
|
+
if (entries.some((entry) => entry.name === name && entry.isFile())) {
|
|
38232
|
+
return join17(directory, name);
|
|
38233
|
+
}
|
|
38234
|
+
}
|
|
38235
|
+
for (const entry of entries) {
|
|
38236
|
+
if (entry.isDirectory()) next.push(join17(directory, entry.name));
|
|
38237
|
+
}
|
|
38238
|
+
}
|
|
38239
|
+
frontier = next;
|
|
38240
|
+
}
|
|
38241
|
+
return null;
|
|
38242
|
+
}
|
|
38243
|
+
function withinRoot(root, candidate) {
|
|
38244
|
+
const base = resolvePath(root);
|
|
38245
|
+
const target = resolvePath(candidate);
|
|
38246
|
+
return target === base || target.startsWith(base.endsWith(sep5) ? base : `${base}${sep5}`);
|
|
38247
|
+
}
|
|
38248
|
+
function downloadedBinaryName(command, source, platform = process.platform) {
|
|
38249
|
+
if (platform !== "win32") return command;
|
|
38250
|
+
const extension = /(\.[A-Za-z0-9]{1,8})$/.exec(new URL(source).pathname)?.[1]?.toLowerCase();
|
|
38251
|
+
if (extension !== ".exe" && extension !== ".com") {
|
|
38252
|
+
throw new Error(
|
|
38253
|
+
"a direct Windows download must be a .exe or .com file; use the tool\u2019s .zip release instead"
|
|
38254
|
+
);
|
|
38255
|
+
}
|
|
38256
|
+
return `${command}${extension}`;
|
|
38257
|
+
}
|
|
38258
|
+
async function placeDownloadedPayload(body, request, options) {
|
|
38259
|
+
const platform = options.platform ?? process.platform;
|
|
38260
|
+
const { toolsRoot } = options;
|
|
38261
|
+
const staging = join17(toolsRoot, ".staging", randomUUID11());
|
|
38262
|
+
const stagedPackage = join17(staging, "pkg");
|
|
38263
|
+
const packageRoot = join17(toolsRoot, "pkgs", request.command);
|
|
38264
|
+
const binDirectory = platform === "win32" ? toolsRoot : join17(toolsRoot, "bin");
|
|
38265
|
+
const kind = archiveKindFor(request.source);
|
|
38266
|
+
await mkdir11(stagedPackage, { recursive: true, mode: 448 });
|
|
38267
|
+
try {
|
|
38268
|
+
if (kind === "binary") {
|
|
38269
|
+
await writeFile7(
|
|
38270
|
+
join17(stagedPackage, downloadedBinaryName(request.command, request.source, platform)),
|
|
38271
|
+
body,
|
|
38272
|
+
{
|
|
38273
|
+
mode: 448
|
|
38274
|
+
}
|
|
38275
|
+
);
|
|
38276
|
+
} else {
|
|
38277
|
+
await writeFile7(join17(staging, "archive"), body, { mode: 448 });
|
|
38278
|
+
if (kind === "tar" || platform !== "linux") {
|
|
38279
|
+
await runProcess(
|
|
38280
|
+
{
|
|
38281
|
+
command: await resolveTarCommand(platform),
|
|
38282
|
+
args: ["-xf", "archive", "-C", "pkg"],
|
|
38283
|
+
cwd: staging
|
|
38284
|
+
},
|
|
38285
|
+
"the archive extraction"
|
|
38286
|
+
);
|
|
38287
|
+
} else {
|
|
38288
|
+
await runProcess(
|
|
38289
|
+
{ command: "unzip", args: ["-q", "-o", "archive", "-d", "pkg"], cwd: staging },
|
|
38290
|
+
"the archive extraction"
|
|
38291
|
+
);
|
|
38292
|
+
}
|
|
38293
|
+
await rm10(join17(staging, "archive"), { force: true }).catch(() => void 0);
|
|
38294
|
+
}
|
|
38295
|
+
const stagedExecutable = await findExtractedExecutable(
|
|
38296
|
+
stagedPackage,
|
|
38297
|
+
request.command,
|
|
38298
|
+
platform
|
|
38299
|
+
);
|
|
38300
|
+
if (!stagedExecutable) {
|
|
38301
|
+
throw new Error(`the download did not contain an executable named ${request.command}`);
|
|
38302
|
+
}
|
|
38303
|
+
if (!withinRoot(stagedPackage, stagedExecutable)) {
|
|
38304
|
+
throw new Error("the archive tried to place its executable outside the Zixt folder");
|
|
38305
|
+
}
|
|
38306
|
+
await mkdir11(join17(toolsRoot, "pkgs"), { recursive: true, mode: 448 });
|
|
38307
|
+
await rm10(packageRoot, { recursive: true, force: true });
|
|
38308
|
+
await rename6(stagedPackage, packageRoot);
|
|
38309
|
+
const executable = join17(packageRoot, relative8(stagedPackage, stagedExecutable));
|
|
38310
|
+
await mkdir11(binDirectory, { recursive: true, mode: 448 });
|
|
38311
|
+
if (platform === "win32") {
|
|
38312
|
+
const shim = join17(binDirectory, `${request.command}.cmd`);
|
|
38313
|
+
await writeFile7(shim, `@echo off\r
|
|
38314
|
+
${quoteForCmd(executable)} %*\r
|
|
38315
|
+
`, {
|
|
38316
|
+
encoding: "utf8",
|
|
38317
|
+
mode: 448
|
|
38318
|
+
});
|
|
38319
|
+
return shim;
|
|
38320
|
+
}
|
|
38321
|
+
await chmod6(executable, 493);
|
|
38322
|
+
const link = join17(binDirectory, request.command);
|
|
38323
|
+
await rm10(link, { force: true });
|
|
38324
|
+
await symlink2(executable, link);
|
|
38325
|
+
return link;
|
|
38326
|
+
} finally {
|
|
38327
|
+
await rm10(staging, { recursive: true, force: true }).catch(() => void 0);
|
|
38328
|
+
}
|
|
38329
|
+
}
|
|
38330
|
+
function createSoftwareInstaller(options = {}) {
|
|
38331
|
+
const platform = options.platform ?? process.platform;
|
|
38332
|
+
const toolsRoot = options.toolsRoot ?? defaultSoftwareToolsRoot();
|
|
38333
|
+
const now = options.now ?? Date.now;
|
|
38334
|
+
const manifestPath = join17(toolsRoot, MANIFEST_NAME);
|
|
38335
|
+
const inFlight = /* @__PURE__ */ new Map();
|
|
38336
|
+
const failures = /* @__PURE__ */ new Map();
|
|
38337
|
+
const searchPath = () => {
|
|
38338
|
+
const inherited = options.resolution?.searchPath ?? process.env.PATH ?? "";
|
|
38339
|
+
const separator = platform === "win32" ? ";" : ":";
|
|
38340
|
+
return [inherited, ...softwareSearchPathEntries(toolsRoot)].filter(Boolean).join(separator);
|
|
38341
|
+
};
|
|
38342
|
+
const resolveCommand = async (command) => resolveTrustedCliCommand(command, {
|
|
38343
|
+
...options.resolution ?? {},
|
|
38344
|
+
platform,
|
|
38345
|
+
searchPath: searchPath()
|
|
38346
|
+
});
|
|
38347
|
+
const readManifest = async () => {
|
|
38348
|
+
try {
|
|
38349
|
+
const parsed = JSON.parse(await readFile10(manifestPath, "utf8"));
|
|
38350
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
38351
|
+
} catch {
|
|
38352
|
+
return [];
|
|
38353
|
+
}
|
|
38354
|
+
};
|
|
38355
|
+
let manifestTurn = Promise.resolve();
|
|
38356
|
+
const recordInstall = (record2) => {
|
|
38357
|
+
const write = manifestTurn.then(async () => {
|
|
38358
|
+
const existing = (await readManifest()).filter((entry) => entry.command !== record2.command);
|
|
38359
|
+
const staged = `${manifestPath}.${randomUUID11()}`;
|
|
38360
|
+
await writeFile7(staged, `${JSON.stringify([...existing, record2], null, 2)}
|
|
38361
|
+
`, {
|
|
38362
|
+
encoding: "utf8",
|
|
38363
|
+
mode: 384
|
|
38364
|
+
});
|
|
38365
|
+
await rename6(staged, manifestPath);
|
|
38366
|
+
});
|
|
38367
|
+
manifestTurn = write.catch(() => void 0);
|
|
38368
|
+
return write;
|
|
38369
|
+
};
|
|
38370
|
+
const installFromNpm = async (request) => {
|
|
38371
|
+
await mkdir11(toolsRoot, { recursive: true, mode: 448 });
|
|
38372
|
+
const npm = await resolveInstallerCommand({ platform });
|
|
38373
|
+
const args = [
|
|
38374
|
+
"install",
|
|
38375
|
+
"-g",
|
|
38376
|
+
"--prefix",
|
|
38377
|
+
toolsRoot,
|
|
38378
|
+
"--no-audit",
|
|
38379
|
+
"--no-fund",
|
|
38380
|
+
"--ignore-scripts",
|
|
38381
|
+
// `--` ends npm's flag parsing, so even a spec that slipped the pattern
|
|
38382
|
+
// could not become an npm option.
|
|
38383
|
+
"--",
|
|
38384
|
+
request.source
|
|
38385
|
+
];
|
|
38386
|
+
if (platform === "win32") {
|
|
38387
|
+
await runProcess(
|
|
38388
|
+
{ shellLine: windowsInstallerCommandLine(npm, args), cwd: toolsRoot },
|
|
38389
|
+
"the npm install"
|
|
38390
|
+
);
|
|
38391
|
+
} else {
|
|
38392
|
+
await runProcess({ command: npm, args, cwd: toolsRoot }, "the npm install");
|
|
38393
|
+
}
|
|
38394
|
+
};
|
|
38395
|
+
const installFromDownload = async (request) => {
|
|
38396
|
+
const response = await fetch(request.source, {
|
|
38397
|
+
redirect: "follow",
|
|
38398
|
+
signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS)
|
|
38399
|
+
});
|
|
38400
|
+
if (!response.ok) throw new Error(`the download answered HTTP ${response.status}`);
|
|
38401
|
+
if (response.url && !response.url.startsWith("https:")) {
|
|
38402
|
+
throw new Error("the download redirected off HTTPS and was not installed");
|
|
38403
|
+
}
|
|
38404
|
+
const declared = Number(response.headers.get("content-length") ?? "0");
|
|
38405
|
+
if (Number.isFinite(declared) && declared > MAX_DOWNLOAD_BYTES) {
|
|
38406
|
+
throw new Error("the download is larger than Zixt installs unattended");
|
|
38407
|
+
}
|
|
38408
|
+
if (!response.body) throw new Error("the download had no body");
|
|
38409
|
+
const reader = response.body.getReader();
|
|
38410
|
+
const chunks = [];
|
|
38411
|
+
let total = 0;
|
|
38412
|
+
for (; ; ) {
|
|
38413
|
+
const { done, value } = await reader.read();
|
|
38414
|
+
if (done) break;
|
|
38415
|
+
total += value.byteLength;
|
|
38416
|
+
if (total > MAX_DOWNLOAD_BYTES) {
|
|
38417
|
+
await reader.cancel().catch(() => void 0);
|
|
38418
|
+
throw new Error("the download is larger than Zixt installs unattended");
|
|
38419
|
+
}
|
|
38420
|
+
chunks.push(Buffer.from(value));
|
|
38421
|
+
}
|
|
38422
|
+
const body = Buffer.concat(chunks);
|
|
38423
|
+
if (body.length === 0) throw new Error("the download was empty");
|
|
38424
|
+
const digest = createHash6("sha256").update(body).digest("hex");
|
|
38425
|
+
if (request.sha256 && digest !== request.sha256.toLowerCase()) {
|
|
38426
|
+
throw new Error("the download did not match the expected sha256");
|
|
38427
|
+
}
|
|
38428
|
+
await placeDownloadedPayload(body, request, { toolsRoot, platform });
|
|
38429
|
+
};
|
|
38430
|
+
const perform = options.perform ?? (async (request) => {
|
|
38431
|
+
if (request.method === "npm") await installFromNpm(request);
|
|
38432
|
+
else await installFromDownload(request);
|
|
38433
|
+
const resolved = await resolveCommand(request.command);
|
|
38434
|
+
if (!resolved) {
|
|
38435
|
+
throw new Error(
|
|
38436
|
+
`the install finished but ${request.command} is still not runnable on this Machine`
|
|
38437
|
+
);
|
|
38438
|
+
}
|
|
38439
|
+
return resolved;
|
|
38440
|
+
});
|
|
38441
|
+
const attempt = async (request) => {
|
|
38442
|
+
options.onEvent?.({ command: request.command, state: "started" });
|
|
38443
|
+
try {
|
|
38444
|
+
const path = await perform(request, toolsRoot);
|
|
38445
|
+
if (!withinRoot(toolsRoot, path)) {
|
|
38446
|
+
throw new Error(
|
|
38447
|
+
`${request.command} resolves outside the Zixt folder and was not installed by Zixt`
|
|
38448
|
+
);
|
|
38449
|
+
}
|
|
38450
|
+
const record2 = {
|
|
38451
|
+
command: request.command,
|
|
38452
|
+
method: request.method,
|
|
38453
|
+
source: request.source,
|
|
38454
|
+
path,
|
|
38455
|
+
sha256: request.sha256 ? request.sha256.toLowerCase() : null,
|
|
38456
|
+
installedAt: new Date(now()).toISOString()
|
|
38457
|
+
};
|
|
38458
|
+
await recordInstall(record2).catch(() => void 0);
|
|
38459
|
+
options.onEvent?.({ command: request.command, state: "completed" });
|
|
38460
|
+
return { ok: true, record: record2 };
|
|
38461
|
+
} catch (error52) {
|
|
38462
|
+
const message = error52 instanceof Error ? error52.message : "unknown software install error";
|
|
38463
|
+
options.onEvent?.({ command: request.command, state: "failed", error: message });
|
|
38464
|
+
return { ok: false, error: message };
|
|
38465
|
+
}
|
|
38466
|
+
};
|
|
38467
|
+
return {
|
|
38468
|
+
toolsRoot,
|
|
38469
|
+
async probe(command) {
|
|
38470
|
+
if (!COMMAND_PATTERN.test(command)) {
|
|
38471
|
+
return { command, present: false, path: null, managed: false };
|
|
38472
|
+
}
|
|
38473
|
+
const path = await resolveCommand(command);
|
|
38474
|
+
return {
|
|
38475
|
+
command,
|
|
38476
|
+
present: path !== null,
|
|
38477
|
+
path,
|
|
38478
|
+
managed: path !== null && withinRoot(toolsRoot, path)
|
|
38479
|
+
};
|
|
38480
|
+
},
|
|
38481
|
+
async install(request) {
|
|
38482
|
+
const refusal = refuseSoftwareRequest(request);
|
|
38483
|
+
if (refusal) return { ok: false, error: refusal };
|
|
38484
|
+
const key = [
|
|
38485
|
+
request.command,
|
|
38486
|
+
request.method,
|
|
38487
|
+
request.source,
|
|
38488
|
+
request.sha256?.toLowerCase() ?? ""
|
|
38489
|
+
].join("\n");
|
|
38490
|
+
const running = inFlight.get(key);
|
|
38491
|
+
if (running) return running;
|
|
38492
|
+
const failure2 = failures.get(key);
|
|
38493
|
+
if (failure2 && now() - failure2.at < FAILURE_COOLDOWN_MS2) {
|
|
38494
|
+
return {
|
|
38495
|
+
ok: false,
|
|
38496
|
+
error: `This exact install already failed on this Machine: ${failure2.error}. Do not repeat it. Finish the work another way, or tell the person what is missing and the command they would run.`
|
|
38497
|
+
};
|
|
38498
|
+
}
|
|
38499
|
+
const started = (async () => {
|
|
38500
|
+
const result = await attempt(request);
|
|
38501
|
+
if (result.ok) failures.delete(key);
|
|
38502
|
+
else failures.set(key, { at: now(), error: result.error });
|
|
38503
|
+
return result;
|
|
38504
|
+
})();
|
|
38505
|
+
inFlight.set(key, started);
|
|
38506
|
+
try {
|
|
38507
|
+
return await started;
|
|
38508
|
+
} finally {
|
|
38509
|
+
inFlight.delete(key);
|
|
38510
|
+
}
|
|
38511
|
+
},
|
|
38512
|
+
async installed() {
|
|
38513
|
+
return readManifest();
|
|
38514
|
+
}
|
|
38515
|
+
};
|
|
38516
|
+
}
|
|
38517
|
+
|
|
38518
|
+
// src/runners/ask-user-server.ts
|
|
38099
38519
|
var CADENCE_PROPS = {
|
|
38100
38520
|
cadence_kind: {
|
|
38101
38521
|
type: "string",
|
|
@@ -38211,6 +38631,55 @@ var TOOLS = [
|
|
|
38211
38631
|
additionalProperties: false
|
|
38212
38632
|
}
|
|
38213
38633
|
},
|
|
38634
|
+
{
|
|
38635
|
+
name: "check_software",
|
|
38636
|
+
description: "Check whether a command is already available on this Machine before assuming it is missing. Returns whether it is present, where it resolved, and whether Zixt is the one that installed it.",
|
|
38637
|
+
inputSchema: {
|
|
38638
|
+
type: "object",
|
|
38639
|
+
properties: {
|
|
38640
|
+
command: {
|
|
38641
|
+
type: "string",
|
|
38642
|
+
description: "The plain command name, for example ffmpeg or gh. No path, no arguments."
|
|
38643
|
+
}
|
|
38644
|
+
},
|
|
38645
|
+
required: ["command"],
|
|
38646
|
+
additionalProperties: false
|
|
38647
|
+
}
|
|
38648
|
+
},
|
|
38649
|
+
{
|
|
38650
|
+
name: "install_software",
|
|
38651
|
+
description: "Install a command this Machine is missing, into the folder Zixt owns, after the person approves it. Prefer not to call this. Installing software on someone else\u2019s computer is friction, so first try to finish the work with what the Machine already has: a different tool, a project dependency, or another approach. Call it only when the missing command genuinely blocks the work or is clearly the right way to do it, and never speculatively. Zixt can install an npm package, or download and unpack a release from an HTTPS URL. It cannot use a system package manager such as apt, brew, winget, or choco, cannot ask for elevation or sudo, and cannot build from source. When the tool needs any of those, or the install looks complicated, do not call this: tell the person what is missing, why this work needs it, and the exact command they would run on their operating system. The person sees your reason and the exact source before anything runs, and may say no.",
|
|
38652
|
+
inputSchema: {
|
|
38653
|
+
type: "object",
|
|
38654
|
+
properties: {
|
|
38655
|
+
command: {
|
|
38656
|
+
type: "string",
|
|
38657
|
+
description: "The plain command name the work needs on PATH, for example ffmpeg."
|
|
38658
|
+
},
|
|
38659
|
+
reason: {
|
|
38660
|
+
type: "string",
|
|
38661
|
+
minLength: 1,
|
|
38662
|
+
maxLength: 500,
|
|
38663
|
+
description: "Why this work needs it, in one plain sentence. The person reads this before deciding."
|
|
38664
|
+
},
|
|
38665
|
+
method: {
|
|
38666
|
+
type: "string",
|
|
38667
|
+
enum: [...SOFTWARE_INSTALL_METHODS],
|
|
38668
|
+
description: "npm for an npm package; download for a release archive or binary."
|
|
38669
|
+
},
|
|
38670
|
+
source: {
|
|
38671
|
+
type: "string",
|
|
38672
|
+
description: "npm: the package name, optionally name@version with an exact version. download: the HTTPS URL of the release archive or binary."
|
|
38673
|
+
},
|
|
38674
|
+
sha256: {
|
|
38675
|
+
type: "string",
|
|
38676
|
+
description: "download only: the published SHA-256 of that file, when the project publishes one. Include it whenever you can."
|
|
38677
|
+
}
|
|
38678
|
+
},
|
|
38679
|
+
required: ["command", "reason", "method", "source"],
|
|
38680
|
+
additionalProperties: false
|
|
38681
|
+
}
|
|
38682
|
+
},
|
|
38214
38683
|
{
|
|
38215
38684
|
name: "publish_file",
|
|
38216
38685
|
description: "Snapshot a file you created in this Task workspace into Zixt so the user can download it. This only creates the Zixt file; it does not send it anywhere externally. The result returns an artifact_id.",
|
|
@@ -38996,6 +39465,57 @@ function createAskUserServer() {
|
|
|
38996
39465
|
}
|
|
38997
39466
|
return;
|
|
38998
39467
|
}
|
|
39468
|
+
if (surface.platform && (name === "check_software" || name === "install_software")) {
|
|
39469
|
+
if (!handlers.software) {
|
|
39470
|
+
toolText("Software checks are unavailable for this runner.", true);
|
|
39471
|
+
return;
|
|
39472
|
+
}
|
|
39473
|
+
const command = typeof args["command"] === "string" ? args["command"].trim() : "";
|
|
39474
|
+
if (!command) {
|
|
39475
|
+
toolText("missing required argument `command`", true);
|
|
39476
|
+
return;
|
|
39477
|
+
}
|
|
39478
|
+
try {
|
|
39479
|
+
if (name === "check_software") {
|
|
39480
|
+
toolText(JSON.stringify(await handlers.software.check(command), null, 2));
|
|
39481
|
+
return;
|
|
39482
|
+
}
|
|
39483
|
+
const reason = typeof args["reason"] === "string" ? args["reason"].trim() : "";
|
|
39484
|
+
const method = typeof args["method"] === "string" ? args["method"] : "";
|
|
39485
|
+
const source = typeof args["source"] === "string" ? args["source"].trim() : "";
|
|
39486
|
+
const sha256 = typeof args["sha256"] === "string" && args["sha256"] ? args["sha256"] : void 0;
|
|
39487
|
+
if (!reason) {
|
|
39488
|
+
toolText(
|
|
39489
|
+
"missing required argument `reason`: the person decides by reading why this work needs it",
|
|
39490
|
+
true
|
|
39491
|
+
);
|
|
39492
|
+
return;
|
|
39493
|
+
}
|
|
39494
|
+
if (!SOFTWARE_INSTALL_METHODS.includes(method)) {
|
|
39495
|
+
toolText(`\`method\` must be one of ${SOFTWARE_INSTALL_METHODS.join(", ")}.`, true);
|
|
39496
|
+
return;
|
|
39497
|
+
}
|
|
39498
|
+
const request = {
|
|
39499
|
+
command,
|
|
39500
|
+
method,
|
|
39501
|
+
source,
|
|
39502
|
+
sha256
|
|
39503
|
+
};
|
|
39504
|
+
const refusal = refuseSoftwareRequest(request);
|
|
39505
|
+
if (refusal) {
|
|
39506
|
+
toolText(refusal, true);
|
|
39507
|
+
return;
|
|
39508
|
+
}
|
|
39509
|
+
const outcome = await handlers.software.install({ ...request, reason });
|
|
39510
|
+
toolText(outcome.detail, !outcome.ok);
|
|
39511
|
+
} catch (err) {
|
|
39512
|
+
toolText(
|
|
39513
|
+
`The software request could not be completed: ${String(err instanceof Error ? err.message : err)}`,
|
|
39514
|
+
true
|
|
39515
|
+
);
|
|
39516
|
+
}
|
|
39517
|
+
return;
|
|
39518
|
+
}
|
|
38999
39519
|
if (surface.platform && name === "publish_file") {
|
|
39000
39520
|
if (!handlers.publishFile) {
|
|
39001
39521
|
toolText("file publishing is unavailable for this runner", true);
|
|
@@ -39111,6 +39631,7 @@ function createAskUserServer() {
|
|
|
39111
39631
|
agentOp: input.agentOp,
|
|
39112
39632
|
..."requestApproval" in input && input.requestApproval ? { requestApproval: input.requestApproval } : {},
|
|
39113
39633
|
..."publishFile" in input && input.publishFile ? { publishFile: input.publishFile } : {},
|
|
39634
|
+
..."software" in input && input.software ? { software: input.software } : {},
|
|
39114
39635
|
...toolPacks.length > 0 ? { toolPacks } : {}
|
|
39115
39636
|
};
|
|
39116
39637
|
const toolOwners = /* @__PURE__ */ new Map();
|
|
@@ -39263,7 +39784,10 @@ function buildRunnerEnv(input) {
|
|
|
39263
39784
|
env[name] = value;
|
|
39264
39785
|
}
|
|
39265
39786
|
}
|
|
39266
|
-
const searchPath =
|
|
39787
|
+
const searchPath = [
|
|
39788
|
+
sanitizeInheritedSearchPath(inheritedValue(input.inherited, "PATH")),
|
|
39789
|
+
...(input.softwareToolsPath ?? []).filter((entry) => isAbsolute14(entry))
|
|
39790
|
+
].filter((entry) => entry !== "").join(delimiter2);
|
|
39267
39791
|
const gitConfig = input.githubShell ? [
|
|
39268
39792
|
["credential.helper", ""],
|
|
39269
39793
|
["credential.helper", input.githubShell.gitCredentialHelper],
|
|
@@ -39330,9 +39854,9 @@ function buildRunnerEnv(input) {
|
|
|
39330
39854
|
// src/runners/github-shell-auth.ts
|
|
39331
39855
|
import { execFile } from "node:child_process";
|
|
39332
39856
|
import { randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
39333
|
-
import { chmod as
|
|
39857
|
+
import { chmod as chmod7, lstat as lstat10, mkdir as mkdir12, realpath as realpath7, writeFile as writeFile8 } from "node:fs/promises";
|
|
39334
39858
|
import { createServer as createServer3 } from "node:http";
|
|
39335
|
-
import { isAbsolute as isAbsolute15, join as
|
|
39859
|
+
import { isAbsolute as isAbsolute15, join as join18, relative as relative9 } from "node:path";
|
|
39336
39860
|
var MAX_REQUEST_BYTES2 = 16 * 1024;
|
|
39337
39861
|
var DIRECTORY_MODE4 = 448;
|
|
39338
39862
|
var PRIVATE_FILE_MODE = 384;
|
|
@@ -39696,7 +40220,7 @@ function activationCredential(grant, now = Date.now()) {
|
|
|
39696
40220
|
return expiresAt.getTime() <= now ? null : { accessToken: grant.accessToken, expiresAt };
|
|
39697
40221
|
}
|
|
39698
40222
|
function assertChildPath2(parent, child) {
|
|
39699
|
-
const path =
|
|
40223
|
+
const path = relative9(parent, child);
|
|
39700
40224
|
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") || isAbsolute15(path)) {
|
|
39701
40225
|
throw new Error("GitHub shell helper path escaped its private run directory");
|
|
39702
40226
|
}
|
|
@@ -39708,11 +40232,11 @@ function quoteForPosixShell(value) {
|
|
|
39708
40232
|
return quoteForGitShell2(value);
|
|
39709
40233
|
}
|
|
39710
40234
|
async function writePrivate(path, content, executable = false) {
|
|
39711
|
-
await
|
|
40235
|
+
await writeFile8(path, content, {
|
|
39712
40236
|
flag: "wx",
|
|
39713
40237
|
mode: executable ? EXECUTABLE_FILE_MODE : PRIVATE_FILE_MODE
|
|
39714
40238
|
});
|
|
39715
|
-
await
|
|
40239
|
+
await chmod7(path, executable ? EXECUTABLE_FILE_MODE : PRIVATE_FILE_MODE);
|
|
39716
40240
|
}
|
|
39717
40241
|
async function prepareHelpers(input) {
|
|
39718
40242
|
const rootEntry = await lstat10(input.runRoot);
|
|
@@ -39720,7 +40244,7 @@ async function prepareHelpers(input) {
|
|
|
39720
40244
|
throw new Error("GitHub shell authentication requires a private real run directory");
|
|
39721
40245
|
}
|
|
39722
40246
|
const runRoot = await realpath7(input.runRoot);
|
|
39723
|
-
const helperPath =
|
|
40247
|
+
const helperPath = join18(runRoot, "github-shell-git-credential.cjs");
|
|
39724
40248
|
assertChildPath2(runRoot, helperPath);
|
|
39725
40249
|
await writePrivate(helperPath, GIT_HELPER_SOURCE);
|
|
39726
40250
|
if (!input.ghExecutablePath) {
|
|
@@ -39731,14 +40255,14 @@ async function prepareHelpers(input) {
|
|
|
39731
40255
|
wrapperSourcePath: null
|
|
39732
40256
|
};
|
|
39733
40257
|
}
|
|
39734
|
-
const shellToolsDirectory =
|
|
40258
|
+
const shellToolsDirectory = join18(runRoot, "shell-tools");
|
|
39735
40259
|
assertChildPath2(runRoot, shellToolsDirectory);
|
|
39736
|
-
await
|
|
39737
|
-
await
|
|
39738
|
-
const wrapperSourcePath =
|
|
40260
|
+
await mkdir12(shellToolsDirectory, { mode: DIRECTORY_MODE4 });
|
|
40261
|
+
await chmod7(shellToolsDirectory, DIRECTORY_MODE4);
|
|
40262
|
+
const wrapperSourcePath = join18(runRoot, "github-shell-gh-wrapper.cjs");
|
|
39739
40263
|
assertChildPath2(runRoot, wrapperSourcePath);
|
|
39740
40264
|
await writePrivate(wrapperSourcePath, GH_WRAPPER_SOURCE);
|
|
39741
|
-
const wrapperPath =
|
|
40265
|
+
const wrapperPath = join18(shellToolsDirectory, process.platform === "win32" ? "gh.cmd" : "gh");
|
|
39742
40266
|
assertChildPath2(runRoot, wrapperPath);
|
|
39743
40267
|
const launcher = process.platform === "win32" ? `@"${process.execPath.replaceAll('"', '""')}" "${wrapperSourcePath.replaceAll('"', '""')}" %*\r
|
|
39744
40268
|
` : `#!/bin/sh
|
|
@@ -39961,7 +40485,7 @@ password=${credential.accessToken}
|
|
|
39961
40485
|
}
|
|
39962
40486
|
|
|
39963
40487
|
// src/runners/working-context.ts
|
|
39964
|
-
import { spawn as
|
|
40488
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
39965
40489
|
import { resolve as resolve9 } from "node:path";
|
|
39966
40490
|
var COMMAND_TIMEOUT_MS = 5e3;
|
|
39967
40491
|
var OUTPUT_LIMIT_BYTES = 128 * 1024;
|
|
@@ -40092,7 +40616,7 @@ async function stopWorkingContextCommand(child, childExited, options = {}) {
|
|
|
40092
40616
|
function run(command, args, cwd, env, signal) {
|
|
40093
40617
|
if (signal?.aborted) return Promise.resolve(null);
|
|
40094
40618
|
return new Promise((resolvePromise) => {
|
|
40095
|
-
const child =
|
|
40619
|
+
const child = spawn10(command, [...args], {
|
|
40096
40620
|
cwd,
|
|
40097
40621
|
env: { ...env, GIT_OPTIONAL_LOCKS: "0" },
|
|
40098
40622
|
detached: process.platform !== "win32",
|
|
@@ -40510,6 +41034,7 @@ var WorkingContextPullRequestCache = class {
|
|
|
40510
41034
|
};
|
|
40511
41035
|
|
|
40512
41036
|
// src/runners/cli-runner.ts
|
|
41037
|
+
var softwareInstaller = createSoftwareInstaller();
|
|
40513
41038
|
var PRIVATE_CLEANUP_FAILURE = "Private runner cleanup could not be completed. Restart the Zixt Host before accepting more work.";
|
|
40514
41039
|
var PROCESS_CLEANUP_FAILURE = "Runner process cleanup could not be confirmed. Restart the Zixt Host before accepting more work.";
|
|
40515
41040
|
var PROVIDER_CLEANUP_FAILURE = "Provider tool cleanup could not be completed. Restart the Zixt Host before accepting more work.";
|
|
@@ -40532,7 +41057,7 @@ async function settlesWithin(promise2, timeoutMs) {
|
|
|
40532
41057
|
}
|
|
40533
41058
|
}
|
|
40534
41059
|
function defaultRunnerWorkspaceRoot() {
|
|
40535
|
-
return
|
|
41060
|
+
return join19(homedir7(), ".zixt", "workspaces");
|
|
40536
41061
|
}
|
|
40537
41062
|
function defaultRunnerArtifactRoot() {
|
|
40538
41063
|
return defaultRunArtifactRoot();
|
|
@@ -40581,7 +41106,7 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
40581
41106
|
const prefixArgs = opts.commandPrefixArgs ?? [];
|
|
40582
41107
|
const maxWallTimeMs = opts.maxWallTimeMs;
|
|
40583
41108
|
const workspaceRoot = opts.workspaceRoot ?? defaultRunnerWorkspaceRoot();
|
|
40584
|
-
const artifactRoot = opts.artifactRoot ?? (opts.workspaceRoot === void 0 ? defaultRunnerArtifactRoot() :
|
|
41109
|
+
const artifactRoot = opts.artifactRoot ?? (opts.workspaceRoot === void 0 ? defaultRunnerArtifactRoot() : join19(dirname10(workspaceRoot), "run-artifacts"));
|
|
40585
41110
|
const runRegistryRoot2 = opts.runRegistryRoot ?? defaultRunRegistryRoot();
|
|
40586
41111
|
const createArtifacts = opts.createArtifacts ?? createRunArtifacts;
|
|
40587
41112
|
const toolPackRegistry2 = opts.toolPackRegistry ?? createDefaultToolPackRegistry();
|
|
@@ -40599,7 +41124,7 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
40599
41124
|
};
|
|
40600
41125
|
const askUserServer = createAskUserServer();
|
|
40601
41126
|
const windowsRoot = process.env.SystemRoot ?? process.env.WINDIR;
|
|
40602
|
-
const windowsComspecCandidate = process.platform === "win32" && windowsRoot ?
|
|
41127
|
+
const windowsComspecCandidate = process.platform === "win32" && windowsRoot ? join19(windowsRoot, "System32", "cmd.exe") : void 0;
|
|
40603
41128
|
let safetyFailure;
|
|
40604
41129
|
return async (task) => {
|
|
40605
41130
|
if (safetyFailure) {
|
|
@@ -40639,8 +41164,8 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
40639
41164
|
usage: { inputTokens: 0, outputTokens: 0 }
|
|
40640
41165
|
};
|
|
40641
41166
|
}
|
|
40642
|
-
const taskRoot =
|
|
40643
|
-
await
|
|
41167
|
+
const taskRoot = join19(workspaceRoot, task.agentId);
|
|
41168
|
+
await mkdir13(taskRoot, { recursive: true });
|
|
40644
41169
|
if (task.cancelledNow()) return cancelledBeforeRun();
|
|
40645
41170
|
const configuredWorkspace = task.spec.workspace;
|
|
40646
41171
|
let cwd = taskRoot;
|
|
@@ -40687,7 +41212,7 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
40687
41212
|
summaryEvidence: "host_observed"
|
|
40688
41213
|
};
|
|
40689
41214
|
}
|
|
40690
|
-
const runToken =
|
|
41215
|
+
const runToken = randomUUID12();
|
|
40691
41216
|
const artifacts = await createArtifacts({
|
|
40692
41217
|
root: artifactRoot,
|
|
40693
41218
|
agentId: task.agentId,
|
|
@@ -40743,7 +41268,8 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
40743
41268
|
runner: { type: adapter.type, auth: runner.auth },
|
|
40744
41269
|
gitIdentity: githubCommitIdentity(providerGrants),
|
|
40745
41270
|
isolation: artifacts,
|
|
40746
|
-
githubShell
|
|
41271
|
+
githubShell,
|
|
41272
|
+
softwareToolsPath: softwareSearchPathEntries(softwareInstaller.toolsRoot)
|
|
40747
41273
|
});
|
|
40748
41274
|
toolPacks = await toolPackRegistry2.createInstances(providerGrants, {
|
|
40749
41275
|
taskId: task.taskId,
|
|
@@ -40836,6 +41362,51 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
40836
41362
|
}
|
|
40837
41363
|
},
|
|
40838
41364
|
publishFile,
|
|
41365
|
+
// AG-4a. The person approves in the Task thread through the ordinary
|
|
41366
|
+
// approvals pipeline, so the wall clock pauses while they decide, and
|
|
41367
|
+
// a refusal is an answer the session can act on rather than a failure.
|
|
41368
|
+
software: {
|
|
41369
|
+
check: (command2) => softwareInstaller.probe(command2),
|
|
41370
|
+
install: async ({ reason, ...request }) => {
|
|
41371
|
+
pendingAsks++;
|
|
41372
|
+
let decision;
|
|
41373
|
+
try {
|
|
41374
|
+
decision = await task.requestApproval(
|
|
41375
|
+
"agent.question",
|
|
41376
|
+
`Install ${request.command} on this Machine: ${reason}`.slice(0, 500),
|
|
41377
|
+
JSON.stringify({
|
|
41378
|
+
command: request.command,
|
|
41379
|
+
reason,
|
|
41380
|
+
method: request.method,
|
|
41381
|
+
source: request.source,
|
|
41382
|
+
...request.sha256 ? { sha256: request.sha256 } : {},
|
|
41383
|
+
folder: softwareInstaller.toolsRoot
|
|
41384
|
+
}).slice(0, MAX_APPROVAL_PAYLOAD)
|
|
41385
|
+
);
|
|
41386
|
+
} finally {
|
|
41387
|
+
pendingAsks--;
|
|
41388
|
+
}
|
|
41389
|
+
if (!decision.approved) {
|
|
41390
|
+
return {
|
|
41391
|
+
ok: false,
|
|
41392
|
+
detail: decision.guidance ?? `The person did not approve installing ${request.command}. Do not ask again for this task. Finish the work another way, or explain what is blocked.`
|
|
41393
|
+
};
|
|
41394
|
+
}
|
|
41395
|
+
task.event("status", `Installing ${request.command} on this Machine`, {
|
|
41396
|
+
tool: "install_software"
|
|
41397
|
+
});
|
|
41398
|
+
const result2 = await softwareInstaller.install(request);
|
|
41399
|
+
task.event(
|
|
41400
|
+
"status",
|
|
41401
|
+
result2.ok ? `Installed ${request.command} on this Machine` : `Could not install ${request.command} on this Machine`,
|
|
41402
|
+
{ tool: "install_software" }
|
|
41403
|
+
);
|
|
41404
|
+
return result2.ok ? {
|
|
41405
|
+
ok: true,
|
|
41406
|
+
detail: `${request.command} is installed at ${result2.record.path} and is on your PATH. Continue the work.`
|
|
41407
|
+
} : { ok: false, detail: result2.error };
|
|
41408
|
+
}
|
|
41409
|
+
},
|
|
40839
41410
|
agentOp: (op) => task.agentOp(op),
|
|
40840
41411
|
// GitHub repository work belongs in the installed `git` and `gh`
|
|
40841
41412
|
// commands backed by GithubShellAuth. Do not advertise the bundled
|
|
@@ -41060,8 +41631,8 @@ ${attachmentSection}` : prompt;
|
|
|
41060
41631
|
}
|
|
41061
41632
|
comspec = resolvedWindowsComspec;
|
|
41062
41633
|
}
|
|
41063
|
-
const exitMarker = `__ZIXT_RUNNER_EXIT_${
|
|
41064
|
-
const guardianNonce =
|
|
41634
|
+
const exitMarker = `__ZIXT_RUNNER_EXIT_${randomUUID12()}__`;
|
|
41635
|
+
const guardianNonce = randomUUID12();
|
|
41065
41636
|
return runCliProcess({
|
|
41066
41637
|
command: resolvedCommand,
|
|
41067
41638
|
args,
|
|
@@ -41418,8 +41989,8 @@ function runCliProcess(options) {
|
|
|
41418
41989
|
}
|
|
41419
41990
|
return new Promise((resolve19) => {
|
|
41420
41991
|
const platform = options.platform ?? process.platform;
|
|
41421
|
-
const containmentGateNonce = options.guardian && platform === "win32" ?
|
|
41422
|
-
const child = options.guardian ?
|
|
41992
|
+
const containmentGateNonce = options.guardian && platform === "win32" ? randomUUID12() : void 0;
|
|
41993
|
+
const child = options.guardian ? spawn11(
|
|
41423
41994
|
options.guardian.nodeCommand,
|
|
41424
41995
|
[
|
|
41425
41996
|
options.guardian.scriptPath,
|
|
@@ -41707,12 +42278,12 @@ function runCliProcess(options) {
|
|
|
41707
42278
|
}
|
|
41708
42279
|
|
|
41709
42280
|
// src/runners/claude-code.ts
|
|
41710
|
-
import { randomUUID as
|
|
42281
|
+
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
41711
42282
|
|
|
41712
42283
|
// src/runners/runtime-observation.ts
|
|
41713
|
-
import { open as open6, readdir as
|
|
42284
|
+
import { open as open6, readdir as readdir6, realpath as realpath9 } from "node:fs/promises";
|
|
41714
42285
|
import { homedir as homedir8 } from "node:os";
|
|
41715
|
-
import { join as
|
|
42286
|
+
import { join as join20 } from "node:path";
|
|
41716
42287
|
var READ_WINDOW_BYTES = 1024 * 1024;
|
|
41717
42288
|
var CATALOG_TIMEOUT_MS = 15e3;
|
|
41718
42289
|
var CATALOG_OUTPUT_LIMIT_BYTES = 4 * 1024 * 1024;
|
|
@@ -41772,9 +42343,9 @@ function displayValue(value, maxLength) {
|
|
|
41772
42343
|
return trimmed;
|
|
41773
42344
|
}
|
|
41774
42345
|
function claudeTranscriptPath(input) {
|
|
41775
|
-
const configDir = input.env["CLAUDE_CONFIG_DIR"] ||
|
|
42346
|
+
const configDir = input.env["CLAUDE_CONFIG_DIR"] || join20(homeFrom(input.env), ".claude");
|
|
41776
42347
|
const slug = input.resolvedCwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
41777
|
-
return
|
|
42348
|
+
return join20(configDir, "projects", slug, `${input.sessionId}.jsonl`);
|
|
41778
42349
|
}
|
|
41779
42350
|
async function readClaudeSessionEffort(input) {
|
|
41780
42351
|
const resolvedCwd = await realpath9(input.cwd).catch(() => input.cwd);
|
|
@@ -41789,19 +42360,19 @@ async function readClaudeSessionEffort(input) {
|
|
|
41789
42360
|
return null;
|
|
41790
42361
|
}
|
|
41791
42362
|
async function newestDirectories(root, limit) {
|
|
41792
|
-
const entries = await
|
|
41793
|
-
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort((left, right) => right.localeCompare(left)).slice(0, limit).map((name) =>
|
|
42363
|
+
const entries = await readdir6(root, { withFileTypes: true }).catch(() => []);
|
|
42364
|
+
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort((left, right) => right.localeCompare(left)).slice(0, limit).map((name) => join20(root, name));
|
|
41794
42365
|
}
|
|
41795
42366
|
async function findCodexRolloutPath(input) {
|
|
41796
|
-
const codexHome = input.env["CODEX_HOME"] ||
|
|
41797
|
-
const sessions =
|
|
42367
|
+
const codexHome = input.env["CODEX_HOME"] || join20(homeFrom(input.env), ".codex");
|
|
42368
|
+
const sessions = join20(codexHome, "sessions");
|
|
41798
42369
|
const suffix = `-${input.threadId}.jsonl`;
|
|
41799
42370
|
for (const year of await newestDirectories(sessions, 2)) {
|
|
41800
42371
|
for (const month of await newestDirectories(year, 2)) {
|
|
41801
42372
|
for (const day of await newestDirectories(month, 3)) {
|
|
41802
|
-
const files = await
|
|
42373
|
+
const files = await readdir6(day).catch(() => []);
|
|
41803
42374
|
const match = files.find((name) => name.endsWith(suffix));
|
|
41804
|
-
if (match) return
|
|
42375
|
+
if (match) return join20(day, match);
|
|
41805
42376
|
}
|
|
41806
42377
|
}
|
|
41807
42378
|
}
|
|
@@ -41899,7 +42470,7 @@ var claudeCodeAdapter = {
|
|
|
41899
42470
|
input.gitDetected,
|
|
41900
42471
|
liveInput
|
|
41901
42472
|
);
|
|
41902
|
-
const sessionId = input.task.spec.sessionKey ??
|
|
42473
|
+
const sessionId = input.task.spec.sessionKey ?? randomUUID13();
|
|
41903
42474
|
const observeRuntime = createRuntimeReporter(input, sessionId);
|
|
41904
42475
|
return {
|
|
41905
42476
|
argsFor: (mode) => [
|
|
@@ -42028,7 +42599,7 @@ function createClaudeLiveParser(onStream, onSessionModel) {
|
|
|
42028
42599
|
...parser,
|
|
42029
42600
|
async start(writer, prompt) {
|
|
42030
42601
|
write = writer;
|
|
42031
|
-
await writer(input(
|
|
42602
|
+
await writer(input(randomUUID13(), prompt));
|
|
42032
42603
|
},
|
|
42033
42604
|
async steer(followUp) {
|
|
42034
42605
|
if (!write) return false;
|
|
@@ -42195,22 +42766,22 @@ function improveErrorMessage(error52) {
|
|
|
42195
42766
|
}
|
|
42196
42767
|
|
|
42197
42768
|
// src/runners/codex.ts
|
|
42198
|
-
import { mkdir as
|
|
42199
|
-
import { randomUUID as
|
|
42769
|
+
import { mkdir as mkdir14, readFile as readFile11, writeFile as writeFile9 } from "node:fs/promises";
|
|
42770
|
+
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
42200
42771
|
import { homedir as homedir9 } from "node:os";
|
|
42201
|
-
import { join as
|
|
42772
|
+
import { join as join21 } from "node:path";
|
|
42202
42773
|
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.";
|
|
42203
42774
|
function defaultCodexThreadIndexRoot() {
|
|
42204
|
-
return
|
|
42775
|
+
return join21(homedir9(), ".zixt", "codex-threads");
|
|
42205
42776
|
}
|
|
42206
42777
|
var SAFE_SEGMENT3 = /^[A-Za-z0-9_-]{1,200}$/;
|
|
42207
42778
|
function threadIndexPath(root, agentId, sessionKey) {
|
|
42208
42779
|
if (!SAFE_SEGMENT3.test(agentId) || !SAFE_SEGMENT3.test(sessionKey)) return null;
|
|
42209
|
-
return
|
|
42780
|
+
return join21(root, agentId, `${sessionKey}.json`);
|
|
42210
42781
|
}
|
|
42211
42782
|
async function readThreadId(path) {
|
|
42212
42783
|
try {
|
|
42213
|
-
const parsed = JSON.parse(await
|
|
42784
|
+
const parsed = JSON.parse(await readFile11(path, "utf8"));
|
|
42214
42785
|
return typeof parsed.threadId === "string" && /^[A-Za-z0-9-]{1,120}$/.test(parsed.threadId) ? parsed.threadId : null;
|
|
42215
42786
|
} catch {
|
|
42216
42787
|
return null;
|
|
@@ -42310,7 +42881,7 @@ ${value}` : value;
|
|
|
42310
42881
|
const recordedThreadId = indexPath ? await readThreadId(indexPath) : null;
|
|
42311
42882
|
const rememberThread = (threadId) => {
|
|
42312
42883
|
if (!indexPath) return;
|
|
42313
|
-
void
|
|
42884
|
+
void mkdir14(join21(threadIndexRoot, task.agentId), { recursive: true }).then(() => writeFile9(indexPath, JSON.stringify({ threadId }), "utf8")).catch(() => {
|
|
42314
42885
|
});
|
|
42315
42886
|
};
|
|
42316
42887
|
const observeRuntime = (threadId) => {
|
|
@@ -42414,7 +42985,7 @@ function createCodexAppServerParser(onStream, options) {
|
|
|
42414
42985
|
params: {
|
|
42415
42986
|
threadId,
|
|
42416
42987
|
input: [{ type: "text", text: prompt }],
|
|
42417
|
-
clientUserMessageId:
|
|
42988
|
+
clientUserMessageId: randomUUID14(),
|
|
42418
42989
|
...options.model ? { model: options.model } : {},
|
|
42419
42990
|
...options.effort ? { effort: options.effort } : {}
|
|
42420
42991
|
}
|
|
@@ -42773,7 +43344,7 @@ function improveCodexErrorMessage(error52) {
|
|
|
42773
43344
|
}
|
|
42774
43345
|
|
|
42775
43346
|
// src/runners/git-preflight.ts
|
|
42776
|
-
import { spawn as
|
|
43347
|
+
import { spawn as spawn12 } from "node:child_process";
|
|
42777
43348
|
import { realpath as realpath10 } from "node:fs/promises";
|
|
42778
43349
|
import { isAbsolute as isAbsolute17, resolve as resolve11 } from "node:path";
|
|
42779
43350
|
var OUTPUT_LIMIT = 8192;
|
|
@@ -42822,7 +43393,7 @@ async function preflightGit(options = {}) {
|
|
|
42822
43393
|
}
|
|
42823
43394
|
async function runVersionProbe(input) {
|
|
42824
43395
|
return new Promise((resolvePromise) => {
|
|
42825
|
-
const child =
|
|
43396
|
+
const child = spawn12(input.executablePath, input.args, {
|
|
42826
43397
|
cwd: input.cwd,
|
|
42827
43398
|
env: {
|
|
42828
43399
|
...process.env.SystemRoot ? { SystemRoot: process.env.SystemRoot } : {},
|
|
@@ -43044,16 +43615,16 @@ function run2(command, args) {
|
|
|
43044
43615
|
}
|
|
43045
43616
|
|
|
43046
43617
|
// src/linux-service.ts
|
|
43047
|
-
import { spawn as
|
|
43618
|
+
import { spawn as spawn13 } from "node:child_process";
|
|
43048
43619
|
import { constants as constants2 } from "node:fs";
|
|
43049
|
-
import { access as access5, chmod as
|
|
43620
|
+
import { access as access5, chmod as chmod9, mkdir as mkdir16, open as open7, rename as rename8, rm as rm12 } from "node:fs/promises";
|
|
43050
43621
|
import { homedir as homedir11, userInfo } from "node:os";
|
|
43051
|
-
import { basename as basename4, dirname as dirname11, join as
|
|
43622
|
+
import { basename as basename4, dirname as dirname11, join as join23, relative as relative10, resolve as resolve13, sep as sep7 } from "node:path";
|
|
43052
43623
|
|
|
43053
43624
|
// src/service-runtime.ts
|
|
43054
|
-
import { access as access4, chmod as
|
|
43625
|
+
import { access as access4, chmod as chmod8, copyFile, mkdir as mkdir15, rename as rename7, rm as rm11 } from "node:fs/promises";
|
|
43055
43626
|
import { homedir as homedir10 } from "node:os";
|
|
43056
|
-
import { join as
|
|
43627
|
+
import { join as join22, resolve as resolve12, sep as sep6 } from "node:path";
|
|
43057
43628
|
async function ensureDurableServiceNode(options = {}) {
|
|
43058
43629
|
const execPath = resolve12(options.execPath ?? process.execPath);
|
|
43059
43630
|
const home = options.home ?? homedir10();
|
|
@@ -43063,22 +43634,22 @@ async function ensureDurableServiceNode(options = {}) {
|
|
|
43063
43634
|
throw new Error("the Node runtime version is not a safe directory name");
|
|
43064
43635
|
}
|
|
43065
43636
|
const zixtRoot = resolve12(home, ".zixt");
|
|
43066
|
-
if (execPath === zixtRoot || execPath.startsWith(zixtRoot +
|
|
43067
|
-
const directory =
|
|
43068
|
-
const destination =
|
|
43637
|
+
if (execPath === zixtRoot || execPath.startsWith(zixtRoot + sep6)) return execPath;
|
|
43638
|
+
const directory = join22(zixtRoot, "runtime", `node-${version2}`);
|
|
43639
|
+
const destination = join22(directory, platform === "win32" ? "node.exe" : "node");
|
|
43069
43640
|
const alreadyCopied = await access4(destination).then(
|
|
43070
43641
|
() => true,
|
|
43071
43642
|
() => false
|
|
43072
43643
|
);
|
|
43073
43644
|
if (alreadyCopied) return destination;
|
|
43074
|
-
await
|
|
43645
|
+
await mkdir15(directory, { recursive: true, mode: 448 });
|
|
43075
43646
|
const temporary = `${destination}.${process.pid}.${crypto.randomUUID()}.tmp`;
|
|
43076
43647
|
try {
|
|
43077
43648
|
await copyFile(execPath, temporary);
|
|
43078
|
-
await
|
|
43079
|
-
await
|
|
43649
|
+
await chmod8(temporary, 493);
|
|
43650
|
+
await rename7(temporary, destination);
|
|
43080
43651
|
} catch (error52) {
|
|
43081
|
-
await
|
|
43652
|
+
await rm11(temporary, { force: true }).catch(() => void 0);
|
|
43082
43653
|
throw error52;
|
|
43083
43654
|
}
|
|
43084
43655
|
await options.syncDirectory?.(directory);
|
|
@@ -43114,7 +43685,7 @@ function boundedAppend(current, chunk) {
|
|
|
43114
43685
|
async function defaultRunCommand(command, args) {
|
|
43115
43686
|
const commandEnvironment3 = systemServiceCommandEnvironment();
|
|
43116
43687
|
return new Promise((resolve19) => {
|
|
43117
|
-
const child =
|
|
43688
|
+
const child = spawn13(command, [...args], {
|
|
43118
43689
|
stdio: ["ignore", "pipe", "pipe"],
|
|
43119
43690
|
env: commandEnvironment3,
|
|
43120
43691
|
windowsHide: true
|
|
@@ -43186,33 +43757,33 @@ async function defaultSyncDirectory(path) {
|
|
|
43186
43757
|
}
|
|
43187
43758
|
}
|
|
43188
43759
|
async function ensureDirectory(path, mode, syncDirectory8) {
|
|
43189
|
-
const firstCreated = await
|
|
43760
|
+
const firstCreated = await mkdir16(path, { recursive: true, mode });
|
|
43190
43761
|
if (!firstCreated) return;
|
|
43191
43762
|
const first = resolve13(firstCreated);
|
|
43192
43763
|
const target = resolve13(path);
|
|
43193
43764
|
await syncDirectory8(dirname11(first));
|
|
43194
43765
|
let current = first;
|
|
43195
|
-
const descendants =
|
|
43196
|
-
for (const part of descendants ? descendants.split(
|
|
43766
|
+
const descendants = relative10(first, target);
|
|
43767
|
+
for (const part of descendants ? descendants.split(sep7) : []) {
|
|
43197
43768
|
await syncDirectory8(current);
|
|
43198
|
-
current =
|
|
43769
|
+
current = join23(current, part);
|
|
43199
43770
|
}
|
|
43200
43771
|
}
|
|
43201
43772
|
async function replacePrivateFile(path, contents, mode, syncDirectory8) {
|
|
43202
43773
|
const parent = dirname11(path);
|
|
43203
43774
|
await ensureDirectory(parent, 448, syncDirectory8);
|
|
43204
|
-
const temporary =
|
|
43775
|
+
const temporary = join23(parent, `.${basename4(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
43205
43776
|
const handle = await open7(temporary, "wx", mode);
|
|
43206
43777
|
try {
|
|
43207
43778
|
await handle.writeFile(contents, "utf8");
|
|
43208
43779
|
await handle.sync();
|
|
43209
43780
|
await handle.close();
|
|
43210
|
-
await
|
|
43211
|
-
await
|
|
43781
|
+
await rename8(temporary, path);
|
|
43782
|
+
await chmod9(path, mode);
|
|
43212
43783
|
await syncDirectory8(parent);
|
|
43213
43784
|
} catch (error52) {
|
|
43214
43785
|
await handle.close().catch(() => void 0);
|
|
43215
|
-
await
|
|
43786
|
+
await rm12(temporary, { force: true }).catch(() => void 0);
|
|
43216
43787
|
throw error52;
|
|
43217
43788
|
}
|
|
43218
43789
|
}
|
|
@@ -43253,11 +43824,11 @@ async function installLinuxService(options) {
|
|
|
43253
43824
|
"command search path"
|
|
43254
43825
|
);
|
|
43255
43826
|
const cloudUrl = options.cloudUrl ? oneLine(options.cloudUrl, "Zixt Cloud address") : void 0;
|
|
43256
|
-
const xdgConfigHome = env.XDG_CONFIG_HOME ? oneLine(env.XDG_CONFIG_HOME, "Linux configuration path") :
|
|
43257
|
-
const configRoot = options.serviceConfigRoot ??
|
|
43258
|
-
const unitRoot = options.userUnitRoot ??
|
|
43259
|
-
const environmentPath =
|
|
43260
|
-
const unitPath =
|
|
43827
|
+
const xdgConfigHome = env.XDG_CONFIG_HOME ? oneLine(env.XDG_CONFIG_HOME, "Linux configuration path") : join23(home, ".config");
|
|
43828
|
+
const configRoot = options.serviceConfigRoot ?? join23(xdgConfigHome, "zixt");
|
|
43829
|
+
const unitRoot = options.userUnitRoot ?? join23(xdgConfigHome, "systemd", "user");
|
|
43830
|
+
const environmentPath = join23(configRoot, "host.env");
|
|
43831
|
+
const unitPath = join23(unitRoot, SERVICE_NAME);
|
|
43261
43832
|
const installVersion = options.installVersion ?? ((version2, onFailure) => installRelease(version2, onFailure ? { onFailure } : {}));
|
|
43262
43833
|
const activateVersion = options.activateVersion ?? (options.installVersion ? async (entry) => entry : activateInstalledRelease);
|
|
43263
43834
|
const resolveCommand = options.resolveCommand ?? defaultResolveCommand;
|
|
@@ -43297,7 +43868,7 @@ async function installLinuxService(options) {
|
|
|
43297
43868
|
}
|
|
43298
43869
|
}
|
|
43299
43870
|
await ensureDirectory(configRoot, 448, syncDirectory8);
|
|
43300
|
-
await
|
|
43871
|
+
await chmod9(configRoot, 448);
|
|
43301
43872
|
const serviceEnvironment = [
|
|
43302
43873
|
`ZIXT_HOST_TOKEN=${systemdEnvironmentValue(token2)}`,
|
|
43303
43874
|
...cloudUrl ? [`ZIXT_CLOUD_URL=${systemdEnvironmentValue(cloudUrl)}`] : [],
|
|
@@ -43385,11 +43956,11 @@ async function installLinuxService(options) {
|
|
|
43385
43956
|
}
|
|
43386
43957
|
|
|
43387
43958
|
// src/macos-service.ts
|
|
43388
|
-
import { spawn as
|
|
43959
|
+
import { spawn as spawn14 } from "node:child_process";
|
|
43389
43960
|
import { constants as constants3 } from "node:fs";
|
|
43390
|
-
import { access as access6, chmod as
|
|
43961
|
+
import { access as access6, chmod as chmod10, mkdir as mkdir17, open as open8, rename as rename9, rm as rm13 } from "node:fs/promises";
|
|
43391
43962
|
import { homedir as homedir12, userInfo as userInfo2 } from "node:os";
|
|
43392
|
-
import { basename as basename5, dirname as dirname12, join as
|
|
43963
|
+
import { basename as basename5, dirname as dirname12, join as join24, relative as relative11, resolve as resolve14, sep as sep8 } from "node:path";
|
|
43393
43964
|
var LAUNCH_AGENT_LABEL = "ai.zixt.host";
|
|
43394
43965
|
var SERVICE_STABILITY_DELAY_MS2 = 2e3;
|
|
43395
43966
|
var STATUS_WAIT_MS = 2e4;
|
|
@@ -43414,32 +43985,32 @@ async function syncDirectory4(path) {
|
|
|
43414
43985
|
}
|
|
43415
43986
|
}
|
|
43416
43987
|
async function ensureDirectory2(path, sync) {
|
|
43417
|
-
const firstCreated = await
|
|
43988
|
+
const firstCreated = await mkdir17(path, { recursive: true, mode: 448 });
|
|
43418
43989
|
if (!firstCreated) return;
|
|
43419
43990
|
const first = resolve14(firstCreated);
|
|
43420
43991
|
const target = resolve14(path);
|
|
43421
43992
|
await sync(dirname12(first));
|
|
43422
43993
|
let current = first;
|
|
43423
|
-
for (const part of
|
|
43994
|
+
for (const part of relative11(first, target).split(sep8).filter(Boolean)) {
|
|
43424
43995
|
await sync(current);
|
|
43425
|
-
current =
|
|
43996
|
+
current = join24(current, part);
|
|
43426
43997
|
}
|
|
43427
43998
|
}
|
|
43428
43999
|
async function replacePrivateFile2(path, contents, mode, sync) {
|
|
43429
44000
|
const parent = dirname12(path);
|
|
43430
44001
|
await ensureDirectory2(parent, sync);
|
|
43431
|
-
const temporary =
|
|
44002
|
+
const temporary = join24(parent, `.${basename5(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
43432
44003
|
const handle = await open8(temporary, "wx", mode);
|
|
43433
44004
|
try {
|
|
43434
44005
|
await handle.writeFile(contents, "utf8");
|
|
43435
44006
|
await handle.sync();
|
|
43436
44007
|
await handle.close();
|
|
43437
|
-
await
|
|
43438
|
-
await
|
|
44008
|
+
await rename9(temporary, path);
|
|
44009
|
+
await chmod10(path, mode);
|
|
43439
44010
|
await sync(parent);
|
|
43440
44011
|
} catch (error52) {
|
|
43441
44012
|
await handle.close().catch(() => void 0);
|
|
43442
|
-
await
|
|
44013
|
+
await rm13(temporary, { force: true }).catch(() => void 0);
|
|
43443
44014
|
throw error52;
|
|
43444
44015
|
}
|
|
43445
44016
|
}
|
|
@@ -43453,7 +44024,7 @@ function commandEnvironment(env) {
|
|
|
43453
44024
|
}
|
|
43454
44025
|
async function defaultRunCommand2(command, args, env) {
|
|
43455
44026
|
return new Promise((resolveResult) => {
|
|
43456
|
-
const child =
|
|
44027
|
+
const child = spawn14(command, [...args], {
|
|
43457
44028
|
stdio: ["ignore", "pipe", "pipe"],
|
|
43458
44029
|
env: commandEnvironment(env)
|
|
43459
44030
|
});
|
|
@@ -43525,14 +44096,14 @@ async function installMacosService(options) {
|
|
|
43525
44096
|
options.path ?? env.PATH ?? "/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin",
|
|
43526
44097
|
"command search path"
|
|
43527
44098
|
);
|
|
43528
|
-
const configRoot = options.configRoot ??
|
|
43529
|
-
const launchAgentsRoot = options.launchAgentsRoot ??
|
|
43530
|
-
const logRoot = options.logRoot ??
|
|
43531
|
-
const configPath =
|
|
43532
|
-
const launcherPath =
|
|
43533
|
-
const plistPath =
|
|
43534
|
-
const stdoutPath =
|
|
43535
|
-
const stderrPath =
|
|
44099
|
+
const configRoot = options.configRoot ?? join24(home, "Library", "Application Support", "Zixt");
|
|
44100
|
+
const launchAgentsRoot = options.launchAgentsRoot ?? join24(home, "Library", "LaunchAgents");
|
|
44101
|
+
const logRoot = options.logRoot ?? join24(home, "Library", "Logs", "Zixt");
|
|
44102
|
+
const configPath = join24(configRoot, "host.env");
|
|
44103
|
+
const launcherPath = join24(configRoot, "host-launcher.sh");
|
|
44104
|
+
const plistPath = join24(launchAgentsRoot, `${LAUNCH_AGENT_LABEL}.plist`);
|
|
44105
|
+
const stdoutPath = join24(logRoot, "host.log");
|
|
44106
|
+
const stderrPath = join24(logRoot, "host-error.log");
|
|
43536
44107
|
const installVersion = options.installVersion ?? ((version2, onFailure) => installRelease(version2, onFailure ? { onFailure } : {}));
|
|
43537
44108
|
const activateVersion = options.activateVersion ?? (options.installVersion ? async (entry) => entry : (entry) => activateInstalledRelease(entry));
|
|
43538
44109
|
const resolveCommand = options.resolveCommand ?? (async () => defaultResolveCommand2());
|
|
@@ -43555,7 +44126,7 @@ async function installMacosService(options) {
|
|
|
43555
44126
|
await ensureDirectory2(configRoot, sync);
|
|
43556
44127
|
await ensureDirectory2(launchAgentsRoot, sync);
|
|
43557
44128
|
await ensureDirectory2(logRoot, sync);
|
|
43558
|
-
await
|
|
44129
|
+
await chmod10(configRoot, 448);
|
|
43559
44130
|
const serviceEnvironment = [
|
|
43560
44131
|
`ZIXT_HOST_TOKEN=${shellValue(token2)}`,
|
|
43561
44132
|
...cloudUrl ? [`ZIXT_CLOUD_URL=${shellValue(cloudUrl)}`] : [],
|
|
@@ -43633,11 +44204,11 @@ async function installMacosService(options) {
|
|
|
43633
44204
|
}
|
|
43634
44205
|
|
|
43635
44206
|
// src/windows-service.ts
|
|
43636
|
-
import { spawn as
|
|
44207
|
+
import { spawn as spawn15 } from "node:child_process";
|
|
43637
44208
|
import { constants as constants4 } from "node:fs";
|
|
43638
|
-
import { access as access7, mkdir as
|
|
44209
|
+
import { access as access7, mkdir as mkdir18, open as open9, readFile as readFile12, rename as rename10, rm as rm14 } from "node:fs/promises";
|
|
43639
44210
|
import { homedir as homedir13 } from "node:os";
|
|
43640
|
-
import { basename as basename6, dirname as dirname13, isAbsolute as isAbsolute18, join as
|
|
44211
|
+
import { basename as basename6, dirname as dirname13, isAbsolute as isAbsolute18, join as join25, relative as relative12, resolve as resolve15, sep as sep9 } from "node:path";
|
|
43641
44212
|
var TASK_NAME = "Zixt Host";
|
|
43642
44213
|
var COMMAND_TIMEOUT_MS3 = 7e4;
|
|
43643
44214
|
var SERVICE_STABILITY_DELAY_MS3 = 2e3;
|
|
@@ -43663,31 +44234,31 @@ async function syncDirectory5(path) {
|
|
|
43663
44234
|
}
|
|
43664
44235
|
}
|
|
43665
44236
|
async function ensureDirectory3(path, sync) {
|
|
43666
|
-
const firstCreated = await
|
|
44237
|
+
const firstCreated = await mkdir18(path, { recursive: true, mode: 448 });
|
|
43667
44238
|
if (!firstCreated) return;
|
|
43668
44239
|
const first = resolve15(firstCreated);
|
|
43669
44240
|
const target = resolve15(path);
|
|
43670
44241
|
await sync(dirname13(first));
|
|
43671
44242
|
let current = first;
|
|
43672
|
-
for (const part of
|
|
44243
|
+
for (const part of relative12(first, target).split(sep9).filter(Boolean)) {
|
|
43673
44244
|
await sync(current);
|
|
43674
|
-
current =
|
|
44245
|
+
current = join25(current, part);
|
|
43675
44246
|
}
|
|
43676
44247
|
}
|
|
43677
44248
|
async function replacePrivateFile3(path, contents, sync, encoding = "utf8") {
|
|
43678
44249
|
const parent = dirname13(path);
|
|
43679
44250
|
await ensureDirectory3(parent, sync);
|
|
43680
|
-
const temporary =
|
|
44251
|
+
const temporary = join25(parent, `.${basename6(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
43681
44252
|
const handle = await open9(temporary, "wx", 384);
|
|
43682
44253
|
try {
|
|
43683
44254
|
await handle.writeFile(encoding === "utf16le" ? `\uFEFF${contents}` : contents, encoding);
|
|
43684
44255
|
await handle.sync();
|
|
43685
44256
|
await handle.close();
|
|
43686
|
-
await
|
|
44257
|
+
await rename10(temporary, path);
|
|
43687
44258
|
await sync(parent);
|
|
43688
44259
|
} catch (error52) {
|
|
43689
44260
|
await handle.close().catch(() => void 0);
|
|
43690
|
-
await
|
|
44261
|
+
await rm14(temporary, { force: true }).catch(() => void 0);
|
|
43691
44262
|
throw error52;
|
|
43692
44263
|
}
|
|
43693
44264
|
}
|
|
@@ -43698,7 +44269,7 @@ function commandEnvironment2(env) {
|
|
|
43698
44269
|
}
|
|
43699
44270
|
async function runChild(command, args, env, input) {
|
|
43700
44271
|
return new Promise((resolveResult) => {
|
|
43701
|
-
const child =
|
|
44272
|
+
const child = spawn15(command, [...args], {
|
|
43702
44273
|
stdio: [input === void 0 ? "ignore" : "pipe", "pipe", "pipe"],
|
|
43703
44274
|
env: commandEnvironment2(env),
|
|
43704
44275
|
windowsHide: true
|
|
@@ -43732,7 +44303,7 @@ async function runChild(command, args, env, input) {
|
|
|
43732
44303
|
async function defaultResolveCommand3(name, env) {
|
|
43733
44304
|
const root = env.SYSTEMROOT ?? env.WINDIR;
|
|
43734
44305
|
if (!root || !isAbsolute18(root)) return null;
|
|
43735
|
-
const candidate = name === "powershell" ?
|
|
44306
|
+
const candidate = name === "powershell" ? join25(root, "System32", "WindowsPowerShell", "v1.0", "powershell.exe") : join25(root, "System32", `${name}.exe`);
|
|
43736
44307
|
return access7(candidate, constants4.X_OK).then(
|
|
43737
44308
|
() => candidate,
|
|
43738
44309
|
() => null
|
|
@@ -43822,7 +44393,7 @@ exit $code
|
|
|
43822
44393
|
}
|
|
43823
44394
|
async function defaultObserveStatus(path, generation) {
|
|
43824
44395
|
try {
|
|
43825
|
-
const text = (await
|
|
44396
|
+
const text = (await readFile12(path, "utf8")).replace(/^\uFEFF/, "");
|
|
43826
44397
|
const value = JSON.parse(text);
|
|
43827
44398
|
if (value.schema !== 1 || value.generation !== generation || typeof value.pid !== "number" || !Number.isSafeInteger(value.pid) || value.pid <= 0) {
|
|
43828
44399
|
return null;
|
|
@@ -43883,12 +44454,12 @@ async function installWindowsService(options) {
|
|
|
43883
44454
|
const token2 = oneLine3(options.token, "pairing code");
|
|
43884
44455
|
const cloudUrl = options.cloudUrl ? oneLine3(options.cloudUrl, "Zixt Cloud address") : void 0;
|
|
43885
44456
|
const path = oneLine3(options.path ?? env.PATH ?? "", "command search path");
|
|
43886
|
-
const configRoot = options.configRoot ??
|
|
43887
|
-
const configPath =
|
|
43888
|
-
const launcherPath =
|
|
43889
|
-
const launchShimPath =
|
|
43890
|
-
const taskXmlPath =
|
|
43891
|
-
const statusPath =
|
|
44457
|
+
const configRoot = options.configRoot ?? join25(localAppData, "Zixt", "Host");
|
|
44458
|
+
const configPath = join25(configRoot, "host.json");
|
|
44459
|
+
const launcherPath = join25(configRoot, "host-launcher.ps1");
|
|
44460
|
+
const launchShimPath = join25(configRoot, "host-launch.vbs");
|
|
44461
|
+
const taskXmlPath = join25(configRoot, "host-task.xml");
|
|
44462
|
+
const statusPath = join25(configRoot, "host-status.json");
|
|
43892
44463
|
const installVersion = options.installVersion ?? ((version2, onFailure) => installRelease(version2, onFailure ? { onFailure } : {}));
|
|
43893
44464
|
const activateVersion = options.activateVersion ?? (options.installVersion ? async (entry) => entry : (entry) => activateInstalledRelease(entry));
|
|
43894
44465
|
const resolveCommand = options.resolveCommand ?? ((name) => defaultResolveCommand3(name, env));
|
|
@@ -43955,7 +44526,7 @@ async function installWindowsService(options) {
|
|
|
43955
44526
|
sync,
|
|
43956
44527
|
"utf16le"
|
|
43957
44528
|
);
|
|
43958
|
-
await
|
|
44529
|
+
await rm14(statusPath, { force: true });
|
|
43959
44530
|
const acl = await run3(icacls, [
|
|
43960
44531
|
configRoot,
|
|
43961
44532
|
"/inheritance:r",
|
|
@@ -44015,23 +44586,23 @@ async function installSystemService(options) {
|
|
|
44015
44586
|
}
|
|
44016
44587
|
|
|
44017
44588
|
// src/terminal-outcomes.ts
|
|
44018
|
-
import { chmod as
|
|
44589
|
+
import { chmod as chmod11, lstat as lstat12, mkdir as mkdir19, open as open10, readdir as readdir7, readFile as readFile13, rename as rename11, rm as rm15 } from "node:fs/promises";
|
|
44019
44590
|
import { homedir as homedir14 } from "node:os";
|
|
44020
|
-
import { dirname as dirname14, join as
|
|
44591
|
+
import { dirname as dirname14, join as join26, relative as relative13, resolve as resolve16, sep as sep10 } from "node:path";
|
|
44021
44592
|
var DIRECTORY_MODE5 = 448;
|
|
44022
44593
|
var FILE_MODE4 = 384;
|
|
44023
44594
|
var MAX_OUTCOME_BYTES = 4 * 1024 * 1024;
|
|
44024
44595
|
var HOST_DIRECTORY = /^hst_[0-9a-f]{32}$/;
|
|
44025
44596
|
var OUTCOME_FILE = /^(tsk_[0-9a-f]{32})\.([1-9][0-9]*)\.json$/;
|
|
44026
44597
|
function defaultTerminalOutcomeRoot() {
|
|
44027
|
-
return
|
|
44598
|
+
return join26(homedir14(), ".zixt", "terminal-outcomes");
|
|
44028
44599
|
}
|
|
44029
44600
|
function hostOutcomeRoot(root, hostId) {
|
|
44030
44601
|
if (!HOST_DIRECTORY.test(hostId)) throw new Error("terminal outcome Host identity is malformed");
|
|
44031
|
-
return
|
|
44602
|
+
return join26(root, hostId);
|
|
44032
44603
|
}
|
|
44033
44604
|
function outcomePath(root, hostId, taskId, epoch) {
|
|
44034
|
-
return
|
|
44605
|
+
return join26(hostOutcomeRoot(root, hostId), `${taskId}.${epoch}.json`);
|
|
44035
44606
|
}
|
|
44036
44607
|
async function syncDirectory6(root) {
|
|
44037
44608
|
if (process.platform === "win32") return;
|
|
@@ -44043,22 +44614,22 @@ async function syncDirectory6(root) {
|
|
|
44043
44614
|
}
|
|
44044
44615
|
}
|
|
44045
44616
|
async function requirePrivateRoot(root, sync = syncDirectory6) {
|
|
44046
|
-
const firstCreated = await
|
|
44617
|
+
const firstCreated = await mkdir19(root, { recursive: true, mode: DIRECTORY_MODE5 });
|
|
44047
44618
|
if (firstCreated) {
|
|
44048
44619
|
const first = resolve16(firstCreated);
|
|
44049
44620
|
const target = resolve16(root);
|
|
44050
44621
|
await sync(dirname14(first));
|
|
44051
44622
|
let current = first;
|
|
44052
|
-
for (const part of
|
|
44623
|
+
for (const part of relative13(first, target).split(sep10).filter(Boolean)) {
|
|
44053
44624
|
await sync(current);
|
|
44054
|
-
current =
|
|
44625
|
+
current = join26(current, part);
|
|
44055
44626
|
}
|
|
44056
44627
|
}
|
|
44057
44628
|
const stat4 = await lstat12(root);
|
|
44058
44629
|
if (stat4.isSymbolicLink() || !stat4.isDirectory()) {
|
|
44059
44630
|
throw new Error("terminal outcome journal root is not a trusted directory");
|
|
44060
44631
|
}
|
|
44061
|
-
await
|
|
44632
|
+
await chmod11(root, DIRECTORY_MODE5);
|
|
44062
44633
|
}
|
|
44063
44634
|
function parseCommittedOutcome(text, taskId, epoch) {
|
|
44064
44635
|
let json2;
|
|
@@ -44082,7 +44653,7 @@ async function recordTerminalOutcome(hostId, input, root = defaultTerminalOutcom
|
|
|
44082
44653
|
const destination = outcomePath(root, hostId, outcome.taskId, outcome.epoch);
|
|
44083
44654
|
try {
|
|
44084
44655
|
const existing = parseCommittedOutcome(
|
|
44085
|
-
await
|
|
44656
|
+
await readFile13(destination, { encoding: "utf8", flag: "r" }),
|
|
44086
44657
|
outcome.taskId,
|
|
44087
44658
|
outcome.epoch
|
|
44088
44659
|
);
|
|
@@ -44091,7 +44662,7 @@ async function recordTerminalOutcome(hostId, input, root = defaultTerminalOutcom
|
|
|
44091
44662
|
} catch (error52) {
|
|
44092
44663
|
if (error52.code !== "ENOENT") throw error52;
|
|
44093
44664
|
}
|
|
44094
|
-
const temporary =
|
|
44665
|
+
const temporary = join26(
|
|
44095
44666
|
scopedRoot,
|
|
44096
44667
|
`.${outcome.taskId}.${outcome.epoch}.${process.pid}.${Date.now()}.${outcome.resultId}.tmp`
|
|
44097
44668
|
);
|
|
@@ -44102,13 +44673,13 @@ async function recordTerminalOutcome(hostId, input, root = defaultTerminalOutcom
|
|
|
44102
44673
|
await handle.sync();
|
|
44103
44674
|
await handle.close();
|
|
44104
44675
|
handle = void 0;
|
|
44105
|
-
await
|
|
44676
|
+
await rename11(temporary, destination);
|
|
44106
44677
|
await sync(scopedRoot);
|
|
44107
44678
|
await sync(root);
|
|
44108
44679
|
} finally {
|
|
44109
44680
|
await handle?.close().catch(() => {
|
|
44110
44681
|
});
|
|
44111
|
-
await
|
|
44682
|
+
await rm15(temporary, { force: true }).catch(() => {
|
|
44112
44683
|
});
|
|
44113
44684
|
}
|
|
44114
44685
|
}
|
|
@@ -44123,8 +44694,8 @@ async function readTerminalOutcomesStrict(root = defaultTerminalOutcomeRoot()) {
|
|
|
44123
44694
|
if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
|
|
44124
44695
|
throw new Error("terminal outcome journal root is not a trusted directory");
|
|
44125
44696
|
}
|
|
44126
|
-
await
|
|
44127
|
-
const hostEntries = await
|
|
44697
|
+
await chmod11(root, DIRECTORY_MODE5);
|
|
44698
|
+
const hostEntries = await readdir7(root, { withFileTypes: true });
|
|
44128
44699
|
const outcomes = [];
|
|
44129
44700
|
const resultIds = /* @__PURE__ */ new Set();
|
|
44130
44701
|
for (const hostEntry of hostEntries) {
|
|
@@ -44136,21 +44707,21 @@ async function readTerminalOutcomesStrict(root = defaultTerminalOutcomeRoot()) {
|
|
|
44136
44707
|
if (scopedStat.isSymbolicLink() || !scopedStat.isDirectory()) {
|
|
44137
44708
|
throw new Error("terminal outcome Host scope is not a trusted directory");
|
|
44138
44709
|
}
|
|
44139
|
-
await
|
|
44140
|
-
const entries = await
|
|
44710
|
+
await chmod11(scopedRoot, DIRECTORY_MODE5);
|
|
44711
|
+
const entries = await readdir7(scopedRoot, { withFileTypes: true });
|
|
44141
44712
|
for (const entry of entries) {
|
|
44142
44713
|
if (!entry.name.endsWith(".json")) continue;
|
|
44143
44714
|
const match = OUTCOME_FILE.exec(entry.name);
|
|
44144
44715
|
if (!match || !entry.isFile() || entry.isSymbolicLink()) {
|
|
44145
44716
|
throw new Error("committed terminal outcome is not a trusted regular file");
|
|
44146
44717
|
}
|
|
44147
|
-
const path =
|
|
44718
|
+
const path = join26(scopedRoot, entry.name);
|
|
44148
44719
|
const stat4 = await lstat12(path);
|
|
44149
44720
|
if (!stat4.isFile() || stat4.isSymbolicLink() || stat4.size > MAX_OUTCOME_BYTES) {
|
|
44150
44721
|
throw new Error("committed terminal outcome is not a trusted regular file");
|
|
44151
44722
|
}
|
|
44152
44723
|
const outcome = parseCommittedOutcome(
|
|
44153
|
-
await
|
|
44724
|
+
await readFile13(path, "utf8"),
|
|
44154
44725
|
match[1],
|
|
44155
44726
|
Number(match[2])
|
|
44156
44727
|
);
|
|
@@ -44177,7 +44748,7 @@ async function forgetAcknowledgedTerminalOutcomes(refs, root = defaultTerminalOu
|
|
|
44177
44748
|
if (acknowledged.get(`${hostId}:${outcome.taskId}:${outcome.epoch}`) !== outcome.resultId) {
|
|
44178
44749
|
continue;
|
|
44179
44750
|
}
|
|
44180
|
-
await
|
|
44751
|
+
await rm15(outcomePath(root, hostId, outcome.taskId, outcome.epoch), { force: true });
|
|
44181
44752
|
changedHostRoots.add(hostOutcomeRoot(root, hostId));
|
|
44182
44753
|
}
|
|
44183
44754
|
for (const scopedRoot of changedHostRoots) await syncDirectory6(scopedRoot);
|
|
@@ -44189,22 +44760,22 @@ async function forgetSupersededTerminalOutcomes(hostId, taskId, epoch, root = de
|
|
|
44189
44760
|
if (scoped.hostId !== hostId) continue;
|
|
44190
44761
|
const { outcome } = scoped;
|
|
44191
44762
|
if (outcome.taskId !== taskId || outcome.epoch >= epoch) continue;
|
|
44192
|
-
await
|
|
44763
|
+
await rm15(outcomePath(root, hostId, outcome.taskId, outcome.epoch), { force: true });
|
|
44193
44764
|
removed = true;
|
|
44194
44765
|
}
|
|
44195
44766
|
if (removed) await syncDirectory6(hostOutcomeRoot(root, hostId));
|
|
44196
44767
|
}
|
|
44197
44768
|
|
|
44198
44769
|
// src/accepted-assignments.ts
|
|
44199
|
-
import { chmod as
|
|
44770
|
+
import { chmod as chmod12, lstat as lstat13, mkdir as mkdir20, open as open11, readdir as readdir8, rename as rename12, rm as rm16 } from "node:fs/promises";
|
|
44200
44771
|
import { homedir as homedir15 } from "node:os";
|
|
44201
|
-
import { dirname as dirname15, join as
|
|
44772
|
+
import { dirname as dirname15, join as join27, relative as relative14, resolve as resolve17, sep as sep11 } from "node:path";
|
|
44202
44773
|
var DIRECTORY_MODE6 = 448;
|
|
44203
44774
|
var FILE_MODE5 = 384;
|
|
44204
44775
|
var CLAIM_FILE = /^(tsk_[0-9a-f]{32})\.([1-9][0-9]*)\.json$/;
|
|
44205
44776
|
var TASK_ID = /^tsk_[0-9a-f]{32}$/;
|
|
44206
44777
|
function defaultAcceptedAssignmentRoot() {
|
|
44207
|
-
return
|
|
44778
|
+
return join27(homedir15(), ".zixt", "accepted-assignments");
|
|
44208
44779
|
}
|
|
44209
44780
|
async function syncDirectory7(root) {
|
|
44210
44781
|
if (process.platform === "win32") return;
|
|
@@ -44216,29 +44787,29 @@ async function syncDirectory7(root) {
|
|
|
44216
44787
|
}
|
|
44217
44788
|
}
|
|
44218
44789
|
async function requirePrivateRoot2(root, sync = syncDirectory7) {
|
|
44219
|
-
const firstCreated = await
|
|
44790
|
+
const firstCreated = await mkdir20(root, { recursive: true, mode: DIRECTORY_MODE6 });
|
|
44220
44791
|
if (firstCreated) {
|
|
44221
44792
|
const first = resolve17(firstCreated);
|
|
44222
44793
|
const target = resolve17(root);
|
|
44223
44794
|
await sync(dirname15(first));
|
|
44224
44795
|
let current = first;
|
|
44225
|
-
for (const part of
|
|
44796
|
+
for (const part of relative14(first, target).split(sep11).filter(Boolean)) {
|
|
44226
44797
|
await sync(current);
|
|
44227
|
-
current =
|
|
44798
|
+
current = join27(current, part);
|
|
44228
44799
|
}
|
|
44229
44800
|
}
|
|
44230
44801
|
const stat4 = await lstat13(root);
|
|
44231
44802
|
if (stat4.isSymbolicLink() || !stat4.isDirectory()) {
|
|
44232
44803
|
throw new Error("accepted assignment journal root is not a trusted directory");
|
|
44233
44804
|
}
|
|
44234
|
-
await
|
|
44805
|
+
await chmod12(root, DIRECTORY_MODE6);
|
|
44235
44806
|
}
|
|
44236
44807
|
function claimPath(root, taskId, epoch) {
|
|
44237
44808
|
if (!TASK_ID.test(taskId)) throw new Error("accepted assignment Task identity is malformed");
|
|
44238
44809
|
if (!Number.isSafeInteger(epoch) || epoch < 1) {
|
|
44239
44810
|
throw new Error("accepted assignment epoch is malformed");
|
|
44240
44811
|
}
|
|
44241
|
-
return
|
|
44812
|
+
return join27(root, `${taskId}.${epoch}.json`);
|
|
44242
44813
|
}
|
|
44243
44814
|
async function recordAcceptedAssignment(assignment, root = defaultAcceptedAssignmentRoot(), options = {}) {
|
|
44244
44815
|
const sync = options.syncDirectory ?? syncDirectory7;
|
|
@@ -44248,7 +44819,7 @@ async function recordAcceptedAssignment(assignment, root = defaultAcceptedAssign
|
|
|
44248
44819
|
} catch {
|
|
44249
44820
|
return false;
|
|
44250
44821
|
}
|
|
44251
|
-
const temporary =
|
|
44822
|
+
const temporary = join27(
|
|
44252
44823
|
root,
|
|
44253
44824
|
`.${assignment.taskId}.${assignment.epoch}.${process.pid}.${Date.now()}.tmp`
|
|
44254
44825
|
);
|
|
@@ -44260,7 +44831,7 @@ async function recordAcceptedAssignment(assignment, root = defaultAcceptedAssign
|
|
|
44260
44831
|
await handle.sync();
|
|
44261
44832
|
await handle.close();
|
|
44262
44833
|
handle = void 0;
|
|
44263
|
-
await
|
|
44834
|
+
await rename12(temporary, destination);
|
|
44264
44835
|
if (process.platform !== "win32") await sync(root);
|
|
44265
44836
|
return true;
|
|
44266
44837
|
} catch {
|
|
@@ -44268,7 +44839,7 @@ async function recordAcceptedAssignment(assignment, root = defaultAcceptedAssign
|
|
|
44268
44839
|
} finally {
|
|
44269
44840
|
await handle?.close().catch(() => {
|
|
44270
44841
|
});
|
|
44271
|
-
await
|
|
44842
|
+
await rm16(temporary, { force: true }).catch(() => {
|
|
44272
44843
|
});
|
|
44273
44844
|
}
|
|
44274
44845
|
}
|
|
@@ -44283,9 +44854,9 @@ async function recoverAcceptedAssignments(root = defaultAcceptedAssignmentRoot()
|
|
|
44283
44854
|
if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) {
|
|
44284
44855
|
throw new Error("accepted assignment journal root is not a trusted directory");
|
|
44285
44856
|
}
|
|
44286
|
-
await
|
|
44857
|
+
await chmod12(root, DIRECTORY_MODE6);
|
|
44287
44858
|
const claims = [];
|
|
44288
|
-
for (const entry of await
|
|
44859
|
+
for (const entry of await readdir8(root, { withFileTypes: true })) {
|
|
44289
44860
|
if (!entry.isFile()) continue;
|
|
44290
44861
|
const match = CLAIM_FILE.exec(entry.name);
|
|
44291
44862
|
if (!match) continue;
|
|
@@ -44302,7 +44873,7 @@ async function forgetAcceptedAssignment(assignment, root = defaultAcceptedAssign
|
|
|
44302
44873
|
} catch {
|
|
44303
44874
|
return;
|
|
44304
44875
|
}
|
|
44305
|
-
await
|
|
44876
|
+
await rm16(path, { force: true }).catch(() => {
|
|
44306
44877
|
});
|
|
44307
44878
|
}
|
|
44308
44879
|
async function forgetAcknowledgedAcceptedAssignments(assignments, root = defaultAcceptedAssignmentRoot()) {
|
|
@@ -44310,9 +44881,9 @@ async function forgetAcknowledgedAcceptedAssignments(assignments, root = default
|
|
|
44310
44881
|
}
|
|
44311
44882
|
|
|
44312
44883
|
// src/local-observability.ts
|
|
44313
|
-
import { appendFile, mkdir as
|
|
44884
|
+
import { appendFile, mkdir as mkdir21, open as open12, readdir as readdir9, rename as rename13, rm as rm17, stat as stat3 } from "node:fs/promises";
|
|
44314
44885
|
import { homedir as homedir16 } from "node:os";
|
|
44315
|
-
import { basename as basename7, dirname as dirname16, join as
|
|
44886
|
+
import { basename as basename7, dirname as dirname16, join as join28 } from "node:path";
|
|
44316
44887
|
|
|
44317
44888
|
// src/logger.ts
|
|
44318
44889
|
var ANSI = {
|
|
@@ -44424,11 +44995,11 @@ var LOCAL_STATUS_FILE = "status.json";
|
|
|
44424
44995
|
var LOCAL_REQUESTS_DIR = "requests";
|
|
44425
44996
|
var DEFAULT_CONSOLE_ROTATE_BYTES = 2 * 1024 * 1024;
|
|
44426
44997
|
function defaultLocalObservabilityRoot() {
|
|
44427
|
-
return
|
|
44998
|
+
return join28(homedir16(), ".zixt", "observability");
|
|
44428
44999
|
}
|
|
44429
45000
|
function createLocalConsoleSink(options = {}) {
|
|
44430
45001
|
const root = options.root ?? defaultLocalObservabilityRoot();
|
|
44431
|
-
const consolePath =
|
|
45002
|
+
const consolePath = join28(root, LOCAL_CONSOLE_FILE);
|
|
44432
45003
|
const rotateBytes = options.rotateBytes ?? DEFAULT_CONSOLE_ROTATE_BYTES;
|
|
44433
45004
|
let disabled = false;
|
|
44434
45005
|
let prepared = false;
|
|
@@ -44438,7 +45009,7 @@ function createLocalConsoleSink(options = {}) {
|
|
|
44438
45009
|
if (disabled) return;
|
|
44439
45010
|
try {
|
|
44440
45011
|
if (!prepared) {
|
|
44441
|
-
await
|
|
45012
|
+
await mkdir21(root, { recursive: true, mode: 448 });
|
|
44442
45013
|
approximateBytes = await stat3(consolePath).then(
|
|
44443
45014
|
(existing) => existing.size,
|
|
44444
45015
|
() => 0
|
|
@@ -44446,8 +45017,8 @@ function createLocalConsoleSink(options = {}) {
|
|
|
44446
45017
|
prepared = true;
|
|
44447
45018
|
}
|
|
44448
45019
|
if (approximateBytes >= rotateBytes) {
|
|
44449
|
-
await
|
|
44450
|
-
await
|
|
45020
|
+
await rm17(join28(root, LOCAL_CONSOLE_PREVIOUS_FILE), { force: true });
|
|
45021
|
+
await rename13(consolePath, join28(root, LOCAL_CONSOLE_PREVIOUS_FILE)).catch(
|
|
44451
45022
|
(error52) => {
|
|
44452
45023
|
if (error52.code !== "ENOENT") throw error52;
|
|
44453
45024
|
}
|
|
@@ -44478,11 +45049,11 @@ function createLocalConsoleSink(options = {}) {
|
|
|
44478
45049
|
};
|
|
44479
45050
|
}
|
|
44480
45051
|
async function consumeRunnerInstallRequests(root = defaultLocalObservabilityRoot()) {
|
|
44481
|
-
const directory =
|
|
45052
|
+
const directory = join28(root, LOCAL_REQUESTS_DIR);
|
|
44482
45053
|
const requested = /* @__PURE__ */ new Set();
|
|
44483
45054
|
let names;
|
|
44484
45055
|
try {
|
|
44485
|
-
names = await
|
|
45056
|
+
names = await readdir9(directory);
|
|
44486
45057
|
} catch {
|
|
44487
45058
|
return requested;
|
|
44488
45059
|
}
|
|
@@ -44490,7 +45061,7 @@ async function consumeRunnerInstallRequests(root = defaultLocalObservabilityRoot
|
|
|
44490
45061
|
const name = `install-runner-${type}.json`;
|
|
44491
45062
|
if (!names.includes(name)) continue;
|
|
44492
45063
|
try {
|
|
44493
|
-
await
|
|
45064
|
+
await rm17(join28(directory, name), { force: true });
|
|
44494
45065
|
requested.add(type);
|
|
44495
45066
|
} catch {
|
|
44496
45067
|
}
|
|
@@ -44498,13 +45069,13 @@ async function consumeRunnerInstallRequests(root = defaultLocalObservabilityRoot
|
|
|
44498
45069
|
return requested;
|
|
44499
45070
|
}
|
|
44500
45071
|
async function writeLocalStatus(status, root = defaultLocalObservabilityRoot()) {
|
|
44501
|
-
const destination =
|
|
44502
|
-
const temporary =
|
|
45072
|
+
const destination = join28(root, LOCAL_STATUS_FILE);
|
|
45073
|
+
const temporary = join28(
|
|
44503
45074
|
dirname16(destination),
|
|
44504
45075
|
`.${basename7(destination)}.${process.pid}.${crypto.randomUUID()}.tmp`
|
|
44505
45076
|
);
|
|
44506
45077
|
try {
|
|
44507
|
-
await
|
|
45078
|
+
await mkdir21(root, { recursive: true, mode: 448 });
|
|
44508
45079
|
const handle = await open12(temporary, "wx", 384);
|
|
44509
45080
|
try {
|
|
44510
45081
|
await handle.writeFile(`${JSON.stringify(status)}
|
|
@@ -44512,14 +45083,14 @@ async function writeLocalStatus(status, root = defaultLocalObservabilityRoot())
|
|
|
44512
45083
|
} finally {
|
|
44513
45084
|
await handle.close();
|
|
44514
45085
|
}
|
|
44515
|
-
await
|
|
45086
|
+
await rename13(temporary, destination);
|
|
44516
45087
|
} catch {
|
|
44517
|
-
await
|
|
45088
|
+
await rm17(temporary, { force: true }).catch(() => void 0);
|
|
44518
45089
|
}
|
|
44519
45090
|
}
|
|
44520
45091
|
|
|
44521
45092
|
// src/demo-state.ts
|
|
44522
|
-
import { isAbsolute as isAbsolute19, join as
|
|
45093
|
+
import { isAbsolute as isAbsolute19, join as join29, parse as parse3, resolve as resolve18 } from "node:path";
|
|
44523
45094
|
var DEMO_STATE_ROOT_ENV = "ZIXT_DEMO_STATE_ROOT";
|
|
44524
45095
|
function resolveDemoHostStatePaths(env = process.env) {
|
|
44525
45096
|
const configured = env.ZIXT_RUNNER === "demo" ? env[DEMO_STATE_ROOT_ENV] : void 0;
|
|
@@ -44529,14 +45100,14 @@ function resolveDemoHostStatePaths(env = process.env) {
|
|
|
44529
45100
|
throw new Error(`${DEMO_STATE_ROOT_ENV} must be a dedicated absolute directory`);
|
|
44530
45101
|
}
|
|
44531
45102
|
return {
|
|
44532
|
-
runRegistryRoot:
|
|
44533
|
-
terminalOutcomeRoot:
|
|
44534
|
-
acceptedAssignmentRoot:
|
|
44535
|
-
runArtifactRoot:
|
|
44536
|
-
browserProfileRoot:
|
|
44537
|
-
runnerWorkspaceRoot:
|
|
44538
|
-
codexThreadIndexRoot:
|
|
44539
|
-
localObservabilityRoot:
|
|
45103
|
+
runRegistryRoot: join29(root, "run-registry"),
|
|
45104
|
+
terminalOutcomeRoot: join29(root, "terminal-outcomes"),
|
|
45105
|
+
acceptedAssignmentRoot: join29(root, "accepted-assignments"),
|
|
45106
|
+
runArtifactRoot: join29(root, "run-artifacts"),
|
|
45107
|
+
browserProfileRoot: join29(root, "browser-profiles"),
|
|
45108
|
+
runnerWorkspaceRoot: join29(root, "workspaces"),
|
|
45109
|
+
codexThreadIndexRoot: join29(root, "codex-threads"),
|
|
45110
|
+
localObservabilityRoot: join29(root, "local-observability")
|
|
44540
45111
|
};
|
|
44541
45112
|
}
|
|
44542
45113
|
|