@vtxmacro/cli 2026.8.20 → 2026.8.21
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/bin/vtx.js +240 -63
- package/package.json +1 -1
package/bin/vtx.js
CHANGED
|
@@ -38,7 +38,7 @@ var init_agent_cli_release = __esm({
|
|
|
38
38
|
"agent-cli-release.json"() {
|
|
39
39
|
agent_cli_release_default = {
|
|
40
40
|
package_name: "@vtxmacro/cli",
|
|
41
|
-
package_version: "2026.8.
|
|
41
|
+
package_version: "2026.8.21",
|
|
42
42
|
codex_package_name: "@openai/codex",
|
|
43
43
|
codex_version: "0.147.0",
|
|
44
44
|
platforms: {
|
|
@@ -19837,6 +19837,9 @@ child.once('close', async () => {
|
|
|
19837
19837
|
this.fatalListeners.add(listener);
|
|
19838
19838
|
return () => this.fatalListeners.delete(listener);
|
|
19839
19839
|
}
|
|
19840
|
+
isUsable() {
|
|
19841
|
+
return !this.closed && this.fatalError === null && this.process.exitCode === null;
|
|
19842
|
+
}
|
|
19840
19843
|
async readAccountSnapshot(deadlineAtMs, signal, refreshToken = false) {
|
|
19841
19844
|
const result2 = await this.request("account/read", { refreshToken }, {
|
|
19842
19845
|
timeoutMs: Math.max(1, deadlineAtMs - Date.now()),
|
|
@@ -20196,6 +20199,30 @@ child.once('close', async () => {
|
|
|
20196
20199
|
});
|
|
20197
20200
|
const startedAt = Date.now();
|
|
20198
20201
|
const unsubscribe = this.subscribe(({ method, params }) => {
|
|
20202
|
+
const eventThreadId = String(params.threadId || "");
|
|
20203
|
+
const scopedMethod = method.startsWith("thread/") || method.startsWith("turn/") || method.startsWith("item/") || method.startsWith("rawResponse") || method === "model/rerouted";
|
|
20204
|
+
if (scopedMethod && !eventThreadId) {
|
|
20205
|
+
terminalReject(new CodexAppServerError({
|
|
20206
|
+
message: "Codex notification omitted its thread scope.",
|
|
20207
|
+
category: "adapter",
|
|
20208
|
+
code: "missing_thread_notification_scope",
|
|
20209
|
+
retryable: false,
|
|
20210
|
+
dispatchOutcome: requestWritten ? turnId ? "confirmed_dispatched" : "outcome_unknown" : "not_dispatched"
|
|
20211
|
+
}));
|
|
20212
|
+
return;
|
|
20213
|
+
}
|
|
20214
|
+
if (scopedMethod && eventThreadId !== request.thread.threadId) {
|
|
20215
|
+
if (!this.threads.has(eventThreadId)) {
|
|
20216
|
+
terminalReject(new CodexAppServerError({
|
|
20217
|
+
message: "Codex notification crossed thread scope.",
|
|
20218
|
+
category: "adapter",
|
|
20219
|
+
code: "cross_thread_notification",
|
|
20220
|
+
retryable: false,
|
|
20221
|
+
dispatchOutcome: turnId ? "confirmed_dispatched" : "outcome_unknown"
|
|
20222
|
+
}));
|
|
20223
|
+
}
|
|
20224
|
+
return;
|
|
20225
|
+
}
|
|
20199
20226
|
if (forbiddenMethod(method)) {
|
|
20200
20227
|
terminalReject(new CodexAppServerError({
|
|
20201
20228
|
message: "Codex attempted to use forbidden child authority.",
|
|
@@ -20231,18 +20258,6 @@ child.once('close', async () => {
|
|
|
20231
20258
|
return;
|
|
20232
20259
|
}
|
|
20233
20260
|
}
|
|
20234
|
-
const eventThreadId = String(params.threadId || "");
|
|
20235
|
-
const scopedMethod = method.startsWith("thread/") || method.startsWith("turn/") || method.startsWith("item/") || method.startsWith("rawResponse") || method === "model/rerouted";
|
|
20236
|
-
if (scopedMethod && eventThreadId !== request.thread.threadId) {
|
|
20237
|
-
terminalReject(new CodexAppServerError({
|
|
20238
|
-
message: "Codex notification crossed thread scope.",
|
|
20239
|
-
category: "adapter",
|
|
20240
|
-
code: "cross_thread_notification",
|
|
20241
|
-
retryable: false,
|
|
20242
|
-
dispatchOutcome: turnId ? "confirmed_dispatched" : "outcome_unknown"
|
|
20243
|
-
}));
|
|
20244
|
-
return;
|
|
20245
|
-
}
|
|
20246
20261
|
const eventTurn = objectOrNull(params.turn);
|
|
20247
20262
|
const eventTurnId = String(params.turnId || eventTurn?.id || "");
|
|
20248
20263
|
const turnScopedMethod = method.startsWith("turn/") || method.startsWith("item/") || method.startsWith("rawResponse") || method === "model/rerouted";
|
|
@@ -20884,7 +20899,7 @@ var init_codex_adapter = __esm({
|
|
|
20884
20899
|
context.addIssue({ code: "custom", message: "Codex recovery thread identity is incomplete." });
|
|
20885
20900
|
}
|
|
20886
20901
|
const guardianManaged = value.processToken !== null || value.processReceiptPath !== null;
|
|
20887
|
-
if (value.processToken === null !== (value.processReceiptPath === null) || value.processState === "unmanaged" === guardianManaged || value.cleanupConfirmed &&
|
|
20902
|
+
if (value.processToken === null !== (value.processReceiptPath === null) || value.processState === "unmanaged" === guardianManaged || value.cleanupConfirmed && value.processState === "spawn_intent") {
|
|
20888
20903
|
context.addIssue({ code: "custom", message: "Codex recovery process identity is invalid." });
|
|
20889
20904
|
}
|
|
20890
20905
|
});
|
|
@@ -21293,8 +21308,114 @@ var init_codex_adapter = __esm({
|
|
|
21293
21308
|
CodexSubscriptionAdapter = class {
|
|
21294
21309
|
constructor(dependencies = {}) {
|
|
21295
21310
|
this.inFlightAttempts = /* @__PURE__ */ new Map();
|
|
21311
|
+
this.durableSession = null;
|
|
21312
|
+
this.durableSessionStart = null;
|
|
21313
|
+
this.closing = false;
|
|
21314
|
+
this.adapterClosePromise = null;
|
|
21296
21315
|
this.dependencies = dependencies;
|
|
21297
21316
|
}
|
|
21317
|
+
async startDurableSession(codexHome, deadlineAtMs) {
|
|
21318
|
+
const binary = await (this.dependencies.resolveBinary ?? resolvePinnedCodexBinary)();
|
|
21319
|
+
const guardianManaged = Boolean(
|
|
21320
|
+
this.dependencies.recoveryHooks && !this.dependencies.spawnProcess
|
|
21321
|
+
);
|
|
21322
|
+
const bootIdentity = guardianManaged ? await (this.dependencies.readBootIdentity ?? readInferenceSystemBootIdentity)() : null;
|
|
21323
|
+
const processToken = guardianManaged ? randomBytes3(32).toString("hex") : null;
|
|
21324
|
+
const guardianReceiptRoot = guardianManaged ? this.dependencies.guardianReceiptRoot ?? join4(tmpdir2(), "vtx-codex-guardian-receipts") : null;
|
|
21325
|
+
if (guardianReceiptRoot) await ensureInferencePrivateDirectory(guardianReceiptRoot);
|
|
21326
|
+
const processReceiptPath = guardianReceiptRoot && processToken ? join4(guardianReceiptRoot, `${processToken}.json`) : null;
|
|
21327
|
+
const session = await CodexAppServerSession.start({
|
|
21328
|
+
binary,
|
|
21329
|
+
codexHome,
|
|
21330
|
+
deadlineAtMs,
|
|
21331
|
+
spawnProcess: this.dependencies.spawnProcess,
|
|
21332
|
+
guardian: processToken && processReceiptPath ? { processToken, receiptPath: processReceiptPath, bootIdentity: bootIdentity ?? void 0 } : void 0
|
|
21333
|
+
});
|
|
21334
|
+
return {
|
|
21335
|
+
session,
|
|
21336
|
+
codexHome,
|
|
21337
|
+
processToken,
|
|
21338
|
+
processReceiptPath,
|
|
21339
|
+
bootIdentity,
|
|
21340
|
+
terminated: false,
|
|
21341
|
+
closePromise: null
|
|
21342
|
+
};
|
|
21343
|
+
}
|
|
21344
|
+
async acquireDurableSession(codexHome, deadlineAtMs, signal) {
|
|
21345
|
+
if (this.closing) {
|
|
21346
|
+
throw new CodexAppServerError({
|
|
21347
|
+
message: "Codex adapter is closing.",
|
|
21348
|
+
category: "transport",
|
|
21349
|
+
code: "transport_closed",
|
|
21350
|
+
retryable: true
|
|
21351
|
+
});
|
|
21352
|
+
}
|
|
21353
|
+
if (this.durableSession && this.durableSession.codexHome === codexHome && this.durableSession.session.isUsable()) return this.durableSession;
|
|
21354
|
+
if (this.durableSession && this.durableSession.codexHome !== codexHome) {
|
|
21355
|
+
await this.invalidateDurableSession(this.durableSession);
|
|
21356
|
+
}
|
|
21357
|
+
if (this.durableSession && !this.durableSession.session.isUsable()) {
|
|
21358
|
+
await this.invalidateDurableSession(this.durableSession);
|
|
21359
|
+
}
|
|
21360
|
+
if (!this.durableSessionStart) {
|
|
21361
|
+
const start2 = this.startDurableSession(codexHome, deadlineAtMs);
|
|
21362
|
+
this.durableSessionStart = start2;
|
|
21363
|
+
void start2.then((session) => {
|
|
21364
|
+
if (this.durableSessionStart === start2) this.durableSession = session;
|
|
21365
|
+
}).finally(() => {
|
|
21366
|
+
if (this.durableSessionStart === start2) this.durableSessionStart = null;
|
|
21367
|
+
}).catch(() => void 0);
|
|
21368
|
+
}
|
|
21369
|
+
const start = this.durableSessionStart;
|
|
21370
|
+
return await new Promise((resolveSession, reject) => {
|
|
21371
|
+
let settled = false;
|
|
21372
|
+
const finish = (callback) => {
|
|
21373
|
+
if (settled) return;
|
|
21374
|
+
settled = true;
|
|
21375
|
+
clearTimeout(timer);
|
|
21376
|
+
signal?.removeEventListener("abort", onAbort);
|
|
21377
|
+
callback();
|
|
21378
|
+
};
|
|
21379
|
+
const onAbort = () => finish(() => reject(new CodexAppServerError({
|
|
21380
|
+
message: "Codex session acquisition was cancelled.",
|
|
21381
|
+
category: "cancelled",
|
|
21382
|
+
code: "cancelled",
|
|
21383
|
+
retryable: false
|
|
21384
|
+
})));
|
|
21385
|
+
const timer = setTimeout(() => finish(() => reject(new CodexAppServerError({
|
|
21386
|
+
message: "Codex session acquisition exceeded the immutable deadline.",
|
|
21387
|
+
category: "timeout",
|
|
21388
|
+
code: "deadline_exceeded",
|
|
21389
|
+
retryable: false
|
|
21390
|
+
}))), Math.max(1, deadlineAtMs - Date.now()));
|
|
21391
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
21392
|
+
if (signal?.aborted) {
|
|
21393
|
+
onAbort();
|
|
21394
|
+
return;
|
|
21395
|
+
}
|
|
21396
|
+
void start.then(
|
|
21397
|
+
(session) => finish(() => resolveSession(session)),
|
|
21398
|
+
(error48) => finish(() => reject(error48))
|
|
21399
|
+
);
|
|
21400
|
+
});
|
|
21401
|
+
}
|
|
21402
|
+
async invalidateDurableSession(session) {
|
|
21403
|
+
if (this.durableSession === session) this.durableSession = null;
|
|
21404
|
+
if (!session.closePromise) {
|
|
21405
|
+
session.closePromise = (async () => {
|
|
21406
|
+
await session.session.close();
|
|
21407
|
+
if (session.processToken && session.processReceiptPath) {
|
|
21408
|
+
await waitForCodexGuardianState(
|
|
21409
|
+
{ processToken: session.processToken, receiptPath: session.processReceiptPath },
|
|
21410
|
+
"terminated",
|
|
21411
|
+
Date.now() + 5e3
|
|
21412
|
+
);
|
|
21413
|
+
}
|
|
21414
|
+
session.terminated = true;
|
|
21415
|
+
})();
|
|
21416
|
+
}
|
|
21417
|
+
await session.closePromise;
|
|
21418
|
+
}
|
|
21298
21419
|
runAttempt(input) {
|
|
21299
21420
|
const active = this.inFlightAttempts.get(input.attemptId);
|
|
21300
21421
|
if (active) {
|
|
@@ -21352,10 +21473,37 @@ var init_codex_adapter = __esm({
|
|
|
21352
21473
|
dispatchOutcome: checkpoint.dispatchOutcome
|
|
21353
21474
|
});
|
|
21354
21475
|
}
|
|
21355
|
-
await
|
|
21476
|
+
const receipt = await readCodexGuardianReceipt(checkpoint.processReceiptPath);
|
|
21477
|
+
if (checkpoint.processState === "terminated" || receipt === null || receipt.state === "terminated") {
|
|
21478
|
+
await rm3(checkpoint.processReceiptPath, { force: true });
|
|
21479
|
+
}
|
|
21356
21480
|
}
|
|
21357
21481
|
await recoveryHooks.clear(attemptId);
|
|
21358
21482
|
}
|
|
21483
|
+
async close() {
|
|
21484
|
+
if (!this.adapterClosePromise) {
|
|
21485
|
+
this.closing = true;
|
|
21486
|
+
this.adapterClosePromise = (async () => {
|
|
21487
|
+
const sessions = /* @__PURE__ */ new Set();
|
|
21488
|
+
if (this.durableSession) sessions.add(this.durableSession);
|
|
21489
|
+
const starting = this.durableSessionStart;
|
|
21490
|
+
if (starting) {
|
|
21491
|
+
const started = await starting.catch(() => null);
|
|
21492
|
+
if (started) sessions.add(started);
|
|
21493
|
+
}
|
|
21494
|
+
await Promise.all(
|
|
21495
|
+
[...sessions].map((session) => this.invalidateDurableSession(session))
|
|
21496
|
+
);
|
|
21497
|
+
await Promise.allSettled(
|
|
21498
|
+
[...this.inFlightAttempts.values()].map((attempt) => attempt.promise)
|
|
21499
|
+
);
|
|
21500
|
+
for (const session of sessions) {
|
|
21501
|
+
if (session.processReceiptPath) await rm3(session.processReceiptPath, { force: true });
|
|
21502
|
+
}
|
|
21503
|
+
})();
|
|
21504
|
+
}
|
|
21505
|
+
await this.adapterClosePromise;
|
|
21506
|
+
}
|
|
21359
21507
|
async executeAttempt(input) {
|
|
21360
21508
|
const validatedInput = validateAttemptInput(input);
|
|
21361
21509
|
const recoveryHooks = this.dependencies.recoveryHooks;
|
|
@@ -21406,6 +21554,7 @@ var init_codex_adapter = __esm({
|
|
|
21406
21554
|
});
|
|
21407
21555
|
}
|
|
21408
21556
|
let resources = null;
|
|
21557
|
+
let sessionLease = null;
|
|
21409
21558
|
let session = null;
|
|
21410
21559
|
let threadId = null;
|
|
21411
21560
|
let baseCheckpoint = null;
|
|
@@ -21413,22 +21562,20 @@ var init_codex_adapter = __esm({
|
|
|
21413
21562
|
let currentDispatchOutcome = "not_dispatched";
|
|
21414
21563
|
let completedResult = null;
|
|
21415
21564
|
let caughtError = null;
|
|
21565
|
+
let sessionInvalidationError = null;
|
|
21416
21566
|
try {
|
|
21417
|
-
const binary = await (this.dependencies.resolveBinary ?? resolvePinnedCodexBinary)();
|
|
21418
21567
|
resources = await (this.dependencies.createAttemptResources ?? ((attemptId) => createIsolatedCodexAttemptResources(
|
|
21419
21568
|
attemptId,
|
|
21420
21569
|
this.dependencies.codexHome
|
|
21421
21570
|
)))(input.attemptId);
|
|
21422
21571
|
await access2(resources.codexHome, fsConstants2.R_OK | fsConstants2.W_OK);
|
|
21423
21572
|
await access2(resources.workspacePath, fsConstants2.R_OK);
|
|
21424
|
-
|
|
21425
|
-
|
|
21426
|
-
|
|
21427
|
-
|
|
21428
|
-
|
|
21429
|
-
|
|
21430
|
-
}
|
|
21431
|
-
const processReceiptPath = guardianReceiptRoot && processToken ? join4(guardianReceiptRoot, `${processToken}.json`) : null;
|
|
21573
|
+
sessionLease = await this.acquireDurableSession(
|
|
21574
|
+
resources.codexHome,
|
|
21575
|
+
input.deadlineAtMs,
|
|
21576
|
+
input.signal
|
|
21577
|
+
);
|
|
21578
|
+
session = sessionLease.session;
|
|
21432
21579
|
baseCheckpoint = {
|
|
21433
21580
|
schemaVersion: "vtx_codex_attempt_recovery_v1",
|
|
21434
21581
|
attemptId: input.attemptId,
|
|
@@ -21438,10 +21585,10 @@ var init_codex_adapter = __esm({
|
|
|
21438
21585
|
workspacePath: resources.workspacePath,
|
|
21439
21586
|
threadId: null,
|
|
21440
21587
|
threadPath: null,
|
|
21441
|
-
processToken,
|
|
21442
|
-
processReceiptPath,
|
|
21443
|
-
processState:
|
|
21444
|
-
bootIdentity,
|
|
21588
|
+
processToken: sessionLease.processToken,
|
|
21589
|
+
processReceiptPath: sessionLease.processReceiptPath,
|
|
21590
|
+
processState: sessionLease.processToken ? "running" : "unmanaged",
|
|
21591
|
+
bootIdentity: sessionLease.bootIdentity,
|
|
21445
21592
|
cleanupConfirmed: false,
|
|
21446
21593
|
adapterRequestId: null,
|
|
21447
21594
|
adapterResponseId: null,
|
|
@@ -21450,19 +21597,6 @@ var init_codex_adapter = __esm({
|
|
|
21450
21597
|
};
|
|
21451
21598
|
latestCheckpoint = baseCheckpoint;
|
|
21452
21599
|
await recoveryHooks?.save(baseCheckpoint);
|
|
21453
|
-
session = await CodexAppServerSession.start({
|
|
21454
|
-
binary,
|
|
21455
|
-
codexHome: resources.codexHome,
|
|
21456
|
-
deadlineAtMs: input.deadlineAtMs,
|
|
21457
|
-
signal: input.signal,
|
|
21458
|
-
spawnProcess: this.dependencies.spawnProcess,
|
|
21459
|
-
guardian: processToken && processReceiptPath ? { processToken, receiptPath: processReceiptPath, bootIdentity: bootIdentity ?? void 0 } : void 0
|
|
21460
|
-
});
|
|
21461
|
-
if (guardianManaged) {
|
|
21462
|
-
baseCheckpoint = { ...baseCheckpoint, processState: "running" };
|
|
21463
|
-
latestCheckpoint = baseCheckpoint;
|
|
21464
|
-
await recoveryHooks?.save(baseCheckpoint);
|
|
21465
|
-
}
|
|
21466
21600
|
await session.requireManagedChatGptAuth(input.deadlineAtMs, input.signal);
|
|
21467
21601
|
await session.requireModel(
|
|
21468
21602
|
input.requestedModel,
|
|
@@ -21522,6 +21656,20 @@ var init_codex_adapter = __esm({
|
|
|
21522
21656
|
return result2;
|
|
21523
21657
|
} catch (error48) {
|
|
21524
21658
|
caughtError = error48;
|
|
21659
|
+
if (sessionLease && (!sessionLease.session.isUsable() || error48 instanceof CodexAppServerError && (error48.category === "transport" || [
|
|
21660
|
+
"rpc_rejected",
|
|
21661
|
+
"invalid_rpc_result",
|
|
21662
|
+
"rpc_timeout",
|
|
21663
|
+
"invalid_thread_provenance",
|
|
21664
|
+
"thread_cleanup_identity_missing",
|
|
21665
|
+
"thread_delete_unconfirmed"
|
|
21666
|
+
].includes(error48.code)))) {
|
|
21667
|
+
try {
|
|
21668
|
+
await this.invalidateDurableSession(sessionLease);
|
|
21669
|
+
} catch (invalidationError) {
|
|
21670
|
+
sessionInvalidationError = invalidationError;
|
|
21671
|
+
}
|
|
21672
|
+
}
|
|
21525
21673
|
if (error48 instanceof CodexAppServerError) {
|
|
21526
21674
|
const dispatchOutcome = error48.dispatchOutcome === "not_dispatched" ? currentDispatchOutcome : error48.dispatchOutcome;
|
|
21527
21675
|
if (baseCheckpoint && !completedResult) {
|
|
@@ -21584,7 +21732,7 @@ var init_codex_adapter = __esm({
|
|
|
21584
21732
|
}
|
|
21585
21733
|
throw classified;
|
|
21586
21734
|
} finally {
|
|
21587
|
-
let cleanupError =
|
|
21735
|
+
let cleanupError = sessionInvalidationError;
|
|
21588
21736
|
if (session && threadId) {
|
|
21589
21737
|
try {
|
|
21590
21738
|
await session.deleteThread(threadId);
|
|
@@ -21592,23 +21740,9 @@ var init_codex_adapter = __esm({
|
|
|
21592
21740
|
cleanupError = error48;
|
|
21593
21741
|
}
|
|
21594
21742
|
}
|
|
21595
|
-
|
|
21596
|
-
await session?.close();
|
|
21597
|
-
} catch (error48) {
|
|
21598
|
-
cleanupError ??= error48;
|
|
21599
|
-
}
|
|
21600
|
-
if (latestCheckpoint && recoveryHooks) {
|
|
21743
|
+
if (sessionLease && cleanupError) {
|
|
21601
21744
|
try {
|
|
21602
|
-
|
|
21603
|
-
await waitForCodexGuardianState(
|
|
21604
|
-
{
|
|
21605
|
-
processToken: latestCheckpoint.processToken,
|
|
21606
|
-
receiptPath: latestCheckpoint.processReceiptPath
|
|
21607
|
-
},
|
|
21608
|
-
"terminated",
|
|
21609
|
-
Date.now() + 5e3
|
|
21610
|
-
);
|
|
21611
|
-
}
|
|
21745
|
+
await this.invalidateDurableSession(sessionLease);
|
|
21612
21746
|
} catch (error48) {
|
|
21613
21747
|
cleanupError ??= error48;
|
|
21614
21748
|
}
|
|
@@ -21623,7 +21757,7 @@ var init_codex_adapter = __esm({
|
|
|
21623
21757
|
if (latestCheckpoint && recoveryHooks && cleanupError === null) {
|
|
21624
21758
|
latestCheckpoint = {
|
|
21625
21759
|
...latestCheckpoint,
|
|
21626
|
-
processState: latestCheckpoint.processToken ? "terminated" : "unmanaged",
|
|
21760
|
+
processState: latestCheckpoint.processToken ? sessionLease?.terminated ? "terminated" : "running" : "unmanaged",
|
|
21627
21761
|
cleanupConfirmed: true
|
|
21628
21762
|
};
|
|
21629
21763
|
try {
|
|
@@ -29377,7 +29511,11 @@ var init_runner = __esm({
|
|
|
29377
29511
|
} finally {
|
|
29378
29512
|
removeAbortListener();
|
|
29379
29513
|
unregisterSignals();
|
|
29380
|
-
|
|
29514
|
+
try {
|
|
29515
|
+
await this.dependencies.codexAdapter.close?.();
|
|
29516
|
+
} finally {
|
|
29517
|
+
await lock2.release();
|
|
29518
|
+
}
|
|
29381
29519
|
}
|
|
29382
29520
|
}
|
|
29383
29521
|
async persistReceipt(receipt, now) {
|
|
@@ -30382,11 +30520,18 @@ ${result2.stderr}`)) {
|
|
|
30382
30520
|
const startedAt = Date.now();
|
|
30383
30521
|
const log = createWriteStream(manifest.log_path, { flags: "a", mode: 384 });
|
|
30384
30522
|
return await new Promise((resolvePromise, reject) => {
|
|
30523
|
+
let stdout = "";
|
|
30385
30524
|
const child = spawn5(manifest.executable, args, {
|
|
30386
30525
|
env: { ...process.env, ...manifest.runtime_environment },
|
|
30387
30526
|
windowsHide: true,
|
|
30388
|
-
stdio: ["ignore",
|
|
30527
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
30389
30528
|
});
|
|
30529
|
+
child.stdout.on("data", (chunk) => {
|
|
30530
|
+
const text = chunk.toString("utf8");
|
|
30531
|
+
log.write(text);
|
|
30532
|
+
stdout = `${stdout}${text}`.slice(-65536);
|
|
30533
|
+
});
|
|
30534
|
+
child.stderr.on("data", (chunk) => log.write(chunk));
|
|
30390
30535
|
const onAbort = () => child.kill("SIGTERM");
|
|
30391
30536
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
30392
30537
|
child.once("error", (error48) => {
|
|
@@ -30397,7 +30542,24 @@ ${result2.stderr}`)) {
|
|
|
30397
30542
|
child.once("exit", (code) => {
|
|
30398
30543
|
signal.removeEventListener("abort", onAbort);
|
|
30399
30544
|
log.end();
|
|
30400
|
-
|
|
30545
|
+
let drainReason = null;
|
|
30546
|
+
for (const line of stdout.trim().split("\n").reverse()) {
|
|
30547
|
+
try {
|
|
30548
|
+
const parsed = JSON.parse(line);
|
|
30549
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed) && typeof parsed.drain_reason === "string" && /^[a-z0-9_]{1,96}$/u.test(
|
|
30550
|
+
parsed.drain_reason
|
|
30551
|
+
)) {
|
|
30552
|
+
drainReason = parsed.drain_reason;
|
|
30553
|
+
break;
|
|
30554
|
+
}
|
|
30555
|
+
} catch {
|
|
30556
|
+
}
|
|
30557
|
+
}
|
|
30558
|
+
resolvePromise({
|
|
30559
|
+
exitCode: code ?? 1,
|
|
30560
|
+
uptimeMs: Date.now() - startedAt,
|
|
30561
|
+
drainReason
|
|
30562
|
+
});
|
|
30401
30563
|
});
|
|
30402
30564
|
});
|
|
30403
30565
|
};
|
|
@@ -30447,6 +30609,7 @@ ${result2.stderr}`)) {
|
|
|
30447
30609
|
await appendServiceLog(manifest.log_path, "worker_exited", {
|
|
30448
30610
|
exit_code: result2.exitCode,
|
|
30449
30611
|
uptime_ms: result2.uptimeMs,
|
|
30612
|
+
drain_reason: result2.drainReason ?? null,
|
|
30450
30613
|
retry_after_ms: retryAfterMs
|
|
30451
30614
|
});
|
|
30452
30615
|
await sleep4(retryAfterMs);
|
|
@@ -31932,7 +32095,21 @@ Waiting for approval...
|
|
|
31932
32095
|
...dependencies,
|
|
31933
32096
|
registerLifecycleSignalHandlers: unregister
|
|
31934
32097
|
}, warnings);
|
|
31935
|
-
|
|
32098
|
+
let drainReason = null;
|
|
32099
|
+
try {
|
|
32100
|
+
const summary = JSON.parse(result2.stdout);
|
|
32101
|
+
if (summary && typeof summary === "object" && !Array.isArray(summary) && typeof summary.drain_reason === "string" && /^[a-z0-9_]{1,96}$/u.test(
|
|
32102
|
+
summary.drain_reason
|
|
32103
|
+
)) {
|
|
32104
|
+
drainReason = summary.drain_reason;
|
|
32105
|
+
}
|
|
32106
|
+
} catch {
|
|
32107
|
+
}
|
|
32108
|
+
return {
|
|
32109
|
+
exitCode: result2.exitCode,
|
|
32110
|
+
uptimeMs: Date.now() - startedAt,
|
|
32111
|
+
drainReason
|
|
32112
|
+
};
|
|
31936
32113
|
}
|
|
31937
32114
|
}
|
|
31938
32115
|
);
|