@zixt/host 0.0.37 → 0.0.39
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 +514 -39
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ import { homedir } from "node:os";
|
|
|
31
31
|
// package.json
|
|
32
32
|
var package_default = {
|
|
33
33
|
name: "@zixt/host",
|
|
34
|
-
version: "0.0.
|
|
34
|
+
version: "0.0.39",
|
|
35
35
|
type: "module",
|
|
36
36
|
exports: {
|
|
37
37
|
".": "./src/client.ts",
|
|
@@ -15299,6 +15299,8 @@ var HostTelemetry = external_exports.object({
|
|
|
15299
15299
|
* legacy Hosts must receive the original strict refusal frame.
|
|
15300
15300
|
*/
|
|
15301
15301
|
providerOperationGrantRetry: external_exports.literal(true).optional(),
|
|
15302
|
+
/** Accepts durable human follow-ups for an active runner turn. */
|
|
15303
|
+
liveRunnerInput: external_exports.literal(true).optional(),
|
|
15302
15304
|
linearToolPack: external_exports.boolean().default(false),
|
|
15303
15305
|
providerToolPacks: external_exports.array(ProviderToolPackCapability).max(20).superRefine((capabilities, ctx) => {
|
|
15304
15306
|
const providers = capabilities.map(({ provider }) => provider);
|
|
@@ -15866,6 +15868,8 @@ var Task = external_exports.object({
|
|
|
15866
15868
|
/** Follow-ups accepted but not yet folded into a run; the thread renders
|
|
15867
15869
|
* exactly this many trailing prompts as queued rather than answered. */
|
|
15868
15870
|
pendingMessageCount: external_exports.number().int().min(0).default(0),
|
|
15871
|
+
/** Delivery state for each trailing pending prompt, in transcript order. */
|
|
15872
|
+
pendingMessageStates: external_exports.array(external_exports.enum(["queued", "sending", "sent"])).default([]),
|
|
15869
15873
|
/** Present after cancellation; absent on legacy/non-cancelled tasks. */
|
|
15870
15874
|
cancellation: TaskCancellation.nullable().default(null),
|
|
15871
15875
|
/**
|
|
@@ -17292,9 +17296,17 @@ var BrowserCommandFrame = external_exports.object({
|
|
|
17292
17296
|
browserSessionId: external_exports.string().min(1).max(200),
|
|
17293
17297
|
command: BrowserCommand
|
|
17294
17298
|
});
|
|
17299
|
+
var TaskInput = external_exports.object({
|
|
17300
|
+
type: external_exports.literal("task.input"),
|
|
17301
|
+
taskId: TaskId,
|
|
17302
|
+
epoch: external_exports.number().int().min(1),
|
|
17303
|
+
inputId: external_exports.uuid(),
|
|
17304
|
+
text: external_exports.string().min(1).max(1e5)
|
|
17305
|
+
});
|
|
17295
17306
|
var DurableDownMessage = external_exports.discriminatedUnion("type", [
|
|
17296
17307
|
TaskAssign,
|
|
17297
17308
|
TaskCancel,
|
|
17309
|
+
TaskInput,
|
|
17298
17310
|
SecretsGrant,
|
|
17299
17311
|
ApprovalDecision,
|
|
17300
17312
|
ConnectionsGrant
|
|
@@ -17338,6 +17350,13 @@ var TaskTitle = external_exports.object({
|
|
|
17338
17350
|
epoch: external_exports.number().int().min(1),
|
|
17339
17351
|
title: external_exports.string().min(1).max(300)
|
|
17340
17352
|
});
|
|
17353
|
+
var TaskInputResult = external_exports.object({
|
|
17354
|
+
type: external_exports.literal("task.input.result"),
|
|
17355
|
+
taskId: TaskId,
|
|
17356
|
+
epoch: external_exports.number().int().min(1),
|
|
17357
|
+
inputId: external_exports.uuid(),
|
|
17358
|
+
accepted: external_exports.boolean()
|
|
17359
|
+
});
|
|
17341
17360
|
var TaskResult = external_exports.object({
|
|
17342
17361
|
type: external_exports.literal("task.result"),
|
|
17343
17362
|
taskId: TaskId,
|
|
@@ -17365,7 +17384,9 @@ var TaskResult = external_exports.object({
|
|
|
17365
17384
|
detail: external_exports.string().max(1e4).optional(),
|
|
17366
17385
|
evidenceClass: external_exports.enum(["agent_claimed", "host_observed"])
|
|
17367
17386
|
})
|
|
17368
|
-
).max(200).optional()
|
|
17387
|
+
).max(200).optional(),
|
|
17388
|
+
/** Inputs the provider accepted into this exact run before it completed. */
|
|
17389
|
+
acceptedInputIds: external_exports.array(external_exports.uuid()).max(1e3).optional()
|
|
17369
17390
|
});
|
|
17370
17391
|
var DurableTaskResult = TaskResult.extend({ resultId: external_exports.uuid() });
|
|
17371
17392
|
var HostReport = external_exports.object({
|
|
@@ -17427,6 +17448,7 @@ var UpMessage = external_exports.discriminatedUnion("type", [
|
|
|
17427
17448
|
TaskWorkingContextReport,
|
|
17428
17449
|
TaskRunnerRuntimeReport,
|
|
17429
17450
|
TaskTitle,
|
|
17451
|
+
TaskInputResult,
|
|
17430
17452
|
TaskResult,
|
|
17431
17453
|
HostReport,
|
|
17432
17454
|
HostConsoleReport,
|
|
@@ -19476,6 +19498,15 @@ function createWorkerWatchdogSendDrain() {
|
|
|
19476
19498
|
}
|
|
19477
19499
|
};
|
|
19478
19500
|
}
|
|
19501
|
+
function finishWorkerProcess(exitCode, runtime = process) {
|
|
19502
|
+
runtime.exitCode = exitCode;
|
|
19503
|
+
if (runtime.connected && typeof runtime.disconnect === "function") {
|
|
19504
|
+
try {
|
|
19505
|
+
runtime.disconnect();
|
|
19506
|
+
} catch {
|
|
19507
|
+
}
|
|
19508
|
+
}
|
|
19509
|
+
}
|
|
19479
19510
|
function startWorkerWatchdogHeartbeat(env = process.env, argv = process.argv.slice(2)) {
|
|
19480
19511
|
const ownership = consumeWorkerOwnershipArguments(argv, env);
|
|
19481
19512
|
const nonce = env[WORKER_WATCHDOG_NONCE_ENV];
|
|
@@ -19787,6 +19818,10 @@ var HostClient = class _HostClient {
|
|
|
19787
19818
|
onUnwindStalled;
|
|
19788
19819
|
/** Exact identity for each active run; unlike model output this is safe to acknowledge. */
|
|
19789
19820
|
activeAssignments = /* @__PURE__ */ new Map();
|
|
19821
|
+
liveInputHandlers = /* @__PURE__ */ new Map();
|
|
19822
|
+
liveInputBacklog = /* @__PURE__ */ new Map();
|
|
19823
|
+
liveInputInFlight = /* @__PURE__ */ new Map();
|
|
19824
|
+
acceptedLiveInputIds = /* @__PURE__ */ new Map();
|
|
19790
19825
|
/**
|
|
19791
19826
|
* Connection-loss runs confirmed stopped locally but not yet acknowledged
|
|
19792
19827
|
* by a new cloud socket generation. Replayed only inside hello.
|
|
@@ -20302,6 +20337,11 @@ var HostClient = class _HostClient {
|
|
|
20302
20337
|
label: safe(fact.label, 2e3),
|
|
20303
20338
|
...fact.detail !== void 0 ? { detail: safe(fact.detail, 1e4) } : {}
|
|
20304
20339
|
}))
|
|
20340
|
+
} : {},
|
|
20341
|
+
...this.acceptedLiveInputIds.get(`${assign.taskId}:${assign.epoch}`)?.size ? {
|
|
20342
|
+
acceptedInputIds: [
|
|
20343
|
+
...this.acceptedLiveInputIds.get(`${assign.taskId}:${assign.epoch}`)
|
|
20344
|
+
]
|
|
20305
20345
|
} : {}
|
|
20306
20346
|
};
|
|
20307
20347
|
}
|
|
@@ -20552,6 +20592,7 @@ var HostClient = class _HostClient {
|
|
|
20552
20592
|
...measuredCapabilities,
|
|
20553
20593
|
linearToolPack: measured.capabilities?.linearToolPack ?? false,
|
|
20554
20594
|
providerOperationGrantRetry: true,
|
|
20595
|
+
liveRunnerInput: true,
|
|
20555
20596
|
hostConsole: true,
|
|
20556
20597
|
...workerWatchdogIsActive() ? { taskAuthorityLifecycle: true } : {}
|
|
20557
20598
|
},
|
|
@@ -20595,6 +20636,9 @@ var HostClient = class _HostClient {
|
|
|
20595
20636
|
message.purpose === "credential_rollover" ? "credential_rollover" : "cloud_cancel"
|
|
20596
20637
|
);
|
|
20597
20638
|
return;
|
|
20639
|
+
case "task.input":
|
|
20640
|
+
this.queueLiveInput(message);
|
|
20641
|
+
return;
|
|
20598
20642
|
case "secrets.grant": {
|
|
20599
20643
|
const key = `${message.taskId}:${message.epoch}`;
|
|
20600
20644
|
if (!this.cancels.has(key)) return;
|
|
@@ -20658,6 +20702,51 @@ var HostClient = class _HostClient {
|
|
|
20658
20702
|
}
|
|
20659
20703
|
}
|
|
20660
20704
|
}
|
|
20705
|
+
sendLiveInputResult(input, accepted) {
|
|
20706
|
+
this.sendUp({
|
|
20707
|
+
type: "task.input.result",
|
|
20708
|
+
taskId: input.taskId,
|
|
20709
|
+
epoch: input.epoch,
|
|
20710
|
+
inputId: input.inputId,
|
|
20711
|
+
accepted
|
|
20712
|
+
});
|
|
20713
|
+
}
|
|
20714
|
+
deliverLiveInput(key, input) {
|
|
20715
|
+
const accepted = this.acceptedLiveInputIds.get(key);
|
|
20716
|
+
if (accepted?.has(input.inputId)) {
|
|
20717
|
+
this.sendLiveInputResult(input, true);
|
|
20718
|
+
return;
|
|
20719
|
+
}
|
|
20720
|
+
const inFlight = this.liveInputInFlight.get(key) ?? /* @__PURE__ */ new Set();
|
|
20721
|
+
if (inFlight.has(input.inputId)) return;
|
|
20722
|
+
const handler5 = this.liveInputHandlers.get(key);
|
|
20723
|
+
if (!handler5) {
|
|
20724
|
+
const backlog = this.liveInputBacklog.get(key) ?? [];
|
|
20725
|
+
if (!backlog.some((candidate) => candidate.inputId === input.inputId)) backlog.push(input);
|
|
20726
|
+
this.liveInputBacklog.set(key, backlog);
|
|
20727
|
+
return;
|
|
20728
|
+
}
|
|
20729
|
+
inFlight.add(input.inputId);
|
|
20730
|
+
this.liveInputInFlight.set(key, inFlight);
|
|
20731
|
+
void handler5({ inputId: input.inputId, text: input.text }).then((wasAccepted) => {
|
|
20732
|
+
if (wasAccepted) {
|
|
20733
|
+
const acceptedIds = this.acceptedLiveInputIds.get(key) ?? /* @__PURE__ */ new Set();
|
|
20734
|
+
acceptedIds.add(input.inputId);
|
|
20735
|
+
this.acceptedLiveInputIds.set(key, acceptedIds);
|
|
20736
|
+
}
|
|
20737
|
+
this.sendLiveInputResult(input, wasAccepted);
|
|
20738
|
+
}).catch(() => this.sendLiveInputResult(input, false)).finally(() => {
|
|
20739
|
+
this.liveInputInFlight.get(key)?.delete(input.inputId);
|
|
20740
|
+
});
|
|
20741
|
+
}
|
|
20742
|
+
queueLiveInput(input) {
|
|
20743
|
+
const key = `${input.taskId}:${input.epoch}`;
|
|
20744
|
+
if (!this.cancels.has(key)) {
|
|
20745
|
+
this.sendLiveInputResult(input, false);
|
|
20746
|
+
return;
|
|
20747
|
+
}
|
|
20748
|
+
this.deliverLiveInput(key, input);
|
|
20749
|
+
}
|
|
20661
20750
|
startTask(assign) {
|
|
20662
20751
|
const key = `${assign.taskId}:${assign.epoch}`;
|
|
20663
20752
|
if (this.activeRuns.has(key)) return;
|
|
@@ -21208,6 +21297,19 @@ var HostClient = class _HostClient {
|
|
|
21208
21297
|
runnerRuntime: emitRunnerRuntime,
|
|
21209
21298
|
siblingTasks: () => [...this.liveTasks.values()].filter((live) => live.agentId === assign.agentId && live.taskId !== assign.taskId).map(({ taskId, title }) => ({ taskId, title })),
|
|
21210
21299
|
fetchAttachment: (attachmentId) => this.fetchAttachment(attachmentId, authorityController.signal),
|
|
21300
|
+
followUps: (handler5) => {
|
|
21301
|
+
if (cancelled) return () => {
|
|
21302
|
+
};
|
|
21303
|
+
this.liveInputHandlers.set(cancelKey, handler5);
|
|
21304
|
+
const backlog = this.liveInputBacklog.get(cancelKey) ?? [];
|
|
21305
|
+
this.liveInputBacklog.delete(cancelKey);
|
|
21306
|
+
for (const input of backlog) this.deliverLiveInput(cancelKey, input);
|
|
21307
|
+
return () => {
|
|
21308
|
+
if (this.liveInputHandlers.get(cancelKey) === handler5) {
|
|
21309
|
+
this.liveInputHandlers.delete(cancelKey);
|
|
21310
|
+
}
|
|
21311
|
+
};
|
|
21312
|
+
},
|
|
21211
21313
|
secrets,
|
|
21212
21314
|
connections,
|
|
21213
21315
|
providers,
|
|
@@ -21285,6 +21387,13 @@ var HostClient = class _HostClient {
|
|
|
21285
21387
|
this.agentOpWaiters.delete(cancelKey);
|
|
21286
21388
|
this.rejectOperationGrantWaiters(cancelKey);
|
|
21287
21389
|
this.rejectBrowserCredentialWaiters(cancelKey);
|
|
21390
|
+
this.liveInputHandlers.delete(cancelKey);
|
|
21391
|
+
for (const input of this.liveInputBacklog.get(cancelKey) ?? []) {
|
|
21392
|
+
this.sendLiveInputResult(input, false);
|
|
21393
|
+
}
|
|
21394
|
+
this.liveInputBacklog.delete(cancelKey);
|
|
21395
|
+
this.liveInputInFlight.delete(cancelKey);
|
|
21396
|
+
this.acceptedLiveInputIds.delete(cancelKey);
|
|
21288
21397
|
sensitiveValues?.clear();
|
|
21289
21398
|
sensitiveValues = null;
|
|
21290
21399
|
if (stopReason === "cloud_cancel") {
|
|
@@ -33099,6 +33208,7 @@ let expectedBytes = null;
|
|
|
33099
33208
|
let config = null;
|
|
33100
33209
|
let launchPending = false;
|
|
33101
33210
|
let stderrTail = '';
|
|
33211
|
+
let postReleaseInput = Buffer.alloc(0);
|
|
33102
33212
|
let reported = false;
|
|
33103
33213
|
const report = (result) => {
|
|
33104
33214
|
if (reported) return;
|
|
@@ -33116,7 +33226,6 @@ prelaunchTimeout.unref();
|
|
|
33116
33226
|
|
|
33117
33227
|
const launchTarget = (release) => {
|
|
33118
33228
|
try {
|
|
33119
|
-
config = release;
|
|
33120
33229
|
const command = config.comspec || config.command;
|
|
33121
33230
|
const args = config.comspec
|
|
33122
33231
|
? ['/d', '/s', '/c', '"' + [config.command, ...config.args].map(quote).join(' ') + '"']
|
|
@@ -33163,11 +33272,16 @@ const launchTarget = (release) => {
|
|
|
33163
33272
|
maybeReport();
|
|
33164
33273
|
});
|
|
33165
33274
|
if (config.prompt) target.stdin.write(config.prompt);
|
|
33275
|
+
if (postReleaseInput.length) {
|
|
33276
|
+
target.stdin.write(postReleaseInput);
|
|
33277
|
+
postReleaseInput = Buffer.alloc(0);
|
|
33278
|
+
}
|
|
33166
33279
|
if (stdinEnded) target.stdin.end();
|
|
33167
33280
|
};
|
|
33168
33281
|
|
|
33169
33282
|
const launch = (release) => {
|
|
33170
33283
|
clearTimeout(prelaunchTimeout);
|
|
33284
|
+
config = release;
|
|
33171
33285
|
launchPending = true;
|
|
33172
33286
|
if (process.platform === 'win32') {
|
|
33173
33287
|
launchTarget(release);
|
|
@@ -33202,6 +33316,11 @@ process.stdin.on('data', (chunk) => {
|
|
|
33202
33316
|
target.stdin.write(chunk);
|
|
33203
33317
|
return;
|
|
33204
33318
|
}
|
|
33319
|
+
if (config) {
|
|
33320
|
+
postReleaseInput = Buffer.concat([postReleaseInput, chunk]);
|
|
33321
|
+
if (postReleaseInput.length > maxReleaseBytes) process.exit(1);
|
|
33322
|
+
return;
|
|
33323
|
+
}
|
|
33205
33324
|
pending = Buffer.concat([pending, chunk]);
|
|
33206
33325
|
if (pending.length > maxReleaseBytes + 256) process.exit(1);
|
|
33207
33326
|
if (!containmentReady) {
|
|
@@ -33223,9 +33342,9 @@ process.stdin.on('data', (chunk) => {
|
|
|
33223
33342
|
pending = pending.subarray(newline + 1);
|
|
33224
33343
|
}
|
|
33225
33344
|
if (pending.length < expectedBytes) return;
|
|
33226
|
-
if (pending.length !== expectedBytes) process.exit(1);
|
|
33227
33345
|
try {
|
|
33228
|
-
const release = JSON.parse(pending.toString('utf8'));
|
|
33346
|
+
const release = JSON.parse(pending.subarray(0, expectedBytes).toString('utf8'));
|
|
33347
|
+
postReleaseInput = pending.subarray(expectedBytes);
|
|
33229
33348
|
pending = Buffer.alloc(0);
|
|
33230
33349
|
launch(release);
|
|
33231
33350
|
} catch {
|
|
@@ -34029,7 +34148,8 @@ function createCliRunner(adapter, opts = {}) {
|
|
|
34029
34148
|
cwd,
|
|
34030
34149
|
command: resolvedCommand,
|
|
34031
34150
|
commandPrefixArgs: prefixArgs,
|
|
34032
|
-
env
|
|
34151
|
+
env,
|
|
34152
|
+
liveInput: opts.liveInput ?? opts.command === void 0
|
|
34033
34153
|
});
|
|
34034
34154
|
const runEnv = prepared.env ? { ...env, ...prepared.env } : env;
|
|
34035
34155
|
let attachmentSection = "";
|
|
@@ -34218,7 +34338,8 @@ ${attachmentSection}` : prompt;
|
|
|
34218
34338
|
...detail.ephemeral === void 0 ? {} : { ephemeral: detail.ephemeral }
|
|
34219
34339
|
});
|
|
34220
34340
|
},
|
|
34221
|
-
createParser: prepared.createParser,
|
|
34341
|
+
createParser: (onStream) => prepared.createParser(onStream, mode2),
|
|
34342
|
+
...task.followUps ? { registerFollowUps: task.followUps } : {},
|
|
34222
34343
|
notFoundMessage: adapter.notFoundMessage,
|
|
34223
34344
|
cliLabel: adapter.type,
|
|
34224
34345
|
// Durable evidence for the next Host process: which assignment this
|
|
@@ -34555,6 +34676,8 @@ function runCliProcess(options) {
|
|
|
34555
34676
|
detached: platform !== "win32"
|
|
34556
34677
|
});
|
|
34557
34678
|
const parser = options.createParser(options.onStream);
|
|
34679
|
+
let unregisterFollowUps;
|
|
34680
|
+
const liveInputSettlements = /* @__PURE__ */ new Set();
|
|
34558
34681
|
let stderrBuf = "";
|
|
34559
34682
|
let settled = false;
|
|
34560
34683
|
let terminalResult;
|
|
@@ -34583,12 +34706,15 @@ function runCliProcess(options) {
|
|
|
34583
34706
|
if (settled) return;
|
|
34584
34707
|
settled = true;
|
|
34585
34708
|
clearInterval(timer);
|
|
34709
|
+
unregisterFollowUps?.();
|
|
34710
|
+
parser.stop?.();
|
|
34586
34711
|
resolve14(result);
|
|
34587
34712
|
};
|
|
34588
34713
|
const terminate = (result) => {
|
|
34589
34714
|
if (settled || forcedResult) return;
|
|
34590
34715
|
forcedResult = result;
|
|
34591
34716
|
clearInterval(timer);
|
|
34717
|
+
child.stdin?.end();
|
|
34592
34718
|
void containmentReady.then(async () => {
|
|
34593
34719
|
if (windowsContainment) {
|
|
34594
34720
|
await windowsContainment.terminate();
|
|
@@ -34604,7 +34730,12 @@ function runCliProcess(options) {
|
|
|
34604
34730
|
} : {}
|
|
34605
34731
|
});
|
|
34606
34732
|
}).then(
|
|
34607
|
-
() =>
|
|
34733
|
+
async () => {
|
|
34734
|
+
unregisterFollowUps?.();
|
|
34735
|
+
parser.stop?.();
|
|
34736
|
+
await Promise.allSettled([...liveInputSettlements]);
|
|
34737
|
+
settle4(result);
|
|
34738
|
+
},
|
|
34608
34739
|
() => settle4({
|
|
34609
34740
|
outcome: "failed",
|
|
34610
34741
|
summary: PROCESS_CLEANUP_FAILURE,
|
|
@@ -34759,7 +34890,7 @@ function runCliProcess(options) {
|
|
|
34759
34890
|
cwd: options.cwd,
|
|
34760
34891
|
env: options.env,
|
|
34761
34892
|
...options.guardian.comspec ? { comspec: options.guardian.comspec } : {},
|
|
34762
|
-
prompt: options.prompt
|
|
34893
|
+
prompt: parser.start ? "" : options.prompt
|
|
34763
34894
|
}),
|
|
34764
34895
|
"utf8"
|
|
34765
34896
|
);
|
|
@@ -34767,9 +34898,39 @@ function runCliProcess(options) {
|
|
|
34767
34898
|
`);
|
|
34768
34899
|
child.stdin?.write(release);
|
|
34769
34900
|
} else {
|
|
34770
|
-
child.stdin?.write(options.prompt);
|
|
34771
34901
|
}
|
|
34772
|
-
|
|
34902
|
+
if (parser.start) {
|
|
34903
|
+
const write = (data) => new Promise((resolveWrite, rejectWrite) => {
|
|
34904
|
+
if (!child.stdin || child.stdin.destroyed || settled || forcedResult) {
|
|
34905
|
+
rejectWrite(new Error("runner input is unavailable"));
|
|
34906
|
+
return;
|
|
34907
|
+
}
|
|
34908
|
+
child.stdin.write(data, (error52) => {
|
|
34909
|
+
if (error52) rejectWrite(error52);
|
|
34910
|
+
else resolveWrite();
|
|
34911
|
+
});
|
|
34912
|
+
});
|
|
34913
|
+
try {
|
|
34914
|
+
await parser.start(write, options.prompt);
|
|
34915
|
+
if (parser.steer && options.registerFollowUps) {
|
|
34916
|
+
unregisterFollowUps = options.registerFollowUps((input) => {
|
|
34917
|
+
const settlement = parser.steer(input);
|
|
34918
|
+
liveInputSettlements.add(settlement);
|
|
34919
|
+
void settlement.finally(() => liveInputSettlements.delete(settlement));
|
|
34920
|
+
return settlement;
|
|
34921
|
+
});
|
|
34922
|
+
}
|
|
34923
|
+
} catch {
|
|
34924
|
+
terminate({
|
|
34925
|
+
outcome: "failed",
|
|
34926
|
+
summary: `${options.cliLabel} input protocol could not be started`,
|
|
34927
|
+
usage: parser.usage()
|
|
34928
|
+
});
|
|
34929
|
+
}
|
|
34930
|
+
} else {
|
|
34931
|
+
if (!options.guardian) child.stdin?.write(options.prompt);
|
|
34932
|
+
child.stdin?.end();
|
|
34933
|
+
}
|
|
34773
34934
|
})();
|
|
34774
34935
|
});
|
|
34775
34936
|
}
|
|
@@ -34955,6 +35116,7 @@ var claudeCodeAdapter = {
|
|
|
34955
35116
|
notFoundMessage: CLAUDE_NOT_FOUND_MESSAGE,
|
|
34956
35117
|
missingApiKeyMessage: 'Runner auth is set to "API key" but no ANTHROPIC_API_KEY credential is granted to this task. Add it in Resources \u2192 Credentials (org-wide or scoped to this agent).',
|
|
34957
35118
|
async prepareRun(input) {
|
|
35119
|
+
const liveInput = input.liveInput && input.task.followUps !== void 0;
|
|
34958
35120
|
const baseArgs = await buildArgs(
|
|
34959
35121
|
input.task,
|
|
34960
35122
|
input.runner,
|
|
@@ -34963,7 +35125,8 @@ var claudeCodeAdapter = {
|
|
|
34963
35125
|
input.preparedWorkspace,
|
|
34964
35126
|
input.taskRoot,
|
|
34965
35127
|
input.cwd,
|
|
34966
|
-
input.gitDetected
|
|
35128
|
+
input.gitDetected,
|
|
35129
|
+
liveInput
|
|
34967
35130
|
);
|
|
34968
35131
|
const sessionId = input.task.spec.sessionKey ?? randomUUID11();
|
|
34969
35132
|
const observeRuntime = createRuntimeReporter(input, sessionId);
|
|
@@ -34974,7 +35137,7 @@ var claudeCodeAdapter = {
|
|
|
34974
35137
|
],
|
|
34975
35138
|
prompt: buildRunnerPrompt(input.task),
|
|
34976
35139
|
recoveryPrompt: buildRunnerPrompt(input.task, true),
|
|
34977
|
-
createParser: (onStream) => createStreamParser(onStream, { onSessionModel: observeRuntime }),
|
|
35140
|
+
createParser: (onStream) => liveInput ? createClaudeLiveParser(onStream, observeRuntime) : createStreamParser(onStream, { onSessionModel: observeRuntime }),
|
|
34978
35141
|
// Self-heal both directions: a crashed first run leaves a transcript
|
|
34979
35142
|
// (new → conflict), a lost workspace breaks resume (resume → not
|
|
34980
35143
|
// found). One flip covers both.
|
|
@@ -35015,7 +35178,7 @@ function delay2(ms) {
|
|
|
35015
35178
|
timer.unref?.();
|
|
35016
35179
|
});
|
|
35017
35180
|
}
|
|
35018
|
-
async function buildArgs(task, runner, artifacts, mcp, preparedWorkspace, taskRoot, workspacePath = taskRoot ?? "", gitDetected = false) {
|
|
35181
|
+
async function buildArgs(task, runner, artifacts, mcp, preparedWorkspace, taskRoot, workspacePath = taskRoot ?? "", gitDetected = false, liveInput = false) {
|
|
35019
35182
|
const args = [
|
|
35020
35183
|
// Hermetic, non-interactive run — no local slash commands or global state.
|
|
35021
35184
|
"--disable-slash-commands",
|
|
@@ -35029,6 +35192,7 @@ async function buildArgs(task, runner, artifacts, mcp, preparedWorkspace, taskRo
|
|
|
35029
35192
|
// guardrails via runner permission hooks are the follow-up (PRD GR-5).
|
|
35030
35193
|
"--dangerously-skip-permissions"
|
|
35031
35194
|
];
|
|
35195
|
+
if (liveInput) args.push("--input-format", "stream-json", "--replay-user-messages");
|
|
35032
35196
|
if (runner.effort) args.push("--effort", runner.effort);
|
|
35033
35197
|
if (runner.model) args.push("--model", runner.model);
|
|
35034
35198
|
const systemPrompt = workspaceSystemPrompt(
|
|
@@ -35060,6 +35224,47 @@ async function buildArgs(task, runner, artifacts, mcp, preparedWorkspace, taskRo
|
|
|
35060
35224
|
);
|
|
35061
35225
|
return args;
|
|
35062
35226
|
}
|
|
35227
|
+
function createClaudeLiveParser(onStream, onSessionModel) {
|
|
35228
|
+
let write = null;
|
|
35229
|
+
const acknowledgements = /* @__PURE__ */ new Map();
|
|
35230
|
+
const input = (uuid3, text) => `${JSON.stringify({
|
|
35231
|
+
type: "user",
|
|
35232
|
+
uuid: uuid3,
|
|
35233
|
+
message: { role: "user", content: text },
|
|
35234
|
+
parent_tool_use_id: null
|
|
35235
|
+
})}
|
|
35236
|
+
`;
|
|
35237
|
+
const parser = createStreamParser(onStream, {
|
|
35238
|
+
onSessionModel,
|
|
35239
|
+
onUserReplay: (uuid3) => {
|
|
35240
|
+
const acknowledge = acknowledgements.get(uuid3);
|
|
35241
|
+
if (!acknowledge) return;
|
|
35242
|
+
acknowledgements.delete(uuid3);
|
|
35243
|
+
acknowledge(true);
|
|
35244
|
+
}
|
|
35245
|
+
});
|
|
35246
|
+
return {
|
|
35247
|
+
...parser,
|
|
35248
|
+
async start(writer, prompt) {
|
|
35249
|
+
write = writer;
|
|
35250
|
+
await writer(input(randomUUID11(), prompt));
|
|
35251
|
+
},
|
|
35252
|
+
async steer(followUp) {
|
|
35253
|
+
if (!write) return false;
|
|
35254
|
+
return await new Promise((resolve14) => {
|
|
35255
|
+
acknowledgements.set(followUp.inputId, resolve14);
|
|
35256
|
+
void write(input(followUp.inputId, followUp.text)).catch(() => {
|
|
35257
|
+
if (acknowledgements.delete(followUp.inputId)) resolve14(false);
|
|
35258
|
+
});
|
|
35259
|
+
});
|
|
35260
|
+
},
|
|
35261
|
+
stop() {
|
|
35262
|
+
write = null;
|
|
35263
|
+
for (const acknowledge of acknowledgements.values()) acknowledge(false);
|
|
35264
|
+
acknowledgements.clear();
|
|
35265
|
+
}
|
|
35266
|
+
};
|
|
35267
|
+
}
|
|
35063
35268
|
function createStreamParser(onStream, hooks = {}) {
|
|
35064
35269
|
let buffer = "";
|
|
35065
35270
|
let responseText = "";
|
|
@@ -35087,6 +35292,10 @@ function createStreamParser(onStream, hooks = {}) {
|
|
|
35087
35292
|
const type = json2["type"];
|
|
35088
35293
|
if (type === "system" && json2["subtype"] === "init") {
|
|
35089
35294
|
if (typeof json2["model"] === "string" && json2["model"]) hooks.onSessionModel?.(json2["model"]);
|
|
35295
|
+
} else if (type === "user") {
|
|
35296
|
+
if (json2["isReplay"] === true && typeof json2["uuid"] === "string") {
|
|
35297
|
+
hooks.onUserReplay?.(json2["uuid"]);
|
|
35298
|
+
}
|
|
35090
35299
|
} else if (type === "assistant") {
|
|
35091
35300
|
const message = json2["message"];
|
|
35092
35301
|
applyUsage(message?.["usage"]);
|
|
@@ -35120,12 +35329,13 @@ function createStreamParser(onStream, hooks = {}) {
|
|
|
35120
35329
|
const errors = Array.isArray(json2["errors"]) ? json2["errors"].filter((e) => typeof e === "string") : [];
|
|
35121
35330
|
const base = typeof json2["result"] === "string" && json2["result"].trim() ? json2["result"] : "";
|
|
35122
35331
|
const message = [base, ...errors].filter(Boolean).join("; ") || "Unknown error";
|
|
35123
|
-
|
|
35332
|
+
const result2 = {
|
|
35124
35333
|
outcome: "failed",
|
|
35125
35334
|
summary: improveErrorMessage(message),
|
|
35126
35335
|
usage: usage(),
|
|
35127
35336
|
sessionConflict: isSessionConflict(errors.join(" "))
|
|
35128
35337
|
};
|
|
35338
|
+
return hooks.shouldCompleteResult?.() === false ? void 0 : result2;
|
|
35129
35339
|
}
|
|
35130
35340
|
const finalText = typeof json2["result"] === "string" && json2["result"].trim() ? json2["result"] : responseText;
|
|
35131
35341
|
if (!finalText.trim() && outputTokens === 0) {
|
|
@@ -35136,7 +35346,8 @@ function createStreamParser(onStream, hooks = {}) {
|
|
|
35136
35346
|
emptyResult: true
|
|
35137
35347
|
};
|
|
35138
35348
|
}
|
|
35139
|
-
|
|
35349
|
+
const result = { outcome: "done", summary: finalText, usage: usage() };
|
|
35350
|
+
return hooks.shouldCompleteResult?.() === false ? void 0 : result;
|
|
35140
35351
|
} else if (type === "error") {
|
|
35141
35352
|
const message = typeof json2["error"] === "string" ? json2["error"] : JSON.stringify(json2);
|
|
35142
35353
|
return {
|
|
@@ -35204,6 +35415,7 @@ function improveErrorMessage(error52) {
|
|
|
35204
35415
|
|
|
35205
35416
|
// src/runners/codex.ts
|
|
35206
35417
|
import { mkdir as mkdir11, readFile as readFile7, writeFile as writeFile6 } from "node:fs/promises";
|
|
35418
|
+
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
35207
35419
|
import { homedir as homedir6 } from "node:os";
|
|
35208
35420
|
import { join as join16 } from "node:path";
|
|
35209
35421
|
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.";
|
|
@@ -35242,20 +35454,23 @@ function createCodexAdapter(threadIndexRoot) {
|
|
|
35242
35454
|
missingApiKeyMessage: 'Runner auth is set to "API key" but no OPENAI_API_KEY credential is granted to this task. Add it in Resources \u2192 Credentials (org-wide or scoped to this agent).',
|
|
35243
35455
|
async prepareRun(input) {
|
|
35244
35456
|
const { task, runner, mcp } = input;
|
|
35245
|
-
const
|
|
35457
|
+
const liveInput = input.liveInput && task.followUps !== void 0;
|
|
35458
|
+
const flags = liveInput ? [
|
|
35459
|
+
"app-server",
|
|
35460
|
+
"--stdio",
|
|
35461
|
+
// Replace machine-configured MCP servers while retaining auth.json.
|
|
35462
|
+
"-c",
|
|
35463
|
+
"mcp_servers={}"
|
|
35464
|
+
] : [
|
|
35246
35465
|
"--json",
|
|
35247
|
-
// The machine's config.toml (its MCP servers, plugins, hooks) stays
|
|
35248
|
-
// out of Zixt-managed sessions; auth.json machine login still applies.
|
|
35249
35466
|
"--ignore-user-config",
|
|
35250
|
-
// A teammate workspace is not necessarily a git repository.
|
|
35251
35467
|
"--skip-git-repo-check",
|
|
35252
|
-
// Headless runs can't answer approval prompts, and guardrails are
|
|
35253
|
-
// instructions-first (PRD GR); the OS sandbox remains the documented
|
|
35254
|
-
// out-of-scope boundary, same as Claude's --dangerously-skip-permissions.
|
|
35255
35468
|
"--dangerously-bypass-approvals-and-sandbox"
|
|
35256
35469
|
];
|
|
35257
|
-
if (runner.model) flags.push("--model", runner.model);
|
|
35258
|
-
if (runner.effort)
|
|
35470
|
+
if (!liveInput && runner.model) flags.push("--model", runner.model);
|
|
35471
|
+
if (!liveInput && runner.effort) {
|
|
35472
|
+
flags.push("-c", `model_reasoning_effort=${tomlString(runner.effort)}`);
|
|
35473
|
+
}
|
|
35259
35474
|
const env = { ZIXT_RUN_TOKEN: mcp.runToken };
|
|
35260
35475
|
flags.push("-c", `mcp_servers.zixt.url=${tomlString(mcp.mcpUrl)}`);
|
|
35261
35476
|
flags.push(
|
|
@@ -35293,13 +35508,13 @@ function createCodexAdapter(threadIndexRoot) {
|
|
|
35293
35508
|
task.siblingTasks(),
|
|
35294
35509
|
input.gitDetected
|
|
35295
35510
|
);
|
|
35296
|
-
const withPlatformInstructions = (
|
|
35511
|
+
const withPlatformInstructions = (value) => platformInstructions ? `<zixt_platform_instructions>
|
|
35297
35512
|
${platformInstructions}
|
|
35298
35513
|
</zixt_platform_instructions>
|
|
35299
35514
|
|
|
35300
|
-
${
|
|
35301
|
-
const prompt = withPlatformInstructions(buildRunnerPrompt(task));
|
|
35302
|
-
const recoveryPrompt = withPlatformInstructions(buildRunnerPrompt(task, true));
|
|
35515
|
+
${value}` : value;
|
|
35516
|
+
const prompt = liveInput ? buildRunnerPrompt(task) : withPlatformInstructions(buildRunnerPrompt(task));
|
|
35517
|
+
const recoveryPrompt = liveInput ? buildRunnerPrompt(task, true) : withPlatformInstructions(buildRunnerPrompt(task, true));
|
|
35303
35518
|
const sessionKey = task.spec.sessionKey;
|
|
35304
35519
|
const indexPath = sessionKey ? threadIndexPath(threadIndexRoot, task.agentId, sessionKey) : null;
|
|
35305
35520
|
const recordedThreadId = indexPath ? await readThreadId(indexPath) : null;
|
|
@@ -35313,20 +35528,28 @@ ${prompt2}` : prompt2;
|
|
|
35313
35528
|
};
|
|
35314
35529
|
return {
|
|
35315
35530
|
argsFor: (mode) => {
|
|
35316
|
-
if (mode === "resume")
|
|
35317
|
-
|
|
35318
|
-
|
|
35319
|
-
return ["exec", ...flags, "-"];
|
|
35531
|
+
if (mode === "resume" && !recordedThreadId) return null;
|
|
35532
|
+
if (liveInput) return flags;
|
|
35533
|
+
return mode === "resume" ? ["exec", "resume", recordedThreadId, ...flags, "-"] : ["exec", ...flags, "-"];
|
|
35320
35534
|
},
|
|
35321
35535
|
prompt,
|
|
35322
35536
|
recoveryPrompt,
|
|
35323
35537
|
env,
|
|
35324
|
-
createParser: (onStream) =>
|
|
35325
|
-
onThreadStarted
|
|
35538
|
+
createParser: (onStream, mode = "new") => {
|
|
35539
|
+
const onThreadStarted = (threadId) => {
|
|
35326
35540
|
rememberThread(threadId);
|
|
35327
35541
|
observeRuntime(threadId);
|
|
35328
|
-
}
|
|
35329
|
-
|
|
35542
|
+
};
|
|
35543
|
+
return liveInput ? createCodexAppServerParser(onStream, {
|
|
35544
|
+
mode,
|
|
35545
|
+
recordedThreadId,
|
|
35546
|
+
cwd: input.cwd,
|
|
35547
|
+
...runner.model ? { model: runner.model } : {},
|
|
35548
|
+
...runner.effort ? { effort: runner.effort } : {},
|
|
35549
|
+
developerInstructions: platformInstructions ?? "",
|
|
35550
|
+
onThreadStarted
|
|
35551
|
+
}) : createCodexStreamParser(onStream, { onThreadStarted });
|
|
35552
|
+
},
|
|
35330
35553
|
// Only one flip is meaningful: a resume whose rollout vanished starts
|
|
35331
35554
|
// over. Codex assigns new-session ids itself, so a new session can
|
|
35332
35555
|
// never collide the way a pre-specified id can.
|
|
@@ -35363,6 +35586,258 @@ function createCodexRunner(opts = {}) {
|
|
|
35363
35586
|
const adapter = createCodexAdapter(opts.threadIndexRoot ?? defaultCodexThreadIndexRoot());
|
|
35364
35587
|
return createCliRunner(adapter, opts);
|
|
35365
35588
|
}
|
|
35589
|
+
function createCodexAppServerParser(onStream, options) {
|
|
35590
|
+
let write = null;
|
|
35591
|
+
let prompt = "";
|
|
35592
|
+
let buffer = "";
|
|
35593
|
+
let threadId = null;
|
|
35594
|
+
let activeTurnId = null;
|
|
35595
|
+
let responseText = "";
|
|
35596
|
+
let inputTokens = 0;
|
|
35597
|
+
let outputTokens = 0;
|
|
35598
|
+
let terminal;
|
|
35599
|
+
let stopped = false;
|
|
35600
|
+
const steerWaiters = /* @__PURE__ */ new Map();
|
|
35601
|
+
const turnReadyWaiters = /* @__PURE__ */ new Set();
|
|
35602
|
+
const usage = () => ({ inputTokens, outputTokens });
|
|
35603
|
+
const settleTurnReadiness = (ready) => {
|
|
35604
|
+
for (const resolve14 of turnReadyWaiters) resolve14(ready);
|
|
35605
|
+
turnReadyWaiters.clear();
|
|
35606
|
+
};
|
|
35607
|
+
const send = async (message) => {
|
|
35608
|
+
if (!write || stopped) throw new Error("Codex app-server input is unavailable");
|
|
35609
|
+
await write(`${JSON.stringify({ jsonrpc: "2.0", ...message })}
|
|
35610
|
+
`);
|
|
35611
|
+
};
|
|
35612
|
+
const threadParams = () => ({
|
|
35613
|
+
cwd: options.cwd,
|
|
35614
|
+
approvalPolicy: "never",
|
|
35615
|
+
sandbox: "danger-full-access",
|
|
35616
|
+
...options.model ? { model: options.model } : {},
|
|
35617
|
+
...options.developerInstructions ? { developerInstructions: options.developerInstructions } : {}
|
|
35618
|
+
});
|
|
35619
|
+
const startTurn = async () => {
|
|
35620
|
+
if (!threadId) throw new Error("Codex app-server did not provide a thread id");
|
|
35621
|
+
await send({
|
|
35622
|
+
id: "turn:start",
|
|
35623
|
+
method: "turn/start",
|
|
35624
|
+
params: {
|
|
35625
|
+
threadId,
|
|
35626
|
+
input: [{ type: "text", text: prompt }],
|
|
35627
|
+
clientUserMessageId: randomUUID12(),
|
|
35628
|
+
...options.model ? { model: options.model } : {},
|
|
35629
|
+
...options.effort ? { effort: options.effort } : {}
|
|
35630
|
+
}
|
|
35631
|
+
});
|
|
35632
|
+
};
|
|
35633
|
+
const itemCompleted = (item) => {
|
|
35634
|
+
const type = item["type"];
|
|
35635
|
+
if (type === "agentMessage" && typeof item["text"] === "string") {
|
|
35636
|
+
responseText = item["text"];
|
|
35637
|
+
onStream("thought", truncateThought(item["text"]));
|
|
35638
|
+
return;
|
|
35639
|
+
}
|
|
35640
|
+
if (type === "reasoning") {
|
|
35641
|
+
const summary = Array.isArray(item["summary"]) ? item["summary"].filter((part) => typeof part === "string") : [];
|
|
35642
|
+
if (summary.length) onStream("thought", truncateThought(summary.join("\n")));
|
|
35643
|
+
return;
|
|
35644
|
+
}
|
|
35645
|
+
if (type === "commandExecution") {
|
|
35646
|
+
const parameter = String(item["command"] ?? "").slice(0, 2e3);
|
|
35647
|
+
onStream("action", `shell${parameter ? `: ${parameter.slice(0, 100)}` : ""}`, {
|
|
35648
|
+
tool: "shell",
|
|
35649
|
+
...parameter ? { parameter } : {},
|
|
35650
|
+
ephemeral: true
|
|
35651
|
+
});
|
|
35652
|
+
return;
|
|
35653
|
+
}
|
|
35654
|
+
if (type === "mcpToolCall") {
|
|
35655
|
+
const tool = `${String(item["server"] ?? "mcp")}.${String(item["tool"] ?? "tool")}`.slice(
|
|
35656
|
+
0,
|
|
35657
|
+
200
|
|
35658
|
+
);
|
|
35659
|
+
const args = item["arguments"];
|
|
35660
|
+
const parameter = (typeof args === "string" ? args : args ? JSON.stringify(args) : "").slice(
|
|
35661
|
+
0,
|
|
35662
|
+
2e3
|
|
35663
|
+
);
|
|
35664
|
+
onStream("action", `${tool}${parameter ? `: ${parameter.slice(0, 100)}` : ""}`, {
|
|
35665
|
+
tool,
|
|
35666
|
+
...parameter ? { parameter } : {},
|
|
35667
|
+
ephemeral: true
|
|
35668
|
+
});
|
|
35669
|
+
return;
|
|
35670
|
+
}
|
|
35671
|
+
if (type === "fileChange") {
|
|
35672
|
+
const changes = Array.isArray(item["changes"]) ? item["changes"].map((change) => String(change["path"] ?? "")).filter(Boolean) : [];
|
|
35673
|
+
const parameter = changes.join(", ").slice(0, 2e3);
|
|
35674
|
+
onStream("action", `file_change${parameter ? `: ${parameter.slice(0, 100)}` : ""}`, {
|
|
35675
|
+
tool: "file_change",
|
|
35676
|
+
...parameter ? { parameter } : {},
|
|
35677
|
+
ephemeral: true,
|
|
35678
|
+
...changes.length ? { localPaths: changes } : {}
|
|
35679
|
+
});
|
|
35680
|
+
}
|
|
35681
|
+
};
|
|
35682
|
+
const processLine = (line) => {
|
|
35683
|
+
if (!line.trim()) return void 0;
|
|
35684
|
+
let message;
|
|
35685
|
+
try {
|
|
35686
|
+
message = JSON.parse(line);
|
|
35687
|
+
} catch {
|
|
35688
|
+
return void 0;
|
|
35689
|
+
}
|
|
35690
|
+
const id = typeof message["id"] === "string" ? message["id"] : null;
|
|
35691
|
+
const error52 = message["error"];
|
|
35692
|
+
if (id && error52) {
|
|
35693
|
+
const detail = typeof error52["message"] === "string" ? error52["message"] : JSON.stringify(error52);
|
|
35694
|
+
if (id.startsWith("steer:")) {
|
|
35695
|
+
const inputId = id.slice("steer:".length);
|
|
35696
|
+
steerWaiters.get(inputId)?.(false);
|
|
35697
|
+
steerWaiters.delete(inputId);
|
|
35698
|
+
return void 0;
|
|
35699
|
+
}
|
|
35700
|
+
terminal = {
|
|
35701
|
+
outcome: "failed",
|
|
35702
|
+
summary: improveCodexErrorMessage(detail),
|
|
35703
|
+
usage: usage(),
|
|
35704
|
+
sessionConflict: isCodexSessionConflict(detail)
|
|
35705
|
+
};
|
|
35706
|
+
return terminal;
|
|
35707
|
+
}
|
|
35708
|
+
const result = message["result"];
|
|
35709
|
+
if (id === "initialize" && result) {
|
|
35710
|
+
void send({ method: "initialized" }).then(
|
|
35711
|
+
() => send({
|
|
35712
|
+
id: "thread:open",
|
|
35713
|
+
method: options.mode === "resume" ? "thread/resume" : "thread/start",
|
|
35714
|
+
params: options.mode === "resume" ? { ...threadParams(), threadId: options.recordedThreadId } : threadParams()
|
|
35715
|
+
})
|
|
35716
|
+
).catch(() => {
|
|
35717
|
+
});
|
|
35718
|
+
} else if (id === "thread:open" && result) {
|
|
35719
|
+
const thread = result["thread"];
|
|
35720
|
+
if (typeof thread?.["id"] === "string") {
|
|
35721
|
+
threadId = thread["id"];
|
|
35722
|
+
options.onThreadStarted(threadId);
|
|
35723
|
+
void startTurn().catch(() => {
|
|
35724
|
+
});
|
|
35725
|
+
}
|
|
35726
|
+
} else if (id === "turn:start" && result) {
|
|
35727
|
+
const turn = result["turn"];
|
|
35728
|
+
if (typeof turn?.["id"] === "string") {
|
|
35729
|
+
activeTurnId = turn["id"];
|
|
35730
|
+
}
|
|
35731
|
+
} else if (id?.startsWith("steer:") && result) {
|
|
35732
|
+
const inputId = id.slice("steer:".length);
|
|
35733
|
+
const accepted = typeof result["turnId"] === "string";
|
|
35734
|
+
steerWaiters.get(inputId)?.(accepted);
|
|
35735
|
+
steerWaiters.delete(inputId);
|
|
35736
|
+
}
|
|
35737
|
+
const method = message["method"];
|
|
35738
|
+
const params = message["params"];
|
|
35739
|
+
if (method === "thread/started") {
|
|
35740
|
+
const thread = params?.["thread"];
|
|
35741
|
+
if (!threadId && typeof thread?.["id"] === "string") {
|
|
35742
|
+
threadId = thread["id"];
|
|
35743
|
+
options.onThreadStarted(threadId);
|
|
35744
|
+
}
|
|
35745
|
+
} else if (method === "turn/started") {
|
|
35746
|
+
const turn = params?.["turn"];
|
|
35747
|
+
if (typeof turn?.["id"] === "string") {
|
|
35748
|
+
activeTurnId = turn["id"];
|
|
35749
|
+
settleTurnReadiness(true);
|
|
35750
|
+
}
|
|
35751
|
+
} else if (method === "item/completed") {
|
|
35752
|
+
const item = params?.["item"];
|
|
35753
|
+
if (item && typeof item === "object") itemCompleted(item);
|
|
35754
|
+
} else if (method === "thread/tokenUsage/updated") {
|
|
35755
|
+
const tokenUsage = params?.["tokenUsage"];
|
|
35756
|
+
const total = tokenUsage?.["total"];
|
|
35757
|
+
if (typeof total?.["inputTokens"] === "number") inputTokens = total["inputTokens"];
|
|
35758
|
+
if (typeof total?.["outputTokens"] === "number") outputTokens = total["outputTokens"];
|
|
35759
|
+
} else if (method === "turn/completed") {
|
|
35760
|
+
const turn = params?.["turn"];
|
|
35761
|
+
activeTurnId = null;
|
|
35762
|
+
settleTurnReadiness(false);
|
|
35763
|
+
const status = turn?.["status"];
|
|
35764
|
+
const turnError = turn?.["error"];
|
|
35765
|
+
const detail = typeof turnError?.["message"] === "string" ? turnError["message"] : "Codex turn failed";
|
|
35766
|
+
terminal = status === "completed" ? { outcome: "done", summary: responseText, usage: usage() } : { outcome: "failed", summary: improveCodexErrorMessage(detail), usage: usage() };
|
|
35767
|
+
return terminal;
|
|
35768
|
+
}
|
|
35769
|
+
return void 0;
|
|
35770
|
+
};
|
|
35771
|
+
return {
|
|
35772
|
+
usage,
|
|
35773
|
+
async start(writer, initialPrompt) {
|
|
35774
|
+
write = writer;
|
|
35775
|
+
prompt = initialPrompt;
|
|
35776
|
+
await send({
|
|
35777
|
+
id: "initialize",
|
|
35778
|
+
method: "initialize",
|
|
35779
|
+
params: { clientInfo: { name: "zixt", version: "1" } }
|
|
35780
|
+
});
|
|
35781
|
+
},
|
|
35782
|
+
async steer(input) {
|
|
35783
|
+
if (stopped) return false;
|
|
35784
|
+
if (!activeTurnId) {
|
|
35785
|
+
const ready = await new Promise((resolve14) => turnReadyWaiters.add(resolve14));
|
|
35786
|
+
if (!ready || stopped) return false;
|
|
35787
|
+
}
|
|
35788
|
+
if (!threadId || !activeTurnId) return false;
|
|
35789
|
+
return await new Promise((resolve14) => {
|
|
35790
|
+
steerWaiters.set(input.inputId, resolve14);
|
|
35791
|
+
void send({
|
|
35792
|
+
id: `steer:${input.inputId}`,
|
|
35793
|
+
method: "turn/steer",
|
|
35794
|
+
params: {
|
|
35795
|
+
threadId,
|
|
35796
|
+
expectedTurnId: activeTurnId,
|
|
35797
|
+
input: [{ type: "text", text: input.text }],
|
|
35798
|
+
clientUserMessageId: input.inputId
|
|
35799
|
+
}
|
|
35800
|
+
}).catch(() => {
|
|
35801
|
+
if (steerWaiters.delete(input.inputId)) resolve14(false);
|
|
35802
|
+
});
|
|
35803
|
+
});
|
|
35804
|
+
},
|
|
35805
|
+
stop() {
|
|
35806
|
+
stopped = true;
|
|
35807
|
+
write = null;
|
|
35808
|
+
settleTurnReadiness(false);
|
|
35809
|
+
for (const resolve14 of steerWaiters.values()) resolve14(false);
|
|
35810
|
+
steerWaiters.clear();
|
|
35811
|
+
},
|
|
35812
|
+
push(chunk) {
|
|
35813
|
+
buffer += chunk;
|
|
35814
|
+
const lines = buffer.split(/\r?\n/);
|
|
35815
|
+
buffer = lines.pop() ?? "";
|
|
35816
|
+
for (const line of lines) {
|
|
35817
|
+
const parsed = processLine(line);
|
|
35818
|
+
if (parsed) return parsed;
|
|
35819
|
+
}
|
|
35820
|
+
return void 0;
|
|
35821
|
+
},
|
|
35822
|
+
finish(stderr, exitCode = 0) {
|
|
35823
|
+
if (buffer.trim()) {
|
|
35824
|
+
const parsed = processLine(buffer);
|
|
35825
|
+
buffer = "";
|
|
35826
|
+
if (parsed) return parsed;
|
|
35827
|
+
}
|
|
35828
|
+
if (terminal) return terminal;
|
|
35829
|
+
const detail = stderr.trim() || "Codex app-server exited before the turn completed";
|
|
35830
|
+
return {
|
|
35831
|
+
outcome: "failed",
|
|
35832
|
+
summary: improveCodexErrorMessage(
|
|
35833
|
+
exitCode ? `codex exited with code ${exitCode}: ${detail}` : detail
|
|
35834
|
+
),
|
|
35835
|
+
usage: usage(),
|
|
35836
|
+
sessionConflict: isCodexSessionConflict(detail)
|
|
35837
|
+
};
|
|
35838
|
+
}
|
|
35839
|
+
};
|
|
35840
|
+
}
|
|
35366
35841
|
function createCodexStreamParser(onStream, hooks = {}) {
|
|
35367
35842
|
let buffer = "";
|
|
35368
35843
|
let responseText = "";
|
|
@@ -37551,11 +38026,11 @@ function shutdown(exitCode = 0) {
|
|
|
37551
38026
|
const recoveringLiveRuns = activeSessions > 0;
|
|
37552
38027
|
setTimeout(
|
|
37553
38028
|
() => {
|
|
37554
|
-
|
|
38029
|
+
finishWorkerProcess(recoveringLiveRuns ? 1 : exitCode);
|
|
37555
38030
|
},
|
|
37556
38031
|
recoveringLiveRuns ? 3e4 : 2e3
|
|
37557
38032
|
).unref();
|
|
37558
|
-
void workerWatchdog.stop().then(() => client.stop()).then(() =>
|
|
38033
|
+
void workerWatchdog.stop().then(() => client.stop()).then(() => finishWorkerProcess(exitCode));
|
|
37559
38034
|
}
|
|
37560
38035
|
stopUpdateWatch = !packagedBuild ? () => {
|
|
37561
38036
|
} : watchForUpdates({
|