@zixt/host 0.0.80 → 0.0.82
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 +676 -328
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -16,22 +16,22 @@ import { fstatSync } from "node:fs";
|
|
|
16
16
|
import {
|
|
17
17
|
access as access2,
|
|
18
18
|
lstat as lstat5,
|
|
19
|
-
mkdir as
|
|
19
|
+
mkdir as mkdir5,
|
|
20
20
|
open as open4,
|
|
21
|
-
readFile as
|
|
21
|
+
readFile as readFile7,
|
|
22
22
|
readlink,
|
|
23
|
-
readdir as
|
|
23
|
+
readdir as readdir4,
|
|
24
24
|
rename as rename3,
|
|
25
|
-
rm as
|
|
25
|
+
rm as rm5,
|
|
26
26
|
symlink
|
|
27
27
|
} from "node:fs/promises";
|
|
28
|
-
import { basename as basename3, dirname as dirname4, isAbsolute as
|
|
29
|
-
import { homedir as
|
|
28
|
+
import { basename as basename3, dirname as dirname4, isAbsolute as isAbsolute9, join as join8, relative as relative4, resolve as resolve5, sep as sep4 } from "node:path";
|
|
29
|
+
import { homedir as homedir3 } from "node:os";
|
|
30
30
|
|
|
31
31
|
// package.json
|
|
32
32
|
var package_default = {
|
|
33
33
|
name: "@zixt/host",
|
|
34
|
-
version: "0.0.
|
|
34
|
+
version: "0.0.82",
|
|
35
35
|
type: "module",
|
|
36
36
|
exports: {
|
|
37
37
|
".": "./src/client.ts",
|
|
@@ -14661,6 +14661,8 @@ var ID_PREFIXES = {
|
|
|
14661
14661
|
conversationEvent: "cve",
|
|
14662
14662
|
/** One human-confirmed integration action prepared by the Manager. */
|
|
14663
14663
|
managerIntegrationAction: "mia",
|
|
14664
|
+
/** One Manager-prepared secure Credential entry card (MG-17). */
|
|
14665
|
+
managerCredentialRequest: "mcr",
|
|
14664
14666
|
/** One Manager inference call's token-metering row (MG-8). */
|
|
14665
14667
|
managerUsage: "mgu",
|
|
14666
14668
|
/** One ordered Manager reply awaiting Slack delivery. */
|
|
@@ -14712,6 +14714,10 @@ var ManagerIntegrationActionId = idSchema(
|
|
|
14712
14714
|
ID_PREFIXES.managerIntegrationAction,
|
|
14713
14715
|
"Manager integration action id"
|
|
14714
14716
|
);
|
|
14717
|
+
var ManagerCredentialRequestId = idSchema(
|
|
14718
|
+
ID_PREFIXES.managerCredentialRequest,
|
|
14719
|
+
"Manager credential request id"
|
|
14720
|
+
);
|
|
14715
14721
|
var ManagerEmailInboxId = idSchema(
|
|
14716
14722
|
ID_PREFIXES.managerEmailInbox,
|
|
14717
14723
|
"Manager email inbox id"
|
|
@@ -18331,7 +18337,9 @@ var ConversationEventProjection = external_exports.discriminatedUnion("kind", [
|
|
|
18331
18337
|
taskId: TaskId.nullable(),
|
|
18332
18338
|
agentId: AgentId.nullable(),
|
|
18333
18339
|
/** Present only for a confirmation card; OAuth authority never appears here. */
|
|
18334
|
-
integrationActionId: ManagerIntegrationActionId.nullable().optional()
|
|
18340
|
+
integrationActionId: ManagerIntegrationActionId.nullable().optional(),
|
|
18341
|
+
/** Present only for a secure Credential entry card; never a value (MG-17). */
|
|
18342
|
+
credentialRequestId: ManagerCredentialRequestId.nullable().optional()
|
|
18335
18343
|
}).strict(),
|
|
18336
18344
|
/** A mirrored child-Task event: what the teammate wrote or became. */
|
|
18337
18345
|
external_exports.object({
|
|
@@ -18397,6 +18405,48 @@ var ManagerIntegrationActionResponse = external_exports.object({
|
|
|
18397
18405
|
action: ManagerIntegrationActionProjection,
|
|
18398
18406
|
oauth: ManagerIntegrationOAuthStart.nullable()
|
|
18399
18407
|
}).strict();
|
|
18408
|
+
var ManagerCredentialRequestStatus = external_exports.enum([
|
|
18409
|
+
"awaiting_entry",
|
|
18410
|
+
"storing",
|
|
18411
|
+
"stored",
|
|
18412
|
+
"cancelled",
|
|
18413
|
+
"expired",
|
|
18414
|
+
"failed"
|
|
18415
|
+
]);
|
|
18416
|
+
var ManagerCredentialRequestProjection = external_exports.object({
|
|
18417
|
+
id: ManagerCredentialRequestId,
|
|
18418
|
+
conversationId: ConversationId,
|
|
18419
|
+
/** The Credential name, exactly as it will appear in Credentials. */
|
|
18420
|
+
name: external_exports.string().min(1).max(120),
|
|
18421
|
+
/** `env` reaches a Task as an environment variable; `web_login` fills a sign-in form. */
|
|
18422
|
+
kind: external_exports.enum(["env", "web_login"]),
|
|
18423
|
+
/** Saved as the Credential's description so teammates know what they hold. */
|
|
18424
|
+
purpose: external_exports.string().max(500).nullable(),
|
|
18425
|
+
scope: external_exports.enum(["organization", "teammates"]),
|
|
18426
|
+
/** Named teammates for a teammate-scoped Credential; empty for organization scope. */
|
|
18427
|
+
teammates: external_exports.array(external_exports.object({ agentId: AgentId, name: external_exports.string().min(1).max(200) }).strict()).max(100),
|
|
18428
|
+
/** Suggested sign-in page for a website login; the person can correct it. */
|
|
18429
|
+
loginUrl: external_exports.url().max(2e3).nullable(),
|
|
18430
|
+
status: ManagerCredentialRequestStatus,
|
|
18431
|
+
outcome: external_exports.string().max(1e3).nullable(),
|
|
18432
|
+
createdAt: external_exports.string(),
|
|
18433
|
+
expiresAt: external_exports.string()
|
|
18434
|
+
}).strict();
|
|
18435
|
+
var SubmitManagerCredentialRequest = external_exports.object({
|
|
18436
|
+
requestId: external_exports.uuid(),
|
|
18437
|
+
/** env kind. */
|
|
18438
|
+
value: external_exports.string().min(1).max(1e4).optional(),
|
|
18439
|
+
/** web_login kind. */
|
|
18440
|
+
webLogin: WebLoginValue.optional()
|
|
18441
|
+
}).strict().superRefine((request, ctx) => {
|
|
18442
|
+
if (request.value === void 0 === (request.webLogin === void 0)) {
|
|
18443
|
+
ctx.addIssue({
|
|
18444
|
+
code: "custom",
|
|
18445
|
+
path: ["value"],
|
|
18446
|
+
message: "submit exactly one of value or webLogin, matching the requested kind"
|
|
18447
|
+
});
|
|
18448
|
+
}
|
|
18449
|
+
});
|
|
18400
18450
|
var NonEmptyTaskRunnerSelection = TaskRunnerSelection.refine(
|
|
18401
18451
|
(selection) => selection.type !== void 0 || selection.model !== void 0 || selection.effort !== void 0,
|
|
18402
18452
|
"choose at least one runtime preference"
|
|
@@ -20892,6 +20942,7 @@ var WORKER_WATCHDOG_FILE_ENV = "ZIXT_HOST_WORKER_WATCHDOG_FILE";
|
|
|
20892
20942
|
var WORKER_WATCHDOG_BOUNDARY_PID_ENV = "ZIXT_MANAGED_PROCESS_BOUNDARY_PID";
|
|
20893
20943
|
var WORKER_WATCHDOG_MESSAGE = "zixt.host.worker-heartbeat.v1";
|
|
20894
20944
|
var WORKER_READINESS_MESSAGE = "zixt.host.worker-readiness.v1";
|
|
20945
|
+
var WORKER_SHUTDOWN_MESSAGE = "zixt.host.worker-shutdown.v1";
|
|
20895
20946
|
var WORKER_HEARTBEAT_MS = 1e3;
|
|
20896
20947
|
var SAFE_NONCE = /^[A-Za-z0-9_-]{16,200}$/;
|
|
20897
20948
|
function createWorkerWatchdogLaunch(ownershipDirectory) {
|
|
@@ -20917,10 +20968,16 @@ function isWorkerReadinessMilestone(value, launch, pid) {
|
|
|
20917
20968
|
const message = value;
|
|
20918
20969
|
return message.type === WORKER_READINESS_MESSAGE && message.nonce === launch.nonce && typeof message.pid === "number" && Number.isSafeInteger(message.pid) && message.pid === pid && typeof message.sequence === "number" && Number.isSafeInteger(message.sequence) && message.sequence > 0 && typeof message.heartbeatSequence === "number" && Number.isSafeInteger(message.heartbeatSequence) && message.heartbeatSequence > 0;
|
|
20919
20970
|
}
|
|
20971
|
+
function isWorkerShutdownIntent(value, launch, pid) {
|
|
20972
|
+
if (!value || typeof value !== "object") return false;
|
|
20973
|
+
const message = value;
|
|
20974
|
+
return message.type === WORKER_SHUTDOWN_MESSAGE && message.nonce === launch.nonce && typeof message.pid === "number" && Number.isSafeInteger(message.pid) && message.pid === pid && typeof message.sequence === "number" && Number.isSafeInteger(message.sequence) && message.sequence > 0 && typeof message.exitCode === "number" && Number.isSafeInteger(message.exitCode) && message.exitCode >= 0 && message.exitCode <= 255 && typeof message.activeTasks === "number" && Number.isSafeInteger(message.activeTasks) && message.activeTasks >= 0;
|
|
20975
|
+
}
|
|
20920
20976
|
var heartbeatActive = false;
|
|
20921
20977
|
var heartbeatUsesIpc = false;
|
|
20922
20978
|
var heartbeatHasDurableOwner = false;
|
|
20923
20979
|
var readinessReporter = null;
|
|
20980
|
+
var shutdownReporter = null;
|
|
20924
20981
|
function createWorkerWatchdogSendDrain() {
|
|
20925
20982
|
let pending = 0;
|
|
20926
20983
|
const drained = [];
|
|
@@ -20957,6 +21014,7 @@ function startWorkerWatchdogHeartbeat(env = process.env, argv = process.argv.sli
|
|
|
20957
21014
|
heartbeatUsesIpc = false;
|
|
20958
21015
|
heartbeatHasDurableOwner = false;
|
|
20959
21016
|
readinessReporter = null;
|
|
21017
|
+
shutdownReporter = null;
|
|
20960
21018
|
return { active: false, argv: ownership.argv, async stop() {
|
|
20961
21019
|
} };
|
|
20962
21020
|
}
|
|
@@ -20968,6 +21026,7 @@ function startWorkerWatchdogHeartbeat(env = process.env, argv = process.argv.sli
|
|
|
20968
21026
|
heartbeatUsesIpc = false;
|
|
20969
21027
|
heartbeatHasDurableOwner = false;
|
|
20970
21028
|
readinessReporter = null;
|
|
21029
|
+
shutdownReporter = null;
|
|
20971
21030
|
return { active: false, argv: ownership.argv, async stop() {
|
|
20972
21031
|
} };
|
|
20973
21032
|
}
|
|
@@ -20979,6 +21038,7 @@ function startWorkerWatchdogHeartbeat(env = process.env, argv = process.argv.sli
|
|
|
20979
21038
|
heartbeatUsesIpc = false;
|
|
20980
21039
|
heartbeatHasDurableOwner = false;
|
|
20981
21040
|
readinessReporter = null;
|
|
21041
|
+
shutdownReporter = null;
|
|
20982
21042
|
return { active: false, argv: ownership.argv, async stop() {
|
|
20983
21043
|
} };
|
|
20984
21044
|
}
|
|
@@ -20987,6 +21047,7 @@ function startWorkerWatchdogHeartbeat(env = process.env, argv = process.argv.sli
|
|
|
20987
21047
|
heartbeatUsesIpc = false;
|
|
20988
21048
|
heartbeatHasDurableOwner = false;
|
|
20989
21049
|
readinessReporter = null;
|
|
21050
|
+
shutdownReporter = null;
|
|
20990
21051
|
return { active: false, argv: ownership.argv, async stop() {
|
|
20991
21052
|
} };
|
|
20992
21053
|
}
|
|
@@ -21019,6 +21080,32 @@ function startWorkerWatchdogHeartbeat(env = process.env, argv = process.argv.sli
|
|
|
21019
21080
|
return false;
|
|
21020
21081
|
}
|
|
21021
21082
|
};
|
|
21083
|
+
let shutdownSequence = 0;
|
|
21084
|
+
const reportShutdown = (exitCode, activeTasks) => {
|
|
21085
|
+
if (stopped || !ipc || sequence === 0 || !process.connected || typeof process.send !== "function") {
|
|
21086
|
+
return false;
|
|
21087
|
+
}
|
|
21088
|
+
const message = {
|
|
21089
|
+
type: WORKER_SHUTDOWN_MESSAGE,
|
|
21090
|
+
nonce,
|
|
21091
|
+
pid: boundaryPid,
|
|
21092
|
+
sequence: ++shutdownSequence,
|
|
21093
|
+
exitCode,
|
|
21094
|
+
activeTasks
|
|
21095
|
+
};
|
|
21096
|
+
const sendComplete = sendDrain.begin();
|
|
21097
|
+
try {
|
|
21098
|
+
process.send(message, (error52) => {
|
|
21099
|
+
sendComplete();
|
|
21100
|
+
if (error52) stop();
|
|
21101
|
+
});
|
|
21102
|
+
return true;
|
|
21103
|
+
} catch {
|
|
21104
|
+
sendComplete();
|
|
21105
|
+
stop();
|
|
21106
|
+
return false;
|
|
21107
|
+
}
|
|
21108
|
+
};
|
|
21022
21109
|
const stop = async () => {
|
|
21023
21110
|
if (!stopped) {
|
|
21024
21111
|
stopped = true;
|
|
@@ -21026,6 +21113,7 @@ function startWorkerWatchdogHeartbeat(env = process.env, argv = process.argv.sli
|
|
|
21026
21113
|
heartbeatUsesIpc = false;
|
|
21027
21114
|
heartbeatHasDurableOwner = false;
|
|
21028
21115
|
if (readinessReporter === reportReadiness) readinessReporter = null;
|
|
21116
|
+
if (shutdownReporter === reportShutdown) shutdownReporter = null;
|
|
21029
21117
|
clearInterval(timer);
|
|
21030
21118
|
process.off("disconnect", onDisconnect);
|
|
21031
21119
|
}
|
|
@@ -21079,11 +21167,15 @@ function startWorkerWatchdogHeartbeat(env = process.env, argv = process.argv.sli
|
|
|
21079
21167
|
heartbeatHasDurableOwner = ipc;
|
|
21080
21168
|
heartbeatActive = true;
|
|
21081
21169
|
readinessReporter = ipc ? reportReadiness : null;
|
|
21170
|
+
shutdownReporter = ipc ? reportShutdown : null;
|
|
21082
21171
|
return { active: true, argv: ownership.argv, stop };
|
|
21083
21172
|
}
|
|
21084
21173
|
function reportWorkerReadiness() {
|
|
21085
21174
|
return readinessReporter?.() ?? false;
|
|
21086
21175
|
}
|
|
21176
|
+
function reportWorkerShutdown(exitCode, activeTasks) {
|
|
21177
|
+
return shutdownReporter?.(exitCode, activeTasks) ?? false;
|
|
21178
|
+
}
|
|
21087
21179
|
function workerWatchdogIsActive() {
|
|
21088
21180
|
return heartbeatActive && heartbeatHasDurableOwner && heartbeatUsesIpc && process.connected;
|
|
21089
21181
|
}
|
|
@@ -24042,27 +24134,135 @@ function createReleaseStateStore(root) {
|
|
|
24042
24134
|
};
|
|
24043
24135
|
}
|
|
24044
24136
|
|
|
24137
|
+
// src/worker-diagnostics.ts
|
|
24138
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
24139
|
+
import { mkdir as mkdir3, readdir as readdir2, readFile as readFile5, rm as rm3, writeFile } from "node:fs/promises";
|
|
24140
|
+
import { homedir } from "node:os";
|
|
24141
|
+
import { isAbsolute as isAbsolute6, join as join6 } from "node:path";
|
|
24142
|
+
var WORKER_DIAGNOSTICS_DIR_ENV = "ZIXT_HOST_DIAGNOSTICS_DIR";
|
|
24143
|
+
var RETAINED_RECORDS = 20;
|
|
24144
|
+
var STDERR_TAIL_LINES = 40;
|
|
24145
|
+
var STDERR_LINE_LIMIT = 800;
|
|
24146
|
+
var RECORD_TTL_MS = 7 * 24 * 60 * 6e4;
|
|
24147
|
+
var RECORD_FILE = /^[0-9a-f-]{36}\.json$/;
|
|
24148
|
+
function defaultWorkerDiagnosticsRoot() {
|
|
24149
|
+
return join6(homedir(), ".zixt", "host-diagnostics");
|
|
24150
|
+
}
|
|
24151
|
+
function configuredWorkerDiagnosticsRoot(env = process.env) {
|
|
24152
|
+
const configured = env[WORKER_DIAGNOSTICS_DIR_ENV];
|
|
24153
|
+
return typeof configured === "string" && isAbsolute6(configured) ? configured : null;
|
|
24154
|
+
}
|
|
24155
|
+
function boundedStderr(lines) {
|
|
24156
|
+
return lines.slice(-STDERR_TAIL_LINES).map(
|
|
24157
|
+
(line) => line.length > STDERR_LINE_LIMIT ? `${line.slice(0, STDERR_LINE_LIMIT)}\u2026` : line
|
|
24158
|
+
);
|
|
24159
|
+
}
|
|
24160
|
+
async function recordWorkerExit(root, record2) {
|
|
24161
|
+
try {
|
|
24162
|
+
await mkdir3(root, { recursive: true, mode: 448 });
|
|
24163
|
+
const stored = {
|
|
24164
|
+
...record2,
|
|
24165
|
+
schema: 1,
|
|
24166
|
+
stderr: boundedStderr(record2.stderr)
|
|
24167
|
+
};
|
|
24168
|
+
await writeFile(join6(root, `${randomUUID2()}.json`), JSON.stringify(stored), {
|
|
24169
|
+
encoding: "utf8",
|
|
24170
|
+
mode: 384
|
|
24171
|
+
});
|
|
24172
|
+
await pruneWorkerExits(root, Date.parse(record2.at));
|
|
24173
|
+
return true;
|
|
24174
|
+
} catch {
|
|
24175
|
+
return false;
|
|
24176
|
+
}
|
|
24177
|
+
}
|
|
24178
|
+
function parseRecord2(raw) {
|
|
24179
|
+
let value;
|
|
24180
|
+
try {
|
|
24181
|
+
value = JSON.parse(raw);
|
|
24182
|
+
} catch {
|
|
24183
|
+
return null;
|
|
24184
|
+
}
|
|
24185
|
+
if (!value || typeof value !== "object") return null;
|
|
24186
|
+
const record2 = value;
|
|
24187
|
+
if (record2.schema !== 1 || typeof record2.at !== "string" || !Number.isFinite(Date.parse(record2.at)))
|
|
24188
|
+
return null;
|
|
24189
|
+
if (!Array.isArray(record2.stderr) || record2.stderr.some((line) => typeof line !== "string")) {
|
|
24190
|
+
return null;
|
|
24191
|
+
}
|
|
24192
|
+
return { ...record2, stderr: boundedStderr(record2.stderr) };
|
|
24193
|
+
}
|
|
24194
|
+
async function readWorkerExits(root) {
|
|
24195
|
+
let names;
|
|
24196
|
+
try {
|
|
24197
|
+
names = await readdir2(root);
|
|
24198
|
+
} catch {
|
|
24199
|
+
return [];
|
|
24200
|
+
}
|
|
24201
|
+
const stored = [];
|
|
24202
|
+
for (const name of names) {
|
|
24203
|
+
if (!RECORD_FILE.test(name)) continue;
|
|
24204
|
+
const file2 = join6(root, name);
|
|
24205
|
+
try {
|
|
24206
|
+
const record2 = parseRecord2(await readFile5(file2, "utf8"));
|
|
24207
|
+
if (record2) stored.push({ file: file2, record: record2 });
|
|
24208
|
+
} catch {
|
|
24209
|
+
}
|
|
24210
|
+
}
|
|
24211
|
+
return stored.sort((a, b) => Date.parse(a.record.at) - Date.parse(b.record.at));
|
|
24212
|
+
}
|
|
24213
|
+
async function forgetWorkerExits(files) {
|
|
24214
|
+
await Promise.all(files.map((file2) => rm3(file2, { force: true }).catch(() => {
|
|
24215
|
+
})));
|
|
24216
|
+
}
|
|
24217
|
+
async function pruneWorkerExits(root, nowMs) {
|
|
24218
|
+
const stored = await readWorkerExits(root);
|
|
24219
|
+
const expired = stored.filter(({ record: record2 }) => nowMs - Date.parse(record2.at) > RECORD_TTL_MS);
|
|
24220
|
+
const surplus = stored.filter((entry) => !expired.includes(entry)).slice(0, Math.max(0, stored.length - expired.length - RETAINED_RECORDS));
|
|
24221
|
+
await forgetWorkerExits([...expired, ...surplus].map(({ file: file2 }) => file2));
|
|
24222
|
+
}
|
|
24223
|
+
var CONTAINMENT_SUMMARY = {
|
|
24224
|
+
watchdog_liveness: "stopped answering the supervisor and was terminated",
|
|
24225
|
+
watchdog_shutdown_deadline: "did not finish stopping and was terminated",
|
|
24226
|
+
probation_readiness: "did not prove cloud readiness during probation",
|
|
24227
|
+
probation_commit: "could not commit its probation evidence"
|
|
24228
|
+
};
|
|
24229
|
+
function describeWorkerExit(record2) {
|
|
24230
|
+
return {
|
|
24231
|
+
summary: record2.containment ? CONTAINMENT_SUMMARY[record2.containment] : record2.signal ? `was killed by ${record2.signal}` : `exited unexpectedly with code ${record2.code ?? "unknown"}`,
|
|
24232
|
+
context: {
|
|
24233
|
+
...record2.version ? { version: record2.version } : {},
|
|
24234
|
+
...record2.pid === null ? {} : { pid: record2.pid },
|
|
24235
|
+
exit: record2.signal ?? (record2.code === null ? "unknown" : String(record2.code)),
|
|
24236
|
+
uptime: `${Math.round(record2.uptimeMs / 100) / 10}s`,
|
|
24237
|
+
announced: record2.announcedExitCode === null ? "none" : record2.announcedExitCode === UPDATE_EXIT_CODE ? `update (${record2.announcedExitCode})` : String(record2.announcedExitCode),
|
|
24238
|
+
heartbeats: record2.heartbeats,
|
|
24239
|
+
readiness: record2.readinessMilestones,
|
|
24240
|
+
...record2.msSinceHeartbeat === null ? {} : { sinceHeartbeat: `${record2.msSinceHeartbeat}ms` }
|
|
24241
|
+
}
|
|
24242
|
+
};
|
|
24243
|
+
}
|
|
24244
|
+
|
|
24045
24245
|
// src/runners/run-artifacts.ts
|
|
24046
24246
|
import { spawn as spawn4 } from "node:child_process";
|
|
24047
24247
|
import {
|
|
24048
24248
|
chmod as chmod2,
|
|
24049
24249
|
lstat as lstat4,
|
|
24050
|
-
mkdir as
|
|
24250
|
+
mkdir as mkdir4,
|
|
24051
24251
|
open as open3,
|
|
24052
|
-
readdir as
|
|
24053
|
-
readFile as
|
|
24252
|
+
readdir as readdir3,
|
|
24253
|
+
readFile as readFile6,
|
|
24054
24254
|
realpath as realpath3,
|
|
24055
24255
|
rename as rename2,
|
|
24056
|
-
rm as
|
|
24057
|
-
writeFile
|
|
24256
|
+
rm as rm4,
|
|
24257
|
+
writeFile as writeFile2
|
|
24058
24258
|
} from "node:fs/promises";
|
|
24059
|
-
import { homedir } from "node:os";
|
|
24060
|
-
import { dirname as dirname3, isAbsolute as
|
|
24259
|
+
import { homedir as homedir2 } from "node:os";
|
|
24260
|
+
import { dirname as dirname3, isAbsolute as isAbsolute8, join as join7, relative as relative3, resolve as resolve4, sep as sep3, win32 as win322 } from "node:path";
|
|
24061
24261
|
|
|
24062
24262
|
// src/windows-job.ts
|
|
24063
24263
|
import { spawn as spawn3 } from "node:child_process";
|
|
24064
|
-
import { randomUUID as
|
|
24065
|
-
import { isAbsolute as
|
|
24264
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
24265
|
+
import { isAbsolute as isAbsolute7, win32 } from "node:path";
|
|
24066
24266
|
var WINDOWS_CONTAINMENT_GATE_ENV = "ZIXT_WINDOWS_CONTAINMENT_GATE";
|
|
24067
24267
|
var WINDOWS_CONTAINMENT_GATE_PREFIX = "__ZIXT_WINDOWS_CONTAINMENT_READY__";
|
|
24068
24268
|
var WINDOWS_POST_CONTAINMENT_CWD_ENV = "ZIXT_WINDOWS_POST_CONTAINMENT_CWD";
|
|
@@ -24373,7 +24573,7 @@ async function createWindowsJobContainment(pid, options) {
|
|
|
24373
24573
|
throw new Error("Windows Job Object timeout is invalid");
|
|
24374
24574
|
}
|
|
24375
24575
|
const env = options.env ?? process.env;
|
|
24376
|
-
const nonce =
|
|
24576
|
+
const nonce = randomUUID3();
|
|
24377
24577
|
const encodedSource = encodedPowershellSource(WINDOWS_JOB_HELPER_SOURCE);
|
|
24378
24578
|
const helper = options.spawnHelper ? options.spawnHelper(nonce, encodedSource) : spawn3(
|
|
24379
24579
|
options.powershellCommand ?? defaultPowershellCommand(env),
|
|
@@ -24558,7 +24758,7 @@ async function awaitWindowsContainmentGate(env = process.env, input = process.st
|
|
|
24558
24758
|
const postContainmentCwd = env[WINDOWS_POST_CONTAINMENT_CWD_ENV];
|
|
24559
24759
|
delete env[WINDOWS_POST_CONTAINMENT_CWD_ENV];
|
|
24560
24760
|
if (postContainmentCwd !== void 0) {
|
|
24561
|
-
if (!
|
|
24761
|
+
if (!isAbsolute7(postContainmentCwd)) return finish(false);
|
|
24562
24762
|
try {
|
|
24563
24763
|
process.chdir(postContainmentCwd);
|
|
24564
24764
|
} catch {
|
|
@@ -24796,7 +24996,7 @@ foreach ($path in $paths) {
|
|
|
24796
24996
|
}
|
|
24797
24997
|
`;
|
|
24798
24998
|
function defaultRunArtifactRoot() {
|
|
24799
|
-
return
|
|
24999
|
+
return join7(homedir2(), ".zixt", "run-artifacts");
|
|
24800
25000
|
}
|
|
24801
25001
|
function requireSafeSegment(value, field) {
|
|
24802
25002
|
if (!SAFE_SEGMENT.test(value)) {
|
|
@@ -24808,7 +25008,7 @@ function isMissing(error52) {
|
|
|
24808
25008
|
}
|
|
24809
25009
|
function assertBelow(parent, child) {
|
|
24810
25010
|
const path = relative3(parent, child);
|
|
24811
|
-
const escapes = path === "" || path === ".." || path.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ||
|
|
25011
|
+
const escapes = path === "" || path === ".." || path.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || isAbsolute8(path);
|
|
24812
25012
|
if (escapes) throw new Error("run artifact path escapes its private root");
|
|
24813
25013
|
}
|
|
24814
25014
|
async function requireRealDirectory(path, label) {
|
|
@@ -24843,7 +25043,7 @@ async function prepareRoot(root) {
|
|
|
24843
25043
|
const absolute = resolve4(root);
|
|
24844
25044
|
let realProfile;
|
|
24845
25045
|
if (process.platform === "win32") {
|
|
24846
|
-
const profile = resolve4(
|
|
25046
|
+
const profile = resolve4(homedir2());
|
|
24847
25047
|
assertWindowsProfileBoundary(profile, absolute);
|
|
24848
25048
|
await rejectWindowsSymlinkAncestors(profile, absolute);
|
|
24849
25049
|
realProfile = await realpath3(profile);
|
|
@@ -24852,7 +25052,7 @@ async function prepareRoot(root) {
|
|
|
24852
25052
|
await lstat4(absolute);
|
|
24853
25053
|
} catch (error52) {
|
|
24854
25054
|
if (!isMissing(error52)) throw error52;
|
|
24855
|
-
await
|
|
25055
|
+
await mkdir4(absolute, { recursive: true, mode: DIRECTORY_MODE });
|
|
24856
25056
|
}
|
|
24857
25057
|
const real = await requireRealDirectory(absolute, "run artifact root");
|
|
24858
25058
|
if (realProfile) assertWindowsProfileBoundary(realProfile, real);
|
|
@@ -24860,14 +25060,14 @@ async function prepareRoot(root) {
|
|
|
24860
25060
|
return real;
|
|
24861
25061
|
}
|
|
24862
25062
|
async function prepareAgentRoot(root, agentId) {
|
|
24863
|
-
const path =
|
|
25063
|
+
const path = join7(root, agentId);
|
|
24864
25064
|
assertBelow(root, path);
|
|
24865
25065
|
try {
|
|
24866
25066
|
await lstat4(path);
|
|
24867
25067
|
} catch (error52) {
|
|
24868
25068
|
if (!isMissing(error52)) throw error52;
|
|
24869
25069
|
try {
|
|
24870
|
-
await
|
|
25070
|
+
await mkdir4(path, { mode: DIRECTORY_MODE });
|
|
24871
25071
|
} catch (mkdirError) {
|
|
24872
25072
|
if (mkdirError.code !== "EEXIST") throw mkdirError;
|
|
24873
25073
|
}
|
|
@@ -24883,7 +25083,7 @@ async function lockDownWindowsDirectories(paths) {
|
|
|
24883
25083
|
if (!windowsRoot || !win322.isAbsolute(windowsRoot)) {
|
|
24884
25084
|
throw new Error("private Windows run-artifact ACL authority is unavailable");
|
|
24885
25085
|
}
|
|
24886
|
-
const powershell =
|
|
25086
|
+
const powershell = join7(windowsRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
|
|
24887
25087
|
const encoded = Buffer.from(WINDOWS_PRIVATE_DACL_SCRIPT, "utf16le").toString("base64");
|
|
24888
25088
|
await new Promise((resolvePromise, reject3) => {
|
|
24889
25089
|
const helper = spawn4(
|
|
@@ -24925,16 +25125,16 @@ async function lockDownWindowsDirectories(paths) {
|
|
|
24925
25125
|
});
|
|
24926
25126
|
}
|
|
24927
25127
|
async function createPrivateDirectory(parent, name) {
|
|
24928
|
-
const path =
|
|
25128
|
+
const path = join7(parent, name);
|
|
24929
25129
|
assertBelow(parent, path);
|
|
24930
|
-
await
|
|
25130
|
+
await mkdir4(path, { mode: DIRECTORY_MODE });
|
|
24931
25131
|
await chmod2(path, DIRECTORY_MODE);
|
|
24932
25132
|
const real = await realpath3(path);
|
|
24933
25133
|
assertBelow(parent, real);
|
|
24934
25134
|
return real;
|
|
24935
25135
|
}
|
|
24936
25136
|
async function writePrivateFile(path, content) {
|
|
24937
|
-
await
|
|
25137
|
+
await writeFile2(path, content, { flag: "wx", mode: FILE_MODE });
|
|
24938
25138
|
await chmod2(path, FILE_MODE);
|
|
24939
25139
|
}
|
|
24940
25140
|
function quotePosix(value) {
|
|
@@ -24954,24 +25154,24 @@ async function createRunArtifacts(input) {
|
|
|
24954
25154
|
requireSafeSegment(input.agentId, "agentId");
|
|
24955
25155
|
requireSafeSegment(input.runToken, "runToken");
|
|
24956
25156
|
const root = await prepareRoot(input.root);
|
|
24957
|
-
const removeTree = input.removeTree ?? ((path) =>
|
|
25157
|
+
const removeTree = input.removeTree ?? ((path) => rm4(path, { recursive: true, force: true }));
|
|
24958
25158
|
const cleanupRetryDelayMs = input.cleanupRetryDelayMs ?? CLEANUP_RETRY_DELAY_MS;
|
|
24959
25159
|
const agentRoot = await prepareAgentRoot(root, input.agentId);
|
|
24960
25160
|
await lockDownWindowsDirectories([root, agentRoot]);
|
|
24961
|
-
const runRoot =
|
|
25161
|
+
const runRoot = join7(agentRoot, input.runToken);
|
|
24962
25162
|
assertBelow(agentRoot, runRoot);
|
|
24963
25163
|
try {
|
|
24964
|
-
await
|
|
25164
|
+
await mkdir4(runRoot, { mode: DIRECTORY_MODE });
|
|
24965
25165
|
await chmod2(runRoot, DIRECTORY_MODE);
|
|
24966
25166
|
const realRunRoot = await realpath3(runRoot);
|
|
24967
25167
|
assertBelow(agentRoot, realRunRoot);
|
|
24968
25168
|
const emptyGithubConfigDirectory = await createPrivateDirectory(realRunRoot, "gh-config");
|
|
24969
25169
|
const emptyGitHooksDirectory = await createPrivateDirectory(realRunRoot, "git-hooks");
|
|
24970
25170
|
const gitBridgesDirectory = await createPrivateDirectory(realRunRoot, "git-bridges");
|
|
24971
|
-
const denySshScript =
|
|
24972
|
-
const runnerWrapperScript =
|
|
24973
|
-
const systemPromptPath =
|
|
24974
|
-
const mcpConfigPath =
|
|
25171
|
+
const denySshScript = join7(realRunRoot, "deny-ssh.cjs");
|
|
25172
|
+
const runnerWrapperScript = join7(realRunRoot, "runner-wrapper.cjs");
|
|
25173
|
+
const systemPromptPath = join7(realRunRoot, "system-prompt.txt");
|
|
25174
|
+
const mcpConfigPath = join7(realRunRoot, "mcp.json");
|
|
24975
25175
|
await writePrivateFile(denySshScript, "process.exitCode = 127;");
|
|
24976
25176
|
await writePrivateFile(runnerWrapperScript, RUNNER_GUARDIAN);
|
|
24977
25177
|
return {
|
|
@@ -25016,7 +25216,7 @@ async function sweepOrphanedRunArtifacts(root) {
|
|
|
25016
25216
|
const absolute = resolve4(root);
|
|
25017
25217
|
let realProfile;
|
|
25018
25218
|
if (process.platform === "win32") {
|
|
25019
|
-
const profile = resolve4(
|
|
25219
|
+
const profile = resolve4(homedir2());
|
|
25020
25220
|
assertWindowsProfileBoundary(profile, absolute);
|
|
25021
25221
|
await rejectWindowsSymlinkAncestors(profile, absolute);
|
|
25022
25222
|
realProfile = await realpath3(profile);
|
|
@@ -25031,24 +25231,24 @@ async function sweepOrphanedRunArtifacts(root) {
|
|
|
25031
25231
|
if (realProfile) assertWindowsProfileBoundary(realProfile, realRoot);
|
|
25032
25232
|
await chmod2(realRoot, DIRECTORY_MODE);
|
|
25033
25233
|
await lockDownWindowsDirectories([realRoot]);
|
|
25034
|
-
const agents = await
|
|
25234
|
+
const agents = await readdir3(realRoot, { withFileTypes: true });
|
|
25035
25235
|
let removed = 0;
|
|
25036
25236
|
for (const agent of agents) {
|
|
25037
25237
|
if (!SAFE_SEGMENT.test(agent.name) || !agent.isDirectory() || agent.isSymbolicLink()) continue;
|
|
25038
|
-
const agentPath =
|
|
25039
|
-
const runs = await
|
|
25238
|
+
const agentPath = join7(realRoot, agent.name);
|
|
25239
|
+
const runs = await readdir3(agentPath, { withFileTypes: true });
|
|
25040
25240
|
for (const run3 of runs) {
|
|
25041
25241
|
if (!SAFE_SEGMENT.test(run3.name) || !run3.isDirectory() || run3.isSymbolicLink()) continue;
|
|
25042
|
-
const runPath =
|
|
25242
|
+
const runPath = join7(agentPath, run3.name);
|
|
25043
25243
|
assertBelow(agentPath, runPath);
|
|
25044
|
-
await
|
|
25244
|
+
await rm4(runPath, { recursive: true, force: true });
|
|
25045
25245
|
removed++;
|
|
25046
25246
|
}
|
|
25047
25247
|
}
|
|
25048
25248
|
return removed;
|
|
25049
25249
|
}
|
|
25050
25250
|
function defaultRunRegistryRoot() {
|
|
25051
|
-
return
|
|
25251
|
+
return join7(homedir2(), ".zixt", "run-registry");
|
|
25052
25252
|
}
|
|
25053
25253
|
async function terminateRecordedRunProcesses(registryRoot = defaultRunRegistryRoot(), terminate = terminateRecordedProcessTree) {
|
|
25054
25254
|
const entries = await readRecordedRunAssignmentEntriesStrict(registryRoot);
|
|
@@ -25074,7 +25274,7 @@ async function syncRunRegistryDirectory(path) {
|
|
|
25074
25274
|
}
|
|
25075
25275
|
}
|
|
25076
25276
|
async function ensureDurableRunRegistryRoot(registryRoot, syncDirectory8) {
|
|
25077
|
-
const firstCreated = await
|
|
25277
|
+
const firstCreated = await mkdir4(registryRoot, { recursive: true, mode: DIRECTORY_MODE });
|
|
25078
25278
|
if (firstCreated && process.platform !== "win32") {
|
|
25079
25279
|
const first = resolve4(firstCreated);
|
|
25080
25280
|
const target = resolve4(registryRoot);
|
|
@@ -25082,15 +25282,15 @@ async function ensureDurableRunRegistryRoot(registryRoot, syncDirectory8) {
|
|
|
25082
25282
|
let current = first;
|
|
25083
25283
|
for (const part of relative3(first, target).split(sep3).filter(Boolean)) {
|
|
25084
25284
|
await syncDirectory8(current);
|
|
25085
|
-
current =
|
|
25285
|
+
current = join7(current, part);
|
|
25086
25286
|
}
|
|
25087
25287
|
}
|
|
25088
25288
|
await chmod2(registryRoot, DIRECTORY_MODE);
|
|
25089
25289
|
}
|
|
25090
25290
|
async function recordRunAssignment(runToken, record2, registryRoot = defaultRunRegistryRoot(), options = {}) {
|
|
25091
25291
|
if (!SAFE_SEGMENT.test(runToken)) return false;
|
|
25092
|
-
const destination =
|
|
25093
|
-
const temporary =
|
|
25292
|
+
const destination = join7(registryRoot, `${runToken}.json`);
|
|
25293
|
+
const temporary = join7(registryRoot, `.${runToken}.${process.pid}.${Date.now()}.tmp`);
|
|
25094
25294
|
let handle;
|
|
25095
25295
|
try {
|
|
25096
25296
|
const syncDirectory8 = options.syncDirectory ?? syncRunRegistryDirectory;
|
|
@@ -25110,7 +25310,7 @@ async function recordRunAssignment(runToken, record2, registryRoot = defaultRunR
|
|
|
25110
25310
|
} finally {
|
|
25111
25311
|
await handle?.close().catch(() => {
|
|
25112
25312
|
});
|
|
25113
|
-
await
|
|
25313
|
+
await rm4(temporary, { force: true }).catch(() => {
|
|
25114
25314
|
});
|
|
25115
25315
|
}
|
|
25116
25316
|
}
|
|
@@ -25122,7 +25322,7 @@ async function forgetRunAssignment(runToken, registryRoot = defaultRunRegistryRo
|
|
|
25122
25322
|
if (retainingAssignments) return;
|
|
25123
25323
|
if (!SAFE_SEGMENT.test(runToken)) return;
|
|
25124
25324
|
try {
|
|
25125
|
-
await
|
|
25325
|
+
await rm4(join7(registryRoot, `${runToken}.json`), { force: true });
|
|
25126
25326
|
} catch {
|
|
25127
25327
|
}
|
|
25128
25328
|
}
|
|
@@ -25156,7 +25356,7 @@ function parseAssignment(text) {
|
|
|
25156
25356
|
async function readRecordedRunAssignmentEntries(registryRoot = defaultRunRegistryRoot()) {
|
|
25157
25357
|
let entries;
|
|
25158
25358
|
try {
|
|
25159
|
-
entries = await
|
|
25359
|
+
entries = await readdir3(registryRoot, { withFileTypes: true });
|
|
25160
25360
|
} catch {
|
|
25161
25361
|
return [];
|
|
25162
25362
|
}
|
|
@@ -25167,7 +25367,7 @@ async function readRecordedRunAssignmentEntries(registryRoot = defaultRunRegistr
|
|
|
25167
25367
|
if (!SAFE_SEGMENT.test(runToken)) continue;
|
|
25168
25368
|
let text;
|
|
25169
25369
|
try {
|
|
25170
|
-
text = await
|
|
25370
|
+
text = await readFile6(join7(registryRoot, entry.name), "utf8");
|
|
25171
25371
|
} catch {
|
|
25172
25372
|
continue;
|
|
25173
25373
|
}
|
|
@@ -25189,7 +25389,7 @@ async function readRecordedRunAssignmentEntriesStrict(registryRoot = defaultRunR
|
|
|
25189
25389
|
}
|
|
25190
25390
|
let entries;
|
|
25191
25391
|
try {
|
|
25192
|
-
entries = await
|
|
25392
|
+
entries = await readdir3(registryRoot, { withFileTypes: true });
|
|
25193
25393
|
} catch {
|
|
25194
25394
|
throw new Error("run registry state could not be observed");
|
|
25195
25395
|
}
|
|
@@ -25203,7 +25403,7 @@ async function readRecordedRunAssignmentEntriesStrict(registryRoot = defaultRunR
|
|
|
25203
25403
|
}
|
|
25204
25404
|
let text;
|
|
25205
25405
|
try {
|
|
25206
|
-
text = await
|
|
25406
|
+
text = await readFile6(join7(registryRoot, entry.name), "utf8");
|
|
25207
25407
|
} catch {
|
|
25208
25408
|
throw new Error("committed run registry witness could not be read");
|
|
25209
25409
|
}
|
|
@@ -25220,13 +25420,13 @@ async function forgetAcknowledgedRunAssignments(assignments, registryRoot = defa
|
|
|
25220
25420
|
);
|
|
25221
25421
|
const entries = await readRecordedRunAssignmentEntries(registryRoot);
|
|
25222
25422
|
await Promise.all(
|
|
25223
|
-
entries.filter(({ record: record2 }) => acknowledged.has(`${record2.taskId}:${record2.epoch}`)).map(({ runToken }) =>
|
|
25423
|
+
entries.filter(({ record: record2 }) => acknowledged.has(`${record2.taskId}:${record2.epoch}`)).map(({ runToken }) => rm4(join7(registryRoot, `${runToken}.json`), { force: true }))
|
|
25224
25424
|
);
|
|
25225
25425
|
}
|
|
25226
25426
|
async function forgetSupersededRunAssignments(taskId, epoch, registryRoot = defaultRunRegistryRoot()) {
|
|
25227
25427
|
const entries = await readRecordedRunAssignmentEntries(registryRoot);
|
|
25228
25428
|
await Promise.all(
|
|
25229
|
-
entries.filter(({ record: record2 }) => record2.taskId === taskId && record2.epoch < epoch).map(({ runToken }) =>
|
|
25429
|
+
entries.filter(({ record: record2 }) => record2.taskId === taskId && record2.epoch < epoch).map(({ runToken }) => rm4(join7(registryRoot, `${runToken}.json`), { force: true }))
|
|
25230
25430
|
);
|
|
25231
25431
|
}
|
|
25232
25432
|
|
|
@@ -25237,6 +25437,7 @@ var WORKER_ROLE = "worker";
|
|
|
25237
25437
|
var WORKER_PROXY_ROLE = "worker_proxy";
|
|
25238
25438
|
var SUPERVISOR_ROLE = "supervisor";
|
|
25239
25439
|
var WORKER_PROXY_ENTRY_ENV = "ZIXT_HOST_WORKER_PROXY_ENTRY";
|
|
25440
|
+
var HOST_CONSOLE_COLOR_ENV = "ZIXT_HOST_CONSOLE_COLOR";
|
|
25240
25441
|
var SUPERVISOR_PROTOCOL_ENV = "ZIXT_HOST_SUPERVISOR_PROTOCOL";
|
|
25241
25442
|
var SUPERVISOR_VERSION_ENV = "ZIXT_HOST_SUPERVISOR_VERSION";
|
|
25242
25443
|
var SUPERVISOR_PROTOCOL = "2";
|
|
@@ -25252,6 +25453,8 @@ var INSTALL_TIMEOUT_MS = 5 * 6e4;
|
|
|
25252
25453
|
var WORKER_WATCHDOG_CHECK_MS = 1e3;
|
|
25253
25454
|
var WORKER_WATCHDOG_TIMEOUT_MS = 15e3;
|
|
25254
25455
|
var WORKER_WATCHDOG_STARTUP_MS = 6e4;
|
|
25456
|
+
var WORKER_SHUTDOWN_DEADLINE_MS = 6e4;
|
|
25457
|
+
var WORKER_STDERR_TAIL_LINES = 40;
|
|
25255
25458
|
var WORKER_READINESS_TIMEOUT_MS = 9e4;
|
|
25256
25459
|
var CLEANUP_ATTEMPTS2 = 3;
|
|
25257
25460
|
var VERSION_DIR = /^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/;
|
|
@@ -25267,8 +25470,28 @@ function signalWorkerGroup(child, signal) {
|
|
|
25267
25470
|
} catch {
|
|
25268
25471
|
}
|
|
25269
25472
|
}
|
|
25473
|
+
function captureWorkerStderr(child) {
|
|
25474
|
+
const stderr = child.stderr;
|
|
25475
|
+
if (!stderr) return () => [];
|
|
25476
|
+
const lines = [];
|
|
25477
|
+
let partial2 = "";
|
|
25478
|
+
stderr.on("data", (chunk) => {
|
|
25479
|
+
const text = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
25480
|
+
process.stderr.write(text);
|
|
25481
|
+
partial2 += text;
|
|
25482
|
+
const complete = partial2.split(/\r?\n/);
|
|
25483
|
+
partial2 = complete.pop() ?? "";
|
|
25484
|
+
for (const line of complete) {
|
|
25485
|
+
lines.push(line);
|
|
25486
|
+
if (lines.length > WORKER_STDERR_TAIL_LINES) lines.shift();
|
|
25487
|
+
}
|
|
25488
|
+
});
|
|
25489
|
+
stderr.on("error", () => {
|
|
25490
|
+
});
|
|
25491
|
+
return () => (partial2 ? [...lines, partial2] : [...lines]).slice(-WORKER_STDERR_TAIL_LINES);
|
|
25492
|
+
}
|
|
25270
25493
|
function versionsRoot() {
|
|
25271
|
-
return process.env.ZIXT_HOST_VERSIONS_DIR ??
|
|
25494
|
+
return process.env.ZIXT_HOST_VERSIONS_DIR ?? join8(homedir3(), ".zixt", "host-versions");
|
|
25272
25495
|
}
|
|
25273
25496
|
function npmCommand(platform = process.platform) {
|
|
25274
25497
|
return platform === "win32" ? "npm.cmd" : "npm";
|
|
@@ -25277,19 +25500,19 @@ function windowsInstallerCommandLine(command, args) {
|
|
|
25277
25500
|
return [command, ...args].map(quoteForCmd).join(" ");
|
|
25278
25501
|
}
|
|
25279
25502
|
function installedReleaseEntry(version2, root = versionsRoot()) {
|
|
25280
|
-
return
|
|
25503
|
+
return join8(root, version2, "node_modules", PACKAGE_NAME, "dist", "index.js");
|
|
25281
25504
|
}
|
|
25282
25505
|
function releaseEntryAtPrefix(prefix) {
|
|
25283
|
-
return
|
|
25506
|
+
return join8(prefix, "node_modules", PACKAGE_NAME, "dist", "index.js");
|
|
25284
25507
|
}
|
|
25285
25508
|
function releaseManifestAtPrefix(prefix) {
|
|
25286
|
-
return
|
|
25509
|
+
return join8(prefix, "node_modules", PACKAGE_NAME, "package.json");
|
|
25287
25510
|
}
|
|
25288
25511
|
async function validReleaseAtPrefix(prefix, version2) {
|
|
25289
25512
|
try {
|
|
25290
25513
|
const [entry, manifestText] = await Promise.all([
|
|
25291
25514
|
lstat5(releaseEntryAtPrefix(prefix)),
|
|
25292
|
-
|
|
25515
|
+
readFile7(releaseManifestAtPrefix(prefix), "utf8")
|
|
25293
25516
|
]);
|
|
25294
25517
|
if (!entry.isFile()) return false;
|
|
25295
25518
|
const manifest = JSON.parse(manifestText);
|
|
@@ -25308,9 +25531,9 @@ async function syncDirectory3(path) {
|
|
|
25308
25531
|
}
|
|
25309
25532
|
}
|
|
25310
25533
|
function installedReleaseVersion(entry, root = versionsRoot()) {
|
|
25311
|
-
if (!
|
|
25534
|
+
if (!isAbsolute9(entry)) return null;
|
|
25312
25535
|
const relativeEntry = relative4(resolve5(root), resolve5(entry));
|
|
25313
|
-
if (!relativeEntry || relativeEntry.startsWith(`..${sep4}`) ||
|
|
25536
|
+
if (!relativeEntry || relativeEntry.startsWith(`..${sep4}`) || isAbsolute9(relativeEntry)) {
|
|
25314
25537
|
return null;
|
|
25315
25538
|
}
|
|
25316
25539
|
const version2 = relativeEntry.split(sep4)[0];
|
|
@@ -25318,10 +25541,10 @@ function installedReleaseVersion(entry, root = versionsRoot()) {
|
|
|
25318
25541
|
return resolve5(entry) === resolve5(installedReleaseEntry(version2, root)) ? version2 : null;
|
|
25319
25542
|
}
|
|
25320
25543
|
function currentReleaseEntry(root = versionsRoot(), platform = process.platform) {
|
|
25321
|
-
return
|
|
25544
|
+
return join8(root, platform === "win32" ? "current-launcher.cjs" : CURRENT_RELEASE_ENTRY);
|
|
25322
25545
|
}
|
|
25323
25546
|
function windowsReleasePointer(root = versionsRoot()) {
|
|
25324
|
-
return
|
|
25547
|
+
return join8(root, WINDOWS_RELEASE_POINTER);
|
|
25325
25548
|
}
|
|
25326
25549
|
var WINDOWS_STABLE_LAUNCHER = `${WINDOWS_LAUNCHER_MARKER}
|
|
25327
25550
|
'use strict';
|
|
@@ -25357,8 +25580,8 @@ child.once('exit', (code) => process.exit(code == null ? 1 : code));
|
|
|
25357
25580
|
`;
|
|
25358
25581
|
async function replaceDurableFile(path, contents, sync = syncDirectory3) {
|
|
25359
25582
|
const parent = dirname4(path);
|
|
25360
|
-
await
|
|
25361
|
-
const temporary =
|
|
25583
|
+
await mkdir5(parent, { recursive: true, mode: 448 });
|
|
25584
|
+
const temporary = join8(parent, `.${CURRENT_RELEASE_ENTRY}.${process.pid}.${crypto.randomUUID()}`);
|
|
25362
25585
|
const handle = await open4(temporary, "wx", 384);
|
|
25363
25586
|
try {
|
|
25364
25587
|
await handle.writeFile(contents, "utf8");
|
|
@@ -25368,7 +25591,7 @@ async function replaceDurableFile(path, contents, sync = syncDirectory3) {
|
|
|
25368
25591
|
await sync(parent);
|
|
25369
25592
|
} catch (error52) {
|
|
25370
25593
|
await handle.close().catch(() => void 0);
|
|
25371
|
-
await
|
|
25594
|
+
await rm5(temporary, { force: true }).catch(() => void 0);
|
|
25372
25595
|
throw error52;
|
|
25373
25596
|
}
|
|
25374
25597
|
}
|
|
@@ -25378,7 +25601,7 @@ async function activateInstalledRelease(entry, root = versionsRoot(), platform =
|
|
|
25378
25601
|
}
|
|
25379
25602
|
await access2(entry);
|
|
25380
25603
|
if (platform === "win32") {
|
|
25381
|
-
await
|
|
25604
|
+
await mkdir5(root, { recursive: true, mode: 448 });
|
|
25382
25605
|
const launcher = currentReleaseEntry(root, platform);
|
|
25383
25606
|
const existingLauncher = await lstat5(launcher).catch((error52) => {
|
|
25384
25607
|
if (error52.code === "ENOENT") return null;
|
|
@@ -25388,7 +25611,7 @@ async function activateInstalledRelease(entry, root = versionsRoot(), platform =
|
|
|
25388
25611
|
if (!existingLauncher.isFile()) {
|
|
25389
25612
|
throw new Error("the Zixt Host Windows launcher is not a regular file");
|
|
25390
25613
|
}
|
|
25391
|
-
const contents = await
|
|
25614
|
+
const contents = await readFile7(launcher, "utf8");
|
|
25392
25615
|
if (!contents.startsWith(WINDOWS_LAUNCHER_OWNED_MARKER)) {
|
|
25393
25616
|
throw new Error("the Zixt Host Windows launcher is not owned by Zixt");
|
|
25394
25617
|
}
|
|
@@ -25409,7 +25632,7 @@ async function activateInstalledRelease(entry, root = versionsRoot(), platform =
|
|
|
25409
25632
|
}
|
|
25410
25633
|
let prior;
|
|
25411
25634
|
try {
|
|
25412
|
-
prior = JSON.parse(await
|
|
25635
|
+
prior = JSON.parse(await readFile7(pointerPath, "utf8"));
|
|
25413
25636
|
} catch {
|
|
25414
25637
|
throw new Error("the Zixt Host Windows release pointer is invalid");
|
|
25415
25638
|
}
|
|
@@ -25427,7 +25650,7 @@ async function activateInstalledRelease(entry, root = versionsRoot(), platform =
|
|
|
25427
25650
|
return launcher;
|
|
25428
25651
|
}
|
|
25429
25652
|
if (platform !== "linux" && platform !== "darwin") return entry;
|
|
25430
|
-
await
|
|
25653
|
+
await mkdir5(root, { recursive: true, mode: 448 });
|
|
25431
25654
|
const current = currentReleaseEntry(root, platform);
|
|
25432
25655
|
const existing = await lstat5(current).catch((error52) => {
|
|
25433
25656
|
if (error52.code === "ENOENT") return null;
|
|
@@ -25436,13 +25659,13 @@ async function activateInstalledRelease(entry, root = versionsRoot(), platform =
|
|
|
25436
25659
|
if (existing && !existing.isSymbolicLink()) {
|
|
25437
25660
|
throw new Error("the Zixt Host current-release entry is not a symbolic link");
|
|
25438
25661
|
}
|
|
25439
|
-
const temporary =
|
|
25662
|
+
const temporary = join8(root, `.${CURRENT_RELEASE_ENTRY}.${process.pid}.${crypto.randomUUID()}`);
|
|
25440
25663
|
try {
|
|
25441
25664
|
await symlink(entry, temporary, "file");
|
|
25442
25665
|
await rename3(temporary, current);
|
|
25443
25666
|
await sync(root);
|
|
25444
25667
|
} catch (error52) {
|
|
25445
|
-
await
|
|
25668
|
+
await rm5(temporary, { force: true }).catch(() => void 0);
|
|
25446
25669
|
throw error52;
|
|
25447
25670
|
}
|
|
25448
25671
|
return current;
|
|
@@ -25453,7 +25676,7 @@ async function activatedReleaseVersion(root = versionsRoot(), platform = process
|
|
|
25453
25676
|
const pointerPath = windowsReleasePointer(root);
|
|
25454
25677
|
const metadata = await lstat5(pointerPath);
|
|
25455
25678
|
if (!metadata.isFile() || metadata.size > 4 * 1024) return null;
|
|
25456
|
-
const value = JSON.parse(await
|
|
25679
|
+
const value = JSON.parse(await readFile7(pointerPath, "utf8"));
|
|
25457
25680
|
return value.schema === 1 && typeof value.entry === "string" ? installedReleaseVersion(value.entry, root) : null;
|
|
25458
25681
|
} catch {
|
|
25459
25682
|
return null;
|
|
@@ -25567,13 +25790,13 @@ async function installRelease(version2, options = {}) {
|
|
|
25567
25790
|
const platform = options.platform ?? process.platform;
|
|
25568
25791
|
const installerCommand = options.installerCommand ?? npmCommand(platform);
|
|
25569
25792
|
const root = options.root ?? versionsRoot();
|
|
25570
|
-
const prefix =
|
|
25793
|
+
const prefix = join8(root, version2);
|
|
25571
25794
|
const entry = installedReleaseEntry(version2, root);
|
|
25572
25795
|
if (await validReleaseAtPrefix(prefix, version2)) return entry;
|
|
25573
25796
|
if (options.signal?.aborted) return null;
|
|
25574
|
-
await
|
|
25575
|
-
const staging =
|
|
25576
|
-
const quarantine =
|
|
25797
|
+
await mkdir5(root, { recursive: true, mode: 448 });
|
|
25798
|
+
const staging = join8(root, `.install-${version2}-${process.pid}-${crypto.randomUUID()}`);
|
|
25799
|
+
const quarantine = join8(root, `.invalid-${version2}-${process.pid}-${crypto.randomUUID()}`);
|
|
25577
25800
|
const usesWindowsInstallerGuardian = platform === "win32" && options.spawnInstaller === void 0;
|
|
25578
25801
|
const installerGateNonce = usesWindowsInstallerGuardian ? crypto.randomUUID() : null;
|
|
25579
25802
|
const installerArguments = (installPrefix, installVersion) => [
|
|
@@ -25605,7 +25828,7 @@ async function installRelease(version2, options = {}) {
|
|
|
25605
25828
|
try {
|
|
25606
25829
|
child = spawnInstaller(staging, version2);
|
|
25607
25830
|
} catch {
|
|
25608
|
-
await
|
|
25831
|
+
await rm5(staging, { recursive: true, force: true }).catch(() => void 0);
|
|
25609
25832
|
return null;
|
|
25610
25833
|
}
|
|
25611
25834
|
let resolveChildExited;
|
|
@@ -25755,8 +25978,8 @@ async function installRelease(version2, options = {}) {
|
|
|
25755
25978
|
await syncDirectory3(root);
|
|
25756
25979
|
return await validReleaseAtPrefix(prefix, version2) ? entry : null;
|
|
25757
25980
|
} finally {
|
|
25758
|
-
await
|
|
25759
|
-
await
|
|
25981
|
+
await rm5(staging, { recursive: true, force: true }).catch(() => void 0);
|
|
25982
|
+
await rm5(quarantine, { recursive: true, force: true }).catch(() => void 0);
|
|
25760
25983
|
}
|
|
25761
25984
|
}
|
|
25762
25985
|
async function pruneInstalledVersions(keep, root = versionsRoot()) {
|
|
@@ -25764,17 +25987,17 @@ async function pruneInstalledVersions(keep, root = versionsRoot()) {
|
|
|
25764
25987
|
const running = process.argv[1] ? resolve5(process.argv[1]) : null;
|
|
25765
25988
|
let entries;
|
|
25766
25989
|
try {
|
|
25767
|
-
entries = await
|
|
25990
|
+
entries = await readdir4(root);
|
|
25768
25991
|
} catch {
|
|
25769
25992
|
return [];
|
|
25770
25993
|
}
|
|
25771
25994
|
const removed = [];
|
|
25772
25995
|
for (const name of entries) {
|
|
25773
25996
|
if (protectedDirs.has(name) || !VERSION_DIR.test(name)) continue;
|
|
25774
|
-
const dir =
|
|
25997
|
+
const dir = join8(root, name);
|
|
25775
25998
|
if (running && running.startsWith(`${dir}${sep4}`)) continue;
|
|
25776
25999
|
try {
|
|
25777
|
-
await
|
|
26000
|
+
await rm5(dir, { recursive: true, force: true });
|
|
25778
26001
|
removed.push(name);
|
|
25779
26002
|
} catch {
|
|
25780
26003
|
}
|
|
@@ -25785,7 +26008,7 @@ function durableState(phase, candidateVersion, fallbackVersion) {
|
|
|
25785
26008
|
return { schema: 1, phase, candidateVersion, fallbackVersion };
|
|
25786
26009
|
}
|
|
25787
26010
|
async function validInstalledRelease(version2, root = versionsRoot()) {
|
|
25788
|
-
return validReleaseAtPrefix(
|
|
26011
|
+
return validReleaseAtPrefix(join8(root, version2), version2);
|
|
25789
26012
|
}
|
|
25790
26013
|
async function recoverDurableReleaseState(store, runningVersion, activeBootVersion, activate, log2) {
|
|
25791
26014
|
const state = await store.load();
|
|
@@ -25874,7 +26097,7 @@ async function recoverDurableReleaseState(store, runningVersion, activeBootVersi
|
|
|
25874
26097
|
}
|
|
25875
26098
|
return rolledBack();
|
|
25876
26099
|
}
|
|
25877
|
-
function defaultSpawn(command, argv, supervisorVersion, watchdog, compatibilityOwnership, containmentGateNonce, platform = process.platform) {
|
|
26100
|
+
function defaultSpawn(command, argv, supervisorVersion, watchdog, compatibilityOwnership, containmentGateNonce, platform = process.platform, diagnosticsRoot2 = null) {
|
|
25878
26101
|
const ownership = watchdog ?? compatibilityOwnership;
|
|
25879
26102
|
const compatibilityProxy = watchdog === null && compatibilityOwnership !== null;
|
|
25880
26103
|
const env = {
|
|
@@ -25894,14 +26117,21 @@ function defaultSpawn(command, argv, supervisorVersion, watchdog, compatibilityO
|
|
|
25894
26117
|
if (!containmentGateNonce) delete env[WINDOWS_POST_CONTAINMENT_CWD_ENV];
|
|
25895
26118
|
if (supervisorVersion) env[SUPERVISOR_VERSION_ENV] = supervisorVersion;
|
|
25896
26119
|
else delete env[SUPERVISOR_VERSION_ENV];
|
|
26120
|
+
delete env[WORKER_DIAGNOSTICS_DIR_ENV];
|
|
26121
|
+
if (diagnosticsRoot2) env[WORKER_DIAGNOSTICS_DIR_ENV] = diagnosticsRoot2;
|
|
26122
|
+
delete env[HOST_CONSOLE_COLOR_ENV];
|
|
26123
|
+
if (process.stderr.isTTY === true && process.env.NO_COLOR === void 0) {
|
|
26124
|
+
env[HOST_CONSOLE_COLOR_ENV] = "1";
|
|
26125
|
+
}
|
|
25897
26126
|
delete env.ZIXT_HOST_REJECT_VERSION;
|
|
25898
26127
|
if (command.rejectedVersion) env.ZIXT_HOST_REJECT_VERSION = command.rejectedVersion;
|
|
25899
26128
|
const entry = compatibilityProxy ? process.argv[1] ?? "" : command.entry ?? process.argv[1] ?? "";
|
|
25900
26129
|
const child = spawn5(process.execPath, [entry, ...argv, ...ownership?.argv ?? []], {
|
|
25901
26130
|
// stdin is a pipe this process owns: closing it is how the worker is
|
|
25902
26131
|
// asked to stop, which works identically on Windows, where there is no
|
|
25903
|
-
// real SIGINT to send. stdout
|
|
25904
|
-
|
|
26132
|
+
// real SIGINT to send. stdout stays the person's terminal; stderr is teed
|
|
26133
|
+
// through this process so a crash stack survives the exit that hid it.
|
|
26134
|
+
stdio: watchdog ? ["pipe", "inherit", "pipe", "ipc"] : ["pipe", "inherit", "pipe"],
|
|
25905
26135
|
env,
|
|
25906
26136
|
...containmentGateNonce ? {
|
|
25907
26137
|
cwd: ownership?.ownershipFile ? dirname4(ownership.ownershipFile) : dirname4(entry)
|
|
@@ -25933,7 +26163,7 @@ async function runWorkerCompatibilityProxy(env = process.env, argv = process.arg
|
|
|
25933
26163
|
const ownership = consumeWorkerOwnershipArguments(argv, env);
|
|
25934
26164
|
const nonce = env[WORKER_WATCHDOG_NONCE_ENV];
|
|
25935
26165
|
const ownershipFile = env[WORKER_OWNERSHIP_FILE_ENV];
|
|
25936
|
-
if (typeof target !== "string" || !
|
|
26166
|
+
if (typeof target !== "string" || !isAbsolute9(target) || typeof nonce !== "string" || typeof ownershipFile !== "string" || !ownership.requested || !ownership.valid) {
|
|
25937
26167
|
return 1;
|
|
25938
26168
|
}
|
|
25939
26169
|
if (!recordWorkerOwnership(ownershipFile, nonce)) return 1;
|
|
@@ -26004,7 +26234,7 @@ async function launchHostSupervisor(options = {}) {
|
|
|
26004
26234
|
const generationNonce = ownershipDirectory ? basename3(ownershipDirectory) : null;
|
|
26005
26235
|
if (ownershipDirectory && generationNonce) {
|
|
26006
26236
|
env[LAUNCHER_OWNERSHIP_DIR_ENV] = ownershipDirectory;
|
|
26007
|
-
env[SUPERVISOR_OWNERSHIP_FILE_ENV] =
|
|
26237
|
+
env[SUPERVISOR_OWNERSHIP_FILE_ENV] = join8(ownershipDirectory, `${generationNonce}.json`);
|
|
26008
26238
|
} else {
|
|
26009
26239
|
delete env[LAUNCHER_OWNERSHIP_DIR_ENV];
|
|
26010
26240
|
}
|
|
@@ -26027,8 +26257,8 @@ async function launchHostSupervisor(options = {}) {
|
|
|
26027
26257
|
});
|
|
26028
26258
|
const customDelay = options.delay;
|
|
26029
26259
|
const ownsWorkerBoundary = options.spawnSupervisor === void 0 || options.ownershipRoot !== void 0;
|
|
26030
|
-
const ownershipRoot = options.ownershipRoot ??
|
|
26031
|
-
const runRegistryRoot2 = options.runRegistryRoot ?? (options.ownershipRoot ?
|
|
26260
|
+
const ownershipRoot = options.ownershipRoot ?? join8(versionsRoot(), "launcher-ownership");
|
|
26261
|
+
const runRegistryRoot2 = options.runRegistryRoot ?? (options.ownershipRoot ? join8(dirname4(options.ownershipRoot), "run-registry") : defaultRunRegistryRoot());
|
|
26032
26262
|
const terminateRecordedOwnership = options.terminateRecordedOwnership ?? terminateRecordedProcessTree;
|
|
26033
26263
|
const createSupervisorContainment = options.createSupervisorContainment ?? (platform === "win32" && options.spawnSupervisor === void 0 ? async (target, identityNonce, signal) => {
|
|
26034
26264
|
if (!target.pid) throw new Error("supervisor process id is unavailable");
|
|
@@ -26295,10 +26525,10 @@ async function superviseHost(options = {}) {
|
|
|
26295
26525
|
const log2 = options.log ?? ((message) => console.error(message));
|
|
26296
26526
|
const signalWorker = options.signalWorker ?? signalWorkerGroup;
|
|
26297
26527
|
const inheritedOwnershipDirectory = process.env[LAUNCHER_OWNERSHIP_DIR_ENV];
|
|
26298
|
-
const launcherOwnershipDirectory = productionLifecycle && typeof inheritedOwnershipDirectory === "string" &&
|
|
26528
|
+
const launcherOwnershipDirectory = productionLifecycle && typeof inheritedOwnershipDirectory === "string" && isAbsolute9(inheritedOwnershipDirectory) ? inheritedOwnershipDirectory : null;
|
|
26299
26529
|
if (productionLifecycle && isSupervisorRole() && launcherOwnershipDirectory) {
|
|
26300
26530
|
const generationNonce = basename3(launcherOwnershipDirectory);
|
|
26301
|
-
const expectedOwnershipFile =
|
|
26531
|
+
const expectedOwnershipFile = join8(launcherOwnershipDirectory, `${generationNonce}.json`);
|
|
26302
26532
|
const configuredOwnershipFile = process.env[SUPERVISOR_OWNERSHIP_FILE_ENV];
|
|
26303
26533
|
if (process.argv0 !== generationNonce || configuredOwnershipFile !== expectedOwnershipFile || !recordWorkerOwnership(expectedOwnershipFile, generationNonce)) {
|
|
26304
26534
|
log2("Zixt Host: supervisor ownership could not be committed; refusing to start a worker");
|
|
@@ -26310,12 +26540,14 @@ async function superviseHost(options = {}) {
|
|
|
26310
26540
|
const workerWatchdogTimeoutMs = options.workerWatchdogTimeoutMs ?? WORKER_WATCHDOG_TIMEOUT_MS;
|
|
26311
26541
|
const workerWatchdogStartupMs = options.workerWatchdogStartupMs ?? WORKER_WATCHDOG_STARTUP_MS;
|
|
26312
26542
|
const workerReadinessTimeoutMs = options.workerReadinessTimeoutMs ?? WORKER_READINESS_TIMEOUT_MS;
|
|
26543
|
+
const workerShutdownDeadlineMs = options.workerShutdownDeadlineMs ?? WORKER_SHUTDOWN_DEADLINE_MS;
|
|
26313
26544
|
const releaseProbationMs = options.releaseProbationMs ?? RELEASE_PROBATION_MS;
|
|
26314
|
-
if (!Number.isSafeInteger(workerWatchdogCheckMs) || workerWatchdogCheckMs < 10 || workerWatchdogCheckMs > 6e4 || !Number.isSafeInteger(workerWatchdogTimeoutMs) || workerWatchdogTimeoutMs < workerWatchdogCheckMs * 2 || workerWatchdogTimeoutMs > 10 * 6e4 || !Number.isSafeInteger(workerWatchdogStartupMs) || workerWatchdogStartupMs < workerWatchdogCheckMs * 2 || workerWatchdogStartupMs > 10 * 6e4 || !Number.isSafeInteger(workerReadinessTimeoutMs) || workerReadinessTimeoutMs < workerWatchdogCheckMs * 2 || workerReadinessTimeoutMs > 10 * 6e4 || !Number.isSafeInteger(releaseProbationMs) || releaseProbationMs < 10 || releaseProbationMs > 24 * 60 * 6e4) {
|
|
26545
|
+
if (!Number.isSafeInteger(workerWatchdogCheckMs) || workerWatchdogCheckMs < 10 || workerWatchdogCheckMs > 6e4 || !Number.isSafeInteger(workerWatchdogTimeoutMs) || workerWatchdogTimeoutMs < workerWatchdogCheckMs * 2 || workerWatchdogTimeoutMs > 10 * 6e4 || !Number.isSafeInteger(workerWatchdogStartupMs) || workerWatchdogStartupMs < workerWatchdogCheckMs * 2 || workerWatchdogStartupMs > 10 * 6e4 || !Number.isSafeInteger(workerReadinessTimeoutMs) || workerReadinessTimeoutMs < workerWatchdogCheckMs * 2 || workerReadinessTimeoutMs > 10 * 6e4 || !Number.isSafeInteger(workerShutdownDeadlineMs) || workerShutdownDeadlineMs < workerWatchdogCheckMs * 2 || workerShutdownDeadlineMs > 10 * 6e4 || !Number.isSafeInteger(releaseProbationMs) || releaseProbationMs < 10 || releaseProbationMs > 24 * 60 * 6e4) {
|
|
26315
26546
|
throw new Error("worker watchdog durations are invalid");
|
|
26316
26547
|
}
|
|
26317
26548
|
const activeVersion = await activatedReleaseVersion();
|
|
26318
26549
|
const supervisorVersion = options.currentVersion !== void 0 ? options.currentVersion : process.env[SUPERVISOR_VERSION_ENV] ?? activeVersion ?? (productionLifecycle ? package_default.version : null);
|
|
26550
|
+
const workerDiagnosticsRoot = options.workerDiagnosticsRoot === void 0 ? productionLifecycle ? defaultWorkerDiagnosticsRoot() : null : options.workerDiagnosticsRoot;
|
|
26319
26551
|
const spawnWorker = options.spawnWorker ?? ((command2, watchdog, compatibilityOwnership, containmentGateNonce) => defaultSpawn(
|
|
26320
26552
|
command2,
|
|
26321
26553
|
argv,
|
|
@@ -26323,7 +26555,8 @@ async function superviseHost(options = {}) {
|
|
|
26323
26555
|
watchdog,
|
|
26324
26556
|
compatibilityOwnership,
|
|
26325
26557
|
containmentGateNonce,
|
|
26326
|
-
platform
|
|
26558
|
+
platform,
|
|
26559
|
+
workerDiagnosticsRoot
|
|
26327
26560
|
));
|
|
26328
26561
|
const install = options.installVersion ?? ((version2, signal) => installRelease(version2, signal ? { signal } : {}));
|
|
26329
26562
|
const cleanupWorker = options.cleanupWorker ?? (options.spawnWorker ? async () => {
|
|
@@ -26424,6 +26657,16 @@ async function superviseHost(options = {}) {
|
|
|
26424
26657
|
}
|
|
26425
26658
|
return false;
|
|
26426
26659
|
};
|
|
26660
|
+
const reportWorkerExit = async (record2, next) => {
|
|
26661
|
+
const { summary, context } = describeWorkerExit(record2);
|
|
26662
|
+
const detail = Object.entries(context).map(([key, value]) => `${key}=${value}`).join(" ");
|
|
26663
|
+
log2(`Zixt Host: worker ${summary}; ${next} (${detail})`);
|
|
26664
|
+
for (const line of record2.stderr) log2(`Zixt Host: worker stderr | ${line}`);
|
|
26665
|
+
if (!workerDiagnosticsRoot) return;
|
|
26666
|
+
if (!await recordWorkerExit(workerDiagnosticsRoot, record2)) {
|
|
26667
|
+
log2("Zixt Host: this exit could not be journalled, so the cloud will not receive it");
|
|
26668
|
+
}
|
|
26669
|
+
};
|
|
26427
26670
|
const directCommand = (candidate) => {
|
|
26428
26671
|
if (candidate.entry !== null || candidate.version === null) {
|
|
26429
26672
|
return { entry: candidate.entry, version: candidate.version };
|
|
@@ -26518,6 +26761,7 @@ async function superviseHost(options = {}) {
|
|
|
26518
26761
|
if (shuttingDown2) return 0;
|
|
26519
26762
|
child = spawnWorker(command, watchdogLaunch, compatibilityOwnership, containmentGateNonce);
|
|
26520
26763
|
const watchedChild = child;
|
|
26764
|
+
const workerStderr = captureWorkerStderr(watchedChild);
|
|
26521
26765
|
let resolveChildExited;
|
|
26522
26766
|
const childExited = new Promise((resolve18) => {
|
|
26523
26767
|
resolveChildExited = resolve18;
|
|
@@ -26575,10 +26819,14 @@ async function superviseHost(options = {}) {
|
|
|
26575
26819
|
let watchdogTimer;
|
|
26576
26820
|
let watchdogTriggered = false;
|
|
26577
26821
|
let watchdogCleanup = null;
|
|
26822
|
+
let containmentReason = null;
|
|
26578
26823
|
let lastWatchdogHeartbeatAt = now();
|
|
26579
26824
|
let lastWatchdogSequence = 0;
|
|
26580
26825
|
let lastReadinessAt = 0;
|
|
26581
26826
|
let lastReadinessSequence = 0;
|
|
26827
|
+
let announcedExitCode = null;
|
|
26828
|
+
let announcedShutdownAt = 0;
|
|
26829
|
+
let lastShutdownSequence = 0;
|
|
26582
26830
|
const onWatchdogMessage = (message) => {
|
|
26583
26831
|
if (watchdogLaunch && isWorkerWatchdogHeartbeat(message, watchdogLaunch, watchedChild.pid) && message.sequence > lastWatchdogSequence) {
|
|
26584
26832
|
lastWatchdogSequence = message.sequence;
|
|
@@ -26590,10 +26838,19 @@ async function superviseHost(options = {}) {
|
|
|
26590
26838
|
lastReadinessSequence = message.sequence;
|
|
26591
26839
|
lastReadinessAt = now();
|
|
26592
26840
|
}
|
|
26841
|
+
if (watchdogLaunch && isWorkerShutdownIntent(message, watchdogLaunch, watchedChild.pid) && message.sequence > lastShutdownSequence) {
|
|
26842
|
+
lastShutdownSequence = message.sequence;
|
|
26843
|
+
announcedExitCode = message.exitCode;
|
|
26844
|
+
announcedShutdownAt = now();
|
|
26845
|
+
log2(
|
|
26846
|
+
`Zixt Host: worker is stopping with code ${message.exitCode} (activeTasks=${message.activeTasks})`
|
|
26847
|
+
);
|
|
26848
|
+
}
|
|
26593
26849
|
};
|
|
26594
|
-
const containWorker = (message) => {
|
|
26850
|
+
const containWorker = (message, reason) => {
|
|
26595
26851
|
if (shuttingDown2 || watchdogTriggered) return;
|
|
26596
26852
|
watchdogTriggered = true;
|
|
26853
|
+
containmentReason = reason;
|
|
26597
26854
|
if (watchdogTimer) clearInterval(watchdogTimer);
|
|
26598
26855
|
watchdogTimer = void 0;
|
|
26599
26856
|
log2(message);
|
|
@@ -26607,11 +26864,23 @@ async function superviseHost(options = {}) {
|
|
|
26607
26864
|
if (watchdogLaunch) {
|
|
26608
26865
|
watchedChild.on("message", onWatchdogMessage);
|
|
26609
26866
|
watchdogTimer = setInterval(() => {
|
|
26610
|
-
if (shuttingDown2 || watchdogTriggered
|
|
26867
|
+
if (shuttingDown2 || watchdogTriggered) return;
|
|
26868
|
+
if (announcedExitCode !== null) {
|
|
26869
|
+
if (now() - announcedShutdownAt < workerShutdownDeadlineMs) return;
|
|
26870
|
+
containWorker(
|
|
26871
|
+
`Zixt Host: worker did not finish stopping within ${Math.round(
|
|
26872
|
+
workerShutdownDeadlineMs / 1e3
|
|
26873
|
+
)}s; terminating it and honouring the announced exit ${announcedExitCode}`,
|
|
26874
|
+
"watchdog_shutdown_deadline"
|
|
26875
|
+
);
|
|
26876
|
+
return;
|
|
26877
|
+
}
|
|
26878
|
+
if (now() - lastWatchdogHeartbeatAt < (lastWatchdogSequence === 0 ? workerWatchdogStartupMs : workerWatchdogTimeoutMs)) {
|
|
26611
26879
|
return;
|
|
26612
26880
|
}
|
|
26613
26881
|
containWorker(
|
|
26614
|
-
"Zixt Host: worker watchdog expired; terminating the unresponsive worker before restart"
|
|
26882
|
+
"Zixt Host: worker watchdog expired; terminating the unresponsive worker before restart",
|
|
26883
|
+
"watchdog_liveness"
|
|
26615
26884
|
);
|
|
26616
26885
|
}, workerWatchdogCheckMs);
|
|
26617
26886
|
watchdogTimer.unref?.();
|
|
@@ -26623,7 +26892,8 @@ async function superviseHost(options = {}) {
|
|
|
26623
26892
|
probationValidationTimer = setTimeout(() => {
|
|
26624
26893
|
if (lastWatchdogSequence === 0 || now() - lastWatchdogHeartbeatAt >= workerWatchdogTimeoutMs || lastReadinessSequence === 0 || now() - lastReadinessAt >= workerReadinessTimeoutMs) {
|
|
26625
26894
|
containWorker(
|
|
26626
|
-
`Zixt Host: ${candidateVersion} did not prove cloud readiness during probation; restoring the previous working release
|
|
26895
|
+
`Zixt Host: ${candidateVersion} did not prove cloud readiness during probation; restoring the previous working release`,
|
|
26896
|
+
"probation_readiness"
|
|
26627
26897
|
);
|
|
26628
26898
|
return;
|
|
26629
26899
|
}
|
|
@@ -26632,7 +26902,8 @@ async function superviseHost(options = {}) {
|
|
|
26632
26902
|
`Zixt Host: could not persist ${candidateVersion} probation evidence (${error52 instanceof Error ? error52.message : "unknown error"}); restoring the previous working release`
|
|
26633
26903
|
);
|
|
26634
26904
|
containWorker(
|
|
26635
|
-
`Zixt Host: ${candidateVersion} probation could not be committed; containing the candidate
|
|
26905
|
+
`Zixt Host: ${candidateVersion} probation could not be committed; containing the candidate`,
|
|
26906
|
+
"probation_commit"
|
|
26636
26907
|
);
|
|
26637
26908
|
});
|
|
26638
26909
|
}, releaseProbationMs);
|
|
@@ -26647,6 +26918,22 @@ async function superviseHost(options = {}) {
|
|
|
26647
26918
|
if (stopEscalation) clearTimeout(stopEscalation);
|
|
26648
26919
|
stopEscalation = void 0;
|
|
26649
26920
|
const runtimeMs = Math.max(0, now() - startedAt);
|
|
26921
|
+
const effectiveCode = watchdogTriggered && announcedExitCode === UPDATE_EXIT_CODE ? UPDATE_EXIT_CODE : code;
|
|
26922
|
+
const workerExit = {
|
|
26923
|
+
schema: 1,
|
|
26924
|
+
at: new Date(now()).toISOString(),
|
|
26925
|
+
version: command.version,
|
|
26926
|
+
pid: exitedChild.pid ?? null,
|
|
26927
|
+
code,
|
|
26928
|
+
signal,
|
|
26929
|
+
uptimeMs: runtimeMs,
|
|
26930
|
+
announcedExitCode,
|
|
26931
|
+
containment: containmentReason,
|
|
26932
|
+
msSinceHeartbeat: lastWatchdogSequence === 0 ? null : now() - lastWatchdogHeartbeatAt,
|
|
26933
|
+
heartbeats: lastWatchdogSequence,
|
|
26934
|
+
readinessMilestones: lastReadinessSequence,
|
|
26935
|
+
stderr: workerStderr()
|
|
26936
|
+
};
|
|
26650
26937
|
if (probationValidationCommit) await probationValidationCommit;
|
|
26651
26938
|
const orderlyValidatedBoundary = signal === null && !watchdogTriggered && (code === 0 || code === UPDATE_EXIT_CODE) && (releaseState === null && runtimeMs >= releaseProbationMs || releaseState?.phase === "validated" && command.version === releaseState.candidateVersion);
|
|
26652
26939
|
if (orderlyValidatedBoundary && command.version) {
|
|
@@ -26679,12 +26966,13 @@ async function superviseHost(options = {}) {
|
|
|
26679
26966
|
return 1;
|
|
26680
26967
|
}
|
|
26681
26968
|
if (!watchdogTriggered && (code === 0 || code === DO_NOT_RESTART_EXIT_CODE)) {
|
|
26969
|
+
if (code === DO_NOT_RESTART_EXIT_CODE) {
|
|
26970
|
+
await reportWorkerExit(workerExit, "this Machine needs attention before it can restart");
|
|
26971
|
+
}
|
|
26682
26972
|
return code;
|
|
26683
26973
|
}
|
|
26684
|
-
if (
|
|
26685
|
-
|
|
26686
|
-
`Zixt Host: worker ${signal ? `was killed by ${signal}` : `exited unexpectedly with code ${code ?? "unknown"}`}; restarting`
|
|
26687
|
-
);
|
|
26974
|
+
if (effectiveCode !== UPDATE_EXIT_CODE) {
|
|
26975
|
+
await reportWorkerExit(workerExit, "restarting");
|
|
26688
26976
|
if (rollbackCandidate && command.version === rollbackCandidate.failedVersion) {
|
|
26689
26977
|
const failedVersion = rollbackCandidate.failedVersion;
|
|
26690
26978
|
await restoreFallback(failedVersion, rollbackCandidate.command);
|
|
@@ -26695,6 +26983,9 @@ async function superviseHost(options = {}) {
|
|
|
26695
26983
|
if (!await waitAfterCrash(runtimeMs)) return 0;
|
|
26696
26984
|
continue;
|
|
26697
26985
|
}
|
|
26986
|
+
if (watchdogTriggered) {
|
|
26987
|
+
await reportWorkerExit(workerExit, "installing the update it asked for anyway");
|
|
26988
|
+
}
|
|
26698
26989
|
consecutiveCrashes = 0;
|
|
26699
26990
|
if (orderlyValidatedBoundary) rollbackCandidate = null;
|
|
26700
26991
|
const target = await published();
|
|
@@ -26819,15 +27110,47 @@ async function superviseHost(options = {}) {
|
|
|
26819
27110
|
}
|
|
26820
27111
|
}
|
|
26821
27112
|
|
|
27113
|
+
// src/worker-shutdown.ts
|
|
27114
|
+
var IDLE_SHUTDOWN_DEADLINE_MS = 2e3;
|
|
27115
|
+
var RECOVERING_SHUTDOWN_DEADLINE_MS = 3e4;
|
|
27116
|
+
var FORCED_EXIT_DRAIN_MS = 1e3;
|
|
27117
|
+
var defaultSchedule = (run3, ms) => {
|
|
27118
|
+
setTimeout(run3, ms).unref?.();
|
|
27119
|
+
};
|
|
27120
|
+
function beginWorkerShutdown(options) {
|
|
27121
|
+
const announce = options.announce ?? reportWorkerShutdown;
|
|
27122
|
+
const finish = options.finish ?? finishWorkerProcess;
|
|
27123
|
+
const exit = options.exit ?? ((code) => process.exit(code));
|
|
27124
|
+
const schedule = options.schedule ?? defaultSchedule;
|
|
27125
|
+
announce(options.exitCode, options.activeTasks);
|
|
27126
|
+
const recoveringLiveRuns = options.activeTasks > 0;
|
|
27127
|
+
const deadlineMs = recoveringLiveRuns ? RECOVERING_SHUTDOWN_DEADLINE_MS : IDLE_SHUTDOWN_DEADLINE_MS;
|
|
27128
|
+
const forcedExitCode = recoveringLiveRuns ? 1 : options.exitCode;
|
|
27129
|
+
let teardownCompleted = false;
|
|
27130
|
+
schedule(() => {
|
|
27131
|
+
const code = teardownCompleted ? options.exitCode : forcedExitCode;
|
|
27132
|
+
options.onForcedExit?.({ deadlineMs, code, teardownCompleted });
|
|
27133
|
+
void options.stopHeartbeat().then(() => {
|
|
27134
|
+
finish(code);
|
|
27135
|
+
schedule(() => exit(code), FORCED_EXIT_DRAIN_MS);
|
|
27136
|
+
});
|
|
27137
|
+
}, deadlineMs);
|
|
27138
|
+
void options.teardown().then(() => {
|
|
27139
|
+
teardownCompleted = true;
|
|
27140
|
+
return options.stopHeartbeat();
|
|
27141
|
+
}).then(() => finish(options.exitCode)).catch(() => {
|
|
27142
|
+
});
|
|
27143
|
+
}
|
|
27144
|
+
|
|
26822
27145
|
// src/index.ts
|
|
26823
|
-
import { homedir as
|
|
27146
|
+
import { homedir as homedir14, hostname as hostname3 } from "node:os";
|
|
26824
27147
|
|
|
26825
27148
|
// src/hardware.ts
|
|
26826
27149
|
import { existsSync } from "node:fs";
|
|
26827
27150
|
import { statfs } from "node:fs/promises";
|
|
26828
|
-
import { cpus, freemem, homedir as
|
|
27151
|
+
import { cpus, freemem, homedir as homedir4, totalmem } from "node:os";
|
|
26829
27152
|
import { dirname as dirname5, resolve as resolve6 } from "node:path";
|
|
26830
|
-
async function machineHardware(workRoot =
|
|
27153
|
+
async function machineHardware(workRoot = homedir4()) {
|
|
26831
27154
|
return {
|
|
26832
27155
|
// A container or cgroup can hide processors from this count; it is what
|
|
26833
27156
|
// this process can see, which is what its Tasks will actually get.
|
|
@@ -27049,17 +27372,17 @@ function createDemoBrowserAdapterFactory() {
|
|
|
27049
27372
|
}
|
|
27050
27373
|
|
|
27051
27374
|
// src/browser/manager.ts
|
|
27052
|
-
import { lstat as lstat6, mkdir as
|
|
27053
|
-
import { homedir as
|
|
27054
|
-
import { dirname as dirname6, join as
|
|
27375
|
+
import { lstat as lstat6, mkdir as mkdir6, open as open5, opendir, readFile as readFile8, rename as rename4, rm as rm6 } from "node:fs/promises";
|
|
27376
|
+
import { homedir as homedir5 } from "node:os";
|
|
27377
|
+
import { dirname as dirname6, join as join9, resolve as resolve7 } from "node:path";
|
|
27055
27378
|
var SAFE_SEGMENT2 = /^[A-Za-z0-9_-]{1,200}$/;
|
|
27056
27379
|
var FRAME_MIN_INTERVAL_MS = 100;
|
|
27057
27380
|
var IDLE_TIMEOUT_MS = 15 * 6e4;
|
|
27058
27381
|
var BrowserManager = class {
|
|
27059
27382
|
constructor(opts) {
|
|
27060
27383
|
this.opts = opts;
|
|
27061
|
-
this.profileRoot = opts.profileRoot ??
|
|
27062
|
-
this.profileStateRoot =
|
|
27384
|
+
this.profileRoot = opts.profileRoot ?? join9(homedir5(), ".zixt", "browser-profiles");
|
|
27385
|
+
this.profileStateRoot = join9(this.profileRoot, ".profile-state");
|
|
27063
27386
|
this.viewport = opts.viewport ?? BROWSER_DEFAULT_VIEWPORT;
|
|
27064
27387
|
this.idleTimeoutMs = opts.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
|
|
27065
27388
|
this.frameMinIntervalMs = opts.frameMinIntervalMs ?? FRAME_MIN_INTERVAL_MS;
|
|
@@ -27157,7 +27480,7 @@ var BrowserManager = class {
|
|
|
27157
27480
|
return target;
|
|
27158
27481
|
}
|
|
27159
27482
|
async ensureOwnedDirectory(path) {
|
|
27160
|
-
await
|
|
27483
|
+
await mkdir6(path, { recursive: true, mode: 448 });
|
|
27161
27484
|
const stat3 = await lstat6(path);
|
|
27162
27485
|
if (!stat3.isDirectory() || stat3.isSymbolicLink()) {
|
|
27163
27486
|
throw new Error("browser profile root must be an owned directory, not a symbolic link");
|
|
@@ -27193,7 +27516,7 @@ var BrowserManager = class {
|
|
|
27193
27516
|
}
|
|
27194
27517
|
async readProfileState(agentId) {
|
|
27195
27518
|
try {
|
|
27196
|
-
const raw = JSON.parse(await
|
|
27519
|
+
const raw = JSON.parse(await readFile8(this.statePath(agentId), "utf8"));
|
|
27197
27520
|
if (typeof raw !== "object" || raw === null || !Number.isInteger(raw.revision) || Number(raw.revision) < 0 || !["allowed", "purged"].includes(String(raw.state))) {
|
|
27198
27521
|
throw new Error("browser profile lifecycle marker is invalid");
|
|
27199
27522
|
}
|
|
@@ -27223,7 +27546,7 @@ var BrowserManager = class {
|
|
|
27223
27546
|
await this.syncDirectory(this.profileStateRoot);
|
|
27224
27547
|
await this.syncDirectory(this.profileRoot);
|
|
27225
27548
|
} catch (error52) {
|
|
27226
|
-
await
|
|
27549
|
+
await rm6(temporary, { force: true }).catch(() => {
|
|
27227
27550
|
});
|
|
27228
27551
|
throw error52;
|
|
27229
27552
|
}
|
|
@@ -27299,7 +27622,7 @@ var BrowserManager = class {
|
|
|
27299
27622
|
} catch (error52) {
|
|
27300
27623
|
if (error52.code !== "ENOENT") throw error52;
|
|
27301
27624
|
}
|
|
27302
|
-
await
|
|
27625
|
+
await mkdir6(profileDir, { recursive: true, mode: 448 });
|
|
27303
27626
|
const adapter = await this.opts.factory.open({
|
|
27304
27627
|
agentId,
|
|
27305
27628
|
profileDir,
|
|
@@ -27378,7 +27701,7 @@ var BrowserManager = class {
|
|
|
27378
27701
|
purgeId
|
|
27379
27702
|
});
|
|
27380
27703
|
await this.closeLocked(agentId, "stopped");
|
|
27381
|
-
await
|
|
27704
|
+
await rm6(this.profilePath(agentId), { recursive: true, force: true, maxRetries: 3 });
|
|
27382
27705
|
await this.syncDirectory(this.profileRoot);
|
|
27383
27706
|
});
|
|
27384
27707
|
}
|
|
@@ -28078,10 +28401,10 @@ function createPlaywrightBrowserAdapterFactory(dependencies = {}) {
|
|
|
28078
28401
|
|
|
28079
28402
|
// src/runners/cli-runner.ts
|
|
28080
28403
|
import { spawn as spawn8 } from "node:child_process";
|
|
28081
|
-
import { randomUUID as
|
|
28082
|
-
import { lstat as lstat11, mkdir as
|
|
28083
|
-
import { homedir as
|
|
28084
|
-
import { dirname as dirname8, isAbsolute as
|
|
28404
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
28405
|
+
import { lstat as lstat11, mkdir as mkdir11, realpath as realpath8 } from "node:fs/promises";
|
|
28406
|
+
import { homedir as homedir6 } from "node:os";
|
|
28407
|
+
import { dirname as dirname8, isAbsolute as isAbsolute15, join as join15, resolve as resolve10 } from "node:path";
|
|
28085
28408
|
|
|
28086
28409
|
// src/tool-packs/browser/authentication-wall.ts
|
|
28087
28410
|
var AUTH_PATH_SEGMENT = /(?:^|\/)(?:log[-_]?in|sign[-_]?in|sso|saml|auth|authorize|authenticate|oauth2?|session\/new|checkpoint)(?:\/|$)/i;
|
|
@@ -28462,7 +28785,7 @@ function createBrowserToolPack(deps) {
|
|
|
28462
28785
|
}
|
|
28463
28786
|
|
|
28464
28787
|
// src/tool-packs/provider-intents.ts
|
|
28465
|
-
import { createHash as createHash2, randomUUID as
|
|
28788
|
+
import { createHash as createHash2, randomUUID as randomUUID4 } from "node:crypto";
|
|
28466
28789
|
|
|
28467
28790
|
// src/tool-packs/github/rest-transport.ts
|
|
28468
28791
|
var MAX_RESPONSE_BYTES = 2 * 1024 * 1024;
|
|
@@ -28760,7 +29083,7 @@ function terminalForError(intentId2, error52) {
|
|
|
28760
29083
|
}
|
|
28761
29084
|
async function settle(context, terminal) {
|
|
28762
29085
|
try {
|
|
28763
|
-
const result = await context.settleProviderIntent(
|
|
29086
|
+
const result = await context.settleProviderIntent(randomUUID4(), terminal);
|
|
28764
29087
|
if (!result.ok) return { ok: false, error: result.error || RECORDING_FAILED };
|
|
28765
29088
|
return null;
|
|
28766
29089
|
} catch {
|
|
@@ -30252,7 +30575,7 @@ function createPullRequestTools(runtime) {
|
|
|
30252
30575
|
}
|
|
30253
30576
|
|
|
30254
30577
|
// src/tool-packs/github/repository-creation.ts
|
|
30255
|
-
import { randomUUID as
|
|
30578
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
30256
30579
|
var RECORDING_FAILED2 = "The provider call completed, but Zixt could not record its outcome. Do not retry; wait for reconciliation.";
|
|
30257
30580
|
var CLONE_WARNING = "The repository was created, but Zixt could not prepare its local workspace. Do not create it again.";
|
|
30258
30581
|
var REPOSITORY_ACCESS_WARNING = "Repository created, but GitHub access is still needed. Ask a GitHub organization owner to add this repository in the GitHub App settings, then use Check access in Zixt. Do not create it again.";
|
|
@@ -30508,7 +30831,7 @@ function failure(error52) {
|
|
|
30508
30831
|
}
|
|
30509
30832
|
function createGithubRepositoryCreator(input) {
|
|
30510
30833
|
const now = input.now ?? (() => /* @__PURE__ */ new Date());
|
|
30511
|
-
const terminalRequestId = input.terminalRequestId ??
|
|
30834
|
+
const terminalRequestId = input.terminalRequestId ?? randomUUID5;
|
|
30512
30835
|
return async (rawArgs) => {
|
|
30513
30836
|
let args;
|
|
30514
30837
|
try {
|
|
@@ -30697,7 +31020,7 @@ function createGithubRepositoryCreator(input) {
|
|
|
30697
31020
|
}
|
|
30698
31021
|
|
|
30699
31022
|
// src/tool-packs/github/push.ts
|
|
30700
|
-
import { randomUUID as
|
|
31023
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
30701
31024
|
var COMMIT_SHA = /^[a-f0-9]{40}(?:[a-f0-9]{24})?$/;
|
|
30702
31025
|
var RECORDING_FAILED3 = "The provider call completed, but Zixt could not record its outcome. Do not retry; wait for reconciliation.";
|
|
30703
31026
|
function claimResult3(value) {
|
|
@@ -30737,7 +31060,7 @@ function error51(message) {
|
|
|
30737
31060
|
}
|
|
30738
31061
|
function createGithubPushOrchestrator(input) {
|
|
30739
31062
|
const now = input.now ?? (() => /* @__PURE__ */ new Date());
|
|
30740
|
-
const terminalRequestId = input.terminalRequestId ??
|
|
31063
|
+
const terminalRequestId = input.terminalRequestId ?? randomUUID6;
|
|
30741
31064
|
return async (rawArgs) => {
|
|
30742
31065
|
try {
|
|
30743
31066
|
const args = rawArgs;
|
|
@@ -30899,15 +31222,15 @@ function createGithubPushOrchestrator(input) {
|
|
|
30899
31222
|
|
|
30900
31223
|
// src/tool-packs/github/git-bridge.ts
|
|
30901
31224
|
import { spawn as spawn6 } from "node:child_process";
|
|
30902
|
-
import { randomUUID as
|
|
30903
|
-
import { chmod as chmod4, lstat as lstat8, mkdir as
|
|
30904
|
-
import { dirname as dirname7, isAbsolute as
|
|
31225
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
31226
|
+
import { chmod as chmod4, lstat as lstat8, mkdir as mkdir7, realpath as realpath5, rm as rm7 } from "node:fs/promises";
|
|
31227
|
+
import { dirname as dirname7, isAbsolute as isAbsolute11, join as join11, relative as relative6 } from "node:path";
|
|
30905
31228
|
|
|
30906
31229
|
// src/tool-packs/github/git-credential-broker.ts
|
|
30907
31230
|
import { createServer } from "node:http";
|
|
30908
|
-
import { randomBytes, randomUUID as
|
|
30909
|
-
import { chmod as chmod3, lstat as lstat7, realpath as realpath4, writeFile as
|
|
30910
|
-
import { isAbsolute as
|
|
31231
|
+
import { randomBytes, randomUUID as randomUUID7, timingSafeEqual } from "node:crypto";
|
|
31232
|
+
import { chmod as chmod3, lstat as lstat7, realpath as realpath4, writeFile as writeFile3 } from "node:fs/promises";
|
|
31233
|
+
import { isAbsolute as isAbsolute10, join as join10, relative as relative5 } from "node:path";
|
|
30911
31234
|
var MAX_REQUEST_BYTES = 16 * 1024;
|
|
30912
31235
|
var FILE_MODE2 = 384;
|
|
30913
31236
|
var HELPER_SOURCE = String.raw`'use strict';
|
|
@@ -31021,7 +31344,7 @@ async function readBoundedBody2(request) {
|
|
|
31021
31344
|
}
|
|
31022
31345
|
function assertChildPath(parent, child) {
|
|
31023
31346
|
const path = relative5(parent, child);
|
|
31024
|
-
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") ||
|
|
31347
|
+
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") || isAbsolute10(path)) {
|
|
31025
31348
|
throw new Error("Git credential helper path escaped its private run directory");
|
|
31026
31349
|
}
|
|
31027
31350
|
}
|
|
@@ -31036,9 +31359,9 @@ async function createGithubGitCredentialBroker(input) {
|
|
|
31036
31359
|
throw new Error("Git credential broker requires a private real run directory");
|
|
31037
31360
|
}
|
|
31038
31361
|
const runRoot = await realpath4(input.runArtifactsRoot);
|
|
31039
|
-
const helperPath =
|
|
31362
|
+
const helperPath = join10(runRoot, `git-credential-${randomUUID7()}.cjs`);
|
|
31040
31363
|
assertChildPath(runRoot, helperPath);
|
|
31041
|
-
await
|
|
31364
|
+
await writeFile3(helperPath, HELPER_SOURCE, { flag: "wx", mode: FILE_MODE2 });
|
|
31042
31365
|
await chmod3(helperPath, FILE_MODE2);
|
|
31043
31366
|
const capability2 = randomBytes(32).toString("base64url");
|
|
31044
31367
|
const expectedPath = `${input.repositoryFullName}.git`;
|
|
@@ -31136,7 +31459,7 @@ ${stderr}`;
|
|
|
31136
31459
|
}
|
|
31137
31460
|
function assertBelow2(parent, child, label) {
|
|
31138
31461
|
const path = relative6(parent, child);
|
|
31139
|
-
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") ||
|
|
31462
|
+
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") || isAbsolute11(path)) {
|
|
31140
31463
|
throw new GithubGitProcessError("invalid_input");
|
|
31141
31464
|
}
|
|
31142
31465
|
void label;
|
|
@@ -31151,7 +31474,7 @@ async function requireRealDirectory2(path, label) {
|
|
|
31151
31474
|
}
|
|
31152
31475
|
async function validateTokenlessPaths(command) {
|
|
31153
31476
|
if (command.kind === "clone-from-bridge") {
|
|
31154
|
-
if (!
|
|
31477
|
+
if (!isAbsolute11(command.destination)) throw new GithubGitProcessError("invalid_input");
|
|
31155
31478
|
const parent = await requireRealDirectory2(dirname7(command.destination), "clone parent");
|
|
31156
31479
|
assertBelow2(parent, command.destination, "clone destination");
|
|
31157
31480
|
const destination = await lstat8(command.destination).catch((error52) => {
|
|
@@ -31162,7 +31485,7 @@ async function validateTokenlessPaths(command) {
|
|
|
31162
31485
|
return;
|
|
31163
31486
|
}
|
|
31164
31487
|
if ("repositoryPath" in command) {
|
|
31165
|
-
if (!
|
|
31488
|
+
if (!isAbsolute11(command.repositoryPath)) throw new GithubGitProcessError("invalid_input");
|
|
31166
31489
|
const repositoryPath5 = await requireRealDirectory2(command.repositoryPath, "repository path");
|
|
31167
31490
|
if (repositoryPath5 !== command.repositoryPath) throw new GithubGitProcessError("invalid_input");
|
|
31168
31491
|
}
|
|
@@ -31242,7 +31565,7 @@ async function runGit(input, args, env) {
|
|
|
31242
31565
|
if (input.authoritySignal.aborted || input.cancelledNow()) {
|
|
31243
31566
|
throw new GithubGitProcessError("cancelled");
|
|
31244
31567
|
}
|
|
31245
|
-
if (!
|
|
31568
|
+
if (!isAbsolute11(input.executablePath)) throw new GithubGitProcessError("invalid_input");
|
|
31246
31569
|
const timeoutMs = input.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
31247
31570
|
if (!Number.isInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > DEFAULT_TIMEOUT_MS2) {
|
|
31248
31571
|
throw new GithubGitProcessError("invalid_input");
|
|
@@ -31348,7 +31671,7 @@ function tokenlessArgs(command) {
|
|
|
31348
31671
|
switch (command.kind) {
|
|
31349
31672
|
case "clone-from-bridge":
|
|
31350
31673
|
assertRef(command.branch);
|
|
31351
|
-
if (!
|
|
31674
|
+
if (!isAbsolute11(command.destination)) throw new GithubGitProcessError("invalid_input");
|
|
31352
31675
|
return [
|
|
31353
31676
|
"clone",
|
|
31354
31677
|
"--no-recurse-submodules",
|
|
@@ -31360,7 +31683,7 @@ function tokenlessArgs(command) {
|
|
|
31360
31683
|
];
|
|
31361
31684
|
case "fetch-from-bridge":
|
|
31362
31685
|
assertFetchRefspecs(command.refspecs);
|
|
31363
|
-
if (!
|
|
31686
|
+
if (!isAbsolute11(command.repositoryPath)) throw new GithubGitProcessError("invalid_input");
|
|
31364
31687
|
return [
|
|
31365
31688
|
"-C",
|
|
31366
31689
|
command.repositoryPath,
|
|
@@ -31372,7 +31695,7 @@ function tokenlessArgs(command) {
|
|
|
31372
31695
|
...command.refspecs
|
|
31373
31696
|
];
|
|
31374
31697
|
case "copy-commit-to-bridge":
|
|
31375
|
-
if (!
|
|
31698
|
+
if (!isAbsolute11(command.repositoryPath) || !SHA.test(command.sha)) {
|
|
31376
31699
|
throw new GithubGitProcessError("invalid_input");
|
|
31377
31700
|
}
|
|
31378
31701
|
return [
|
|
@@ -31384,11 +31707,11 @@ function tokenlessArgs(command) {
|
|
|
31384
31707
|
`${command.sha}:refs/zixt/push-source`
|
|
31385
31708
|
];
|
|
31386
31709
|
case "rev-parse":
|
|
31387
|
-
if (!
|
|
31710
|
+
if (!isAbsolute11(command.repositoryPath)) throw new GithubGitProcessError("invalid_input");
|
|
31388
31711
|
assertRef(command.ref);
|
|
31389
31712
|
return ["-C", command.repositoryPath, "rev-parse", "--verify", `${command.ref}^{commit}`];
|
|
31390
31713
|
case "remote-configure":
|
|
31391
|
-
if (!
|
|
31714
|
+
if (!isAbsolute11(command.repositoryPath) || !REPOSITORY.test(command.repositoryFullName)) {
|
|
31392
31715
|
throw new GithubGitProcessError("invalid_input");
|
|
31393
31716
|
}
|
|
31394
31717
|
return [
|
|
@@ -31400,7 +31723,7 @@ function tokenlessArgs(command) {
|
|
|
31400
31723
|
`https://github.com/${command.repositoryFullName}.git`
|
|
31401
31724
|
];
|
|
31402
31725
|
case "status":
|
|
31403
|
-
if (!
|
|
31726
|
+
if (!isAbsolute11(command.repositoryPath)) throw new GithubGitProcessError("invalid_input");
|
|
31404
31727
|
return [
|
|
31405
31728
|
"-C",
|
|
31406
31729
|
command.repositoryPath,
|
|
@@ -31430,7 +31753,7 @@ function createGithubGitBridge(input) {
|
|
|
31430
31753
|
})();
|
|
31431
31754
|
const requireBridge = async (value) => {
|
|
31432
31755
|
const current = await roots();
|
|
31433
|
-
if (!
|
|
31756
|
+
if (!isAbsolute11(value) || !active.has(value)) throw new GithubGitProcessError("invalid_input");
|
|
31434
31757
|
const real = await requireRealDirectory2(value, "git bridge");
|
|
31435
31758
|
assertBelow2(current.bridges, real, "git bridge");
|
|
31436
31759
|
if (real !== value) throw new GithubGitProcessError("invalid_input");
|
|
@@ -31440,9 +31763,9 @@ function createGithubGitBridge(input) {
|
|
|
31440
31763
|
async createPrivateBridge() {
|
|
31441
31764
|
if (closed) throw new GithubGitProcessError("cancelled");
|
|
31442
31765
|
const current = await roots();
|
|
31443
|
-
const path =
|
|
31766
|
+
const path = join11(current.bridges, `${randomUUID8()}.git`);
|
|
31444
31767
|
assertBelow2(current.bridges, path, "git bridge");
|
|
31445
|
-
await
|
|
31768
|
+
await mkdir7(path, { mode: DIRECTORY_MODE2 });
|
|
31446
31769
|
await chmod4(path, DIRECTORY_MODE2);
|
|
31447
31770
|
try {
|
|
31448
31771
|
await runGit(
|
|
@@ -31458,16 +31781,16 @@ function createGithubGitBridge(input) {
|
|
|
31458
31781
|
);
|
|
31459
31782
|
const real = await requireRealDirectory2(path, "git bridge");
|
|
31460
31783
|
assertBelow2(current.bridges, real, "git bridge");
|
|
31461
|
-
const hooks =
|
|
31462
|
-
await
|
|
31463
|
-
await
|
|
31784
|
+
const hooks = join11(real, "hooks");
|
|
31785
|
+
await rm7(hooks, { recursive: true, force: true });
|
|
31786
|
+
await mkdir7(hooks, { mode: DIRECTORY_MODE2 });
|
|
31464
31787
|
await chmod4(hooks, DIRECTORY_MODE2);
|
|
31465
|
-
const config2 =
|
|
31788
|
+
const config2 = join11(real, "config");
|
|
31466
31789
|
await chmod4(config2, 384);
|
|
31467
31790
|
active.add(real);
|
|
31468
31791
|
return real;
|
|
31469
31792
|
} catch (error52) {
|
|
31470
|
-
await
|
|
31793
|
+
await rm7(path, { recursive: true, force: true }).catch(() => {
|
|
31471
31794
|
});
|
|
31472
31795
|
throw error52;
|
|
31473
31796
|
}
|
|
@@ -31561,7 +31884,7 @@ function createGithubGitBridge(input) {
|
|
|
31561
31884
|
},
|
|
31562
31885
|
async destroyPrivateBridge(path) {
|
|
31563
31886
|
const bridge = await requireBridge(path);
|
|
31564
|
-
await
|
|
31887
|
+
await rm7(bridge, { recursive: true, force: true });
|
|
31565
31888
|
active.delete(bridge);
|
|
31566
31889
|
credentialed2.delete(bridge);
|
|
31567
31890
|
},
|
|
@@ -31569,7 +31892,7 @@ function createGithubGitBridge(input) {
|
|
|
31569
31892
|
if (closed) return;
|
|
31570
31893
|
closed = true;
|
|
31571
31894
|
const paths = [...active];
|
|
31572
|
-
await Promise.all(paths.map((path) =>
|
|
31895
|
+
await Promise.all(paths.map((path) => rm7(path, { recursive: true, force: true })));
|
|
31573
31896
|
active.clear();
|
|
31574
31897
|
credentialed2.clear();
|
|
31575
31898
|
}
|
|
@@ -31909,9 +32232,9 @@ function createRepositoryTools(runtime) {
|
|
|
31909
32232
|
}
|
|
31910
32233
|
|
|
31911
32234
|
// src/tool-packs/github/workspace.ts
|
|
31912
|
-
import { randomUUID as
|
|
31913
|
-
import { chmod as chmod5, lstat as lstat9, mkdir as
|
|
31914
|
-
import { isAbsolute as
|
|
32235
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
32236
|
+
import { chmod as chmod5, lstat as lstat9, mkdir as mkdir8, readFile as readFile9, realpath as realpath6, rename as rename5, rm as rm8, writeFile as writeFile4 } from "node:fs/promises";
|
|
32237
|
+
import { isAbsolute as isAbsolute12, join as join12, relative as relative7, resolve as resolve8 } from "node:path";
|
|
31915
32238
|
var SAFE_LOCAL_ID = /^[A-Za-z0-9_-]{1,200}$/;
|
|
31916
32239
|
var FULL_NAME2 = /^[A-Za-z0-9_.-]{1,100}\/[A-Za-z0-9_.-]{1,100}$/;
|
|
31917
32240
|
var DIRECTORY_MODE3 = 448;
|
|
@@ -31929,7 +32252,7 @@ function hasControlCharacter2(value) {
|
|
|
31929
32252
|
}
|
|
31930
32253
|
function assertBelow3(parent, child, label) {
|
|
31931
32254
|
const path = relative7(parent, child);
|
|
31932
|
-
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") ||
|
|
32255
|
+
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") || isAbsolute12(path)) {
|
|
31933
32256
|
throw new Error(`${label} escaped the task workspace`);
|
|
31934
32257
|
}
|
|
31935
32258
|
}
|
|
@@ -31948,10 +32271,10 @@ async function requireRealDirectory3(path, label) {
|
|
|
31948
32271
|
return real;
|
|
31949
32272
|
}
|
|
31950
32273
|
async function createOrRequirePrivateDirectory(parent, name, label) {
|
|
31951
|
-
const path =
|
|
32274
|
+
const path = join12(parent, name);
|
|
31952
32275
|
assertBelow3(parent, path, label);
|
|
31953
32276
|
try {
|
|
31954
|
-
await
|
|
32277
|
+
await mkdir8(path, { mode: DIRECTORY_MODE3 });
|
|
31955
32278
|
} catch (error52) {
|
|
31956
32279
|
if (error52.code !== "EEXIST") throw error52;
|
|
31957
32280
|
}
|
|
@@ -32031,8 +32354,8 @@ async function createGithubWorkspaceService(input) {
|
|
|
32031
32354
|
if (expectedFullName !== void 0 && repository.fullName !== expectedFullName) {
|
|
32032
32355
|
throw new Error("GitHub repository name does not match this task grant");
|
|
32033
32356
|
}
|
|
32034
|
-
const destination =
|
|
32035
|
-
const metadataPath =
|
|
32357
|
+
const destination = join12(repositoriesRoot, parsed.data);
|
|
32358
|
+
const metadataPath = join12(metadataRoot, `${parsed.data}.json`);
|
|
32036
32359
|
if (!await pathExists(destination) || !await pathExists(metadataPath)) {
|
|
32037
32360
|
throw new Error("GitHub repository workspace has not been prepared");
|
|
32038
32361
|
}
|
|
@@ -32040,7 +32363,7 @@ async function createGithubWorkspaceService(input) {
|
|
|
32040
32363
|
if (!metadataEntry.isFile() || metadataEntry.isSymbolicLink()) {
|
|
32041
32364
|
throw new Error("GitHub workspace metadata is invalid");
|
|
32042
32365
|
}
|
|
32043
|
-
const metadata = parseMetadata(await
|
|
32366
|
+
const metadata = parseMetadata(await readFile9(metadataPath, "utf8"));
|
|
32044
32367
|
if (metadata.repositoryId !== parsed.data || metadata.fullName !== repository.fullName || !samePath(metadata.path, destination)) {
|
|
32045
32368
|
throw new Error("GitHub workspace metadata does not match this repository");
|
|
32046
32369
|
}
|
|
@@ -32049,14 +32372,14 @@ async function createGithubWorkspaceService(input) {
|
|
|
32049
32372
|
return real;
|
|
32050
32373
|
};
|
|
32051
32374
|
const cloneRepository = async (clone2) => {
|
|
32052
|
-
const destination =
|
|
32053
|
-
const metadataPath =
|
|
32375
|
+
const destination = join12(repositoriesRoot, clone2.repositoryId);
|
|
32376
|
+
const metadataPath = join12(metadataRoot, `${clone2.repositoryId}.json`);
|
|
32054
32377
|
assertBelow3(repositoriesRoot, destination, "repository path");
|
|
32055
32378
|
assertBelow3(metadataRoot, metadataPath, "repository metadata");
|
|
32056
32379
|
if (await pathExists(destination) || await pathExists(metadataPath)) {
|
|
32057
32380
|
throw new Error("GitHub repository workspace already exists or is inconsistent");
|
|
32058
32381
|
}
|
|
32059
|
-
const temporary =
|
|
32382
|
+
const temporary = join12(repositoriesRoot, `.clone-${randomUUID9()}`);
|
|
32060
32383
|
assertBelow3(repositoriesRoot, temporary, "temporary clone");
|
|
32061
32384
|
try {
|
|
32062
32385
|
await input.git.clone({
|
|
@@ -32081,9 +32404,9 @@ async function createGithubWorkspaceService(input) {
|
|
|
32081
32404
|
path: destination,
|
|
32082
32405
|
...clone2.createIntentId === void 0 ? {} : { createIntentId: clone2.createIntentId }
|
|
32083
32406
|
};
|
|
32084
|
-
const metadataTemporary =
|
|
32407
|
+
const metadataTemporary = join12(metadataRoot, `.${clone2.repositoryId}-${randomUUID9()}.tmp`);
|
|
32085
32408
|
assertBelow3(metadataRoot, metadataTemporary, "temporary repository metadata");
|
|
32086
|
-
await
|
|
32409
|
+
await writeFile4(metadataTemporary, `${JSON.stringify(metadata)}
|
|
32087
32410
|
`, {
|
|
32088
32411
|
flag: "wx",
|
|
32089
32412
|
mode: FILE_MODE3
|
|
@@ -32094,11 +32417,11 @@ async function createGithubWorkspaceService(input) {
|
|
|
32094
32417
|
try {
|
|
32095
32418
|
await rename5(metadataTemporary, metadataPath);
|
|
32096
32419
|
} catch (error52) {
|
|
32097
|
-
await
|
|
32420
|
+
await rm8(destination, { recursive: true, force: true });
|
|
32098
32421
|
throw error52;
|
|
32099
32422
|
}
|
|
32100
32423
|
} finally {
|
|
32101
|
-
await
|
|
32424
|
+
await rm8(metadataTemporary, { force: true }).catch(() => {
|
|
32102
32425
|
});
|
|
32103
32426
|
}
|
|
32104
32427
|
const path = await requireRealDirectory3(destination, "GitHub repository");
|
|
@@ -32110,14 +32433,14 @@ async function createGithubWorkspaceService(input) {
|
|
|
32110
32433
|
headSha
|
|
32111
32434
|
};
|
|
32112
32435
|
} finally {
|
|
32113
|
-
await
|
|
32436
|
+
await rm8(temporary, { recursive: true, force: true }).catch(() => {
|
|
32114
32437
|
});
|
|
32115
32438
|
}
|
|
32116
32439
|
};
|
|
32117
32440
|
const prepareRepository = async (authority) => {
|
|
32118
32441
|
const { repository } = authority;
|
|
32119
|
-
const destination =
|
|
32120
|
-
const metadataPath =
|
|
32442
|
+
const destination = join12(repositoriesRoot, repository.repositoryId);
|
|
32443
|
+
const metadataPath = join12(metadataRoot, `${repository.repositoryId}.json`);
|
|
32121
32444
|
assertBelow3(repositoriesRoot, destination, "repository path");
|
|
32122
32445
|
assertBelow3(metadataRoot, metadataPath, "repository metadata");
|
|
32123
32446
|
return withWorkspaceLock(destination, async () => {
|
|
@@ -32142,7 +32465,7 @@ async function createGithubWorkspaceService(input) {
|
|
|
32142
32465
|
if (!metadataEntry.isFile() || metadataEntry.isSymbolicLink()) {
|
|
32143
32466
|
throw new Error("GitHub workspace metadata is invalid");
|
|
32144
32467
|
}
|
|
32145
|
-
const metadata = parseMetadata(await
|
|
32468
|
+
const metadata = parseMetadata(await readFile9(metadataPath, "utf8"));
|
|
32146
32469
|
if (metadata.repositoryId !== repository.repositoryId || metadata.fullName !== repository.fullName || !samePath(metadata.path, destination)) {
|
|
32147
32470
|
throw new Error("GitHub workspace metadata does not match this repository");
|
|
32148
32471
|
}
|
|
@@ -32282,7 +32605,7 @@ async function createGithubWorkspaceService(input) {
|
|
|
32282
32605
|
throw new Error("GitHub created repository is outside this installation");
|
|
32283
32606
|
}
|
|
32284
32607
|
parseGitRef(cloneInput.repository.defaultBranch, "default branch");
|
|
32285
|
-
return withWorkspaceLock(
|
|
32608
|
+
return withWorkspaceLock(join12(repositoriesRoot, repositoryId2), async () => {
|
|
32286
32609
|
const prepared = await cloneRepository({
|
|
32287
32610
|
repositoryId: repositoryId2,
|
|
32288
32611
|
fullName: cloneInput.repository.fullName,
|
|
@@ -32689,7 +33012,7 @@ function createGithubToolPackFactory(options = {}) {
|
|
|
32689
33012
|
var githubToolPackFactory = createGithubToolPackFactory();
|
|
32690
33013
|
|
|
32691
33014
|
// src/runners/linear-api.ts
|
|
32692
|
-
import { createHash as createHash3, randomUUID as
|
|
33015
|
+
import { createHash as createHash3, randomUUID as randomUUID10 } from "node:crypto";
|
|
32693
33016
|
var MAX_RESPONSE_BYTES2 = 2 * 1024 * 1024;
|
|
32694
33017
|
var MAX_RESULT_STRING = 1e5;
|
|
32695
33018
|
var MAX_RESULT_ARRAY = 100;
|
|
@@ -33212,7 +33535,7 @@ function operationFor(name, args, appUserId, heldBy) {
|
|
|
33212
33535
|
case "linear_create_comment": {
|
|
33213
33536
|
const issueId = requiredString(args, "issue_id");
|
|
33214
33537
|
const body = requiredString(args, "body", 1e5);
|
|
33215
|
-
const commentId =
|
|
33538
|
+
const commentId = randomUUID10();
|
|
33216
33539
|
return {
|
|
33217
33540
|
query: `mutation ZixtLinearCreateComment($input: CommentCreateInput!) {
|
|
33218
33541
|
commentCreate(input: $input) { success comment { ${COMMENT_FIELDS} } }
|
|
@@ -33823,8 +34146,8 @@ function createDefaultToolPackRegistry() {
|
|
|
33823
34146
|
}
|
|
33824
34147
|
|
|
33825
34148
|
// src/runners/attachments.ts
|
|
33826
|
-
import { mkdir as
|
|
33827
|
-
import { join as
|
|
34149
|
+
import { mkdir as mkdir9, writeFile as writeFile5 } from "node:fs/promises";
|
|
34150
|
+
import { join as join13 } from "node:path";
|
|
33828
34151
|
var WINDOWS_RESERVED = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\..*)?$/i;
|
|
33829
34152
|
function sanitizeAttachmentFileName(name) {
|
|
33830
34153
|
const base = name.split(/[/\\]/).pop() ?? "";
|
|
@@ -33853,10 +34176,10 @@ async function materializeAttachments(task, taskRoot) {
|
|
|
33853
34176
|
`attached file "${attachment.name}" arrived incomplete (${bytes.byteLength} of ${attachment.size} bytes)`
|
|
33854
34177
|
);
|
|
33855
34178
|
}
|
|
33856
|
-
const directory =
|
|
33857
|
-
await
|
|
33858
|
-
const path =
|
|
33859
|
-
await
|
|
34179
|
+
const directory = join13(taskRoot, ".zixt-attachments", task.taskId, attachment.id);
|
|
34180
|
+
await mkdir9(directory, { recursive: true });
|
|
34181
|
+
const path = join13(directory, sanitizeAttachmentFileName(attachment.name));
|
|
34182
|
+
await writeFile5(path, bytes);
|
|
33860
34183
|
materialized.push({
|
|
33861
34184
|
path,
|
|
33862
34185
|
name: attachment.name,
|
|
@@ -34820,7 +35143,7 @@ function createAskUserServer() {
|
|
|
34820
35143
|
}
|
|
34821
35144
|
|
|
34822
35145
|
// src/runners/runner-env.ts
|
|
34823
|
-
import { delimiter as delimiter2, isAbsolute as
|
|
35146
|
+
import { delimiter as delimiter2, isAbsolute as isAbsolute13 } from "node:path";
|
|
34824
35147
|
var PROVIDER_AUTHORITY_PREFIXES = ["GH_", "GITHUB_", "GIT_", "SSH_"];
|
|
34825
35148
|
var HOST_AUTHORITY_PREFIXES = [
|
|
34826
35149
|
"ZIXT_",
|
|
@@ -34879,7 +35202,7 @@ function inheritedValue(env, name) {
|
|
|
34879
35202
|
}
|
|
34880
35203
|
function sanitizeInheritedSearchPath(path) {
|
|
34881
35204
|
if (!path) return "";
|
|
34882
|
-
return path.split(delimiter2).filter((entry) => entry !== "" &&
|
|
35205
|
+
return path.split(delimiter2).filter((entry) => entry !== "" && isAbsolute13(entry)).join(delimiter2);
|
|
34883
35206
|
}
|
|
34884
35207
|
function buildRunnerEnv(input) {
|
|
34885
35208
|
const env = {};
|
|
@@ -34960,9 +35283,9 @@ function buildRunnerEnv(input) {
|
|
|
34960
35283
|
// src/runners/github-shell-auth.ts
|
|
34961
35284
|
import { execFile } from "node:child_process";
|
|
34962
35285
|
import { randomBytes as randomBytes2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
34963
|
-
import { chmod as chmod6, lstat as lstat10, mkdir as
|
|
35286
|
+
import { chmod as chmod6, lstat as lstat10, mkdir as mkdir10, realpath as realpath7, writeFile as writeFile6 } from "node:fs/promises";
|
|
34964
35287
|
import { createServer as createServer3 } from "node:http";
|
|
34965
|
-
import { isAbsolute as
|
|
35288
|
+
import { isAbsolute as isAbsolute14, join as join14, relative as relative8 } from "node:path";
|
|
34966
35289
|
var MAX_REQUEST_BYTES2 = 16 * 1024;
|
|
34967
35290
|
var DIRECTORY_MODE4 = 448;
|
|
34968
35291
|
var PRIVATE_FILE_MODE = 384;
|
|
@@ -35168,7 +35491,7 @@ function parseGhInvocation(body) {
|
|
|
35168
35491
|
}
|
|
35169
35492
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
35170
35493
|
const { args, cwd } = value;
|
|
35171
|
-
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 || !
|
|
35494
|
+
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 || !isAbsolute14(cwd)) {
|
|
35172
35495
|
return null;
|
|
35173
35496
|
}
|
|
35174
35497
|
return { args, cwd };
|
|
@@ -35327,7 +35650,7 @@ function activationCredential(grant, now = Date.now()) {
|
|
|
35327
35650
|
}
|
|
35328
35651
|
function assertChildPath2(parent, child) {
|
|
35329
35652
|
const path = relative8(parent, child);
|
|
35330
|
-
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") ||
|
|
35653
|
+
if (!path || path === ".." || path.startsWith("../") || path.startsWith("..\\") || isAbsolute14(path)) {
|
|
35331
35654
|
throw new Error("GitHub shell helper path escaped its private run directory");
|
|
35332
35655
|
}
|
|
35333
35656
|
}
|
|
@@ -35338,7 +35661,7 @@ function quoteForPosixShell(value) {
|
|
|
35338
35661
|
return quoteForGitShell2(value);
|
|
35339
35662
|
}
|
|
35340
35663
|
async function writePrivate(path, content, executable = false) {
|
|
35341
|
-
await
|
|
35664
|
+
await writeFile6(path, content, {
|
|
35342
35665
|
flag: "wx",
|
|
35343
35666
|
mode: executable ? EXECUTABLE_FILE_MODE : PRIVATE_FILE_MODE
|
|
35344
35667
|
});
|
|
@@ -35350,7 +35673,7 @@ async function prepareHelpers(input) {
|
|
|
35350
35673
|
throw new Error("GitHub shell authentication requires a private real run directory");
|
|
35351
35674
|
}
|
|
35352
35675
|
const runRoot = await realpath7(input.runRoot);
|
|
35353
|
-
const helperPath =
|
|
35676
|
+
const helperPath = join14(runRoot, "github-shell-git-credential.cjs");
|
|
35354
35677
|
assertChildPath2(runRoot, helperPath);
|
|
35355
35678
|
await writePrivate(helperPath, GIT_HELPER_SOURCE);
|
|
35356
35679
|
if (!input.ghExecutablePath) {
|
|
@@ -35361,14 +35684,14 @@ async function prepareHelpers(input) {
|
|
|
35361
35684
|
wrapperSourcePath: null
|
|
35362
35685
|
};
|
|
35363
35686
|
}
|
|
35364
|
-
const shellToolsDirectory =
|
|
35687
|
+
const shellToolsDirectory = join14(runRoot, "shell-tools");
|
|
35365
35688
|
assertChildPath2(runRoot, shellToolsDirectory);
|
|
35366
|
-
await
|
|
35689
|
+
await mkdir10(shellToolsDirectory, { mode: DIRECTORY_MODE4 });
|
|
35367
35690
|
await chmod6(shellToolsDirectory, DIRECTORY_MODE4);
|
|
35368
|
-
const wrapperSourcePath =
|
|
35691
|
+
const wrapperSourcePath = join14(runRoot, "github-shell-gh-wrapper.cjs");
|
|
35369
35692
|
assertChildPath2(runRoot, wrapperSourcePath);
|
|
35370
35693
|
await writePrivate(wrapperSourcePath, GH_WRAPPER_SOURCE);
|
|
35371
|
-
const wrapperPath =
|
|
35694
|
+
const wrapperPath = join14(shellToolsDirectory, process.platform === "win32" ? "gh.cmd" : "gh");
|
|
35372
35695
|
assertChildPath2(runRoot, wrapperPath);
|
|
35373
35696
|
const launcher = process.platform === "win32" ? `@"${process.execPath.replaceAll('"', '""')}" "${wrapperSourcePath.replaceAll('"', '""')}" %*\r
|
|
35374
35697
|
` : `#!/bin/sh
|
|
@@ -36162,7 +36485,7 @@ async function settlesWithin(promise2, timeoutMs) {
|
|
|
36162
36485
|
}
|
|
36163
36486
|
}
|
|
36164
36487
|
function defaultRunnerWorkspaceRoot() {
|
|
36165
|
-
return
|
|
36488
|
+
return join15(homedir6(), ".zixt", "workspaces");
|
|
36166
36489
|
}
|
|
36167
36490
|
function defaultRunnerArtifactRoot() {
|
|
36168
36491
|
return defaultRunArtifactRoot();
|
|
@@ -36211,7 +36534,7 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
36211
36534
|
const prefixArgs = opts.commandPrefixArgs ?? [];
|
|
36212
36535
|
const maxWallTimeMs = opts.maxWallTimeMs;
|
|
36213
36536
|
const workspaceRoot = opts.workspaceRoot ?? defaultRunnerWorkspaceRoot();
|
|
36214
|
-
const artifactRoot = opts.artifactRoot ?? (opts.workspaceRoot === void 0 ? defaultRunnerArtifactRoot() :
|
|
36537
|
+
const artifactRoot = opts.artifactRoot ?? (opts.workspaceRoot === void 0 ? defaultRunnerArtifactRoot() : join15(dirname8(workspaceRoot), "run-artifacts"));
|
|
36215
36538
|
const runRegistryRoot2 = opts.runRegistryRoot ?? defaultRunRegistryRoot();
|
|
36216
36539
|
const createArtifacts = opts.createArtifacts ?? createRunArtifacts;
|
|
36217
36540
|
const toolPackRegistry2 = opts.toolPackRegistry ?? createDefaultToolPackRegistry();
|
|
@@ -36229,7 +36552,7 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
36229
36552
|
};
|
|
36230
36553
|
const askUserServer = createAskUserServer();
|
|
36231
36554
|
const windowsRoot = process.env.SystemRoot ?? process.env.WINDIR;
|
|
36232
|
-
const windowsComspecCandidate = process.platform === "win32" && windowsRoot ?
|
|
36555
|
+
const windowsComspecCandidate = process.platform === "win32" && windowsRoot ? join15(windowsRoot, "System32", "cmd.exe") : void 0;
|
|
36233
36556
|
let safetyFailure;
|
|
36234
36557
|
return async (task) => {
|
|
36235
36558
|
if (safetyFailure) {
|
|
@@ -36269,8 +36592,8 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
36269
36592
|
usage: { inputTokens: 0, outputTokens: 0 }
|
|
36270
36593
|
};
|
|
36271
36594
|
}
|
|
36272
|
-
const taskRoot =
|
|
36273
|
-
await
|
|
36595
|
+
const taskRoot = join15(workspaceRoot, task.agentId);
|
|
36596
|
+
await mkdir11(taskRoot, { recursive: true });
|
|
36274
36597
|
if (task.cancelledNow()) return cancelledBeforeRun();
|
|
36275
36598
|
const configuredWorkspace = task.spec.workspace;
|
|
36276
36599
|
let cwd = taskRoot;
|
|
@@ -36316,7 +36639,7 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
36316
36639
|
summaryEvidence: "host_observed"
|
|
36317
36640
|
};
|
|
36318
36641
|
}
|
|
36319
|
-
const runToken =
|
|
36642
|
+
const runToken = randomUUID11();
|
|
36320
36643
|
const artifacts = await createArtifacts({
|
|
36321
36644
|
root: artifactRoot,
|
|
36322
36645
|
agentId: task.agentId,
|
|
@@ -36577,7 +36900,7 @@ ${attachmentSection}` : prompt;
|
|
|
36577
36900
|
let changed = false;
|
|
36578
36901
|
for (const path of paths) {
|
|
36579
36902
|
if (!path || path.length > 4096) continue;
|
|
36580
|
-
const absolutePath =
|
|
36903
|
+
const absolutePath = isAbsolute15(path) ? path : resolve10(cwd, path);
|
|
36581
36904
|
const directory = dirname8(absolutePath);
|
|
36582
36905
|
observedWorkingDirectories.delete(directory);
|
|
36583
36906
|
observedWorkingDirectories.add(directory);
|
|
@@ -36658,8 +36981,8 @@ ${attachmentSection}` : prompt;
|
|
|
36658
36981
|
}
|
|
36659
36982
|
comspec = resolvedWindowsComspec;
|
|
36660
36983
|
}
|
|
36661
|
-
const exitMarker = `__ZIXT_RUNNER_EXIT_${
|
|
36662
|
-
const guardianNonce =
|
|
36984
|
+
const exitMarker = `__ZIXT_RUNNER_EXIT_${randomUUID11()}__`;
|
|
36985
|
+
const guardianNonce = randomUUID11();
|
|
36663
36986
|
return runCliProcess({
|
|
36664
36987
|
command: resolvedCommand,
|
|
36665
36988
|
args,
|
|
@@ -37012,7 +37335,7 @@ function runCliProcess(options) {
|
|
|
37012
37335
|
}
|
|
37013
37336
|
return new Promise((resolve18) => {
|
|
37014
37337
|
const platform = options.platform ?? process.platform;
|
|
37015
|
-
const containmentGateNonce = options.guardian && platform === "win32" ?
|
|
37338
|
+
const containmentGateNonce = options.guardian && platform === "win32" ? randomUUID11() : void 0;
|
|
37016
37339
|
const child = options.guardian ? spawn8(
|
|
37017
37340
|
options.guardian.nodeCommand,
|
|
37018
37341
|
[
|
|
@@ -37301,17 +37624,17 @@ function runCliProcess(options) {
|
|
|
37301
37624
|
}
|
|
37302
37625
|
|
|
37303
37626
|
// src/runners/claude-code.ts
|
|
37304
|
-
import { randomUUID as
|
|
37627
|
+
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
37305
37628
|
|
|
37306
37629
|
// src/runners/runtime-observation.ts
|
|
37307
|
-
import { open as open6, readdir as
|
|
37308
|
-
import { homedir as
|
|
37309
|
-
import { join as
|
|
37630
|
+
import { open as open6, readdir as readdir5, realpath as realpath9 } from "node:fs/promises";
|
|
37631
|
+
import { homedir as homedir7 } from "node:os";
|
|
37632
|
+
import { join as join16 } from "node:path";
|
|
37310
37633
|
var READ_WINDOW_BYTES = 1024 * 1024;
|
|
37311
37634
|
var CATALOG_TIMEOUT_MS = 15e3;
|
|
37312
37635
|
var CATALOG_OUTPUT_LIMIT_BYTES = 4 * 1024 * 1024;
|
|
37313
37636
|
function homeFrom(env) {
|
|
37314
|
-
return env["HOME"] || env["USERPROFILE"] ||
|
|
37637
|
+
return env["HOME"] || env["USERPROFILE"] || homedir7();
|
|
37315
37638
|
}
|
|
37316
37639
|
async function readHead(path) {
|
|
37317
37640
|
let handle;
|
|
@@ -37366,9 +37689,9 @@ function displayValue(value, maxLength) {
|
|
|
37366
37689
|
return trimmed;
|
|
37367
37690
|
}
|
|
37368
37691
|
function claudeTranscriptPath(input) {
|
|
37369
|
-
const configDir = input.env["CLAUDE_CONFIG_DIR"] ||
|
|
37692
|
+
const configDir = input.env["CLAUDE_CONFIG_DIR"] || join16(homeFrom(input.env), ".claude");
|
|
37370
37693
|
const slug = input.resolvedCwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
37371
|
-
return
|
|
37694
|
+
return join16(configDir, "projects", slug, `${input.sessionId}.jsonl`);
|
|
37372
37695
|
}
|
|
37373
37696
|
async function readClaudeSessionEffort(input) {
|
|
37374
37697
|
const resolvedCwd = await realpath9(input.cwd).catch(() => input.cwd);
|
|
@@ -37383,19 +37706,19 @@ async function readClaudeSessionEffort(input) {
|
|
|
37383
37706
|
return null;
|
|
37384
37707
|
}
|
|
37385
37708
|
async function newestDirectories(root, limit) {
|
|
37386
|
-
const entries = await
|
|
37387
|
-
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort((left, right) => right.localeCompare(left)).slice(0, limit).map((name) =>
|
|
37709
|
+
const entries = await readdir5(root, { withFileTypes: true }).catch(() => []);
|
|
37710
|
+
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort((left, right) => right.localeCompare(left)).slice(0, limit).map((name) => join16(root, name));
|
|
37388
37711
|
}
|
|
37389
37712
|
async function findCodexRolloutPath(input) {
|
|
37390
|
-
const codexHome = input.env["CODEX_HOME"] ||
|
|
37391
|
-
const sessions =
|
|
37713
|
+
const codexHome = input.env["CODEX_HOME"] || join16(homeFrom(input.env), ".codex");
|
|
37714
|
+
const sessions = join16(codexHome, "sessions");
|
|
37392
37715
|
const suffix = `-${input.threadId}.jsonl`;
|
|
37393
37716
|
for (const year of await newestDirectories(sessions, 2)) {
|
|
37394
37717
|
for (const month of await newestDirectories(year, 2)) {
|
|
37395
37718
|
for (const day of await newestDirectories(month, 3)) {
|
|
37396
|
-
const files = await
|
|
37719
|
+
const files = await readdir5(day).catch(() => []);
|
|
37397
37720
|
const match = files.find((name) => name.endsWith(suffix));
|
|
37398
|
-
if (match) return
|
|
37721
|
+
if (match) return join16(day, match);
|
|
37399
37722
|
}
|
|
37400
37723
|
}
|
|
37401
37724
|
}
|
|
@@ -37493,7 +37816,7 @@ var claudeCodeAdapter = {
|
|
|
37493
37816
|
input.gitDetected,
|
|
37494
37817
|
liveInput
|
|
37495
37818
|
);
|
|
37496
|
-
const sessionId = input.task.spec.sessionKey ??
|
|
37819
|
+
const sessionId = input.task.spec.sessionKey ?? randomUUID12();
|
|
37497
37820
|
const observeRuntime = createRuntimeReporter(input, sessionId);
|
|
37498
37821
|
return {
|
|
37499
37822
|
argsFor: (mode) => [
|
|
@@ -37612,7 +37935,7 @@ function createClaudeLiveParser(onStream, onSessionModel) {
|
|
|
37612
37935
|
...parser,
|
|
37613
37936
|
async start(writer, prompt) {
|
|
37614
37937
|
write = writer;
|
|
37615
|
-
await writer(input(
|
|
37938
|
+
await writer(input(randomUUID12(), prompt));
|
|
37616
37939
|
},
|
|
37617
37940
|
async steer(followUp) {
|
|
37618
37941
|
if (!write) return false;
|
|
@@ -37779,22 +38102,22 @@ function improveErrorMessage(error52) {
|
|
|
37779
38102
|
}
|
|
37780
38103
|
|
|
37781
38104
|
// src/runners/codex.ts
|
|
37782
|
-
import { mkdir as
|
|
37783
|
-
import { randomUUID as
|
|
37784
|
-
import { homedir as
|
|
37785
|
-
import { join as
|
|
38105
|
+
import { mkdir as mkdir12, readFile as readFile10, writeFile as writeFile7 } from "node:fs/promises";
|
|
38106
|
+
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
38107
|
+
import { homedir as homedir8 } from "node:os";
|
|
38108
|
+
import { join as join17 } from "node:path";
|
|
37786
38109
|
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.";
|
|
37787
38110
|
function defaultCodexThreadIndexRoot() {
|
|
37788
|
-
return
|
|
38111
|
+
return join17(homedir8(), ".zixt", "codex-threads");
|
|
37789
38112
|
}
|
|
37790
38113
|
var SAFE_SEGMENT3 = /^[A-Za-z0-9_-]{1,200}$/;
|
|
37791
38114
|
function threadIndexPath(root, agentId, sessionKey) {
|
|
37792
38115
|
if (!SAFE_SEGMENT3.test(agentId) || !SAFE_SEGMENT3.test(sessionKey)) return null;
|
|
37793
|
-
return
|
|
38116
|
+
return join17(root, agentId, `${sessionKey}.json`);
|
|
37794
38117
|
}
|
|
37795
38118
|
async function readThreadId(path) {
|
|
37796
38119
|
try {
|
|
37797
|
-
const parsed = JSON.parse(await
|
|
38120
|
+
const parsed = JSON.parse(await readFile10(path, "utf8"));
|
|
37798
38121
|
return typeof parsed.threadId === "string" && /^[A-Za-z0-9-]{1,120}$/.test(parsed.threadId) ? parsed.threadId : null;
|
|
37799
38122
|
} catch {
|
|
37800
38123
|
return null;
|
|
@@ -37885,7 +38208,7 @@ ${value}` : value;
|
|
|
37885
38208
|
const recordedThreadId = indexPath ? await readThreadId(indexPath) : null;
|
|
37886
38209
|
const rememberThread = (threadId) => {
|
|
37887
38210
|
if (!indexPath) return;
|
|
37888
|
-
void
|
|
38211
|
+
void mkdir12(join17(threadIndexRoot, task.agentId), { recursive: true }).then(() => writeFile7(indexPath, JSON.stringify({ threadId }), "utf8")).catch(() => {
|
|
37889
38212
|
});
|
|
37890
38213
|
};
|
|
37891
38214
|
const observeRuntime = (threadId) => {
|
|
@@ -37989,7 +38312,7 @@ function createCodexAppServerParser(onStream, options) {
|
|
|
37989
38312
|
params: {
|
|
37990
38313
|
threadId,
|
|
37991
38314
|
input: [{ type: "text", text: prompt }],
|
|
37992
|
-
clientUserMessageId:
|
|
38315
|
+
clientUserMessageId: randomUUID13(),
|
|
37993
38316
|
...options.model ? { model: options.model } : {},
|
|
37994
38317
|
...options.effort ? { effort: options.effort } : {}
|
|
37995
38318
|
}
|
|
@@ -38350,7 +38673,7 @@ function improveCodexErrorMessage(error52) {
|
|
|
38350
38673
|
// src/runners/git-preflight.ts
|
|
38351
38674
|
import { spawn as spawn9 } from "node:child_process";
|
|
38352
38675
|
import { realpath as realpath10 } from "node:fs/promises";
|
|
38353
|
-
import { isAbsolute as
|
|
38676
|
+
import { isAbsolute as isAbsolute16, resolve as resolve11 } from "node:path";
|
|
38354
38677
|
var OUTPUT_LIMIT = 8192;
|
|
38355
38678
|
var DEFAULT_TIMEOUT_MS4 = 1e4;
|
|
38356
38679
|
var VERSION_PATTERN = /^git version [^\r\n]{1,108}$/;
|
|
@@ -38366,7 +38689,7 @@ function unavailable(error52, checkedAt, executablePath = null) {
|
|
|
38366
38689
|
async function preflightGit(options = {}) {
|
|
38367
38690
|
const checkedAt = (options.now?.() ?? /* @__PURE__ */ new Date()).toISOString();
|
|
38368
38691
|
const configured = options.command;
|
|
38369
|
-
if (configured !== void 0 && !
|
|
38692
|
+
if (configured !== void 0 && !isAbsolute16(configured)) {
|
|
38370
38693
|
return unavailable("configured git command must be an absolute file", checkedAt);
|
|
38371
38694
|
}
|
|
38372
38695
|
const trustedCwd = await realpath10(resolve11(options.trustedCwd ?? process.cwd())).catch(() => null);
|
|
@@ -38621,9 +38944,9 @@ function run2(command, args) {
|
|
|
38621
38944
|
// src/linux-service.ts
|
|
38622
38945
|
import { spawn as spawn10 } from "node:child_process";
|
|
38623
38946
|
import { constants as constants2 } from "node:fs";
|
|
38624
|
-
import { access as access4, chmod as chmod7, mkdir as
|
|
38625
|
-
import { homedir as
|
|
38626
|
-
import { basename as basename4, dirname as dirname9, join as
|
|
38947
|
+
import { access as access4, chmod as chmod7, mkdir as mkdir13, open as open7, rename as rename6, rm as rm9 } from "node:fs/promises";
|
|
38948
|
+
import { homedir as homedir9, userInfo } from "node:os";
|
|
38949
|
+
import { basename as basename4, dirname as dirname9, join as join18, relative as relative9, resolve as resolve12, sep as sep5 } from "node:path";
|
|
38627
38950
|
var SERVICE_NAME = "zixt-host.service";
|
|
38628
38951
|
var SYSTEM_SERVICE_COMMAND_TIMEOUT_MS = 7e4;
|
|
38629
38952
|
var SERVICE_STABILITY_DELAY_MS = 2e3;
|
|
@@ -38724,7 +39047,7 @@ async function defaultSyncDirectory(path) {
|
|
|
38724
39047
|
}
|
|
38725
39048
|
}
|
|
38726
39049
|
async function ensureDirectory(path, mode, syncDirectory8) {
|
|
38727
|
-
const firstCreated = await
|
|
39050
|
+
const firstCreated = await mkdir13(path, { recursive: true, mode });
|
|
38728
39051
|
if (!firstCreated) return;
|
|
38729
39052
|
const first = resolve12(firstCreated);
|
|
38730
39053
|
const target = resolve12(path);
|
|
@@ -38733,13 +39056,13 @@ async function ensureDirectory(path, mode, syncDirectory8) {
|
|
|
38733
39056
|
const descendants = relative9(first, target);
|
|
38734
39057
|
for (const part of descendants ? descendants.split(sep5) : []) {
|
|
38735
39058
|
await syncDirectory8(current);
|
|
38736
|
-
current =
|
|
39059
|
+
current = join18(current, part);
|
|
38737
39060
|
}
|
|
38738
39061
|
}
|
|
38739
39062
|
async function replacePrivateFile(path, contents, mode, syncDirectory8) {
|
|
38740
39063
|
const parent = dirname9(path);
|
|
38741
39064
|
await ensureDirectory(parent, 448, syncDirectory8);
|
|
38742
|
-
const temporary =
|
|
39065
|
+
const temporary = join18(parent, `.${basename4(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
38743
39066
|
const handle = await open7(temporary, "wx", mode);
|
|
38744
39067
|
try {
|
|
38745
39068
|
await handle.writeFile(contents, "utf8");
|
|
@@ -38750,7 +39073,7 @@ async function replacePrivateFile(path, contents, mode, syncDirectory8) {
|
|
|
38750
39073
|
await syncDirectory8(parent);
|
|
38751
39074
|
} catch (error52) {
|
|
38752
39075
|
await handle.close().catch(() => void 0);
|
|
38753
|
-
await
|
|
39076
|
+
await rm9(temporary, { force: true }).catch(() => void 0);
|
|
38754
39077
|
throw error52;
|
|
38755
39078
|
}
|
|
38756
39079
|
}
|
|
@@ -38783,7 +39106,7 @@ async function installLinuxService(options) {
|
|
|
38783
39106
|
throw new Error("Linux automatic startup is available only on Linux.");
|
|
38784
39107
|
}
|
|
38785
39108
|
const env = options.env ?? process.env;
|
|
38786
|
-
const home = options.home ??
|
|
39109
|
+
const home = options.home ?? homedir9();
|
|
38787
39110
|
const username = oneLine(options.username ?? userInfo().username, "user name");
|
|
38788
39111
|
const token2 = oneLine(options.token, "pairing code");
|
|
38789
39112
|
const path = oneLine(
|
|
@@ -38791,11 +39114,11 @@ async function installLinuxService(options) {
|
|
|
38791
39114
|
"command search path"
|
|
38792
39115
|
);
|
|
38793
39116
|
const cloudUrl = options.cloudUrl ? oneLine(options.cloudUrl, "Zixt Cloud address") : void 0;
|
|
38794
|
-
const xdgConfigHome = env.XDG_CONFIG_HOME ? oneLine(env.XDG_CONFIG_HOME, "Linux configuration path") :
|
|
38795
|
-
const configRoot = options.serviceConfigRoot ??
|
|
38796
|
-
const unitRoot = options.userUnitRoot ??
|
|
38797
|
-
const environmentPath =
|
|
38798
|
-
const unitPath =
|
|
39117
|
+
const xdgConfigHome = env.XDG_CONFIG_HOME ? oneLine(env.XDG_CONFIG_HOME, "Linux configuration path") : join18(home, ".config");
|
|
39118
|
+
const configRoot = options.serviceConfigRoot ?? join18(xdgConfigHome, "zixt");
|
|
39119
|
+
const unitRoot = options.userUnitRoot ?? join18(xdgConfigHome, "systemd", "user");
|
|
39120
|
+
const environmentPath = join18(configRoot, "host.env");
|
|
39121
|
+
const unitPath = join18(unitRoot, SERVICE_NAME);
|
|
38799
39122
|
const installVersion = options.installVersion ?? installRelease;
|
|
38800
39123
|
const activateVersion = options.activateVersion ?? (options.installVersion ? async (entry) => entry : activateInstalledRelease);
|
|
38801
39124
|
const resolveCommand = options.resolveCommand ?? defaultResolveCommand;
|
|
@@ -38914,9 +39237,9 @@ async function installLinuxService(options) {
|
|
|
38914
39237
|
// src/macos-service.ts
|
|
38915
39238
|
import { spawn as spawn11 } from "node:child_process";
|
|
38916
39239
|
import { constants as constants3 } from "node:fs";
|
|
38917
|
-
import { access as access5, chmod as chmod8, mkdir as
|
|
38918
|
-
import { homedir as
|
|
38919
|
-
import { basename as basename5, dirname as dirname10, join as
|
|
39240
|
+
import { access as access5, chmod as chmod8, mkdir as mkdir14, open as open8, rename as rename7, rm as rm10 } from "node:fs/promises";
|
|
39241
|
+
import { homedir as homedir10, userInfo as userInfo2 } from "node:os";
|
|
39242
|
+
import { basename as basename5, dirname as dirname10, join as join19, relative as relative10, resolve as resolve13, sep as sep6 } from "node:path";
|
|
38920
39243
|
var LAUNCH_AGENT_LABEL = "ai.zixt.host";
|
|
38921
39244
|
var SERVICE_STABILITY_DELAY_MS2 = 2e3;
|
|
38922
39245
|
var COMMAND_TIMEOUT_MS2 = 7e4;
|
|
@@ -38940,7 +39263,7 @@ async function syncDirectory4(path) {
|
|
|
38940
39263
|
}
|
|
38941
39264
|
}
|
|
38942
39265
|
async function ensureDirectory2(path, sync) {
|
|
38943
|
-
const firstCreated = await
|
|
39266
|
+
const firstCreated = await mkdir14(path, { recursive: true, mode: 448 });
|
|
38944
39267
|
if (!firstCreated) return;
|
|
38945
39268
|
const first = resolve13(firstCreated);
|
|
38946
39269
|
const target = resolve13(path);
|
|
@@ -38948,13 +39271,13 @@ async function ensureDirectory2(path, sync) {
|
|
|
38948
39271
|
let current = first;
|
|
38949
39272
|
for (const part of relative10(first, target).split(sep6).filter(Boolean)) {
|
|
38950
39273
|
await sync(current);
|
|
38951
|
-
current =
|
|
39274
|
+
current = join19(current, part);
|
|
38952
39275
|
}
|
|
38953
39276
|
}
|
|
38954
39277
|
async function replacePrivateFile2(path, contents, mode, sync) {
|
|
38955
39278
|
const parent = dirname10(path);
|
|
38956
39279
|
await ensureDirectory2(parent, sync);
|
|
38957
|
-
const temporary =
|
|
39280
|
+
const temporary = join19(parent, `.${basename5(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
38958
39281
|
const handle = await open8(temporary, "wx", mode);
|
|
38959
39282
|
try {
|
|
38960
39283
|
await handle.writeFile(contents, "utf8");
|
|
@@ -38965,7 +39288,7 @@ async function replacePrivateFile2(path, contents, mode, sync) {
|
|
|
38965
39288
|
await sync(parent);
|
|
38966
39289
|
} catch (error52) {
|
|
38967
39290
|
await handle.close().catch(() => void 0);
|
|
38968
|
-
await
|
|
39291
|
+
await rm10(temporary, { force: true }).catch(() => void 0);
|
|
38969
39292
|
throw error52;
|
|
38970
39293
|
}
|
|
38971
39294
|
}
|
|
@@ -39042,7 +39365,7 @@ async function installMacosService(options) {
|
|
|
39042
39365
|
throw new Error("macOS automatic startup is available only on macOS.");
|
|
39043
39366
|
}
|
|
39044
39367
|
const env = options.env ?? process.env;
|
|
39045
|
-
const home = options.home ??
|
|
39368
|
+
const home = options.home ?? homedir10();
|
|
39046
39369
|
const uid = options.uid ?? userInfo2().uid;
|
|
39047
39370
|
if (!Number.isSafeInteger(uid) || uid < 0) throw new Error("macOS user id is invalid.");
|
|
39048
39371
|
const token2 = oneLine2(options.token, "pairing code");
|
|
@@ -39051,14 +39374,14 @@ async function installMacosService(options) {
|
|
|
39051
39374
|
options.path ?? env.PATH ?? "/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin",
|
|
39052
39375
|
"command search path"
|
|
39053
39376
|
);
|
|
39054
|
-
const configRoot = options.configRoot ??
|
|
39055
|
-
const launchAgentsRoot = options.launchAgentsRoot ??
|
|
39056
|
-
const logRoot = options.logRoot ??
|
|
39057
|
-
const configPath =
|
|
39058
|
-
const launcherPath =
|
|
39059
|
-
const plistPath =
|
|
39060
|
-
const stdoutPath =
|
|
39061
|
-
const stderrPath =
|
|
39377
|
+
const configRoot = options.configRoot ?? join19(home, "Library", "Application Support", "Zixt");
|
|
39378
|
+
const launchAgentsRoot = options.launchAgentsRoot ?? join19(home, "Library", "LaunchAgents");
|
|
39379
|
+
const logRoot = options.logRoot ?? join19(home, "Library", "Logs", "Zixt");
|
|
39380
|
+
const configPath = join19(configRoot, "host.env");
|
|
39381
|
+
const launcherPath = join19(configRoot, "host-launcher.sh");
|
|
39382
|
+
const plistPath = join19(launchAgentsRoot, `${LAUNCH_AGENT_LABEL}.plist`);
|
|
39383
|
+
const stdoutPath = join19(logRoot, "host.log");
|
|
39384
|
+
const stderrPath = join19(logRoot, "host-error.log");
|
|
39062
39385
|
const installVersion = options.installVersion ?? installRelease;
|
|
39063
39386
|
const activateVersion = options.activateVersion ?? (options.installVersion ? async (entry) => entry : (entry) => activateInstalledRelease(entry));
|
|
39064
39387
|
const resolveCommand = options.resolveCommand ?? (async () => defaultResolveCommand2());
|
|
@@ -39145,9 +39468,9 @@ async function installMacosService(options) {
|
|
|
39145
39468
|
// src/windows-service.ts
|
|
39146
39469
|
import { spawn as spawn12 } from "node:child_process";
|
|
39147
39470
|
import { constants as constants4 } from "node:fs";
|
|
39148
|
-
import { access as access6, mkdir as
|
|
39149
|
-
import { homedir as
|
|
39150
|
-
import { basename as basename6, dirname as dirname11, isAbsolute as
|
|
39471
|
+
import { access as access6, mkdir as mkdir15, open as open9, readFile as readFile11, rename as rename8, rm as rm11 } from "node:fs/promises";
|
|
39472
|
+
import { homedir as homedir11 } from "node:os";
|
|
39473
|
+
import { basename as basename6, dirname as dirname11, isAbsolute as isAbsolute17, join as join20, relative as relative11, resolve as resolve14, sep as sep7 } from "node:path";
|
|
39151
39474
|
var TASK_NAME = "Zixt Host";
|
|
39152
39475
|
var COMMAND_TIMEOUT_MS3 = 7e4;
|
|
39153
39476
|
var SERVICE_STABILITY_DELAY_MS3 = 2e3;
|
|
@@ -39173,7 +39496,7 @@ async function syncDirectory5(path) {
|
|
|
39173
39496
|
}
|
|
39174
39497
|
}
|
|
39175
39498
|
async function ensureDirectory3(path, sync) {
|
|
39176
|
-
const firstCreated = await
|
|
39499
|
+
const firstCreated = await mkdir15(path, { recursive: true, mode: 448 });
|
|
39177
39500
|
if (!firstCreated) return;
|
|
39178
39501
|
const first = resolve14(firstCreated);
|
|
39179
39502
|
const target = resolve14(path);
|
|
@@ -39181,13 +39504,13 @@ async function ensureDirectory3(path, sync) {
|
|
|
39181
39504
|
let current = first;
|
|
39182
39505
|
for (const part of relative11(first, target).split(sep7).filter(Boolean)) {
|
|
39183
39506
|
await sync(current);
|
|
39184
|
-
current =
|
|
39507
|
+
current = join20(current, part);
|
|
39185
39508
|
}
|
|
39186
39509
|
}
|
|
39187
39510
|
async function replacePrivateFile3(path, contents, sync) {
|
|
39188
39511
|
const parent = dirname11(path);
|
|
39189
39512
|
await ensureDirectory3(parent, sync);
|
|
39190
|
-
const temporary =
|
|
39513
|
+
const temporary = join20(parent, `.${basename6(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
|
|
39191
39514
|
const handle = await open9(temporary, "wx", 384);
|
|
39192
39515
|
try {
|
|
39193
39516
|
await handle.writeFile(contents, "utf8");
|
|
@@ -39197,7 +39520,7 @@ async function replacePrivateFile3(path, contents, sync) {
|
|
|
39197
39520
|
await sync(parent);
|
|
39198
39521
|
} catch (error52) {
|
|
39199
39522
|
await handle.close().catch(() => void 0);
|
|
39200
|
-
await
|
|
39523
|
+
await rm11(temporary, { force: true }).catch(() => void 0);
|
|
39201
39524
|
throw error52;
|
|
39202
39525
|
}
|
|
39203
39526
|
}
|
|
@@ -39241,8 +39564,8 @@ async function runChild(command, args, env, input) {
|
|
|
39241
39564
|
}
|
|
39242
39565
|
async function defaultResolveCommand3(name, env) {
|
|
39243
39566
|
const root = env.SYSTEMROOT ?? env.WINDIR;
|
|
39244
|
-
if (!root || !
|
|
39245
|
-
const candidate = name === "powershell" ?
|
|
39567
|
+
if (!root || !isAbsolute17(root)) return null;
|
|
39568
|
+
const candidate = name === "powershell" ? join20(root, "System32", "WindowsPowerShell", "v1.0", "powershell.exe") : join20(root, "System32", `${name}.exe`);
|
|
39246
39569
|
return access6(candidate, constants4.X_OK).then(
|
|
39247
39570
|
() => candidate,
|
|
39248
39571
|
() => null
|
|
@@ -39330,7 +39653,7 @@ exit $code
|
|
|
39330
39653
|
}
|
|
39331
39654
|
async function defaultObserveStatus(path, generation) {
|
|
39332
39655
|
try {
|
|
39333
|
-
const text = (await
|
|
39656
|
+
const text = (await readFile11(path, "utf8")).replace(/^\uFEFF/, "");
|
|
39334
39657
|
const value = JSON.parse(text);
|
|
39335
39658
|
if (value.schema !== 1 || value.generation !== generation || typeof value.pid !== "number" || !Number.isSafeInteger(value.pid) || value.pid <= 0) {
|
|
39336
39659
|
return null;
|
|
@@ -39371,19 +39694,19 @@ async function installWindowsService(options) {
|
|
|
39371
39694
|
throw new Error("Windows automatic startup is available only on Windows.");
|
|
39372
39695
|
}
|
|
39373
39696
|
const env = options.env ?? process.env;
|
|
39374
|
-
const home = options.home ??
|
|
39697
|
+
const home = options.home ?? homedir11();
|
|
39375
39698
|
const localAppData = options.localAppData ?? env.LOCALAPPDATA;
|
|
39376
|
-
if (!localAppData || !
|
|
39699
|
+
if (!localAppData || !isAbsolute17(localAppData)) {
|
|
39377
39700
|
throw new Error("Windows local application data path is unavailable.");
|
|
39378
39701
|
}
|
|
39379
39702
|
const token2 = oneLine3(options.token, "pairing code");
|
|
39380
39703
|
const cloudUrl = options.cloudUrl ? oneLine3(options.cloudUrl, "Zixt Cloud address") : void 0;
|
|
39381
39704
|
const path = oneLine3(options.path ?? env.PATH ?? "", "command search path");
|
|
39382
|
-
const configRoot = options.configRoot ??
|
|
39383
|
-
const configPath =
|
|
39384
|
-
const launcherPath =
|
|
39385
|
-
const taskXmlPath =
|
|
39386
|
-
const statusPath =
|
|
39705
|
+
const configRoot = options.configRoot ?? join20(localAppData, "Zixt", "Host");
|
|
39706
|
+
const configPath = join20(configRoot, "host.json");
|
|
39707
|
+
const launcherPath = join20(configRoot, "host-launcher.ps1");
|
|
39708
|
+
const taskXmlPath = join20(configRoot, "host-task.xml");
|
|
39709
|
+
const statusPath = join20(configRoot, "host-status.json");
|
|
39387
39710
|
const installVersion = options.installVersion ?? installRelease;
|
|
39388
39711
|
const activateVersion = options.activateVersion ?? (options.installVersion ? async (entry) => entry : (entry) => activateInstalledRelease(entry));
|
|
39389
39712
|
const resolveCommand = options.resolveCommand ?? ((name) => defaultResolveCommand3(name, env));
|
|
@@ -39432,7 +39755,7 @@ async function installWindowsService(options) {
|
|
|
39432
39755
|
);
|
|
39433
39756
|
await replacePrivateFile3(launcherPath, launcherSource2(configPath, statusPath), sync);
|
|
39434
39757
|
await replacePrivateFile3(taskXmlPath, taskXml({ sid, powershell, launcherPath, home }), sync);
|
|
39435
|
-
await
|
|
39758
|
+
await rm11(statusPath, { force: true });
|
|
39436
39759
|
const acl = await run3(icacls, [
|
|
39437
39760
|
configRoot,
|
|
39438
39761
|
"/inheritance:r",
|
|
@@ -39484,23 +39807,23 @@ async function installSystemService(options) {
|
|
|
39484
39807
|
}
|
|
39485
39808
|
|
|
39486
39809
|
// src/terminal-outcomes.ts
|
|
39487
|
-
import { chmod as chmod9, lstat as lstat12, mkdir as
|
|
39488
|
-
import { homedir as
|
|
39489
|
-
import { dirname as dirname12, join as
|
|
39810
|
+
import { chmod as chmod9, lstat as lstat12, mkdir as mkdir16, open as open10, readdir as readdir6, readFile as readFile12, rename as rename9, rm as rm12 } from "node:fs/promises";
|
|
39811
|
+
import { homedir as homedir12 } from "node:os";
|
|
39812
|
+
import { dirname as dirname12, join as join21, relative as relative12, resolve as resolve15, sep as sep8 } from "node:path";
|
|
39490
39813
|
var DIRECTORY_MODE5 = 448;
|
|
39491
39814
|
var FILE_MODE4 = 384;
|
|
39492
39815
|
var MAX_OUTCOME_BYTES = 4 * 1024 * 1024;
|
|
39493
39816
|
var HOST_DIRECTORY = /^hst_[0-9a-f]{32}$/;
|
|
39494
39817
|
var OUTCOME_FILE = /^(tsk_[0-9a-f]{32})\.([1-9][0-9]*)\.json$/;
|
|
39495
39818
|
function defaultTerminalOutcomeRoot() {
|
|
39496
|
-
return
|
|
39819
|
+
return join21(homedir12(), ".zixt", "terminal-outcomes");
|
|
39497
39820
|
}
|
|
39498
39821
|
function hostOutcomeRoot(root, hostId) {
|
|
39499
39822
|
if (!HOST_DIRECTORY.test(hostId)) throw new Error("terminal outcome Host identity is malformed");
|
|
39500
|
-
return
|
|
39823
|
+
return join21(root, hostId);
|
|
39501
39824
|
}
|
|
39502
39825
|
function outcomePath(root, hostId, taskId, epoch) {
|
|
39503
|
-
return
|
|
39826
|
+
return join21(hostOutcomeRoot(root, hostId), `${taskId}.${epoch}.json`);
|
|
39504
39827
|
}
|
|
39505
39828
|
async function syncDirectory6(root) {
|
|
39506
39829
|
if (process.platform === "win32") return;
|
|
@@ -39512,7 +39835,7 @@ async function syncDirectory6(root) {
|
|
|
39512
39835
|
}
|
|
39513
39836
|
}
|
|
39514
39837
|
async function requirePrivateRoot(root, sync = syncDirectory6) {
|
|
39515
|
-
const firstCreated = await
|
|
39838
|
+
const firstCreated = await mkdir16(root, { recursive: true, mode: DIRECTORY_MODE5 });
|
|
39516
39839
|
if (firstCreated) {
|
|
39517
39840
|
const first = resolve15(firstCreated);
|
|
39518
39841
|
const target = resolve15(root);
|
|
@@ -39520,7 +39843,7 @@ async function requirePrivateRoot(root, sync = syncDirectory6) {
|
|
|
39520
39843
|
let current = first;
|
|
39521
39844
|
for (const part of relative12(first, target).split(sep8).filter(Boolean)) {
|
|
39522
39845
|
await sync(current);
|
|
39523
|
-
current =
|
|
39846
|
+
current = join21(current, part);
|
|
39524
39847
|
}
|
|
39525
39848
|
}
|
|
39526
39849
|
const stat3 = await lstat12(root);
|
|
@@ -39551,7 +39874,7 @@ async function recordTerminalOutcome(hostId, input, root = defaultTerminalOutcom
|
|
|
39551
39874
|
const destination = outcomePath(root, hostId, outcome.taskId, outcome.epoch);
|
|
39552
39875
|
try {
|
|
39553
39876
|
const existing = parseCommittedOutcome(
|
|
39554
|
-
await
|
|
39877
|
+
await readFile12(destination, { encoding: "utf8", flag: "r" }),
|
|
39555
39878
|
outcome.taskId,
|
|
39556
39879
|
outcome.epoch
|
|
39557
39880
|
);
|
|
@@ -39560,7 +39883,7 @@ async function recordTerminalOutcome(hostId, input, root = defaultTerminalOutcom
|
|
|
39560
39883
|
} catch (error52) {
|
|
39561
39884
|
if (error52.code !== "ENOENT") throw error52;
|
|
39562
39885
|
}
|
|
39563
|
-
const temporary =
|
|
39886
|
+
const temporary = join21(
|
|
39564
39887
|
scopedRoot,
|
|
39565
39888
|
`.${outcome.taskId}.${outcome.epoch}.${process.pid}.${Date.now()}.${outcome.resultId}.tmp`
|
|
39566
39889
|
);
|
|
@@ -39577,7 +39900,7 @@ async function recordTerminalOutcome(hostId, input, root = defaultTerminalOutcom
|
|
|
39577
39900
|
} finally {
|
|
39578
39901
|
await handle?.close().catch(() => {
|
|
39579
39902
|
});
|
|
39580
|
-
await
|
|
39903
|
+
await rm12(temporary, { force: true }).catch(() => {
|
|
39581
39904
|
});
|
|
39582
39905
|
}
|
|
39583
39906
|
}
|
|
@@ -39593,7 +39916,7 @@ async function readTerminalOutcomesStrict(root = defaultTerminalOutcomeRoot()) {
|
|
|
39593
39916
|
throw new Error("terminal outcome journal root is not a trusted directory");
|
|
39594
39917
|
}
|
|
39595
39918
|
await chmod9(root, DIRECTORY_MODE5);
|
|
39596
|
-
const hostEntries = await
|
|
39919
|
+
const hostEntries = await readdir6(root, { withFileTypes: true });
|
|
39597
39920
|
const outcomes = [];
|
|
39598
39921
|
const resultIds = /* @__PURE__ */ new Set();
|
|
39599
39922
|
for (const hostEntry of hostEntries) {
|
|
@@ -39606,20 +39929,20 @@ async function readTerminalOutcomesStrict(root = defaultTerminalOutcomeRoot()) {
|
|
|
39606
39929
|
throw new Error("terminal outcome Host scope is not a trusted directory");
|
|
39607
39930
|
}
|
|
39608
39931
|
await chmod9(scopedRoot, DIRECTORY_MODE5);
|
|
39609
|
-
const entries = await
|
|
39932
|
+
const entries = await readdir6(scopedRoot, { withFileTypes: true });
|
|
39610
39933
|
for (const entry of entries) {
|
|
39611
39934
|
if (!entry.name.endsWith(".json")) continue;
|
|
39612
39935
|
const match = OUTCOME_FILE.exec(entry.name);
|
|
39613
39936
|
if (!match || !entry.isFile() || entry.isSymbolicLink()) {
|
|
39614
39937
|
throw new Error("committed terminal outcome is not a trusted regular file");
|
|
39615
39938
|
}
|
|
39616
|
-
const path =
|
|
39939
|
+
const path = join21(scopedRoot, entry.name);
|
|
39617
39940
|
const stat3 = await lstat12(path);
|
|
39618
39941
|
if (!stat3.isFile() || stat3.isSymbolicLink() || stat3.size > MAX_OUTCOME_BYTES) {
|
|
39619
39942
|
throw new Error("committed terminal outcome is not a trusted regular file");
|
|
39620
39943
|
}
|
|
39621
39944
|
const outcome = parseCommittedOutcome(
|
|
39622
|
-
await
|
|
39945
|
+
await readFile12(path, "utf8"),
|
|
39623
39946
|
match[1],
|
|
39624
39947
|
Number(match[2])
|
|
39625
39948
|
);
|
|
@@ -39646,7 +39969,7 @@ async function forgetAcknowledgedTerminalOutcomes(refs, root = defaultTerminalOu
|
|
|
39646
39969
|
if (acknowledged.get(`${hostId}:${outcome.taskId}:${outcome.epoch}`) !== outcome.resultId) {
|
|
39647
39970
|
continue;
|
|
39648
39971
|
}
|
|
39649
|
-
await
|
|
39972
|
+
await rm12(outcomePath(root, hostId, outcome.taskId, outcome.epoch), { force: true });
|
|
39650
39973
|
changedHostRoots.add(hostOutcomeRoot(root, hostId));
|
|
39651
39974
|
}
|
|
39652
39975
|
for (const scopedRoot of changedHostRoots) await syncDirectory6(scopedRoot);
|
|
@@ -39658,22 +39981,22 @@ async function forgetSupersededTerminalOutcomes(hostId, taskId, epoch, root = de
|
|
|
39658
39981
|
if (scoped.hostId !== hostId) continue;
|
|
39659
39982
|
const { outcome } = scoped;
|
|
39660
39983
|
if (outcome.taskId !== taskId || outcome.epoch >= epoch) continue;
|
|
39661
|
-
await
|
|
39984
|
+
await rm12(outcomePath(root, hostId, outcome.taskId, outcome.epoch), { force: true });
|
|
39662
39985
|
removed = true;
|
|
39663
39986
|
}
|
|
39664
39987
|
if (removed) await syncDirectory6(hostOutcomeRoot(root, hostId));
|
|
39665
39988
|
}
|
|
39666
39989
|
|
|
39667
39990
|
// src/accepted-assignments.ts
|
|
39668
|
-
import { chmod as chmod10, lstat as lstat13, mkdir as
|
|
39669
|
-
import { homedir as
|
|
39670
|
-
import { dirname as dirname13, join as
|
|
39991
|
+
import { chmod as chmod10, lstat as lstat13, mkdir as mkdir17, open as open11, readdir as readdir7, rename as rename10, rm as rm13 } from "node:fs/promises";
|
|
39992
|
+
import { homedir as homedir13 } from "node:os";
|
|
39993
|
+
import { dirname as dirname13, join as join22, relative as relative13, resolve as resolve16, sep as sep9 } from "node:path";
|
|
39671
39994
|
var DIRECTORY_MODE6 = 448;
|
|
39672
39995
|
var FILE_MODE5 = 384;
|
|
39673
39996
|
var CLAIM_FILE = /^(tsk_[0-9a-f]{32})\.([1-9][0-9]*)\.json$/;
|
|
39674
39997
|
var TASK_ID = /^tsk_[0-9a-f]{32}$/;
|
|
39675
39998
|
function defaultAcceptedAssignmentRoot() {
|
|
39676
|
-
return
|
|
39999
|
+
return join22(homedir13(), ".zixt", "accepted-assignments");
|
|
39677
40000
|
}
|
|
39678
40001
|
async function syncDirectory7(root) {
|
|
39679
40002
|
if (process.platform === "win32") return;
|
|
@@ -39685,7 +40008,7 @@ async function syncDirectory7(root) {
|
|
|
39685
40008
|
}
|
|
39686
40009
|
}
|
|
39687
40010
|
async function requirePrivateRoot2(root, sync = syncDirectory7) {
|
|
39688
|
-
const firstCreated = await
|
|
40011
|
+
const firstCreated = await mkdir17(root, { recursive: true, mode: DIRECTORY_MODE6 });
|
|
39689
40012
|
if (firstCreated) {
|
|
39690
40013
|
const first = resolve16(firstCreated);
|
|
39691
40014
|
const target = resolve16(root);
|
|
@@ -39693,7 +40016,7 @@ async function requirePrivateRoot2(root, sync = syncDirectory7) {
|
|
|
39693
40016
|
let current = first;
|
|
39694
40017
|
for (const part of relative13(first, target).split(sep9).filter(Boolean)) {
|
|
39695
40018
|
await sync(current);
|
|
39696
|
-
current =
|
|
40019
|
+
current = join22(current, part);
|
|
39697
40020
|
}
|
|
39698
40021
|
}
|
|
39699
40022
|
const stat3 = await lstat13(root);
|
|
@@ -39707,7 +40030,7 @@ function claimPath(root, taskId, epoch) {
|
|
|
39707
40030
|
if (!Number.isSafeInteger(epoch) || epoch < 1) {
|
|
39708
40031
|
throw new Error("accepted assignment epoch is malformed");
|
|
39709
40032
|
}
|
|
39710
|
-
return
|
|
40033
|
+
return join22(root, `${taskId}.${epoch}.json`);
|
|
39711
40034
|
}
|
|
39712
40035
|
async function recordAcceptedAssignment(assignment, root = defaultAcceptedAssignmentRoot(), options = {}) {
|
|
39713
40036
|
const sync = options.syncDirectory ?? syncDirectory7;
|
|
@@ -39717,7 +40040,7 @@ async function recordAcceptedAssignment(assignment, root = defaultAcceptedAssign
|
|
|
39717
40040
|
} catch {
|
|
39718
40041
|
return false;
|
|
39719
40042
|
}
|
|
39720
|
-
const temporary =
|
|
40043
|
+
const temporary = join22(
|
|
39721
40044
|
root,
|
|
39722
40045
|
`.${assignment.taskId}.${assignment.epoch}.${process.pid}.${Date.now()}.tmp`
|
|
39723
40046
|
);
|
|
@@ -39737,7 +40060,7 @@ async function recordAcceptedAssignment(assignment, root = defaultAcceptedAssign
|
|
|
39737
40060
|
} finally {
|
|
39738
40061
|
await handle?.close().catch(() => {
|
|
39739
40062
|
});
|
|
39740
|
-
await
|
|
40063
|
+
await rm13(temporary, { force: true }).catch(() => {
|
|
39741
40064
|
});
|
|
39742
40065
|
}
|
|
39743
40066
|
}
|
|
@@ -39754,7 +40077,7 @@ async function recoverAcceptedAssignments(root = defaultAcceptedAssignmentRoot()
|
|
|
39754
40077
|
}
|
|
39755
40078
|
await chmod10(root, DIRECTORY_MODE6);
|
|
39756
40079
|
const claims = [];
|
|
39757
|
-
for (const entry of await
|
|
40080
|
+
for (const entry of await readdir7(root, { withFileTypes: true })) {
|
|
39758
40081
|
if (!entry.isFile()) continue;
|
|
39759
40082
|
const match = CLAIM_FILE.exec(entry.name);
|
|
39760
40083
|
if (!match) continue;
|
|
@@ -39771,7 +40094,7 @@ async function forgetAcceptedAssignment(assignment, root = defaultAcceptedAssign
|
|
|
39771
40094
|
} catch {
|
|
39772
40095
|
return;
|
|
39773
40096
|
}
|
|
39774
|
-
await
|
|
40097
|
+
await rm13(path, { force: true }).catch(() => {
|
|
39775
40098
|
});
|
|
39776
40099
|
}
|
|
39777
40100
|
async function forgetAcknowledgedAcceptedAssignments(assignments, root = defaultAcceptedAssignmentRoot()) {
|
|
@@ -39880,23 +40203,23 @@ function createHostLogger(options = {}) {
|
|
|
39880
40203
|
}
|
|
39881
40204
|
|
|
39882
40205
|
// src/demo-state.ts
|
|
39883
|
-
import { isAbsolute as
|
|
40206
|
+
import { isAbsolute as isAbsolute18, join as join23, parse as parse3, resolve as resolve17 } from "node:path";
|
|
39884
40207
|
var DEMO_STATE_ROOT_ENV = "ZIXT_DEMO_STATE_ROOT";
|
|
39885
40208
|
function resolveDemoHostStatePaths(env = process.env) {
|
|
39886
40209
|
const configured = env.ZIXT_RUNNER === "demo" ? env[DEMO_STATE_ROOT_ENV] : void 0;
|
|
39887
40210
|
if (!configured) return null;
|
|
39888
40211
|
const root = resolve17(configured);
|
|
39889
|
-
if (!
|
|
40212
|
+
if (!isAbsolute18(configured) || root === parse3(root).root) {
|
|
39890
40213
|
throw new Error(`${DEMO_STATE_ROOT_ENV} must be a dedicated absolute directory`);
|
|
39891
40214
|
}
|
|
39892
40215
|
return {
|
|
39893
|
-
runRegistryRoot:
|
|
39894
|
-
terminalOutcomeRoot:
|
|
39895
|
-
acceptedAssignmentRoot:
|
|
39896
|
-
runArtifactRoot:
|
|
39897
|
-
browserProfileRoot:
|
|
39898
|
-
runnerWorkspaceRoot:
|
|
39899
|
-
codexThreadIndexRoot:
|
|
40216
|
+
runRegistryRoot: join23(root, "run-registry"),
|
|
40217
|
+
terminalOutcomeRoot: join23(root, "terminal-outcomes"),
|
|
40218
|
+
acceptedAssignmentRoot: join23(root, "accepted-assignments"),
|
|
40219
|
+
runArtifactRoot: join23(root, "run-artifacts"),
|
|
40220
|
+
browserProfileRoot: join23(root, "browser-profiles"),
|
|
40221
|
+
runnerWorkspaceRoot: join23(root, "workspaces"),
|
|
40222
|
+
codexThreadIndexRoot: join23(root, "codex-threads")
|
|
39900
40223
|
};
|
|
39901
40224
|
}
|
|
39902
40225
|
|
|
@@ -40058,7 +40381,7 @@ try {
|
|
|
40058
40381
|
console.error(hostHelpText());
|
|
40059
40382
|
process.exit(DO_NOT_RESTART_EXIT_CODE);
|
|
40060
40383
|
}
|
|
40061
|
-
var colorOverride = forcedColor(cliOptions.color);
|
|
40384
|
+
var colorOverride = forcedColor(cliOptions.color) ?? (process.env[HOST_CONSOLE_COLOR_ENV] === "1" ? true : void 0);
|
|
40062
40385
|
var hostConsoleTail = [];
|
|
40063
40386
|
var hostConsoleSequence = 0;
|
|
40064
40387
|
var clientForConsole = {};
|
|
@@ -40322,7 +40645,7 @@ async function telemetry() {
|
|
|
40322
40645
|
// Measured per heartbeat: free memory and free disk are only useful while
|
|
40323
40646
|
// they are current, and a demo Host reports its own private root so the
|
|
40324
40647
|
// number describes the filesystem its Tasks would really write to.
|
|
40325
|
-
hardware: await machineHardware(runnerWorkspaceRoot ??
|
|
40648
|
+
hardware: await machineHardware(runnerWorkspaceRoot ?? homedir14()),
|
|
40326
40649
|
capabilities: {
|
|
40327
40650
|
linearToolPack: providerToolPacks.some(
|
|
40328
40651
|
(pack) => pack.provider === "linear" && pack.health === "ready"
|
|
@@ -40493,6 +40816,9 @@ var client = new HostClient({
|
|
|
40493
40816
|
switch (status) {
|
|
40494
40817
|
case "connected":
|
|
40495
40818
|
log.success("Connected to Zixt Cloud", connectionContext);
|
|
40819
|
+
if (reportedWorkerExits.length > 0) {
|
|
40820
|
+
void forgetWorkerExits(reportedWorkerExits.map(({ file: file2 }) => file2));
|
|
40821
|
+
}
|
|
40496
40822
|
break;
|
|
40497
40823
|
case "disconnected":
|
|
40498
40824
|
log.warn("Connection lost; retrying", {
|
|
@@ -40531,6 +40857,18 @@ var client = new HostClient({
|
|
|
40531
40857
|
browser: browserManager
|
|
40532
40858
|
});
|
|
40533
40859
|
clientForConsole.current = client;
|
|
40860
|
+
var diagnosticsRoot = configuredWorkerDiagnosticsRoot();
|
|
40861
|
+
var reportedWorkerExits = diagnosticsRoot ? await readWorkerExits(diagnosticsRoot) : [];
|
|
40862
|
+
for (const { record: record2 } of reportedWorkerExits) {
|
|
40863
|
+
const { summary, context } = describeWorkerExit(record2);
|
|
40864
|
+
log.error(`The previous Zixt Host worker ${summary}`, {
|
|
40865
|
+
machine,
|
|
40866
|
+
at: record2.at,
|
|
40867
|
+
...context,
|
|
40868
|
+
next: "This Machine restarted itself; report it if the same exit repeats"
|
|
40869
|
+
});
|
|
40870
|
+
for (const line of record2.stderr) log.error("Previous worker output", { machine, line });
|
|
40871
|
+
}
|
|
40534
40872
|
log.info("Starting Zixt Host", connectionContext);
|
|
40535
40873
|
client.start();
|
|
40536
40874
|
var shuttingDown = false;
|
|
@@ -40539,14 +40877,24 @@ function shutdown(exitCode = 0) {
|
|
|
40539
40877
|
shuttingDown = true;
|
|
40540
40878
|
retainRunAssignments();
|
|
40541
40879
|
log.info("Stopping Zixt Host", { machine, activeTasks: activeSessions });
|
|
40542
|
-
|
|
40543
|
-
|
|
40544
|
-
|
|
40545
|
-
|
|
40546
|
-
|
|
40547
|
-
|
|
40548
|
-
|
|
40549
|
-
|
|
40880
|
+
beginWorkerShutdown({
|
|
40881
|
+
activeTasks: activeSessions,
|
|
40882
|
+
exitCode,
|
|
40883
|
+
teardown: () => client.stop(),
|
|
40884
|
+
stopHeartbeat: () => workerWatchdog.stop(),
|
|
40885
|
+
onForcedExit: ({ deadlineMs, code, teardownCompleted }) => {
|
|
40886
|
+
log.warn(
|
|
40887
|
+
teardownCompleted ? "Zixt Host finished stopping but the process stayed alive; exiting now" : "Zixt Host did not finish stopping in time; exiting now",
|
|
40888
|
+
{
|
|
40889
|
+
machine,
|
|
40890
|
+
deadline: formatDuration(deadlineMs),
|
|
40891
|
+
exit: code,
|
|
40892
|
+
activeTasks: activeSessions,
|
|
40893
|
+
next: "The Host restarts automatically; report this if it repeats"
|
|
40894
|
+
}
|
|
40895
|
+
);
|
|
40896
|
+
}
|
|
40897
|
+
});
|
|
40550
40898
|
}
|
|
40551
40899
|
stopUpdateWatch = !packagedBuild ? () => {
|
|
40552
40900
|
} : watchForUpdates({
|