@linzumi/cli 0.0.74-beta → 0.0.75-beta
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/README.md +1 -1
- package/bin/remote-codex-harness-worker.js +17 -0
- package/dist/index.js +1508 -158
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -934,6 +934,7 @@ function codexThreadRuntimeOverrides(options) {
|
|
|
934
934
|
...session.model === void 0 ? {} : { model: session.model },
|
|
935
935
|
...session.reasoningEffort === void 0 ? {} : { reasoningEffort: session.reasoningEffort },
|
|
936
936
|
...options.fast === true ? { serviceTier: "fast" } : {},
|
|
937
|
+
...session.codexEnvironmentId === void 0 ? {} : { environmentId: session.codexEnvironmentId },
|
|
937
938
|
approvalPolicy: codexApprovalPolicyForRequest(
|
|
938
939
|
session.approvalPolicy,
|
|
939
940
|
session.sandbox
|
|
@@ -948,6 +949,7 @@ function codexTurnRuntimeOverrides(options) {
|
|
|
948
949
|
...session.model === void 0 ? {} : { model: session.model },
|
|
949
950
|
...session.reasoningEffort === void 0 ? {} : { effort: session.reasoningEffort },
|
|
950
951
|
...options.fast === true ? { serviceTier: "fast" } : {},
|
|
952
|
+
...session.codexEnvironmentId === void 0 ? {} : { environmentId: session.codexEnvironmentId },
|
|
951
953
|
approvalPolicy: codexApprovalPolicyForRequest(
|
|
952
954
|
session.approvalPolicy,
|
|
953
955
|
session.sandbox
|
|
@@ -3822,6 +3824,14 @@ async function attachChannelSession(args) {
|
|
|
3822
3824
|
case "turn/cancelled":
|
|
3823
3825
|
case "turn/failed":
|
|
3824
3826
|
if (turnId !== void 0) {
|
|
3827
|
+
clearInterruptedThreadOnlyCompletionForExplicitTerminal(
|
|
3828
|
+
state,
|
|
3829
|
+
threadId,
|
|
3830
|
+
turnId
|
|
3831
|
+
);
|
|
3832
|
+
if (turnTerminalNotificationIsStale(args, state, turnId)) {
|
|
3833
|
+
break;
|
|
3834
|
+
}
|
|
3825
3835
|
void failActiveCodexTurn(
|
|
3826
3836
|
args,
|
|
3827
3837
|
state,
|
|
@@ -3837,6 +3847,16 @@ async function attachChannelSession(args) {
|
|
|
3837
3847
|
}
|
|
3838
3848
|
break;
|
|
3839
3849
|
case "turn/completed": {
|
|
3850
|
+
if (turnId !== void 0) {
|
|
3851
|
+
clearInterruptedThreadOnlyCompletionForExplicitTerminal(
|
|
3852
|
+
state,
|
|
3853
|
+
threadId,
|
|
3854
|
+
turnId
|
|
3855
|
+
);
|
|
3856
|
+
}
|
|
3857
|
+
if (turnId !== void 0 && turnTerminalNotificationIsStale(args, state, turnId)) {
|
|
3858
|
+
break;
|
|
3859
|
+
}
|
|
3840
3860
|
const completedTurnId = turnId ?? inferThreadOnlyCompletedTurnId(args, state, threadId);
|
|
3841
3861
|
if (completedTurnId !== void 0) {
|
|
3842
3862
|
enqueueWebSearchProgressCompletion(args, state, completedTurnId);
|
|
@@ -4023,7 +4043,9 @@ function initialChannelSessionState(cursor, rootSeq, kandanThreadId, codexThread
|
|
|
4023
4043
|
queue: createPendingKandanMessageQueue(),
|
|
4024
4044
|
forwardedTurnIds: /* @__PURE__ */ new Set(),
|
|
4025
4045
|
forwardingTurnIds: /* @__PURE__ */ new Set(),
|
|
4046
|
+
completionForwardingTurnIds: /* @__PURE__ */ new Set(),
|
|
4026
4047
|
recoveredCompletingTurnIds: /* @__PURE__ */ new Set(),
|
|
4048
|
+
pendingInterruptedThreadOnlyCompletions: [],
|
|
4027
4049
|
retryableTurnIds: /* @__PURE__ */ new Set(),
|
|
4028
4050
|
completedAssistantItemKeys: /* @__PURE__ */ new Set(),
|
|
4029
4051
|
completedAssistantItemTurns: createBoundedCache(maxForwardedTurnIds),
|
|
@@ -4143,6 +4165,10 @@ async function bindChannelSession(args, state, payloadContext) {
|
|
|
4143
4165
|
if (state.rootSeq !== void 0) {
|
|
4144
4166
|
state.minSeq = Math.max(state.minSeq, state.rootSeq);
|
|
4145
4167
|
}
|
|
4168
|
+
} else if (session.startCodexThread === true) {
|
|
4169
|
+
state.codexThreadId = await startCodexThread(args.codex, args.options);
|
|
4170
|
+
await hydrateKandanThreadTitleFromThreadContext(args, state);
|
|
4171
|
+
await bindCurrentCodexThread(args, state);
|
|
4146
4172
|
} else if (state.codexThreadId !== void 0) {
|
|
4147
4173
|
await hydrateKandanThreadTitleFromThreadContext(args, state);
|
|
4148
4174
|
await bindCurrentCodexThread(args, state);
|
|
@@ -4193,6 +4219,55 @@ async function recoverCompletingCodexTurn(args, state, reason) {
|
|
|
4193
4219
|
reason
|
|
4194
4220
|
});
|
|
4195
4221
|
}
|
|
4222
|
+
async function recoverInterruptedCodexTurn(args, state, threadId, turnId, queuedSeq) {
|
|
4223
|
+
interruptCodexTurnBestEffort(args, threadId, turnId);
|
|
4224
|
+
state.turn = { status: "idle" };
|
|
4225
|
+
clearActiveProcessingState(state, queuedSeq);
|
|
4226
|
+
rememberForwardedTurnId(state, turnId);
|
|
4227
|
+
state.pendingInterruptedThreadOnlyCompletions.push({
|
|
4228
|
+
threadId,
|
|
4229
|
+
interruptedTurnId: turnId,
|
|
4230
|
+
interruptedQueuedSeq: queuedSeq
|
|
4231
|
+
});
|
|
4232
|
+
trimBoundedArray(
|
|
4233
|
+
state.pendingInterruptedThreadOnlyCompletions,
|
|
4234
|
+
maxForwardedTurnIds
|
|
4235
|
+
);
|
|
4236
|
+
forgetRetryableTurnId(state, turnId);
|
|
4237
|
+
forgetLocalTuiTurnId(state, turnId);
|
|
4238
|
+
forgetTurnReplyTarget(state, turnId);
|
|
4239
|
+
rejectPendingApprovalRequestsForTurn(
|
|
4240
|
+
state,
|
|
4241
|
+
turnId,
|
|
4242
|
+
new Error("Codex turn interrupted")
|
|
4243
|
+
);
|
|
4244
|
+
if (state.kandanThreadId !== void 0) {
|
|
4245
|
+
await publishMessageState(
|
|
4246
|
+
args,
|
|
4247
|
+
state.kandanThreadId,
|
|
4248
|
+
queuedSeq,
|
|
4249
|
+
{
|
|
4250
|
+
status: "processed"
|
|
4251
|
+
},
|
|
4252
|
+
void 0,
|
|
4253
|
+
void 0,
|
|
4254
|
+
state.codexThreadId
|
|
4255
|
+
);
|
|
4256
|
+
}
|
|
4257
|
+
await stopCodexTyping(args, state);
|
|
4258
|
+
}
|
|
4259
|
+
function interruptCodexTurnBestEffort(args, threadId, turnId) {
|
|
4260
|
+
void args.codex.request("turn/interrupt", {
|
|
4261
|
+
threadId,
|
|
4262
|
+
turnId
|
|
4263
|
+
}).catch((error) => {
|
|
4264
|
+
args.log("codex.turn_interrupt_failed", {
|
|
4265
|
+
thread_id: threadId,
|
|
4266
|
+
turn_id: turnId,
|
|
4267
|
+
message: error instanceof Error ? error.message : String(error)
|
|
4268
|
+
});
|
|
4269
|
+
});
|
|
4270
|
+
}
|
|
4196
4271
|
async function handleChannelSessionControl(args, state, payloadContext, control) {
|
|
4197
4272
|
if (control.type === "update_session_settings") {
|
|
4198
4273
|
return updateSessionSettings(args, state, payloadContext, control);
|
|
@@ -4236,23 +4311,12 @@ async function handleChannelSessionControl(args, state, payloadContext, control)
|
|
|
4236
4311
|
}
|
|
4237
4312
|
switch (state.turn.status) {
|
|
4238
4313
|
case "active":
|
|
4239
|
-
|
|
4240
|
-
await args.codex.request("turn/interrupt", {
|
|
4241
|
-
threadId: state.codexThreadId,
|
|
4242
|
-
turnId: state.turn.turnId
|
|
4243
|
-
});
|
|
4244
|
-
state.turn = { status: "idle" };
|
|
4245
|
-
clearActiveProcessingState(state, interruptedActiveSeq);
|
|
4246
|
-
await publishMessageState(
|
|
4314
|
+
await recoverInterruptedCodexTurn(
|
|
4247
4315
|
args,
|
|
4248
|
-
state
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
},
|
|
4253
|
-
void 0,
|
|
4254
|
-
void 0,
|
|
4255
|
-
state.codexThreadId
|
|
4316
|
+
state,
|
|
4317
|
+
state.codexThreadId,
|
|
4318
|
+
state.turn.turnId,
|
|
4319
|
+
state.turn.queuedSeq
|
|
4256
4320
|
);
|
|
4257
4321
|
break;
|
|
4258
4322
|
case "starting":
|
|
@@ -5525,25 +5589,13 @@ async function drainKandanMessageQueue(args, state, payloadContext) {
|
|
|
5525
5589
|
rememberTurnReplyTarget(state, turnId, next.seq);
|
|
5526
5590
|
args.log("codex.turn_started", { turn_id: turnId });
|
|
5527
5591
|
if (interruptAfterStart) {
|
|
5528
|
-
await
|
|
5529
|
-
|
|
5530
|
-
|
|
5531
|
-
|
|
5532
|
-
|
|
5533
|
-
|
|
5534
|
-
|
|
5535
|
-
await publishMessageState(
|
|
5536
|
-
args,
|
|
5537
|
-
state.kandanThreadId,
|
|
5538
|
-
next.seq,
|
|
5539
|
-
{
|
|
5540
|
-
status: "processed"
|
|
5541
|
-
},
|
|
5542
|
-
void 0,
|
|
5543
|
-
void 0,
|
|
5544
|
-
state.codexThreadId
|
|
5545
|
-
);
|
|
5546
|
-
}
|
|
5592
|
+
await recoverInterruptedCodexTurn(
|
|
5593
|
+
args,
|
|
5594
|
+
state,
|
|
5595
|
+
codexThreadId,
|
|
5596
|
+
turnId,
|
|
5597
|
+
next.seq
|
|
5598
|
+
);
|
|
5547
5599
|
await drainKandanMessageQueue(args, state, payloadContext);
|
|
5548
5600
|
}
|
|
5549
5601
|
} catch (error) {
|
|
@@ -5783,43 +5835,44 @@ async function forwardCompletedCodexTurn(args, state, turnId, payloadContext) {
|
|
|
5783
5835
|
if (isLocalTuiTurn(state, turnId)) {
|
|
5784
5836
|
ensureKandanThreadForLocalTuiTurn(state);
|
|
5785
5837
|
}
|
|
5786
|
-
if (state.kandanThreadId === void 0 || state.codexThreadId === void 0 || state.forwardedTurnIds.has(turnId) || state.forwardingTurnIds.has(turnId) || !turnCanForward(state, turnId)) {
|
|
5838
|
+
if (state.kandanThreadId === void 0 || state.codexThreadId === void 0 || state.forwardedTurnIds.has(turnId) || state.forwardingTurnIds.has(turnId) || state.completionForwardingTurnIds.has(turnId) || !turnCanForward(state, turnId)) {
|
|
5787
5839
|
return;
|
|
5788
5840
|
}
|
|
5789
5841
|
const completingQueuedSeq = completingQueuedSeqForTurn(state.turn, turnId);
|
|
5790
5842
|
const completingActiveTurn = completingQueuedSeq !== void 0;
|
|
5791
5843
|
const completingLocalTuiTurn = isLocalTuiTurn(state, turnId);
|
|
5792
|
-
|
|
5793
|
-
state.turn = {
|
|
5794
|
-
status: "completing",
|
|
5795
|
-
turnId,
|
|
5796
|
-
queuedSeq: completingQueuedSeq
|
|
5797
|
-
};
|
|
5798
|
-
}
|
|
5799
|
-
await waitForPendingTuiInputMirror(state, turnId);
|
|
5800
|
-
if (completingTurnWasRecovered(state, turnId)) {
|
|
5801
|
-
return;
|
|
5802
|
-
}
|
|
5803
|
-
await waitForPendingCompletedAssistantItemForwards(state, turnId);
|
|
5804
|
-
if (completingTurnWasRecovered(state, turnId)) {
|
|
5805
|
-
return;
|
|
5806
|
-
}
|
|
5807
|
-
if (completingQueuedSeq !== void 0) {
|
|
5808
|
-
await waitForPendingCompletedAssistantItemSourceForwards(
|
|
5809
|
-
state,
|
|
5810
|
-
completingQueuedSeq
|
|
5811
|
-
);
|
|
5812
|
-
}
|
|
5813
|
-
if (completingTurnWasRecovered(state, turnId)) {
|
|
5814
|
-
return;
|
|
5815
|
-
}
|
|
5816
|
-
await waitForStreamingForwardChains(args, state, payloadContext);
|
|
5817
|
-
if (completingTurnWasRecovered(state, turnId)) {
|
|
5818
|
-
return;
|
|
5819
|
-
}
|
|
5820
|
-
rememberForwardingTurnId(state, turnId);
|
|
5821
|
-
forgetRetryableTurnId(state, turnId);
|
|
5844
|
+
rememberCompletionForwardingTurnId(state, turnId);
|
|
5822
5845
|
try {
|
|
5846
|
+
if (completingQueuedSeq !== void 0) {
|
|
5847
|
+
state.turn = {
|
|
5848
|
+
status: "completing",
|
|
5849
|
+
turnId,
|
|
5850
|
+
queuedSeq: completingQueuedSeq
|
|
5851
|
+
};
|
|
5852
|
+
}
|
|
5853
|
+
await waitForPendingTuiInputMirror(state, turnId);
|
|
5854
|
+
if (completingTurnWasRecovered(state, turnId)) {
|
|
5855
|
+
return;
|
|
5856
|
+
}
|
|
5857
|
+
await waitForPendingCompletedAssistantItemForwards(state, turnId);
|
|
5858
|
+
if (completingTurnWasRecovered(state, turnId)) {
|
|
5859
|
+
return;
|
|
5860
|
+
}
|
|
5861
|
+
if (completingQueuedSeq !== void 0) {
|
|
5862
|
+
await waitForPendingCompletedAssistantItemSourceForwards(
|
|
5863
|
+
state,
|
|
5864
|
+
completingQueuedSeq
|
|
5865
|
+
);
|
|
5866
|
+
}
|
|
5867
|
+
if (completingTurnWasRecovered(state, turnId)) {
|
|
5868
|
+
return;
|
|
5869
|
+
}
|
|
5870
|
+
await waitForStreamingForwardChains(args, state, payloadContext);
|
|
5871
|
+
if (completingTurnWasRecovered(state, turnId)) {
|
|
5872
|
+
return;
|
|
5873
|
+
}
|
|
5874
|
+
rememberForwardingTurnId(state, turnId);
|
|
5875
|
+
forgetRetryableTurnId(state, turnId);
|
|
5823
5876
|
const read = await args.codex.request("thread/read", {
|
|
5824
5877
|
threadId: state.codexThreadId,
|
|
5825
5878
|
includeTurns: true
|
|
@@ -5967,6 +6020,7 @@ async function forwardCompletedCodexTurn(args, state, turnId, payloadContext) {
|
|
|
5967
6020
|
rememberRetryableTurnId(state, turnId);
|
|
5968
6021
|
throw error;
|
|
5969
6022
|
} finally {
|
|
6023
|
+
forgetCompletionForwardingTurnId(state, turnId);
|
|
5970
6024
|
forgetForwardingTurnId(state, turnId);
|
|
5971
6025
|
if (completingActiveTurn && state.turn.status === "completing" && state.turn.turnId === turnId) {
|
|
5972
6026
|
state.turn = { status: "idle" };
|
|
@@ -6157,7 +6211,10 @@ function completedMessagesWithSessionLog(readMessages, sessionLogMessages) {
|
|
|
6157
6211
|
}
|
|
6158
6212
|
nextReadIndex += 1;
|
|
6159
6213
|
}
|
|
6160
|
-
|
|
6214
|
+
const readMessage = readMessages[entry.readIndex];
|
|
6215
|
+
if (readMessage !== void 0) {
|
|
6216
|
+
mergedMessages.push(readMessage);
|
|
6217
|
+
}
|
|
6161
6218
|
nextReadIndex = Math.max(nextReadIndex, entry.readIndex + 1);
|
|
6162
6219
|
break;
|
|
6163
6220
|
case "session":
|
|
@@ -8004,6 +8061,16 @@ function inferThreadOnlyCompletedTurnId(args, state, threadId) {
|
|
|
8004
8061
|
switch (state.turn.status) {
|
|
8005
8062
|
case "active":
|
|
8006
8063
|
case "completing":
|
|
8064
|
+
clearInterruptedThreadOnlyCompletionsBeforeQueuedSeq(
|
|
8065
|
+
state,
|
|
8066
|
+
threadId,
|
|
8067
|
+
state.turn.queuedSeq
|
|
8068
|
+
);
|
|
8069
|
+
rejectPendingApprovalRequestsForTurn(
|
|
8070
|
+
state,
|
|
8071
|
+
state.turn.turnId,
|
|
8072
|
+
new Error("Codex turn completed with thread-only notification")
|
|
8073
|
+
);
|
|
8007
8074
|
args.log("codex.turn_completion_inferred", {
|
|
8008
8075
|
thread_id: threadId,
|
|
8009
8076
|
turn_id: state.turn.turnId,
|
|
@@ -8012,6 +8079,24 @@ function inferThreadOnlyCompletedTurnId(args, state, threadId) {
|
|
|
8012
8079
|
});
|
|
8013
8080
|
return state.turn.turnId;
|
|
8014
8081
|
case "idle":
|
|
8082
|
+
case "starting":
|
|
8083
|
+
break;
|
|
8084
|
+
}
|
|
8085
|
+
const pending = consumeAmbiguousInterruptedThreadOnlyCompletion(
|
|
8086
|
+
state,
|
|
8087
|
+
threadId
|
|
8088
|
+
);
|
|
8089
|
+
if (pending !== void 0) {
|
|
8090
|
+
args.log("codex.thread_only_completion_after_interrupt_ignored", {
|
|
8091
|
+
thread_id: threadId,
|
|
8092
|
+
interrupted_turn_id: pending.interruptedTurnId,
|
|
8093
|
+
interrupted_queued_seq: pending.interruptedQueuedSeq,
|
|
8094
|
+
turn_status: state.turn.status
|
|
8095
|
+
});
|
|
8096
|
+
return void 0;
|
|
8097
|
+
}
|
|
8098
|
+
switch (state.turn.status) {
|
|
8099
|
+
case "idle":
|
|
8015
8100
|
case "starting":
|
|
8016
8101
|
args.log("codex.turn_completion_without_turn_id", {
|
|
8017
8102
|
thread_id: threadId,
|
|
@@ -8021,6 +8106,46 @@ function inferThreadOnlyCompletedTurnId(args, state, threadId) {
|
|
|
8021
8106
|
return void 0;
|
|
8022
8107
|
}
|
|
8023
8108
|
}
|
|
8109
|
+
function consumeAmbiguousInterruptedThreadOnlyCompletion(state, threadId) {
|
|
8110
|
+
const index = state.pendingInterruptedThreadOnlyCompletions.findIndex(
|
|
8111
|
+
(pending2) => pending2.threadId === threadId
|
|
8112
|
+
);
|
|
8113
|
+
if (index < 0) {
|
|
8114
|
+
return void 0;
|
|
8115
|
+
}
|
|
8116
|
+
const [pending] = state.pendingInterruptedThreadOnlyCompletions.splice(
|
|
8117
|
+
index,
|
|
8118
|
+
1
|
|
8119
|
+
);
|
|
8120
|
+
return pending;
|
|
8121
|
+
}
|
|
8122
|
+
function clearInterruptedThreadOnlyCompletionForExplicitTerminal(state, threadId, turnId) {
|
|
8123
|
+
state.pendingInterruptedThreadOnlyCompletions = state.pendingInterruptedThreadOnlyCompletions.filter((pending) => {
|
|
8124
|
+
if (threadId !== void 0 && pending.threadId !== threadId) {
|
|
8125
|
+
return true;
|
|
8126
|
+
}
|
|
8127
|
+
if (pending.interruptedTurnId === turnId) {
|
|
8128
|
+
return false;
|
|
8129
|
+
}
|
|
8130
|
+
return true;
|
|
8131
|
+
});
|
|
8132
|
+
}
|
|
8133
|
+
function clearInterruptedThreadOnlyCompletionsBeforeQueuedSeq(state, threadId, queuedSeq) {
|
|
8134
|
+
state.pendingInterruptedThreadOnlyCompletions = state.pendingInterruptedThreadOnlyCompletions.filter(
|
|
8135
|
+
(pending) => pending.threadId !== threadId || pending.interruptedQueuedSeq >= queuedSeq
|
|
8136
|
+
);
|
|
8137
|
+
}
|
|
8138
|
+
function turnTerminalNotificationIsStale(args, state, turnId) {
|
|
8139
|
+
if (!state.forwardedTurnIds.has(turnId)) {
|
|
8140
|
+
return false;
|
|
8141
|
+
}
|
|
8142
|
+
args.log("codex.stale_turn_terminal_ignored", {
|
|
8143
|
+
turn_id: turnId,
|
|
8144
|
+
active_turn_id: activeTurnId(state.turn) ?? null,
|
|
8145
|
+
turn_status: state.turn.status
|
|
8146
|
+
});
|
|
8147
|
+
return true;
|
|
8148
|
+
}
|
|
8024
8149
|
function codexNotificationActiveTurnFallback(method, state, params, threadId) {
|
|
8025
8150
|
if (threadId === void 0 || state.codexThreadId !== threadId) {
|
|
8026
8151
|
return void 0;
|
|
@@ -8212,6 +8337,9 @@ function rememberTurnReplyTarget(state, turnId, replyToSeq) {
|
|
|
8212
8337
|
replyToSeq
|
|
8213
8338
|
});
|
|
8214
8339
|
}
|
|
8340
|
+
function forgetTurnReplyTarget(state, turnId) {
|
|
8341
|
+
forgetBoundedCacheValue(state.turnReplyTargets, turnId);
|
|
8342
|
+
}
|
|
8215
8343
|
function sourceMessageSeqForTurn(state, turnId) {
|
|
8216
8344
|
return getBoundedCacheValue(state.turnReplyTargets, turnId)?.replyToSeq;
|
|
8217
8345
|
}
|
|
@@ -8282,6 +8410,16 @@ function rememberForwardingTurnId(state, turnId) {
|
|
|
8282
8410
|
function forgetForwardingTurnId(state, turnId) {
|
|
8283
8411
|
state.forwardingTurnIds.delete(turnId);
|
|
8284
8412
|
}
|
|
8413
|
+
function rememberCompletionForwardingTurnId(state, turnId) {
|
|
8414
|
+
rememberBoundedStringSet(
|
|
8415
|
+
state.completionForwardingTurnIds,
|
|
8416
|
+
turnId,
|
|
8417
|
+
maxForwardedTurnIds
|
|
8418
|
+
);
|
|
8419
|
+
}
|
|
8420
|
+
function forgetCompletionForwardingTurnId(state, turnId) {
|
|
8421
|
+
state.completionForwardingTurnIds.delete(turnId);
|
|
8422
|
+
}
|
|
8285
8423
|
function rememberRecoveredCompletingTurnId(state, turnId) {
|
|
8286
8424
|
rememberBoundedStringSet(
|
|
8287
8425
|
state.recoveredCompletingTurnIds,
|
|
@@ -8321,6 +8459,11 @@ function trimBoundedMap(values, maxSize) {
|
|
|
8321
8459
|
values.delete(oldest);
|
|
8322
8460
|
}
|
|
8323
8461
|
}
|
|
8462
|
+
function trimBoundedArray(values, maxSize) {
|
|
8463
|
+
while (values.length > maxSize) {
|
|
8464
|
+
values.shift();
|
|
8465
|
+
}
|
|
8466
|
+
}
|
|
8324
8467
|
async function stopCodexTyping(args, state) {
|
|
8325
8468
|
stopCodexTypingHeartbeat(state);
|
|
8326
8469
|
if (state.kandanThreadId === void 0) {
|
|
@@ -9743,6 +9886,7 @@ import {
|
|
|
9743
9886
|
spawn
|
|
9744
9887
|
} from "node:child_process";
|
|
9745
9888
|
import { createServer } from "node:net";
|
|
9889
|
+
import { WebSocket as NodeWebSocket } from "ws";
|
|
9746
9890
|
async function chooseLoopbackPort() {
|
|
9747
9891
|
return new Promise((resolve11, reject) => {
|
|
9748
9892
|
const server = createServer();
|
|
@@ -9783,7 +9927,7 @@ async function startCodexAppServerAttempt(codexBin, cwd, options, attempt) {
|
|
|
9783
9927
|
});
|
|
9784
9928
|
const child = spawn(codexBin, args, {
|
|
9785
9929
|
cwd,
|
|
9786
|
-
env: codexAppServerEnv(options.env),
|
|
9930
|
+
env: codexAppServerEnv(options.env, options.inheritEnv ?? true),
|
|
9787
9931
|
stdio,
|
|
9788
9932
|
detached: true
|
|
9789
9933
|
});
|
|
@@ -9870,8 +10014,8 @@ function drainCodexAppServerOutput(child, streamName, onText = void 0) {
|
|
|
9870
10014
|
});
|
|
9871
10015
|
});
|
|
9872
10016
|
}
|
|
9873
|
-
function codexAppServerEnv(overrides) {
|
|
9874
|
-
const env = { ...process.env };
|
|
10017
|
+
function codexAppServerEnv(overrides, inheritEnv) {
|
|
10018
|
+
const env = inheritEnv ? { ...process.env } : {};
|
|
9875
10019
|
for (const key of blockedCodexAppServerEnvKeys) {
|
|
9876
10020
|
delete env[key];
|
|
9877
10021
|
}
|
|
@@ -9943,8 +10087,11 @@ function codexConfigArgs(options) {
|
|
|
9943
10087
|
)
|
|
9944
10088
|
];
|
|
9945
10089
|
}
|
|
9946
|
-
async function connectCodexAppServer(websocketUrl, socketFactory = (url) => new
|
|
9947
|
-
const websocket =
|
|
10090
|
+
async function connectCodexAppServer(websocketUrl, socketFactory = (url) => new NodeWebSocket(url)) {
|
|
10091
|
+
const websocket = await openCodexAppServerWebSocket(
|
|
10092
|
+
websocketUrl,
|
|
10093
|
+
socketFactory
|
|
10094
|
+
);
|
|
9948
10095
|
const pending = /* @__PURE__ */ new Map();
|
|
9949
10096
|
const notificationCallbacks = /* @__PURE__ */ new Set();
|
|
9950
10097
|
const requestCallbacks = /* @__PURE__ */ new Set();
|
|
@@ -9994,7 +10141,6 @@ async function connectCodexAppServer(websocketUrl, socketFactory = (url) => new
|
|
|
9994
10141
|
}
|
|
9995
10142
|
}
|
|
9996
10143
|
});
|
|
9997
|
-
await waitForOpen(websocket);
|
|
9998
10144
|
await initialize(websocket, pending);
|
|
9999
10145
|
const request = (method, params) => {
|
|
10000
10146
|
const id = state.nextId;
|
|
@@ -10018,6 +10164,27 @@ async function connectCodexAppServer(websocketUrl, socketFactory = (url) => new
|
|
|
10018
10164
|
close: () => websocket.close()
|
|
10019
10165
|
};
|
|
10020
10166
|
}
|
|
10167
|
+
async function openCodexAppServerWebSocket(websocketUrl, socketFactory, timeoutMs = 2e3) {
|
|
10168
|
+
const deadline = Date.now() + timeoutMs;
|
|
10169
|
+
let lastError;
|
|
10170
|
+
while (Date.now() <= deadline) {
|
|
10171
|
+
const websocket = socketFactory(websocketUrl);
|
|
10172
|
+
try {
|
|
10173
|
+
await waitForOpen(websocket);
|
|
10174
|
+
return websocket;
|
|
10175
|
+
} catch (error) {
|
|
10176
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
10177
|
+
closeWebSocketAfterFailedOpen(websocket);
|
|
10178
|
+
}
|
|
10179
|
+
}
|
|
10180
|
+
throw lastError ?? new Error("websocket open failed");
|
|
10181
|
+
}
|
|
10182
|
+
function closeWebSocketAfterFailedOpen(websocket) {
|
|
10183
|
+
try {
|
|
10184
|
+
websocket.close();
|
|
10185
|
+
} catch (_error) {
|
|
10186
|
+
}
|
|
10187
|
+
}
|
|
10021
10188
|
async function respondToServerRequest(websocket, request, callbacks) {
|
|
10022
10189
|
try {
|
|
10023
10190
|
if (callbacks.size === 0) {
|
|
@@ -10253,21 +10420,62 @@ function codexNotificationConsoleLogPayload(method, params) {
|
|
|
10253
10420
|
};
|
|
10254
10421
|
}
|
|
10255
10422
|
function codexNotificationConsoleStats(method, params) {
|
|
10423
|
+
const creditExhaustion = creditExhaustionStats(method, params);
|
|
10256
10424
|
switch (method) {
|
|
10257
10425
|
case "thread/tokenUsage/updated":
|
|
10258
10426
|
return {
|
|
10259
|
-
token_usage_summary: tokenUsageSummary(params) ?? "seen (no details)"
|
|
10427
|
+
token_usage_summary: tokenUsageSummary(params) ?? "seen (no details)",
|
|
10428
|
+
...creditExhaustion
|
|
10260
10429
|
};
|
|
10261
10430
|
case "account/rateLimits/updated":
|
|
10262
10431
|
return {
|
|
10263
|
-
rate_limit_summary: rateLimitSummary(params) ?? "seen (no details)"
|
|
10432
|
+
rate_limit_summary: rateLimitSummary(params) ?? "seen (no details)",
|
|
10433
|
+
...creditExhaustion
|
|
10264
10434
|
};
|
|
10265
10435
|
case "warning":
|
|
10266
10436
|
case "error":
|
|
10267
|
-
return
|
|
10437
|
+
return {
|
|
10438
|
+
...codexNotificationDiagnosticDetails(method, params),
|
|
10439
|
+
...creditExhaustion
|
|
10440
|
+
};
|
|
10268
10441
|
default:
|
|
10269
|
-
return
|
|
10442
|
+
return creditExhaustion;
|
|
10443
|
+
}
|
|
10444
|
+
}
|
|
10445
|
+
function creditExhaustionStats(method, params) {
|
|
10446
|
+
if (!creditExhaustionDetected(method, params)) {
|
|
10447
|
+
return {};
|
|
10448
|
+
}
|
|
10449
|
+
return {
|
|
10450
|
+
credit_exhaustion_detected: true,
|
|
10451
|
+
credit_exhaustion_summary: "OpenAI credits exhausted. Add credits or upgrade the account to continue Codex jobs."
|
|
10452
|
+
};
|
|
10453
|
+
}
|
|
10454
|
+
function creditExhaustionDetected(method, params) {
|
|
10455
|
+
const haystack = [method, ...diagnosticStrings(params, 0)].join("\n").toLowerCase();
|
|
10456
|
+
return creditExhaustionMatchers.some((matcher) => haystack.includes(matcher));
|
|
10457
|
+
}
|
|
10458
|
+
function diagnosticStrings(value, depth) {
|
|
10459
|
+
if (depth > 4) {
|
|
10460
|
+
return [];
|
|
10461
|
+
}
|
|
10462
|
+
if (typeof value === "string") {
|
|
10463
|
+
return [value];
|
|
10464
|
+
}
|
|
10465
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
10466
|
+
return [String(value)];
|
|
10467
|
+
}
|
|
10468
|
+
if (Array.isArray(value)) {
|
|
10469
|
+
return value.flatMap((entry) => diagnosticStrings(entry, depth + 1));
|
|
10470
|
+
}
|
|
10471
|
+
const object = objectValue4(value);
|
|
10472
|
+
if (object === void 0) {
|
|
10473
|
+
return [];
|
|
10270
10474
|
}
|
|
10475
|
+
return Object.entries(object).flatMap(([key, entry]) => [
|
|
10476
|
+
key,
|
|
10477
|
+
...diagnosticStrings(entry, depth + 1)
|
|
10478
|
+
]);
|
|
10271
10479
|
}
|
|
10272
10480
|
function tokenUsageSummary(params) {
|
|
10273
10481
|
const usage = objectValue4(params.tokenUsage) ?? objectValue4(params.token_usage) ?? objectValue4(params.usage) ?? params;
|
|
@@ -10359,11 +10567,19 @@ function integerValue2(value) {
|
|
|
10359
10567
|
const parsed = Number.parseInt(value, 10);
|
|
10360
10568
|
return Number.isSafeInteger(parsed) && parsed.toString() === value.trim() ? parsed : void 0;
|
|
10361
10569
|
}
|
|
10570
|
+
var creditExhaustionMatchers;
|
|
10362
10571
|
var init_codexNotificationConsoleStats = __esm({
|
|
10363
10572
|
"src/codexNotificationConsoleStats.ts"() {
|
|
10364
10573
|
"use strict";
|
|
10365
10574
|
init_codexNotificationDiagnostics();
|
|
10366
10575
|
init_protocol();
|
|
10576
|
+
creditExhaustionMatchers = [
|
|
10577
|
+
"insufficient_quota",
|
|
10578
|
+
"quota_exceeded",
|
|
10579
|
+
"billing_hard_limit",
|
|
10580
|
+
"billing hard limit",
|
|
10581
|
+
"credit_exhausted"
|
|
10582
|
+
];
|
|
10367
10583
|
}
|
|
10368
10584
|
});
|
|
10369
10585
|
|
|
@@ -11266,6 +11482,263 @@ var init_localConfig = __esm({
|
|
|
11266
11482
|
}
|
|
11267
11483
|
});
|
|
11268
11484
|
|
|
11485
|
+
// src/remoteCodexExecutionContext.ts
|
|
11486
|
+
async function handleRemoteCodexExecControl(control, options) {
|
|
11487
|
+
const requestId = normalizedString(control.requestId) ?? null;
|
|
11488
|
+
const cwd = resolveAllowedCwd(control.cwd, options.allowedCwds);
|
|
11489
|
+
if (!cwd.ok) {
|
|
11490
|
+
return {
|
|
11491
|
+
instanceId: options.instanceId,
|
|
11492
|
+
controlType: control.type,
|
|
11493
|
+
requestId,
|
|
11494
|
+
ok: false,
|
|
11495
|
+
error: cwd.reason
|
|
11496
|
+
};
|
|
11497
|
+
}
|
|
11498
|
+
const command = normalizedString(control.command);
|
|
11499
|
+
if (command === void 0) {
|
|
11500
|
+
return {
|
|
11501
|
+
instanceId: options.instanceId,
|
|
11502
|
+
controlType: control.type,
|
|
11503
|
+
requestId,
|
|
11504
|
+
ok: false,
|
|
11505
|
+
error: "command_required"
|
|
11506
|
+
};
|
|
11507
|
+
}
|
|
11508
|
+
const args = normalizedStringList(control.args);
|
|
11509
|
+
if (args === void 0) {
|
|
11510
|
+
return {
|
|
11511
|
+
instanceId: options.instanceId,
|
|
11512
|
+
controlType: control.type,
|
|
11513
|
+
requestId,
|
|
11514
|
+
ok: false,
|
|
11515
|
+
error: "invalid_args"
|
|
11516
|
+
};
|
|
11517
|
+
}
|
|
11518
|
+
const extraEnv = normalizedEnvOverrideMap(control.env);
|
|
11519
|
+
if (extraEnv === void 0) {
|
|
11520
|
+
return {
|
|
11521
|
+
instanceId: options.instanceId,
|
|
11522
|
+
controlType: control.type,
|
|
11523
|
+
requestId,
|
|
11524
|
+
ok: false,
|
|
11525
|
+
error: "invalid_env"
|
|
11526
|
+
};
|
|
11527
|
+
}
|
|
11528
|
+
const timeoutMs = normalizedTimeoutMs(control.timeoutMs);
|
|
11529
|
+
if (timeoutMs === void 0) {
|
|
11530
|
+
return {
|
|
11531
|
+
instanceId: options.instanceId,
|
|
11532
|
+
controlType: control.type,
|
|
11533
|
+
requestId,
|
|
11534
|
+
ok: false,
|
|
11535
|
+
error: "invalid_timeout"
|
|
11536
|
+
};
|
|
11537
|
+
}
|
|
11538
|
+
if (options.sandboxRunner === void 0) {
|
|
11539
|
+
return {
|
|
11540
|
+
instanceId: options.instanceId,
|
|
11541
|
+
controlType: control.type,
|
|
11542
|
+
requestId,
|
|
11543
|
+
ok: false,
|
|
11544
|
+
cwd: cwd.cwd,
|
|
11545
|
+
matchedRoot: cwd.matchedRoot,
|
|
11546
|
+
command,
|
|
11547
|
+
args,
|
|
11548
|
+
error: "remote_codex_exec_sandbox_unavailable"
|
|
11549
|
+
};
|
|
11550
|
+
}
|
|
11551
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
11552
|
+
try {
|
|
11553
|
+
const result = await runSandboxRunnerWithTimeout(
|
|
11554
|
+
options.sandboxRunner,
|
|
11555
|
+
{
|
|
11556
|
+
command,
|
|
11557
|
+
args,
|
|
11558
|
+
cwd: cwd.cwd,
|
|
11559
|
+
env: remoteExecEnv(options.inheritedEnv ?? process.env, extraEnv),
|
|
11560
|
+
stdin: typeof control.stdin === "string" ? control.stdin : void 0,
|
|
11561
|
+
timeoutMs
|
|
11562
|
+
},
|
|
11563
|
+
options.abortSignal
|
|
11564
|
+
);
|
|
11565
|
+
return {
|
|
11566
|
+
instanceId: options.instanceId,
|
|
11567
|
+
controlType: control.type,
|
|
11568
|
+
requestId,
|
|
11569
|
+
ok: true,
|
|
11570
|
+
cwd: cwd.cwd,
|
|
11571
|
+
matchedRoot: cwd.matchedRoot,
|
|
11572
|
+
command,
|
|
11573
|
+
args,
|
|
11574
|
+
startedAt,
|
|
11575
|
+
finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11576
|
+
exitCode: result.exitCode,
|
|
11577
|
+
signal: result.signal,
|
|
11578
|
+
stdout: result.stdout,
|
|
11579
|
+
stderr: result.stderr,
|
|
11580
|
+
stdoutTruncated: result.stdoutTruncated,
|
|
11581
|
+
stderrTruncated: result.stderrTruncated,
|
|
11582
|
+
timedOut: result.timedOut
|
|
11583
|
+
};
|
|
11584
|
+
} catch (error) {
|
|
11585
|
+
return {
|
|
11586
|
+
instanceId: options.instanceId,
|
|
11587
|
+
controlType: control.type,
|
|
11588
|
+
requestId,
|
|
11589
|
+
ok: false,
|
|
11590
|
+
cwd: cwd.cwd,
|
|
11591
|
+
matchedRoot: cwd.matchedRoot,
|
|
11592
|
+
command,
|
|
11593
|
+
args,
|
|
11594
|
+
error: error instanceof Error ? `remote_codex_exec_failed:${error.message}` : "remote_codex_exec_failed"
|
|
11595
|
+
};
|
|
11596
|
+
}
|
|
11597
|
+
}
|
|
11598
|
+
function runSandboxRunnerWithTimeout(sandboxRunner, request, parentAbortSignal) {
|
|
11599
|
+
const abortController = new AbortController();
|
|
11600
|
+
const timeoutResult = {
|
|
11601
|
+
exitCode: null,
|
|
11602
|
+
signal: null,
|
|
11603
|
+
stdout: "",
|
|
11604
|
+
stderr: "remote_codex_exec_timed_out",
|
|
11605
|
+
stdoutTruncated: false,
|
|
11606
|
+
stderrTruncated: false,
|
|
11607
|
+
timedOut: true
|
|
11608
|
+
};
|
|
11609
|
+
const requestWithSignal = {
|
|
11610
|
+
...request,
|
|
11611
|
+
abortSignal: abortController.signal
|
|
11612
|
+
};
|
|
11613
|
+
let timeout;
|
|
11614
|
+
let timedOut = false;
|
|
11615
|
+
const onParentAbort = () => {
|
|
11616
|
+
abortController.abort(parentAbortSignal?.reason);
|
|
11617
|
+
};
|
|
11618
|
+
if (parentAbortSignal?.aborted === true) {
|
|
11619
|
+
onParentAbort();
|
|
11620
|
+
} else {
|
|
11621
|
+
parentAbortSignal?.addEventListener("abort", onParentAbort, {
|
|
11622
|
+
once: true
|
|
11623
|
+
});
|
|
11624
|
+
}
|
|
11625
|
+
const runnerPromise = sandboxRunner(requestWithSignal).catch((error) => {
|
|
11626
|
+
if (timedOut) {
|
|
11627
|
+
return timeoutResult;
|
|
11628
|
+
}
|
|
11629
|
+
throw error;
|
|
11630
|
+
});
|
|
11631
|
+
const timeoutPromise = new Promise((resolve11) => {
|
|
11632
|
+
timeout = setTimeout(() => {
|
|
11633
|
+
timedOut = true;
|
|
11634
|
+
resolve11(timeoutResult);
|
|
11635
|
+
abortController.abort();
|
|
11636
|
+
}, request.timeoutMs);
|
|
11637
|
+
});
|
|
11638
|
+
return Promise.race([runnerPromise, timeoutPromise]).finally(() => {
|
|
11639
|
+
if (timeout !== void 0) {
|
|
11640
|
+
clearTimeout(timeout);
|
|
11641
|
+
}
|
|
11642
|
+
parentAbortSignal?.removeEventListener("abort", onParentAbort);
|
|
11643
|
+
});
|
|
11644
|
+
}
|
|
11645
|
+
function remoteExecEnv(inheritedEnv, extraEnv) {
|
|
11646
|
+
return {
|
|
11647
|
+
...inheritedEnv.PATH === void 0 ? {} : { PATH: inheritedEnv.PATH },
|
|
11648
|
+
...extraEnv,
|
|
11649
|
+
LINZUMI_REMOTE_CODEX_EXEC: "1"
|
|
11650
|
+
};
|
|
11651
|
+
}
|
|
11652
|
+
function normalizedString(value) {
|
|
11653
|
+
if (typeof value !== "string") {
|
|
11654
|
+
return void 0;
|
|
11655
|
+
}
|
|
11656
|
+
const trimmed = value.trim();
|
|
11657
|
+
return trimmed === "" ? void 0 : trimmed;
|
|
11658
|
+
}
|
|
11659
|
+
function normalizedStringList(value) {
|
|
11660
|
+
if (value === void 0) {
|
|
11661
|
+
return [];
|
|
11662
|
+
}
|
|
11663
|
+
if (!Array.isArray(value)) {
|
|
11664
|
+
return void 0;
|
|
11665
|
+
}
|
|
11666
|
+
const values = value.flatMap(
|
|
11667
|
+
(entry) => typeof entry === "string" ? [entry] : []
|
|
11668
|
+
);
|
|
11669
|
+
return values.length === value.length ? values : void 0;
|
|
11670
|
+
}
|
|
11671
|
+
function normalizedEnvOverrideMap(value) {
|
|
11672
|
+
if (value === void 0) {
|
|
11673
|
+
return {};
|
|
11674
|
+
}
|
|
11675
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
11676
|
+
return void 0;
|
|
11677
|
+
}
|
|
11678
|
+
const entries = Object.entries(value).flatMap(([key, entry]) => {
|
|
11679
|
+
if (ignoredEnvOverrideKeys.has(key) && typeof entry === "string") {
|
|
11680
|
+
return [];
|
|
11681
|
+
}
|
|
11682
|
+
if (typeof entry !== "string" || !validEnvKey(key) || reservedEnvKeys.has(key) || deniedEnvKeys.has(key) || deniedEnvPrefixes.some((prefix) => key.startsWith(prefix))) {
|
|
11683
|
+
return [];
|
|
11684
|
+
}
|
|
11685
|
+
return [[key, entry]];
|
|
11686
|
+
});
|
|
11687
|
+
const expectedEntries = Object.entries(value).filter(
|
|
11688
|
+
([key, entry]) => !(ignoredEnvOverrideKeys.has(key) && typeof entry === "string")
|
|
11689
|
+
);
|
|
11690
|
+
return entries.length === expectedEntries.length ? Object.fromEntries(entries) : void 0;
|
|
11691
|
+
}
|
|
11692
|
+
function validEnvKey(key) {
|
|
11693
|
+
return /^[A-Z_][A-Z0-9_]*$/.test(key);
|
|
11694
|
+
}
|
|
11695
|
+
function normalizedTimeoutMs(value) {
|
|
11696
|
+
if (value === void 0) {
|
|
11697
|
+
return defaultTimeoutMs;
|
|
11698
|
+
}
|
|
11699
|
+
if (!Number.isInteger(value) || value <= 0 || value > maxTimeoutMs) {
|
|
11700
|
+
return void 0;
|
|
11701
|
+
}
|
|
11702
|
+
return value;
|
|
11703
|
+
}
|
|
11704
|
+
var defaultTimeoutMs, maxTimeoutMs, reservedEnvKeys, ignoredEnvOverrideKeys, deniedEnvKeys, deniedEnvPrefixes;
|
|
11705
|
+
var init_remoteCodexExecutionContext = __esm({
|
|
11706
|
+
"src/remoteCodexExecutionContext.ts"() {
|
|
11707
|
+
"use strict";
|
|
11708
|
+
init_localCapabilities();
|
|
11709
|
+
defaultTimeoutMs = 12e4;
|
|
11710
|
+
maxTimeoutMs = 3e5;
|
|
11711
|
+
reservedEnvKeys = /* @__PURE__ */ new Set([
|
|
11712
|
+
"HOME",
|
|
11713
|
+
"LINZUMI_REMOTE_CODEX_EXEC",
|
|
11714
|
+
"NODE_OPTIONS",
|
|
11715
|
+
"SHELL",
|
|
11716
|
+
"TMPDIR"
|
|
11717
|
+
]);
|
|
11718
|
+
ignoredEnvOverrideKeys = /* @__PURE__ */ new Set(["PATH"]);
|
|
11719
|
+
deniedEnvKeys = /* @__PURE__ */ new Set([
|
|
11720
|
+
"BASH_ENV",
|
|
11721
|
+
"ENV",
|
|
11722
|
+
"NODE_PATH",
|
|
11723
|
+
"PERL5LIB",
|
|
11724
|
+
"PYTHONHOME",
|
|
11725
|
+
"PYTHONPATH",
|
|
11726
|
+
"RUBYLIB",
|
|
11727
|
+
"RUBYOPT",
|
|
11728
|
+
"ZDOTDIR"
|
|
11729
|
+
]);
|
|
11730
|
+
deniedEnvPrefixes = [
|
|
11731
|
+
"AWS_",
|
|
11732
|
+
"DYLD_",
|
|
11733
|
+
"GIT_",
|
|
11734
|
+
"LD_",
|
|
11735
|
+
"NPM_CONFIG_",
|
|
11736
|
+
"OPENAI_",
|
|
11737
|
+
"SSH_"
|
|
11738
|
+
];
|
|
11739
|
+
}
|
|
11740
|
+
});
|
|
11741
|
+
|
|
11269
11742
|
// src/helloLinzumiProject.ts
|
|
11270
11743
|
import { existsSync as existsSync4, mkdirSync as mkdirSync4, readFileSync as readFileSync5, rmSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
11271
11744
|
import { dirname as dirname3, join as join7, resolve as resolve5 } from "node:path";
|
|
@@ -13778,14 +14251,17 @@ function codeServerDependencyStatus(args) {
|
|
|
13778
14251
|
}) : probeTool(args.codeServerBin, args.cwd);
|
|
13779
14252
|
}
|
|
13780
14253
|
function assertStartDependencies(status) {
|
|
13781
|
-
|
|
14254
|
+
assertRunnerConnectionDependencies(status);
|
|
14255
|
+
if (!status.codex.available) {
|
|
13782
14256
|
throw new Error(
|
|
13783
|
-
|
|
14257
|
+
`Codex is not available at ${status.codex.command}. Install Codex or pass --codex-bin <path>.`
|
|
13784
14258
|
);
|
|
13785
14259
|
}
|
|
13786
|
-
|
|
14260
|
+
}
|
|
14261
|
+
function assertRunnerConnectionDependencies(status) {
|
|
14262
|
+
if (!status.node.available) {
|
|
13787
14263
|
throw new Error(
|
|
13788
|
-
|
|
14264
|
+
"Node.js is not available. Install Node.js 20+, then rerun the bootstrap command."
|
|
13789
14265
|
);
|
|
13790
14266
|
}
|
|
13791
14267
|
if (status.editorRuntime?.status === "unavailable" || status.codeServer?.available === false && status.codeServer.reason !== "not_configured") {
|
|
@@ -14157,7 +14633,7 @@ var linzumiCliVersion, linzumiCliVersionText;
|
|
|
14157
14633
|
var init_version = __esm({
|
|
14158
14634
|
"src/version.ts"() {
|
|
14159
14635
|
"use strict";
|
|
14160
|
-
linzumiCliVersion = "0.0.
|
|
14636
|
+
linzumiCliVersion = "0.0.75-beta";
|
|
14161
14637
|
linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
|
|
14162
14638
|
}
|
|
14163
14639
|
});
|
|
@@ -14175,11 +14651,7 @@ import {
|
|
|
14175
14651
|
import { dirname as dirname7, join as join11 } from "node:path";
|
|
14176
14652
|
function runnerLockPath(machineId, configPath = localConfigPath(), linzumiUrl) {
|
|
14177
14653
|
const lockName = linzumiUrl === void 0 ? encodeURIComponent(machineId) : localConfigScopeFileStem(linzumiUrl);
|
|
14178
|
-
return join11(
|
|
14179
|
-
dirname7(configPath),
|
|
14180
|
-
"runners",
|
|
14181
|
-
`${lockName}.lock`
|
|
14182
|
-
);
|
|
14654
|
+
return join11(dirname7(configPath), "runners", `${lockName}.lock`);
|
|
14183
14655
|
}
|
|
14184
14656
|
function acquireRunnerLock(options) {
|
|
14185
14657
|
const path2 = runnerLockPath(
|
|
@@ -14196,6 +14668,7 @@ function acquireRunnerLock(options) {
|
|
|
14196
14668
|
cwd: options.cwd,
|
|
14197
14669
|
workspace: options.workspace,
|
|
14198
14670
|
...options.linzumiUrl === void 0 ? {} : { linzumiUrl: kandanHttpBaseUrl(options.linzumiUrl) },
|
|
14671
|
+
...options.launchSource === void 0 ? {} : { launchSource: options.launchSource },
|
|
14199
14672
|
startedAt: (options.now ?? (() => /* @__PURE__ */ new Date()))().toISOString(),
|
|
14200
14673
|
cliVersion: options.cliVersion ?? linzumiCliVersion
|
|
14201
14674
|
};
|
|
@@ -14482,12 +14955,16 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
|
|
|
14482
14955
|
case "codex.notification": {
|
|
14483
14956
|
const tokenUsage = stringValue4(payload.token_usage_summary);
|
|
14484
14957
|
const rateLimit = stringValue4(payload.rate_limit_summary);
|
|
14958
|
+
const creditExhaustion = stringValue4(payload.credit_exhaustion_summary);
|
|
14485
14959
|
if (tokenUsage !== void 0) {
|
|
14486
14960
|
state.tokenUsage = tokenUsage;
|
|
14487
14961
|
}
|
|
14488
14962
|
if (rateLimit !== void 0) {
|
|
14489
14963
|
state.rateLimit = mergeRateLimitSummary(state.rateLimit, rateLimit);
|
|
14490
14964
|
}
|
|
14965
|
+
if (creditExhaustion !== void 0) {
|
|
14966
|
+
state.creditExhaustion = creditExhaustion;
|
|
14967
|
+
}
|
|
14491
14968
|
const method = stringValue4(payload.method);
|
|
14492
14969
|
const metadata = objectValue5(payload.metadata);
|
|
14493
14970
|
const metadataHasJobSignal = stringValue4(metadata?.threadId) !== void 0 || stringValue4(metadata?.turnId) !== void 0 || stringValue4(metadata?.itemId) !== void 0;
|
|
@@ -14499,8 +14976,9 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
|
|
|
14499
14976
|
if (job !== void 0) {
|
|
14500
14977
|
job.codexThreadId = codexThreadId ?? job.codexThreadId;
|
|
14501
14978
|
job.tokenUsage = tokenUsage ?? job.tokenUsage;
|
|
14979
|
+
job.creditExhaustion = creditExhaustion ?? job.creditExhaustion;
|
|
14502
14980
|
job.latestCodexEventId = codexEventId(payload);
|
|
14503
|
-
job.eventType = method ?? event;
|
|
14981
|
+
job.eventType = payload.credit_exhaustion_detected === true ? "credit_exhausted" : method ?? event;
|
|
14504
14982
|
job.turnId = stringValue4(metadata?.turnId) ?? job.turnId;
|
|
14505
14983
|
job.updatedAtMs = nowMs;
|
|
14506
14984
|
}
|
|
@@ -14529,7 +15007,7 @@ function updateRunnerConsoleDashboard(state, event, payload, nowMs) {
|
|
|
14529
15007
|
rememberRawLine(state, event, payload, previousJobKey);
|
|
14530
15008
|
}
|
|
14531
15009
|
function renderRunnerConsoleDashboard(state, nowMs) {
|
|
14532
|
-
if (state.jobs.size === 0 && state.tokenUsage === void 0 && state.rateLimit === void 0) {
|
|
15010
|
+
if (state.jobs.size === 0 && state.tokenUsage === void 0 && state.rateLimit === void 0 && state.creditExhaustion === void 0) {
|
|
14533
15011
|
return void 0;
|
|
14534
15012
|
}
|
|
14535
15013
|
const jobs = dashboardJobs(state);
|
|
@@ -14566,6 +15044,7 @@ function renderDashboardTable(state, jobs, nowMs) {
|
|
|
14566
15044
|
"Linzumi Commander",
|
|
14567
15045
|
"",
|
|
14568
15046
|
`Jobs: ${jobs.length} Last update: ${timeAgo(state.lastUpdateAtMs, nowMs)}`,
|
|
15047
|
+
...creditExhaustionBanner(state.creditExhaustion),
|
|
14569
15048
|
`Overall Token Usage: ${state.tokenUsage ?? "?"}`,
|
|
14570
15049
|
`Account rate limits: ${state.rateLimit ?? "?"}`,
|
|
14571
15050
|
"Controls: up/down select | enter raw job | r raw stream | esc table",
|
|
@@ -14574,6 +15053,12 @@ function renderDashboardTable(state, jobs, nowMs) {
|
|
|
14574
15053
|
""
|
|
14575
15054
|
].join("\n");
|
|
14576
15055
|
}
|
|
15056
|
+
function creditExhaustionBanner(summary) {
|
|
15057
|
+
if (summary === void 0) {
|
|
15058
|
+
return [];
|
|
15059
|
+
}
|
|
15060
|
+
return [`*** ACTION REQUIRED: ${summary} ***`];
|
|
15061
|
+
}
|
|
14577
15062
|
function dashboardTableModel(state, jobs, nowMs) {
|
|
14578
15063
|
const selectedJobKey = selectedDashboardJobKey(state, jobs);
|
|
14579
15064
|
const rows = jobs.length === 0 ? [dashboardTableHeader(), emptyJobRow()] : [
|
|
@@ -14639,7 +15124,9 @@ function formatRunnerConsoleEvent(event, payload) {
|
|
|
14639
15124
|
case "codex.turn_started":
|
|
14640
15125
|
return `Codex turn started: id=${text(payload.turn_id)}`;
|
|
14641
15126
|
case "codex.notification": {
|
|
15127
|
+
const creditExhaustion = stringValue4(payload.credit_exhaustion_summary);
|
|
14642
15128
|
const summary = [
|
|
15129
|
+
creditExhaustion === void 0 ? void 0 : `URGENT ${creditExhaustion}`,
|
|
14643
15130
|
stringValue4(payload.token_usage_summary),
|
|
14644
15131
|
stringValue4(payload.rate_limit_summary),
|
|
14645
15132
|
stringValue4(payload.diagnostic_summary)
|
|
@@ -15142,6 +15629,7 @@ function tuiHeaderContent(state, jobCount, nowMs) {
|
|
|
15142
15629
|
return [
|
|
15143
15630
|
"Linzumi Commander",
|
|
15144
15631
|
`Jobs: ${jobCount} Last update: ${timeAgo(state.lastUpdateAtMs, nowMs)}`,
|
|
15632
|
+
...creditExhaustionBanner(state.creditExhaustion),
|
|
15145
15633
|
`Overall Token Usage: ${state.tokenUsage ?? "?"}`,
|
|
15146
15634
|
`Account rate limits: ${state.rateLimit ?? "?"}`,
|
|
15147
15635
|
"Controls: click row/enter raw job | r raw stream | esc/back table | mouse wheel scroll"
|
|
@@ -15200,6 +15688,7 @@ function dashboardJobForPayload(state, payload, nowMs) {
|
|
|
15200
15688
|
lastAssistantAtMs: void 0,
|
|
15201
15689
|
latestCodexEventId: void 0,
|
|
15202
15690
|
eventType: void 0,
|
|
15691
|
+
creditExhaustion: void 0,
|
|
15203
15692
|
queueDepth: void 0,
|
|
15204
15693
|
turnId: void 0,
|
|
15205
15694
|
updatedAtMs: nowMs
|
|
@@ -15262,6 +15751,7 @@ function dashboardJobForKey(state, key, nowMs) {
|
|
|
15262
15751
|
lastAssistantAtMs: void 0,
|
|
15263
15752
|
latestCodexEventId: void 0,
|
|
15264
15753
|
eventType: void 0,
|
|
15754
|
+
creditExhaustion: void 0,
|
|
15265
15755
|
queueDepth: void 0,
|
|
15266
15756
|
turnId: void 0,
|
|
15267
15757
|
updatedAtMs: nowMs
|
|
@@ -15410,6 +15900,7 @@ var init_runnerConsoleReporter = __esm({
|
|
|
15410
15900
|
selectedJobKey: void 0,
|
|
15411
15901
|
tokenUsage: void 0,
|
|
15412
15902
|
rateLimit: void 0,
|
|
15903
|
+
creditExhaustion: void 0,
|
|
15413
15904
|
lastUpdateAtMs: void 0
|
|
15414
15905
|
};
|
|
15415
15906
|
maxRawLines = 500;
|
|
@@ -16135,8 +16626,272 @@ var init_signupTaskSuggestions = __esm({
|
|
|
16135
16626
|
}
|
|
16136
16627
|
});
|
|
16137
16628
|
|
|
16629
|
+
// src/remoteCodexSandboxRunner.ts
|
|
16630
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
16631
|
+
import { existsSync as existsSync9 } from "node:fs";
|
|
16632
|
+
import { dirname as dirname9, isAbsolute as isAbsolute3 } from "node:path";
|
|
16633
|
+
function createConfiguredRemoteCodexSandboxRunner(args) {
|
|
16634
|
+
const kind = normalizedSandboxKind(args.env.LINZUMI_REMOTE_CODEX_SANDBOX);
|
|
16635
|
+
if (kind === void 0) {
|
|
16636
|
+
return void 0;
|
|
16637
|
+
}
|
|
16638
|
+
const sandboxBin = requiredSandboxBin(kind, args.env);
|
|
16639
|
+
switch (kind) {
|
|
16640
|
+
case "bubblewrap":
|
|
16641
|
+
if (args.platform !== "linux") {
|
|
16642
|
+
throw new Error("bubblewrap remote Codex sandbox requires linux");
|
|
16643
|
+
}
|
|
16644
|
+
break;
|
|
16645
|
+
case "macos-seatbelt":
|
|
16646
|
+
if (args.platform !== "darwin") {
|
|
16647
|
+
throw new Error("macos-seatbelt remote Codex sandbox requires darwin");
|
|
16648
|
+
}
|
|
16649
|
+
break;
|
|
16650
|
+
}
|
|
16651
|
+
if (!existsSync9(sandboxBin)) {
|
|
16652
|
+
throw new Error(`remote Codex sandbox binary not found: ${sandboxBin}`);
|
|
16653
|
+
}
|
|
16654
|
+
return createRemoteCodexSandboxRunner({
|
|
16655
|
+
kind,
|
|
16656
|
+
sandboxBin
|
|
16657
|
+
});
|
|
16658
|
+
}
|
|
16659
|
+
function createRemoteCodexSandboxRunner(config, deps = {}) {
|
|
16660
|
+
const resolvedDeps = {
|
|
16661
|
+
platform: deps.platform ?? process.platform,
|
|
16662
|
+
exists: deps.exists ?? existsSync9,
|
|
16663
|
+
spawnProcess: deps.spawnProcess ?? spawn7
|
|
16664
|
+
};
|
|
16665
|
+
return (request) => runSandboxInvocation(
|
|
16666
|
+
buildRemoteCodexSandboxInvocation(config, request, resolvedDeps),
|
|
16667
|
+
request,
|
|
16668
|
+
resolvedDeps.spawnProcess
|
|
16669
|
+
);
|
|
16670
|
+
}
|
|
16671
|
+
function buildRemoteCodexSandboxInvocation(config, request, deps) {
|
|
16672
|
+
switch (config.kind) {
|
|
16673
|
+
case "bubblewrap":
|
|
16674
|
+
return {
|
|
16675
|
+
command: config.sandboxBin,
|
|
16676
|
+
args: bubblewrapArgs(config.sandboxBin, request, deps.exists),
|
|
16677
|
+
env: {},
|
|
16678
|
+
cwd: request.cwd
|
|
16679
|
+
};
|
|
16680
|
+
case "macos-seatbelt":
|
|
16681
|
+
return {
|
|
16682
|
+
command: config.sandboxBin,
|
|
16683
|
+
args: [
|
|
16684
|
+
"-p",
|
|
16685
|
+
macosSeatbeltProfile(request, deps.exists),
|
|
16686
|
+
"--",
|
|
16687
|
+
request.command,
|
|
16688
|
+
...request.args
|
|
16689
|
+
],
|
|
16690
|
+
env: request.env,
|
|
16691
|
+
cwd: request.cwd
|
|
16692
|
+
};
|
|
16693
|
+
}
|
|
16694
|
+
}
|
|
16695
|
+
function runSandboxInvocation(invocation, request, spawnProcess) {
|
|
16696
|
+
return new Promise((resolve11, reject) => {
|
|
16697
|
+
const child = spawnProcess(invocation.command, invocation.args, {
|
|
16698
|
+
cwd: invocation.cwd,
|
|
16699
|
+
env: invocation.env,
|
|
16700
|
+
shell: false,
|
|
16701
|
+
stdio: "pipe"
|
|
16702
|
+
});
|
|
16703
|
+
const stdout = createBoundedOutputBuffer();
|
|
16704
|
+
const stderr = createBoundedOutputBuffer();
|
|
16705
|
+
let settled = false;
|
|
16706
|
+
const killChild = () => {
|
|
16707
|
+
child.kill("SIGKILL");
|
|
16708
|
+
};
|
|
16709
|
+
child.stdout.on("data", (chunk) => stdout.append(chunk));
|
|
16710
|
+
child.stderr.on("data", (chunk) => stderr.append(chunk));
|
|
16711
|
+
child.on("error", (error) => {
|
|
16712
|
+
if (!settled) {
|
|
16713
|
+
settled = true;
|
|
16714
|
+
reject(error);
|
|
16715
|
+
}
|
|
16716
|
+
});
|
|
16717
|
+
child.on("close", (exitCode, signal) => {
|
|
16718
|
+
if (!settled) {
|
|
16719
|
+
settled = true;
|
|
16720
|
+
resolve11({
|
|
16721
|
+
exitCode,
|
|
16722
|
+
signal,
|
|
16723
|
+
stdout: stdout.value(),
|
|
16724
|
+
stderr: stderr.value(),
|
|
16725
|
+
stdoutTruncated: stdout.truncated(),
|
|
16726
|
+
stderrTruncated: stderr.truncated(),
|
|
16727
|
+
timedOut: false
|
|
16728
|
+
});
|
|
16729
|
+
}
|
|
16730
|
+
});
|
|
16731
|
+
if (request.abortSignal.aborted) {
|
|
16732
|
+
killChild();
|
|
16733
|
+
} else {
|
|
16734
|
+
request.abortSignal.addEventListener("abort", killChild, { once: true });
|
|
16735
|
+
}
|
|
16736
|
+
child.stdin.end(request.stdin ?? "");
|
|
16737
|
+
});
|
|
16738
|
+
}
|
|
16739
|
+
function bubblewrapArgs(sandboxBin, request, exists) {
|
|
16740
|
+
const envArgs = Object.entries(request.env).flatMap(([key, value]) => [
|
|
16741
|
+
"--setenv",
|
|
16742
|
+
key,
|
|
16743
|
+
value
|
|
16744
|
+
]);
|
|
16745
|
+
const readOnlyBindArgs = uniqueStrings2([
|
|
16746
|
+
...linuxReadOnlyRoots,
|
|
16747
|
+
...isAbsolute3(request.command) ? [dirname9(request.command)] : [],
|
|
16748
|
+
dirname9(sandboxBin)
|
|
16749
|
+
]).flatMap((path2) => exists(path2) ? ["--ro-bind", path2, path2] : []);
|
|
16750
|
+
const cwdParentDirs = parentDirs(request.cwd).flatMap((path2) => [
|
|
16751
|
+
"--dir",
|
|
16752
|
+
path2
|
|
16753
|
+
]);
|
|
16754
|
+
return [
|
|
16755
|
+
"--unshare-all",
|
|
16756
|
+
"--die-with-parent",
|
|
16757
|
+
"--new-session",
|
|
16758
|
+
"--clearenv",
|
|
16759
|
+
...envArgs,
|
|
16760
|
+
"--tmpfs",
|
|
16761
|
+
"/tmp",
|
|
16762
|
+
"--proc",
|
|
16763
|
+
"/proc",
|
|
16764
|
+
"--dev",
|
|
16765
|
+
"/dev",
|
|
16766
|
+
...cwdParentDirs,
|
|
16767
|
+
...readOnlyBindArgs,
|
|
16768
|
+
"--bind",
|
|
16769
|
+
request.cwd,
|
|
16770
|
+
request.cwd,
|
|
16771
|
+
"--chdir",
|
|
16772
|
+
request.cwd,
|
|
16773
|
+
"--",
|
|
16774
|
+
request.command,
|
|
16775
|
+
...request.args
|
|
16776
|
+
];
|
|
16777
|
+
}
|
|
16778
|
+
function macosSeatbeltProfile(request, exists) {
|
|
16779
|
+
const readableRoots = uniqueStrings2([
|
|
16780
|
+
...macosReadOnlyRoots,
|
|
16781
|
+
...isAbsolute3(request.command) ? [dirname9(request.command)] : []
|
|
16782
|
+
]).filter(exists);
|
|
16783
|
+
const readableRules = readableRoots.map((path2) => `(allow file-read* (subpath ${sandboxString(path2)}))`).join("\n");
|
|
16784
|
+
const writableTempRules = macosWritableTempRoots.filter(exists).flatMap((path2) => [
|
|
16785
|
+
`(allow file-read* (subpath ${sandboxString(path2)}))`,
|
|
16786
|
+
`(allow file-write* (subpath ${sandboxString(path2)}))`
|
|
16787
|
+
]).join("\n");
|
|
16788
|
+
return [
|
|
16789
|
+
"(version 1)",
|
|
16790
|
+
"(deny default)",
|
|
16791
|
+
"(allow process*)",
|
|
16792
|
+
"(allow signal (target self))",
|
|
16793
|
+
"(allow sysctl-read)",
|
|
16794
|
+
"(allow file-read-metadata)",
|
|
16795
|
+
'(allow file-read* (literal "/dev/null"))',
|
|
16796
|
+
'(allow file-read* (literal "/dev/random"))',
|
|
16797
|
+
'(allow file-read* (literal "/dev/urandom"))',
|
|
16798
|
+
readableRules,
|
|
16799
|
+
writableTempRules,
|
|
16800
|
+
`(allow file-read* (subpath ${sandboxString(request.cwd)}))`,
|
|
16801
|
+
`(allow file-write* (subpath ${sandboxString(request.cwd)}))`
|
|
16802
|
+
].join("\n");
|
|
16803
|
+
}
|
|
16804
|
+
function createBoundedOutputBuffer() {
|
|
16805
|
+
let bytes = 0;
|
|
16806
|
+
let output = "";
|
|
16807
|
+
let isTruncated = false;
|
|
16808
|
+
return {
|
|
16809
|
+
append: (chunk) => {
|
|
16810
|
+
const text2 = Buffer.isBuffer(chunk) ? chunk.toString("utf8") : chunk;
|
|
16811
|
+
const remaining = maxCapturedOutputBytes - bytes;
|
|
16812
|
+
if (remaining <= 0) {
|
|
16813
|
+
isTruncated = true;
|
|
16814
|
+
return;
|
|
16815
|
+
}
|
|
16816
|
+
const buffer = Buffer.from(text2, "utf8");
|
|
16817
|
+
if (buffer.byteLength <= remaining) {
|
|
16818
|
+
bytes += buffer.byteLength;
|
|
16819
|
+
output += text2;
|
|
16820
|
+
return;
|
|
16821
|
+
}
|
|
16822
|
+
bytes = maxCapturedOutputBytes;
|
|
16823
|
+
output += buffer.subarray(0, remaining).toString("utf8");
|
|
16824
|
+
isTruncated = true;
|
|
16825
|
+
},
|
|
16826
|
+
value: () => output,
|
|
16827
|
+
truncated: () => isTruncated
|
|
16828
|
+
};
|
|
16829
|
+
}
|
|
16830
|
+
function normalizedSandboxKind(value) {
|
|
16831
|
+
switch (value) {
|
|
16832
|
+
case void 0:
|
|
16833
|
+
case "":
|
|
16834
|
+
return void 0;
|
|
16835
|
+
case "bubblewrap":
|
|
16836
|
+
case "macos-seatbelt":
|
|
16837
|
+
return value;
|
|
16838
|
+
default:
|
|
16839
|
+
throw new Error(`unsupported remote Codex sandbox: ${value}`);
|
|
16840
|
+
}
|
|
16841
|
+
}
|
|
16842
|
+
function requiredSandboxBin(kind, env) {
|
|
16843
|
+
const value = env.LINZUMI_REMOTE_CODEX_SANDBOX_BIN;
|
|
16844
|
+
if (value === void 0 || value.trim() === "") {
|
|
16845
|
+
throw new Error(`LINZUMI_REMOTE_CODEX_SANDBOX_BIN is required for ${kind}`);
|
|
16846
|
+
}
|
|
16847
|
+
if (!isAbsolute3(value)) {
|
|
16848
|
+
throw new Error("LINZUMI_REMOTE_CODEX_SANDBOX_BIN must be absolute");
|
|
16849
|
+
}
|
|
16850
|
+
return value;
|
|
16851
|
+
}
|
|
16852
|
+
function parentDirs(path2) {
|
|
16853
|
+
const parts = path2.split("/").filter((part) => part !== "");
|
|
16854
|
+
const parents = parts.slice(0, -1);
|
|
16855
|
+
return parents.map(
|
|
16856
|
+
(_part, index) => `/${parents.slice(0, index + 1).join("/")}`
|
|
16857
|
+
);
|
|
16858
|
+
}
|
|
16859
|
+
function uniqueStrings2(values) {
|
|
16860
|
+
return Array.from(new Set(values));
|
|
16861
|
+
}
|
|
16862
|
+
function sandboxString(value) {
|
|
16863
|
+
return JSON.stringify(value);
|
|
16864
|
+
}
|
|
16865
|
+
var maxCapturedOutputBytes, linuxReadOnlyRoots, macosReadOnlyRoots, macosWritableTempRoots;
|
|
16866
|
+
var init_remoteCodexSandboxRunner = __esm({
|
|
16867
|
+
"src/remoteCodexSandboxRunner.ts"() {
|
|
16868
|
+
"use strict";
|
|
16869
|
+
maxCapturedOutputBytes = 512 * 1024;
|
|
16870
|
+
linuxReadOnlyRoots = [
|
|
16871
|
+
"/bin",
|
|
16872
|
+
"/etc/pki",
|
|
16873
|
+
"/etc/ssl",
|
|
16874
|
+
"/lib",
|
|
16875
|
+
"/lib64",
|
|
16876
|
+
"/nix/store",
|
|
16877
|
+
"/usr",
|
|
16878
|
+
"/usr/local"
|
|
16879
|
+
];
|
|
16880
|
+
macosReadOnlyRoots = [
|
|
16881
|
+
"/System",
|
|
16882
|
+
"/Library",
|
|
16883
|
+
"/usr",
|
|
16884
|
+
"/bin",
|
|
16885
|
+
"/sbin",
|
|
16886
|
+
"/opt/homebrew",
|
|
16887
|
+
"/nix/store"
|
|
16888
|
+
];
|
|
16889
|
+
macosWritableTempRoots = ["/tmp", "/private/tmp"];
|
|
16890
|
+
}
|
|
16891
|
+
});
|
|
16892
|
+
|
|
16138
16893
|
// src/runner.ts
|
|
16139
|
-
import { spawn as
|
|
16894
|
+
import { spawn as spawn8, spawnSync as spawnSync4 } from "node:child_process";
|
|
16140
16895
|
import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
|
|
16141
16896
|
import {
|
|
16142
16897
|
chmodSync as chmodSync2,
|
|
@@ -16150,7 +16905,7 @@ import {
|
|
|
16150
16905
|
} from "node:fs";
|
|
16151
16906
|
import { createServer as createServer3 } from "node:http";
|
|
16152
16907
|
import { hostname as hostname2, tmpdir as tmpdir3 } from "node:os";
|
|
16153
|
-
import { dirname as
|
|
16908
|
+
import { dirname as dirname10, isAbsolute as isAbsolute4, join as join14, resolve as resolve7 } from "node:path";
|
|
16154
16909
|
async function runLocalCodexRunner(options) {
|
|
16155
16910
|
const log = makeRunnerLogger(options);
|
|
16156
16911
|
const cleanup = {
|
|
@@ -16173,6 +16928,7 @@ async function runLocalCodexRunner(options) {
|
|
|
16173
16928
|
cwd: options.cwd,
|
|
16174
16929
|
workspace: runnerWorkspaceSlug(options) ?? null,
|
|
16175
16930
|
linzumiUrl: options.kandanUrl,
|
|
16931
|
+
launchSource: options.launchSource,
|
|
16176
16932
|
configPath: options.runnerLockConfigPath
|
|
16177
16933
|
});
|
|
16178
16934
|
cleanup.actions.push(() => runnerLock.release());
|
|
@@ -16214,6 +16970,7 @@ async function runThreadCodexWorker(options) {
|
|
|
16214
16970
|
}
|
|
16215
16971
|
async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
16216
16972
|
const agentProviders = availableRunnerAgentProviders(options);
|
|
16973
|
+
const localCodexAppServerAvailable = hasLocalCodexAppServerCapability(options);
|
|
16217
16974
|
const allowedForwardPorts = options.allowedForwardPorts ?? [];
|
|
16218
16975
|
const liveForwardPorts = new Set(allowedForwardPorts);
|
|
16219
16976
|
const managedForwardPorts = /* @__PURE__ */ new Set();
|
|
@@ -16274,6 +17031,11 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
16274
17031
|
});
|
|
16275
17032
|
const startupAllowedCwds = normalizeAllowedCwds(options.allowedCwds);
|
|
16276
17033
|
const allowedCwds = { value: [...startupAllowedCwds] };
|
|
17034
|
+
const remoteCodexSandboxRunner = options.remoteCodexSandboxRunner ?? createConfiguredRemoteCodexSandboxRunner({
|
|
17035
|
+
env: process.env,
|
|
17036
|
+
platform: process.platform
|
|
17037
|
+
});
|
|
17038
|
+
const activeRemoteCodexExecRequests = /* @__PURE__ */ new Map();
|
|
16277
17039
|
const missingAllowedCwds = {
|
|
16278
17040
|
value: normalizeAllowedCwds(options.missingAllowedCwds ?? [])
|
|
16279
17041
|
};
|
|
@@ -16290,6 +17052,10 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
16290
17052
|
queuedCandidates: /* @__PURE__ */ new Map()
|
|
16291
17053
|
};
|
|
16292
17054
|
cleanup.actions.push(() => {
|
|
17055
|
+
for (const controller of activeRemoteCodexExecRequests.values()) {
|
|
17056
|
+
controller.abort(new Error("local runner stopped"));
|
|
17057
|
+
}
|
|
17058
|
+
activeRemoteCodexExecRequests.clear();
|
|
16293
17059
|
if (localEditorState.value.status === "running") {
|
|
16294
17060
|
localEditorState.value.process.kill("SIGINT");
|
|
16295
17061
|
localEditorState.value.collaboration?.process.kill("SIGINT");
|
|
@@ -16314,8 +17080,8 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
16314
17080
|
};
|
|
16315
17081
|
});
|
|
16316
17082
|
const capabilitiesPayload = () => ({
|
|
16317
|
-
codexAppServer:
|
|
16318
|
-
codexRemoteTui:
|
|
17083
|
+
codexAppServer: localCodexAppServerAvailable,
|
|
17084
|
+
codexRemoteTui: localCodexAppServerAvailable,
|
|
16319
17085
|
agentProviders,
|
|
16320
17086
|
defaultAgentProvider: "codex",
|
|
16321
17087
|
startInstance: allowedCwds.value.length > 0,
|
|
@@ -16331,6 +17097,8 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
16331
17097
|
portForwarding: liveForwardPorts.size > 0,
|
|
16332
17098
|
tcpForwarding: true,
|
|
16333
17099
|
linzumiMcp: true,
|
|
17100
|
+
remoteCodexExecution: remoteCodexSandboxRunner !== void 0 && allowedCwds.value.length > 0,
|
|
17101
|
+
remoteCodexExecutionStatus: remoteCodexSandboxRunner === void 0 ? "sandbox_unavailable" : allowedCwds.value.length > 0 ? "ready" : "cwd_unavailable",
|
|
16334
17102
|
allowedPorts: Array.from(liveForwardPorts).sort(
|
|
16335
17103
|
(left, right) => left - right
|
|
16336
17104
|
),
|
|
@@ -16380,18 +17148,15 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
16380
17148
|
const replacedRunners = replacementRunnerSummaries(
|
|
16381
17149
|
objectValue(joinResponse)?.replaced_runners
|
|
16382
17150
|
);
|
|
16383
|
-
const started = options.codexUrl === void 0 ? await startOwnedCodexAppServer(options) : void 0;
|
|
17151
|
+
const started = options.codexUrl === void 0 && localCodexAppServerAvailable ? await startOwnedCodexAppServer(options) : void 0;
|
|
16384
17152
|
if (started !== void 0) {
|
|
16385
17153
|
cleanup.actions.push(() => {
|
|
16386
17154
|
started.stop();
|
|
16387
17155
|
});
|
|
16388
17156
|
}
|
|
16389
17157
|
const codexUrl = options.codexUrl ?? started?.url;
|
|
16390
|
-
if (codexUrl === void 0) {
|
|
16391
|
-
throw new Error("missing codex app-server websocket URL");
|
|
16392
|
-
}
|
|
16393
17158
|
if (started !== void 0) {
|
|
16394
|
-
const appServerPort = explicitUrlPort(
|
|
17159
|
+
const appServerPort = explicitUrlPort(started.url);
|
|
16395
17160
|
if (appServerPort !== void 0) {
|
|
16396
17161
|
markCommanderManagedForwardPort(appServerPort, {
|
|
16397
17162
|
processName: "Codex app-server",
|
|
@@ -17081,15 +17846,20 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
17081
17846
|
};
|
|
17082
17847
|
void state.exited.then(handleExitAfterInitialStatus);
|
|
17083
17848
|
};
|
|
17084
|
-
const codex = await connectCodexAppServer(codexUrl);
|
|
17085
|
-
|
|
17849
|
+
const codex = codexUrl === void 0 ? void 0 : await connectCodexAppServer(codexUrl);
|
|
17850
|
+
if (codex !== void 0) {
|
|
17851
|
+
cleanup.actions.push(() => codex.close());
|
|
17852
|
+
}
|
|
17853
|
+
if (options.channelSession !== void 0 && codex === void 0) {
|
|
17854
|
+
throw new Error("channel session requires a Codex app-server connection");
|
|
17855
|
+
}
|
|
17086
17856
|
const seq = { value: 0 };
|
|
17087
17857
|
const discoveredCodexThreads = { value: [] };
|
|
17088
17858
|
const runtimeDefaults = runnerRuntimeDefaults(options);
|
|
17089
17859
|
const instancePayload = {
|
|
17090
17860
|
instanceId,
|
|
17091
17861
|
clientId,
|
|
17092
|
-
codexUrl,
|
|
17862
|
+
...codexUrl === void 0 ? {} : { codexUrl },
|
|
17093
17863
|
tuiLaunched: options.launchTui,
|
|
17094
17864
|
cwd: options.cwd,
|
|
17095
17865
|
hostname: runnerHost,
|
|
@@ -17108,7 +17878,7 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
17108
17878
|
workspace: runnerWorkspaceSlug(options) ?? null,
|
|
17109
17879
|
version: linzumiCliVersion,
|
|
17110
17880
|
instanceId,
|
|
17111
|
-
codexUrl,
|
|
17881
|
+
codexUrl: codexUrl ?? null,
|
|
17112
17882
|
replacedRunners
|
|
17113
17883
|
});
|
|
17114
17884
|
const channelSession = options.channelSession === void 0 ? void 0 : await attachChannelSession({
|
|
@@ -17422,6 +18192,8 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
17422
18192
|
options,
|
|
17423
18193
|
agentProviders,
|
|
17424
18194
|
allowedCwds,
|
|
18195
|
+
remoteCodexSandboxRunner,
|
|
18196
|
+
activeRemoteCodexExecRequests,
|
|
17425
18197
|
activeClaudeCodeSessions,
|
|
17426
18198
|
pendingClaudeCodeApprovals,
|
|
17427
18199
|
ensureClaudeCodeForwardPortSession,
|
|
@@ -17444,7 +18216,7 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
17444
18216
|
const heartbeatPayload = () => ({
|
|
17445
18217
|
instanceId,
|
|
17446
18218
|
clientId,
|
|
17447
|
-
codexUrl,
|
|
18219
|
+
...codexUrl === void 0 ? {} : { codexUrl },
|
|
17448
18220
|
cwd: options.cwd,
|
|
17449
18221
|
hostname: runnerHost,
|
|
17450
18222
|
workspace: runnerWorkspaceSlug(options) ?? null,
|
|
@@ -17476,10 +18248,13 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
17476
18248
|
);
|
|
17477
18249
|
cleanup.actions.push(() => forwardTcp.close());
|
|
17478
18250
|
const channelCodexThreadId = channelSession?.currentCodexThreadId();
|
|
17479
|
-
if (options.launchTui &&
|
|
18251
|
+
if (options.launchTui && codex === void 0) {
|
|
18252
|
+
throw new Error("Codex TUI requires a Codex app-server connection");
|
|
18253
|
+
}
|
|
18254
|
+
if (options.launchTui && codex !== void 0 && channelCodexThreadId !== void 0) {
|
|
17480
18255
|
await prepareCodexThreadForTuiResume(codex, channelCodexThreadId);
|
|
17481
18256
|
}
|
|
17482
|
-
const tui = options.launchTui ? launchCodexTui(
|
|
18257
|
+
const tui = options.launchTui && codexUrl !== void 0 ? launchCodexTui(
|
|
17483
18258
|
options.codexBin,
|
|
17484
18259
|
codexUrl,
|
|
17485
18260
|
options.cwd,
|
|
@@ -17492,7 +18267,7 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
17492
18267
|
tui.kill("SIGINT");
|
|
17493
18268
|
});
|
|
17494
18269
|
}
|
|
17495
|
-
codex
|
|
18270
|
+
codex?.onNotification((notification) => {
|
|
17496
18271
|
seq.value += 1;
|
|
17497
18272
|
const params = notification.params ?? {};
|
|
17498
18273
|
const logPayload = codexNotificationConsoleLogPayload(
|
|
@@ -17747,6 +18522,8 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
17747
18522
|
options,
|
|
17748
18523
|
agentProviders,
|
|
17749
18524
|
allowedCwds,
|
|
18525
|
+
remoteCodexSandboxRunner,
|
|
18526
|
+
activeRemoteCodexExecRequests,
|
|
17750
18527
|
activeClaudeCodeSessions,
|
|
17751
18528
|
pendingClaudeCodeApprovals,
|
|
17752
18529
|
ensureClaudeCodeForwardPortSession,
|
|
@@ -17831,6 +18608,8 @@ function controlThreadId(control) {
|
|
|
17831
18608
|
case "forward_tcp_open":
|
|
17832
18609
|
case "forward_tcp_send":
|
|
17833
18610
|
case "forward_tcp_close":
|
|
18611
|
+
case "remote_codex_exec":
|
|
18612
|
+
case "remote_codex_exec_cancel":
|
|
17834
18613
|
case "update_thread_interaction_access": {
|
|
17835
18614
|
const threadId = stringValue(control.threadId)?.trim();
|
|
17836
18615
|
return threadId === void 0 || threadId === "" ? void 0 : threadId;
|
|
@@ -17940,9 +18719,15 @@ function replacementRunnerSummaries(value) {
|
|
|
17940
18719
|
});
|
|
17941
18720
|
}
|
|
17942
18721
|
function makeRunnerLogger(options) {
|
|
18722
|
+
const consoleReporter = options.launchTui && options.consoleReporter === void 0 ? void 0 : (event, payload) => {
|
|
18723
|
+
if (!options.launchTui) {
|
|
18724
|
+
reportRunnerConsoleEvent(event, payload);
|
|
18725
|
+
}
|
|
18726
|
+
options.consoleReporter?.(event, payload);
|
|
18727
|
+
};
|
|
17943
18728
|
return createRunnerLogger(
|
|
17944
18729
|
options.logFile ?? defaultRunnerLogFile(),
|
|
17945
|
-
|
|
18730
|
+
consoleReporter
|
|
17946
18731
|
);
|
|
17947
18732
|
}
|
|
17948
18733
|
function installCleanupHandlers(close) {
|
|
@@ -17971,7 +18756,7 @@ function launchCodexTui(codexBin, codexUrl, cwd, codexThreadId, session, fast) {
|
|
|
17971
18756
|
cwd,
|
|
17972
18757
|
purpose: "codex.tui"
|
|
17973
18758
|
});
|
|
17974
|
-
const child =
|
|
18759
|
+
const child = spawn8(codexBin, args, {
|
|
17975
18760
|
cwd,
|
|
17976
18761
|
env: process.env,
|
|
17977
18762
|
stdio: "inherit"
|
|
@@ -18098,7 +18883,29 @@ async function resumeCodexThreadForReconnect(codex, codexThreadId, resumeOverrid
|
|
|
18098
18883
|
);
|
|
18099
18884
|
}
|
|
18100
18885
|
}
|
|
18101
|
-
async function applyControl(codex, kandan, topic, instanceId, options, agentProviders, allowedCwds, activeClaudeCodeSessions, pendingClaudeCodeApprovals, ensureClaudeCodeForwardPortSession, disposeClaudeCodeForwardPortSession, control, log, onStartedThread, onThreadProcessStart) {
|
|
18886
|
+
async function applyControl(codex, kandan, topic, instanceId, options, agentProviders, allowedCwds, remoteCodexSandboxRunner, activeRemoteCodexExecRequests, activeClaudeCodeSessions, pendingClaudeCodeApprovals, ensureClaudeCodeForwardPortSession, disposeClaudeCodeForwardPortSession, control, log, onStartedThread, onThreadProcessStart) {
|
|
18887
|
+
if (codex === void 0) {
|
|
18888
|
+
switch (control.type) {
|
|
18889
|
+
case "remote_codex_exec":
|
|
18890
|
+
case "remote_codex_exec_cancel":
|
|
18891
|
+
return await applyRemoteCodexExecControl(
|
|
18892
|
+
control,
|
|
18893
|
+
instanceId,
|
|
18894
|
+
allowedCwds.value,
|
|
18895
|
+
remoteCodexSandboxRunner,
|
|
18896
|
+
activeRemoteCodexExecRequests,
|
|
18897
|
+
log
|
|
18898
|
+
);
|
|
18899
|
+
default:
|
|
18900
|
+
return {
|
|
18901
|
+
instanceId,
|
|
18902
|
+
controlType: control.type,
|
|
18903
|
+
requestId: "requestId" in control ? stringValue(control.requestId) ?? null : null,
|
|
18904
|
+
ok: false,
|
|
18905
|
+
error: "agent_provider_unavailable:codex"
|
|
18906
|
+
};
|
|
18907
|
+
}
|
|
18908
|
+
}
|
|
18102
18909
|
switch (control.type) {
|
|
18103
18910
|
case "start_instance": {
|
|
18104
18911
|
const cwd = resolveAllowedCwd(control.cwd, allowedCwds.value);
|
|
@@ -18597,6 +19404,26 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
|
|
|
18597
19404
|
case "suggest_tasks": {
|
|
18598
19405
|
return suggestRunnerTasks(control, options, allowedCwds.value);
|
|
18599
19406
|
}
|
|
19407
|
+
case "remote_codex_exec": {
|
|
19408
|
+
return await applyRemoteCodexExecControl(
|
|
19409
|
+
control,
|
|
19410
|
+
instanceId,
|
|
19411
|
+
allowedCwds.value,
|
|
19412
|
+
remoteCodexSandboxRunner,
|
|
19413
|
+
activeRemoteCodexExecRequests,
|
|
19414
|
+
log
|
|
19415
|
+
);
|
|
19416
|
+
}
|
|
19417
|
+
case "remote_codex_exec_cancel": {
|
|
19418
|
+
return await applyRemoteCodexExecControl(
|
|
19419
|
+
control,
|
|
19420
|
+
instanceId,
|
|
19421
|
+
allowedCwds.value,
|
|
19422
|
+
remoteCodexSandboxRunner,
|
|
19423
|
+
activeRemoteCodexExecRequests,
|
|
19424
|
+
log
|
|
19425
|
+
);
|
|
19426
|
+
}
|
|
18600
19427
|
case "start_turn": {
|
|
18601
19428
|
const response = await codex.request("turn/start", {
|
|
18602
19429
|
threadId: control.threadId,
|
|
@@ -18769,6 +19596,55 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
|
|
|
18769
19596
|
return { instanceId, controlType: control.type, skipped: true };
|
|
18770
19597
|
}
|
|
18771
19598
|
}
|
|
19599
|
+
async function applyRemoteCodexExecControl(control, instanceId, allowedCwds, remoteCodexSandboxRunner, activeRemoteCodexExecRequests, log) {
|
|
19600
|
+
switch (control.type) {
|
|
19601
|
+
case "remote_codex_exec": {
|
|
19602
|
+
const requestId = stringValue(control.requestId)?.trim();
|
|
19603
|
+
const abortController = new AbortController();
|
|
19604
|
+
if (requestId !== void 0 && requestId !== "") {
|
|
19605
|
+
activeRemoteCodexExecRequests.set(requestId, abortController);
|
|
19606
|
+
}
|
|
19607
|
+
const result = await handleRemoteCodexExecControl(control, {
|
|
19608
|
+
instanceId,
|
|
19609
|
+
allowedCwds,
|
|
19610
|
+
sandboxRunner: remoteCodexSandboxRunner,
|
|
19611
|
+
abortSignal: abortController.signal
|
|
19612
|
+
});
|
|
19613
|
+
if (requestId !== void 0 && requestId !== "") {
|
|
19614
|
+
activeRemoteCodexExecRequests.delete(requestId);
|
|
19615
|
+
}
|
|
19616
|
+
log("remote_codex_exec.handled", {
|
|
19617
|
+
requestId: stringValue(control.requestId) ?? null,
|
|
19618
|
+
ok: result.ok === true,
|
|
19619
|
+
error: typeof result.error === "string" ? result.error : null
|
|
19620
|
+
});
|
|
19621
|
+
return result;
|
|
19622
|
+
}
|
|
19623
|
+
case "remote_codex_exec_cancel": {
|
|
19624
|
+
const requestId = stringValue(control.requestId)?.trim();
|
|
19625
|
+
if (requestId === void 0 || requestId === "") {
|
|
19626
|
+
return {
|
|
19627
|
+
instanceId,
|
|
19628
|
+
controlType: control.type,
|
|
19629
|
+
ok: false,
|
|
19630
|
+
error: "request_id_required"
|
|
19631
|
+
};
|
|
19632
|
+
}
|
|
19633
|
+
const activeRequest = activeRemoteCodexExecRequests.get(requestId);
|
|
19634
|
+
if (activeRequest !== void 0) {
|
|
19635
|
+
activeRequest.abort(new Error("remote_codex_exec_cancelled"));
|
|
19636
|
+
activeRemoteCodexExecRequests.delete(requestId);
|
|
19637
|
+
}
|
|
19638
|
+
return {
|
|
19639
|
+
instanceId,
|
|
19640
|
+
controlType: control.type,
|
|
19641
|
+
requestId,
|
|
19642
|
+
ok: true,
|
|
19643
|
+
cancelled: activeRequest !== void 0
|
|
19644
|
+
};
|
|
19645
|
+
}
|
|
19646
|
+
}
|
|
19647
|
+
}
|
|
18772
19648
|
function startInstanceFailureReason(stage, error) {
|
|
18773
19649
|
const detail = truncateFailureDetail(
|
|
18774
19650
|
error instanceof Error ? error.message : String(error)
|
|
@@ -18901,6 +19777,18 @@ function availableRunnerAgentProviders(options) {
|
|
|
18901
19777
|
return ["codex"];
|
|
18902
19778
|
}
|
|
18903
19779
|
}
|
|
19780
|
+
function hasLocalCodexAppServerCapability(options) {
|
|
19781
|
+
if (options.codexUrl !== void 0) {
|
|
19782
|
+
return true;
|
|
19783
|
+
}
|
|
19784
|
+
switch (options.dependencyStatus?.codex.available) {
|
|
19785
|
+
case false:
|
|
19786
|
+
return false;
|
|
19787
|
+
case true:
|
|
19788
|
+
case void 0:
|
|
19789
|
+
return true;
|
|
19790
|
+
}
|
|
19791
|
+
}
|
|
18904
19792
|
function startInstanceAgentProvider(control) {
|
|
18905
19793
|
const value = stringValue(control.agentProvider)?.trim();
|
|
18906
19794
|
switch (value) {
|
|
@@ -20362,7 +21250,7 @@ async function spawnLocalThreadRunnerProcess(options) {
|
|
|
20362
21250
|
cwd: options.cwd,
|
|
20363
21251
|
purpose: "linzumi.thread_runner"
|
|
20364
21252
|
});
|
|
20365
|
-
const child =
|
|
21253
|
+
const child = spawn8(process.execPath, nodeArgs, {
|
|
20366
21254
|
cwd: options.cwd,
|
|
20367
21255
|
env,
|
|
20368
21256
|
stdio: ["inherit", "inherit", "inherit", "ipc"]
|
|
@@ -20477,7 +21365,7 @@ function threadRunnerScriptPath(scriptPath, cwd) {
|
|
|
20477
21365
|
"cannot fork thread runner without current CLI script path"
|
|
20478
21366
|
);
|
|
20479
21367
|
}
|
|
20480
|
-
return
|
|
21368
|
+
return isAbsolute4(scriptPath) ? scriptPath : resolve7(cwd, scriptPath);
|
|
20481
21369
|
}
|
|
20482
21370
|
function threadRunnerLoaderExecArgv(execArgv, index = 0) {
|
|
20483
21371
|
const current = execArgv[index];
|
|
@@ -20870,7 +21758,7 @@ function browseRunnerDirectory(control, options) {
|
|
|
20870
21758
|
error: "not_directory"
|
|
20871
21759
|
};
|
|
20872
21760
|
}
|
|
20873
|
-
const parent =
|
|
21761
|
+
const parent = dirname10(currentPath);
|
|
20874
21762
|
const entries = readdirSync2(currentPath, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => visibleRunnerDirectoryEntryName(entry.name)).map((entry) => {
|
|
20875
21763
|
const path2 = join14(currentPath, entry.name);
|
|
20876
21764
|
return {
|
|
@@ -21090,6 +21978,7 @@ var init_runner = __esm({
|
|
|
21090
21978
|
init_linzumiContext();
|
|
21091
21979
|
init_localCapabilities();
|
|
21092
21980
|
init_localConfig();
|
|
21981
|
+
init_remoteCodexExecutionContext();
|
|
21093
21982
|
init_helloLinzumiProject();
|
|
21094
21983
|
init_localForwarding();
|
|
21095
21984
|
init_localEditor();
|
|
@@ -21109,6 +21998,7 @@ var init_runner = __esm({
|
|
|
21109
21998
|
init_threadCodexWorkerIpc();
|
|
21110
21999
|
init_signupTaskSuggestions();
|
|
21111
22000
|
init_userFacingErrors();
|
|
22001
|
+
init_remoteCodexSandboxRunner();
|
|
21112
22002
|
THREAD_RUNNER_READY_TIMEOUT_MS = 3e4;
|
|
21113
22003
|
claudeSessionStoreSequenceHighWater = /* @__PURE__ */ new Map();
|
|
21114
22004
|
ClaudeCodeOutputPostError = class extends Error {
|
|
@@ -21122,9 +22012,9 @@ var init_runner = __esm({
|
|
|
21122
22012
|
});
|
|
21123
22013
|
|
|
21124
22014
|
// src/kandanTls.ts
|
|
21125
|
-
import { existsSync as
|
|
22015
|
+
import { existsSync as existsSync10, readFileSync as readFileSync11 } from "node:fs";
|
|
21126
22016
|
import { Agent } from "undici";
|
|
21127
|
-
import
|
|
22017
|
+
import WsWebSocket from "ws";
|
|
21128
22018
|
function kandanTlsTrustFromEnv() {
|
|
21129
22019
|
return kandanTlsTrustFromCaFile(process.env.KANDAN_TLS_CA_FILE);
|
|
21130
22020
|
}
|
|
@@ -21133,7 +22023,7 @@ function kandanTlsTrustFromCaFile(caFile) {
|
|
|
21133
22023
|
return void 0;
|
|
21134
22024
|
}
|
|
21135
22025
|
const trimmed = caFile.trim();
|
|
21136
|
-
if (!
|
|
22026
|
+
if (!existsSync10(trimmed)) {
|
|
21137
22027
|
throw new Error(`KANDAN_TLS_CA_FILE does not exist: ${trimmed}`);
|
|
21138
22028
|
}
|
|
21139
22029
|
const ca = readFileSync11(trimmed, "utf8");
|
|
@@ -39919,7 +40809,7 @@ var init_RemoveFileError = __esm({
|
|
|
39919
40809
|
});
|
|
39920
40810
|
|
|
39921
40811
|
// ../../node_modules/@inquirer/external-editor/dist/esm/index.js
|
|
39922
|
-
import { spawn as
|
|
40812
|
+
import { spawn as spawn10, spawnSync as spawnSync5 } from "child_process";
|
|
39923
40813
|
import { readFileSync as readFileSync14, unlinkSync as unlinkSync3, writeFileSync as writeFileSync10 } from "fs";
|
|
39924
40814
|
import path from "node:path";
|
|
39925
40815
|
import os from "node:os";
|
|
@@ -40075,7 +40965,7 @@ var init_esm5 = __esm({
|
|
|
40075
40965
|
}
|
|
40076
40966
|
launchEditorAsync(callback) {
|
|
40077
40967
|
try {
|
|
40078
|
-
const editorProcess =
|
|
40968
|
+
const editorProcess = spawn10(this.editor.bin, this.editor.args.concat([this.tempFile]), { stdio: "inherit" });
|
|
40079
40969
|
editorProcess.on("exit", (code) => {
|
|
40080
40970
|
this.lastExitStatus = code;
|
|
40081
40971
|
setImmediate(callback);
|
|
@@ -41409,9 +42299,9 @@ __export(signupFlow_exports, {
|
|
|
41409
42299
|
signupTaskSuggestionWaitMessageForTest: () => signupTaskSuggestionWaitMessageForTest,
|
|
41410
42300
|
toggleProjectPickerSelectionForTest: () => toggleProjectPickerSelectionForTest
|
|
41411
42301
|
});
|
|
41412
|
-
import { spawn as
|
|
42302
|
+
import { spawn as spawn11, spawnSync as spawnSync6 } from "node:child_process";
|
|
41413
42303
|
import {
|
|
41414
|
-
existsSync as
|
|
42304
|
+
existsSync as existsSync13,
|
|
41415
42305
|
constants as fsConstants,
|
|
41416
42306
|
mkdirSync as mkdirSync12,
|
|
41417
42307
|
mkdtempSync as mkdtempSync5,
|
|
@@ -41423,7 +42313,7 @@ import {
|
|
|
41423
42313
|
} from "node:fs";
|
|
41424
42314
|
import { access } from "node:fs/promises";
|
|
41425
42315
|
import { homedir as homedir12, tmpdir as tmpdir4 } from "node:os";
|
|
41426
|
-
import { delimiter as delimiter3, dirname as
|
|
42316
|
+
import { delimiter as delimiter3, dirname as dirname13, join as join17, resolve as resolve9 } from "node:path";
|
|
41427
42317
|
import { stdin as defaultStdin, stdout as defaultStdout } from "node:process";
|
|
41428
42318
|
import { emitKeypressEvents } from "node:readline";
|
|
41429
42319
|
function signupHelpText() {
|
|
@@ -41522,7 +42412,7 @@ function defaultSignupDraftStore(serviceUrl) {
|
|
|
41522
42412
|
const path2 = defaultSignupDraftPath(serviceUrl);
|
|
41523
42413
|
return {
|
|
41524
42414
|
read: () => {
|
|
41525
|
-
if (!
|
|
42415
|
+
if (!existsSync13(path2)) {
|
|
41526
42416
|
return void 0;
|
|
41527
42417
|
}
|
|
41528
42418
|
let parsed;
|
|
@@ -41537,7 +42427,7 @@ function defaultSignupDraftStore(serviceUrl) {
|
|
|
41537
42427
|
return comparableServiceUrl(parsed.serviceUrl) === comparableServiceUrl(serviceUrl) ? parsed : void 0;
|
|
41538
42428
|
},
|
|
41539
42429
|
write: (draft) => {
|
|
41540
|
-
mkdirSync12(
|
|
42430
|
+
mkdirSync12(dirname13(path2), { recursive: true });
|
|
41541
42431
|
writeFileSync11(path2, `${JSON.stringify(draft, null, 2)}
|
|
41542
42432
|
`, {
|
|
41543
42433
|
encoding: "utf8",
|
|
@@ -41551,7 +42441,7 @@ function defaultSignupDraftStore(serviceUrl) {
|
|
|
41551
42441
|
}
|
|
41552
42442
|
function defaultSignupDraftPath(serviceUrl) {
|
|
41553
42443
|
return join17(
|
|
41554
|
-
|
|
42444
|
+
dirname13(localConfigPath()),
|
|
41555
42445
|
`signup-draft.${localConfigScopeFileStem(serviceUrl)}.json`
|
|
41556
42446
|
);
|
|
41557
42447
|
}
|
|
@@ -41585,7 +42475,7 @@ function defaultSignupTaskCacheStore(serviceUrl) {
|
|
|
41585
42475
|
}
|
|
41586
42476
|
}
|
|
41587
42477
|
};
|
|
41588
|
-
mkdirSync12(
|
|
42478
|
+
mkdirSync12(dirname13(path2), { recursive: true });
|
|
41589
42479
|
writeFileSync11(path2, `${JSON.stringify(next, null, 2)}
|
|
41590
42480
|
`, {
|
|
41591
42481
|
encoding: "utf8",
|
|
@@ -41596,12 +42486,12 @@ function defaultSignupTaskCacheStore(serviceUrl) {
|
|
|
41596
42486
|
}
|
|
41597
42487
|
function defaultSignupTaskCachePath(serviceUrl) {
|
|
41598
42488
|
return join17(
|
|
41599
|
-
|
|
42489
|
+
dirname13(localConfigPath()),
|
|
41600
42490
|
`signup-task-cache.${localConfigScopeFileStem(serviceUrl)}.json`
|
|
41601
42491
|
);
|
|
41602
42492
|
}
|
|
41603
42493
|
function readSignupTaskCache(path2) {
|
|
41604
|
-
if (!
|
|
42494
|
+
if (!existsSync13(path2)) {
|
|
41605
42495
|
return { version: 1, entries: {} };
|
|
41606
42496
|
}
|
|
41607
42497
|
let parsed;
|
|
@@ -42916,7 +43806,7 @@ async function openUrlInBrowser(url) {
|
|
|
42916
43806
|
}
|
|
42917
43807
|
const [command, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
|
|
42918
43808
|
await new Promise((resolve11, reject) => {
|
|
42919
|
-
const child =
|
|
43809
|
+
const child = spawn11(command, args, { stdio: "ignore", detached: true });
|
|
42920
43810
|
child.once("spawn", () => {
|
|
42921
43811
|
child.unref();
|
|
42922
43812
|
resolve11();
|
|
@@ -44114,7 +45004,7 @@ function parseTaskSuggestionResponse2(response) {
|
|
|
44114
45004
|
}
|
|
44115
45005
|
function runProcess3(args) {
|
|
44116
45006
|
return new Promise((resolveProcess, rejectProcess) => {
|
|
44117
|
-
const child =
|
|
45007
|
+
const child = spawn11(args.command, [...args.args], {
|
|
44118
45008
|
cwd: args.cwd,
|
|
44119
45009
|
stdio: ["pipe", "ignore", "pipe"]
|
|
44120
45010
|
});
|
|
@@ -44156,7 +45046,7 @@ function runProcess3(args) {
|
|
|
44156
45046
|
}
|
|
44157
45047
|
function runProcessCapture(args) {
|
|
44158
45048
|
return new Promise((resolveProcess) => {
|
|
44159
|
-
const child =
|
|
45049
|
+
const child = spawn11(args.command, [...args.args], {
|
|
44160
45050
|
cwd: args.cwd,
|
|
44161
45051
|
stdio: ["ignore", "pipe", "ignore"]
|
|
44162
45052
|
});
|
|
@@ -44374,7 +45264,7 @@ function spawnSyncGitOutput(args, cwd) {
|
|
|
44374
45264
|
}
|
|
44375
45265
|
function probeToolWithArgs(command, args, cwd) {
|
|
44376
45266
|
return new Promise((resolve11) => {
|
|
44377
|
-
const child =
|
|
45267
|
+
const child = spawn11(command, [...args], {
|
|
44378
45268
|
cwd,
|
|
44379
45269
|
stdio: ["ignore", "pipe", "pipe"]
|
|
44380
45270
|
});
|
|
@@ -44412,7 +45302,7 @@ async function discoverCodeRoots(homeDir) {
|
|
|
44412
45302
|
const candidates = ["src", "code", "projects"].map(
|
|
44413
45303
|
(name) => join17(homeDir, name)
|
|
44414
45304
|
);
|
|
44415
|
-
return candidates.filter((path2) =>
|
|
45305
|
+
return candidates.filter((path2) => existsSync13(path2)).flatMap((path2) => discoveredProjectNames(path2));
|
|
44416
45306
|
}
|
|
44417
45307
|
function discoveredProjectNames(root) {
|
|
44418
45308
|
try {
|
|
@@ -44516,25 +45406,25 @@ function looksLikeProject(path2) {
|
|
|
44516
45406
|
"pnpm-lock.yaml",
|
|
44517
45407
|
"yarn.lock",
|
|
44518
45408
|
"package-lock.json"
|
|
44519
|
-
].some((name) =>
|
|
45409
|
+
].some((name) => existsSync13(join17(path2, name)));
|
|
44520
45410
|
}
|
|
44521
45411
|
function detectProjectLanguage(path2) {
|
|
44522
|
-
if (
|
|
45412
|
+
if (existsSync13(join17(path2, "pyproject.toml")) || existsSync13(join17(path2, "requirements.txt"))) {
|
|
44523
45413
|
return "Python";
|
|
44524
45414
|
}
|
|
44525
|
-
if (
|
|
45415
|
+
if (existsSync13(join17(path2, "Cargo.toml"))) {
|
|
44526
45416
|
return "Rust";
|
|
44527
45417
|
}
|
|
44528
|
-
if (
|
|
45418
|
+
if (existsSync13(join17(path2, "go.mod"))) {
|
|
44529
45419
|
return "Go";
|
|
44530
45420
|
}
|
|
44531
|
-
if (
|
|
45421
|
+
if (existsSync13(join17(path2, "mix.exs"))) {
|
|
44532
45422
|
return "Elixir";
|
|
44533
45423
|
}
|
|
44534
|
-
if (
|
|
45424
|
+
if (existsSync13(join17(path2, "tsconfig.json")) || packageJsonMentionsTypeScript(path2)) {
|
|
44535
45425
|
return "TypeScript";
|
|
44536
45426
|
}
|
|
44537
|
-
if (
|
|
45427
|
+
if (existsSync13(join17(path2, "package.json"))) {
|
|
44538
45428
|
return "JavaScript";
|
|
44539
45429
|
}
|
|
44540
45430
|
return "Project";
|
|
@@ -44550,7 +45440,7 @@ function packageJsonMentionsTypeScript(path2) {
|
|
|
44550
45440
|
}
|
|
44551
45441
|
}
|
|
44552
45442
|
function hasGitMetadata(path2) {
|
|
44553
|
-
return
|
|
45443
|
+
return existsSync13(join17(path2, ".git"));
|
|
44554
45444
|
}
|
|
44555
45445
|
function childDirectories(root) {
|
|
44556
45446
|
try {
|
|
@@ -44672,7 +45562,7 @@ secure mission control for all your agents on your computers
|
|
|
44672
45562
|
init_runner();
|
|
44673
45563
|
init_claudeCodeSession();
|
|
44674
45564
|
init_authCache();
|
|
44675
|
-
import { existsSync as
|
|
45565
|
+
import { existsSync as existsSync14, readFileSync as readFileSync16, realpathSync as realpathSync6 } from "node:fs";
|
|
44676
45566
|
import { homedir as homedir13 } from "node:os";
|
|
44677
45567
|
import { resolve as resolve10 } from "node:path";
|
|
44678
45568
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
@@ -44734,8 +45624,8 @@ init_kandanTls();
|
|
|
44734
45624
|
init_protocol();
|
|
44735
45625
|
init_json();
|
|
44736
45626
|
init_defaultUrls();
|
|
44737
|
-
import { existsSync as
|
|
44738
|
-
import { dirname as
|
|
45627
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync10, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "node:fs";
|
|
45628
|
+
import { dirname as dirname11, join as join15 } from "node:path";
|
|
44739
45629
|
import { homedir as homedir10 } from "node:os";
|
|
44740
45630
|
async function runAgentCliCommand(args, deps = {
|
|
44741
45631
|
fetchImpl: fetch,
|
|
@@ -45453,10 +46343,10 @@ function authorizationHeaders(token) {
|
|
|
45453
46343
|
return { authorization: `Bearer ${token}` };
|
|
45454
46344
|
}
|
|
45455
46345
|
function readOptionalTextFile(path2) {
|
|
45456
|
-
return
|
|
46346
|
+
return existsSync11(path2) ? readFileSync12(path2, "utf8") : void 0;
|
|
45457
46347
|
}
|
|
45458
46348
|
function writeTextFile(path2, content) {
|
|
45459
|
-
mkdirSync10(
|
|
46349
|
+
mkdirSync10(dirname11(path2), { recursive: true });
|
|
45460
46350
|
writeFileSync8(path2, content);
|
|
45461
46351
|
}
|
|
45462
46352
|
function readStoredAgentTokenFile(path2, readTextFile = readOptionalTextFile) {
|
|
@@ -45544,7 +46434,7 @@ init_helloLinzumiProject();
|
|
|
45544
46434
|
// src/commanderDaemon.ts
|
|
45545
46435
|
init_runnerLogger();
|
|
45546
46436
|
import {
|
|
45547
|
-
existsSync as
|
|
46437
|
+
existsSync as existsSync12,
|
|
45548
46438
|
closeSync as closeSync2,
|
|
45549
46439
|
mkdirSync as mkdirSync11,
|
|
45550
46440
|
openSync as openSync3,
|
|
@@ -45553,8 +46443,8 @@ import {
|
|
|
45553
46443
|
writeFileSync as writeFileSync9
|
|
45554
46444
|
} from "node:fs";
|
|
45555
46445
|
import { homedir as homedir11 } from "node:os";
|
|
45556
|
-
import { dirname as
|
|
45557
|
-
import { execFileSync, spawn as
|
|
46446
|
+
import { dirname as dirname12, join as join16, resolve as resolve8 } from "node:path";
|
|
46447
|
+
import { execFileSync, spawn as spawn9 } from "node:child_process";
|
|
45558
46448
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
45559
46449
|
var connectedMarkers = ["Connected to Linzumi", "Runner connected:"];
|
|
45560
46450
|
function commanderStatusDir() {
|
|
@@ -45586,7 +46476,7 @@ function startCommanderDaemon(options) {
|
|
|
45586
46476
|
logFile
|
|
45587
46477
|
];
|
|
45588
46478
|
mkdirSync11(statusDir, { recursive: true });
|
|
45589
|
-
mkdirSync11(
|
|
46479
|
+
mkdirSync11(dirname12(logFile), { recursive: true });
|
|
45590
46480
|
const out = openSync3(logFile, "a");
|
|
45591
46481
|
const err = openSync3(logFile, "a");
|
|
45592
46482
|
writeCliAuditEvent(
|
|
@@ -45599,7 +46489,7 @@ function startCommanderDaemon(options) {
|
|
|
45599
46489
|
},
|
|
45600
46490
|
{ sessionId: options.runnerId }
|
|
45601
46491
|
);
|
|
45602
|
-
const child = (options.spawnImpl ??
|
|
46492
|
+
const child = (options.spawnImpl ?? spawn9)(nodeBin, command, {
|
|
45603
46493
|
detached: true,
|
|
45604
46494
|
stdio: ["ignore", out, err],
|
|
45605
46495
|
env: process.env
|
|
@@ -45638,7 +46528,7 @@ function startCommanderDaemon(options) {
|
|
|
45638
46528
|
}
|
|
45639
46529
|
function commanderDaemonStatus(runnerId, statusDir = commanderStatusDir(), processIdentityReader = readProcessIdentity) {
|
|
45640
46530
|
const statusFile = commanderStatusFile(runnerId, statusDir);
|
|
45641
|
-
if (!
|
|
46531
|
+
if (!existsSync12(statusFile)) {
|
|
45642
46532
|
return { status: "missing", runnerId, statusFile };
|
|
45643
46533
|
}
|
|
45644
46534
|
const record = parseRecord(readFileSync13(statusFile, "utf8"));
|
|
@@ -45646,7 +46536,7 @@ function commanderDaemonStatus(runnerId, statusDir = commanderStatusDir(), proce
|
|
|
45646
46536
|
}
|
|
45647
46537
|
async function waitForCommanderDaemon(options) {
|
|
45648
46538
|
const now = options.now ?? (() => Date.now());
|
|
45649
|
-
const readTextFile = options.readTextFile ?? ((path2) =>
|
|
46539
|
+
const readTextFile = options.readTextFile ?? ((path2) => existsSync12(path2) ? readFileSync13(path2, "utf8") : void 0);
|
|
45650
46540
|
const statusImpl = options.statusImpl ?? commanderDaemonStatus;
|
|
45651
46541
|
const deadline = now() + options.timeoutMs;
|
|
45652
46542
|
while (now() <= deadline) {
|
|
@@ -57610,6 +58500,8 @@ function createLinzumiMcpApiClient(options) {
|
|
|
57610
58500
|
sendChannelMessage: (params) => request("POST", `${apiPrefix}/channel-message`, params),
|
|
57611
58501
|
prepareMessageUploads: (params) => request("POST", `${apiPrefix}/message-uploads/prepare`, params),
|
|
57612
58502
|
attachMessageFiles: (params) => request("POST", `${apiPrefix}/message-files/attach`, params),
|
|
58503
|
+
prepareCustomEmoji: (params) => request("POST", `${apiPrefix}/custom-emoji/prepare`, params),
|
|
58504
|
+
renameCustomEmoji: (params) => request("POST", `${apiPrefix}/custom-emoji/rename`, params),
|
|
57613
58505
|
sendThreadReply: (params) => request("POST", `${apiPrefix}/thread-reply`, params),
|
|
57614
58506
|
sendDm: (params) => request("POST", `${apiPrefix}/dm`, params),
|
|
57615
58507
|
dmOwner: (params) => request("POST", `${apiPrefix}/dm-owner`, params),
|
|
@@ -57620,6 +58512,17 @@ function createLinzumiMcpApiClient(options) {
|
|
|
57620
58512
|
// src/mcpServer.ts
|
|
57621
58513
|
init_mcpConfig();
|
|
57622
58514
|
init_oauth();
|
|
58515
|
+
init_protocol();
|
|
58516
|
+
var maxCustomEmojiNameLength = 64;
|
|
58517
|
+
function normalizeCustomEmojiNameForSchema(value) {
|
|
58518
|
+
return value.trim().replace(/^:+/, "").replace(/:+$/, "").toLowerCase();
|
|
58519
|
+
}
|
|
58520
|
+
var customEmojiNameSchema = external_exports2.string().min(1).refine(
|
|
58521
|
+
(value) => normalizeCustomEmojiNameForSchema(value).length <= maxCustomEmojiNameLength,
|
|
58522
|
+
{
|
|
58523
|
+
message: `Custom emoji shortcode name must be at most ${maxCustomEmojiNameLength} characters after trimming surrounding colons.`
|
|
58524
|
+
}
|
|
58525
|
+
);
|
|
57623
58526
|
var mcpFlagDefinitions = /* @__PURE__ */ new Map([
|
|
57624
58527
|
["api-url", { kind: "value" }],
|
|
57625
58528
|
["token", { kind: "value" }],
|
|
@@ -57680,6 +58583,10 @@ Tools:
|
|
|
57680
58583
|
linzumi_dm_owner Send a plain-text DM to the configured owner username.
|
|
57681
58584
|
linzumi_get_vault_values
|
|
57682
58585
|
Request approved named vault values for a thread.
|
|
58586
|
+
linzumi_upload_custom_emoji
|
|
58587
|
+
Upload a local image as a workspace custom emoji.
|
|
58588
|
+
linzumi_rename_custom_emoji
|
|
58589
|
+
Rename an existing workspace custom emoji.
|
|
57683
58590
|
|
|
57684
58591
|
Auth:
|
|
57685
58592
|
Uses --token, LINZUMI_MCP_ACCESS_TOKEN, or cached local runner OAuth from linzumi auth.
|
|
@@ -57801,6 +58708,43 @@ async function runMcpServer(args) {
|
|
|
57801
58708
|
{},
|
|
57802
58709
|
async (params) => mcpJsonResult(await client.listVaultSecrets(params))
|
|
57803
58710
|
);
|
|
58711
|
+
server.tool(
|
|
58712
|
+
"linzumi_upload_custom_emoji",
|
|
58713
|
+
"Upload a local image as a workspace custom emoji. For generated emoji art, create a transparent PNG with a simple centered subject, crisp edges, strong contrast, minimal tiny details, and enough outline/highlight separation to read at 16-24px on both dark and light backgrounds. Use lowercase shortcode names without colons unless preserving a user-provided :name:.",
|
|
58714
|
+
{
|
|
58715
|
+
name: customEmojiNameSchema.describe(
|
|
58716
|
+
"Custom emoji shortcode name, with or without surrounding colons."
|
|
58717
|
+
),
|
|
58718
|
+
file: external_exports2.string().min(1).describe(
|
|
58719
|
+
"Local PNG/WebP/GIF/JPEG file path to upload. Prefer transparent PNG for generated emoji."
|
|
58720
|
+
),
|
|
58721
|
+
workspace: external_exports2.string().optional().describe("Workspace slug. Omit to use the authenticated token scope.")
|
|
58722
|
+
},
|
|
58723
|
+
async (params) => mcpJsonResult(
|
|
58724
|
+
await uploadCustomEmojiWithClient({
|
|
58725
|
+
client,
|
|
58726
|
+
cwd,
|
|
58727
|
+
kandanUrl,
|
|
58728
|
+
name: params.name,
|
|
58729
|
+
file: params.file,
|
|
58730
|
+
workspace: params.workspace
|
|
58731
|
+
})
|
|
58732
|
+
)
|
|
58733
|
+
);
|
|
58734
|
+
server.tool(
|
|
58735
|
+
"linzumi_rename_custom_emoji",
|
|
58736
|
+
"Rename an existing workspace custom emoji. The new name may include surrounding colons; Linzumi stores the normalized shortcode without colons.",
|
|
58737
|
+
{
|
|
58738
|
+
emoji_id: external_exports2.union([external_exports2.string(), external_exports2.number().int().positive()]).describe(
|
|
58739
|
+
"Workspace custom emoji id returned by linzumi_upload_custom_emoji or workspace emoji listings."
|
|
58740
|
+
),
|
|
58741
|
+
name: customEmojiNameSchema.describe(
|
|
58742
|
+
"New shortcode name, with or without surrounding colons."
|
|
58743
|
+
),
|
|
58744
|
+
workspace: external_exports2.string().optional().describe("Workspace slug. Omit to use the authenticated token scope.")
|
|
58745
|
+
},
|
|
58746
|
+
async (params) => mcpJsonResult(await client.renameCustomEmoji(params))
|
|
58747
|
+
);
|
|
57804
58748
|
server.tool(
|
|
57805
58749
|
"linzumi_dm_owner",
|
|
57806
58750
|
"Send a plain-text DM to the configured Commander owner. Requires dm.write and a visible owner username.",
|
|
@@ -57936,6 +58880,69 @@ async function uploadFilesWithClient(args) {
|
|
|
57936
58880
|
uploaded_file_ids: uploadedFileIds
|
|
57937
58881
|
});
|
|
57938
58882
|
}
|
|
58883
|
+
async function uploadCustomEmojiWithClient(args) {
|
|
58884
|
+
const file = await commanderUploadFileForPath(args.cwd, args.file);
|
|
58885
|
+
const prepare = await args.client.prepareCustomEmoji({
|
|
58886
|
+
...args.workspace === void 0 ? {} : { workspace: args.workspace },
|
|
58887
|
+
name: args.name,
|
|
58888
|
+
file_name: file.fileName,
|
|
58889
|
+
content_type: file.contentType,
|
|
58890
|
+
size_bytes: file.sizeBytes
|
|
58891
|
+
});
|
|
58892
|
+
const upload = objectValue(prepare.upload);
|
|
58893
|
+
const uploadUrl = stringValue(upload?.upload_url);
|
|
58894
|
+
const uploadMethod = stringValue(upload?.upload_method) ?? "PUT";
|
|
58895
|
+
if (uploadUrl === void 0) {
|
|
58896
|
+
throw new Error("Linzumi custom emoji prepare response missing upload_url");
|
|
58897
|
+
}
|
|
58898
|
+
const bytes = await readFile2(file.path);
|
|
58899
|
+
const uploadBody = bytes.buffer.slice(
|
|
58900
|
+
bytes.byteOffset,
|
|
58901
|
+
bytes.byteOffset + bytes.byteLength
|
|
58902
|
+
);
|
|
58903
|
+
const response = await fetch(
|
|
58904
|
+
resolveLinzumiUploadUrl(args.kandanUrl, uploadUrl),
|
|
58905
|
+
{
|
|
58906
|
+
method: uploadMethod,
|
|
58907
|
+
headers: { "content-type": file.contentType },
|
|
58908
|
+
body: uploadBody
|
|
58909
|
+
}
|
|
58910
|
+
);
|
|
58911
|
+
if (!response.ok) {
|
|
58912
|
+
const fallbackError = `${response.status} ${response.statusText}`;
|
|
58913
|
+
const responseText = await response.text();
|
|
58914
|
+
const trimmedResponseText = responseText.trim();
|
|
58915
|
+
const error = trimmedResponseText === "" ? fallbackError : (() => {
|
|
58916
|
+
try {
|
|
58917
|
+
const parsedError = JSON.parse(trimmedResponseText);
|
|
58918
|
+
return isJsonObject(parsedError) && typeof parsedError.error === "string" ? parsedError.error : trimmedResponseText;
|
|
58919
|
+
} catch {
|
|
58920
|
+
return trimmedResponseText;
|
|
58921
|
+
}
|
|
58922
|
+
})();
|
|
58923
|
+
throw new Error(`Linzumi custom emoji upload failed: ${error}`);
|
|
58924
|
+
}
|
|
58925
|
+
const parsed = await response.json();
|
|
58926
|
+
if (!isJsonObject(parsed)) {
|
|
58927
|
+
throw new Error("Linzumi custom emoji upload returned non-object JSON");
|
|
58928
|
+
}
|
|
58929
|
+
const emoji = objectValue(parsed.custom_emoji);
|
|
58930
|
+
if (emoji === void 0) {
|
|
58931
|
+
throw new Error(
|
|
58932
|
+
"Linzumi custom emoji upload response missing custom_emoji"
|
|
58933
|
+
);
|
|
58934
|
+
}
|
|
58935
|
+
return {
|
|
58936
|
+
ok: true,
|
|
58937
|
+
workspace: prepare.workspace,
|
|
58938
|
+
emoji,
|
|
58939
|
+
asset_id: stringValue(parsed.asset_id),
|
|
58940
|
+
id: integerValue(emoji?.id),
|
|
58941
|
+
name: stringValue(emoji?.name),
|
|
58942
|
+
shortcode: stringValue(emoji?.shortcode),
|
|
58943
|
+
image_url: stringValue(emoji?.image_url)
|
|
58944
|
+
};
|
|
58945
|
+
}
|
|
57939
58946
|
function targetWithDefaultThread(target, defaultThreadId) {
|
|
57940
58947
|
const existingThreadId = stringValue(target.thread_id);
|
|
57941
58948
|
if (existingThreadId !== void 0 || defaultThreadId === void 0) {
|
|
@@ -58124,6 +59131,338 @@ function required(values, key) {
|
|
|
58124
59131
|
return value;
|
|
58125
59132
|
}
|
|
58126
59133
|
|
|
59134
|
+
// src/remoteCodexHarnessWorker.ts
|
|
59135
|
+
init_channelSession();
|
|
59136
|
+
init_codexAppServer();
|
|
59137
|
+
init_phoenix();
|
|
59138
|
+
init_runnerLogger();
|
|
59139
|
+
init_userFacingErrors();
|
|
59140
|
+
init_version();
|
|
59141
|
+
var configEnvKey = "LINZUMI_REMOTE_CODEX_HARNESS_CONFIG_B64";
|
|
59142
|
+
var remoteHarnessEnvironmentId = "linzumi-remote-codex-harness";
|
|
59143
|
+
async function runRemoteCodexHarnessWorkerFromEnv(env = process.env) {
|
|
59144
|
+
await runRemoteCodexHarnessWorker(remoteCodexHarnessWorkerConfigFromEnv(env));
|
|
59145
|
+
}
|
|
59146
|
+
async function runRemoteCodexHarnessWorker(config, deps = {}) {
|
|
59147
|
+
const resolvedDeps = {
|
|
59148
|
+
startCodexAppServer,
|
|
59149
|
+
connectCodexAppServer,
|
|
59150
|
+
connectPhoenixClient,
|
|
59151
|
+
attachChannelSession,
|
|
59152
|
+
waitUntilShutdown: defaultWaitUntilShutdown,
|
|
59153
|
+
writeStdout: (chunk) => process.stdout.write(chunk),
|
|
59154
|
+
log: writeCliAuditEvent,
|
|
59155
|
+
...deps
|
|
59156
|
+
};
|
|
59157
|
+
const started = await resolvedDeps.startCodexAppServer(
|
|
59158
|
+
config.codexBin,
|
|
59159
|
+
config.workerCwd,
|
|
59160
|
+
{
|
|
59161
|
+
model: config.model,
|
|
59162
|
+
reasoningEffort: config.reasoningEffort,
|
|
59163
|
+
fast: config.fast,
|
|
59164
|
+
inheritEnv: false,
|
|
59165
|
+
env: remoteHarnessCodexEnv(process.env, config.execServerUrl)
|
|
59166
|
+
}
|
|
59167
|
+
);
|
|
59168
|
+
let kandan;
|
|
59169
|
+
let codex;
|
|
59170
|
+
let session;
|
|
59171
|
+
const cleanup = async () => {
|
|
59172
|
+
await session?.close();
|
|
59173
|
+
codex?.close();
|
|
59174
|
+
kandan?.close();
|
|
59175
|
+
started.stop();
|
|
59176
|
+
};
|
|
59177
|
+
const cleanupOnce = onceAsync(cleanup);
|
|
59178
|
+
try {
|
|
59179
|
+
codex = await resolvedDeps.connectCodexAppServer(started.url);
|
|
59180
|
+
await registerExecServerEnvironment(codex, config.execServerUrl);
|
|
59181
|
+
kandan = await resolvedDeps.connectPhoenixClient(
|
|
59182
|
+
config.kandanUrl,
|
|
59183
|
+
config.token
|
|
59184
|
+
);
|
|
59185
|
+
const runnerTopic = `local_runner:${config.runnerId}`;
|
|
59186
|
+
const runnerJoinPayload = () => remoteHarnessRunnerJoinPayload(config);
|
|
59187
|
+
const pendingControls = [];
|
|
59188
|
+
const controlDispatcher = { value: void 0 };
|
|
59189
|
+
kandan.onControl((control) => {
|
|
59190
|
+
const dispatcher = controlDispatcher.value;
|
|
59191
|
+
if (dispatcher === void 0) {
|
|
59192
|
+
pendingControls.push(control);
|
|
59193
|
+
return;
|
|
59194
|
+
}
|
|
59195
|
+
dispatcher(control);
|
|
59196
|
+
});
|
|
59197
|
+
await kandan.join(runnerTopic, runnerJoinPayload(), {
|
|
59198
|
+
rejoinPayload: runnerJoinPayload
|
|
59199
|
+
});
|
|
59200
|
+
session = await resolvedDeps.attachChannelSession({
|
|
59201
|
+
kandan,
|
|
59202
|
+
codex,
|
|
59203
|
+
topic: runnerTopic,
|
|
59204
|
+
instanceId: config.instanceId,
|
|
59205
|
+
options: {
|
|
59206
|
+
kandanUrl: config.kandanUrl,
|
|
59207
|
+
token: config.token,
|
|
59208
|
+
runnerId: config.runnerId,
|
|
59209
|
+
cwd: config.cwd,
|
|
59210
|
+
codexBin: config.codexBin,
|
|
59211
|
+
fast: config.fast,
|
|
59212
|
+
launchTui: false,
|
|
59213
|
+
enablePortForwardWatch: false,
|
|
59214
|
+
channelSession: {
|
|
59215
|
+
workspaceSlug: config.workspaceSlug,
|
|
59216
|
+
channelSlug: config.channelSlug,
|
|
59217
|
+
kandanThreadId: config.kandanThreadId,
|
|
59218
|
+
rootSeq: config.rootSeq,
|
|
59219
|
+
startCodexThread: true,
|
|
59220
|
+
linzumiContext: config.linzumiContext,
|
|
59221
|
+
listenUser: config.listenUser,
|
|
59222
|
+
model: config.model,
|
|
59223
|
+
reasoningEffort: config.reasoningEffort,
|
|
59224
|
+
sandbox: config.sandbox,
|
|
59225
|
+
approvalPolicy: config.approvalPolicy,
|
|
59226
|
+
codexEnvironmentId: remoteHarnessEnvironmentId,
|
|
59227
|
+
allowPortForwardingByDefault: config.allowPortForwardingByDefault
|
|
59228
|
+
}
|
|
59229
|
+
},
|
|
59230
|
+
log: resolvedDeps.log
|
|
59231
|
+
});
|
|
59232
|
+
kandan.onReconnect(() => session?.handleKandanReconnect());
|
|
59233
|
+
const dispatchControl = (control) => {
|
|
59234
|
+
const liveSession = session;
|
|
59235
|
+
const liveKandan = kandan;
|
|
59236
|
+
if (liveSession === void 0 || liveKandan === void 0) {
|
|
59237
|
+
pendingControls.push(control);
|
|
59238
|
+
return;
|
|
59239
|
+
}
|
|
59240
|
+
void liveSession.handleControl(control).then(
|
|
59241
|
+
(response) => response === void 0 ? void 0 : liveKandan.push(runnerTopic, "codex_response", response)
|
|
59242
|
+
).catch(
|
|
59243
|
+
(error) => liveKandan.push(runnerTopic, "codex_error", {
|
|
59244
|
+
instanceId: config.instanceId,
|
|
59245
|
+
message: runnerActionErrorMessage(error)
|
|
59246
|
+
})
|
|
59247
|
+
).catch((error) => {
|
|
59248
|
+
resolvedDeps.log("remote_codex_harness.control_push_failed", {
|
|
59249
|
+
message: error instanceof Error ? error.message : String(error)
|
|
59250
|
+
});
|
|
59251
|
+
});
|
|
59252
|
+
};
|
|
59253
|
+
controlDispatcher.value = dispatchControl;
|
|
59254
|
+
pendingControls.splice(0).forEach(dispatchControl);
|
|
59255
|
+
codex.onNotification((notification) => {
|
|
59256
|
+
const params = notification.params ?? {};
|
|
59257
|
+
session?.handleCodexNotification(notification.method, params);
|
|
59258
|
+
});
|
|
59259
|
+
await session.startThreadMessageTurn({
|
|
59260
|
+
seq: config.sourceSeq,
|
|
59261
|
+
body: config.workDescription
|
|
59262
|
+
});
|
|
59263
|
+
resolvedDeps.writeStdout(
|
|
59264
|
+
`LINZUMI_REMOTE_CODEX_HARNESS_READY ${config.readyToken}
|
|
59265
|
+
`
|
|
59266
|
+
);
|
|
59267
|
+
const stopReason = await Promise.race([
|
|
59268
|
+
resolvedDeps.waitUntilShutdown(cleanupOnce).then(() => ({ type: "shutdown" })),
|
|
59269
|
+
waitForCodexAppServerExit(started.process).then((exit) => ({
|
|
59270
|
+
type: "codex_exit",
|
|
59271
|
+
exit
|
|
59272
|
+
}))
|
|
59273
|
+
]);
|
|
59274
|
+
if (stopReason.type === "codex_exit") {
|
|
59275
|
+
resolvedDeps.log("remote_codex_harness.codex_app_server_exited", {
|
|
59276
|
+
code: stopReason.exit.code,
|
|
59277
|
+
signal: stopReason.exit.signal
|
|
59278
|
+
});
|
|
59279
|
+
await cleanupOnce();
|
|
59280
|
+
}
|
|
59281
|
+
} catch (error) {
|
|
59282
|
+
await cleanupOnce();
|
|
59283
|
+
throw error;
|
|
59284
|
+
}
|
|
59285
|
+
}
|
|
59286
|
+
function remoteCodexHarnessWorkerConfigFromEnv(env) {
|
|
59287
|
+
const encoded = env[configEnvKey];
|
|
59288
|
+
if (encoded === void 0 || encoded.trim() === "") {
|
|
59289
|
+
throw new Error(`${configEnvKey} is required`);
|
|
59290
|
+
}
|
|
59291
|
+
return remoteCodexHarnessWorkerConfigFromJson(
|
|
59292
|
+
JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"))
|
|
59293
|
+
);
|
|
59294
|
+
}
|
|
59295
|
+
function remoteCodexHarnessWorkerConfigFromJson(value) {
|
|
59296
|
+
const input = requireObject(value);
|
|
59297
|
+
const config = {
|
|
59298
|
+
kandanUrl: requiredString2(input, "kandanUrl"),
|
|
59299
|
+
token: requiredString2(input, "token"),
|
|
59300
|
+
runnerId: requiredString2(input, "runnerId"),
|
|
59301
|
+
instanceId: requiredString2(input, "instanceId"),
|
|
59302
|
+
workspaceSlug: requiredString2(input, "workspaceSlug"),
|
|
59303
|
+
channelSlug: requiredString2(input, "channelSlug"),
|
|
59304
|
+
kandanThreadId: requiredString2(input, "kandanThreadId"),
|
|
59305
|
+
rootSeq: requiredPositiveInteger(input, "rootSeq"),
|
|
59306
|
+
sourceSeq: requiredPositiveInteger(input, "sourceSeq"),
|
|
59307
|
+
cwd: requiredString2(input, "cwd"),
|
|
59308
|
+
workerCwd: requiredString2(input, "workerCwd"),
|
|
59309
|
+
workDescription: requiredString2(input, "workDescription"),
|
|
59310
|
+
readyToken: requiredString2(input, "readyToken"),
|
|
59311
|
+
codexBin: requiredString2(input, "codexBin"),
|
|
59312
|
+
execServerUrl: requiredString2(input, "execServerUrl"),
|
|
59313
|
+
listenUser: requiredString2(input, "listenUser"),
|
|
59314
|
+
...optionalStringField(input, "model"),
|
|
59315
|
+
...optionalStringField(input, "reasoningEffort"),
|
|
59316
|
+
...optionalStringField(input, "approvalPolicy"),
|
|
59317
|
+
...optionalStringField(input, "sandbox"),
|
|
59318
|
+
...optionalBooleanField(input, "fast"),
|
|
59319
|
+
...optionalBooleanField(input, "allowPortForwardingByDefault"),
|
|
59320
|
+
...optionalObjectField(input, "linzumiContext")
|
|
59321
|
+
};
|
|
59322
|
+
return config;
|
|
59323
|
+
}
|
|
59324
|
+
async function registerExecServerEnvironment(codex, execServerUrl) {
|
|
59325
|
+
const response = await codex.request("environment/add", {
|
|
59326
|
+
environmentId: remoteHarnessEnvironmentId,
|
|
59327
|
+
execServerUrl
|
|
59328
|
+
});
|
|
59329
|
+
assertJsonRpcOk(response, "environment/add");
|
|
59330
|
+
}
|
|
59331
|
+
function assertJsonRpcOk(response, method) {
|
|
59332
|
+
if ("error" in response) {
|
|
59333
|
+
throw new Error(`${method} failed: ${response.error.message}`);
|
|
59334
|
+
}
|
|
59335
|
+
}
|
|
59336
|
+
function remoteHarnessCodexEnv(sourceEnv, execServerUrl) {
|
|
59337
|
+
const env = {
|
|
59338
|
+
CODEX_EXEC_SERVER_URL: execServerUrl,
|
|
59339
|
+
LINZUMI_REMOTE_CODEX_HARNESS: "1"
|
|
59340
|
+
};
|
|
59341
|
+
for (const key of remoteHarnessCodexEnvAllowlist) {
|
|
59342
|
+
const value = sourceEnv[key];
|
|
59343
|
+
if (value !== void 0 && value.trim() !== "") {
|
|
59344
|
+
env[key] = value;
|
|
59345
|
+
}
|
|
59346
|
+
}
|
|
59347
|
+
return env;
|
|
59348
|
+
}
|
|
59349
|
+
var remoteHarnessCodexEnvAllowlist = [
|
|
59350
|
+
"PATH",
|
|
59351
|
+
"HOME",
|
|
59352
|
+
"TMPDIR",
|
|
59353
|
+
"SHELL",
|
|
59354
|
+
"USER",
|
|
59355
|
+
"LOGNAME",
|
|
59356
|
+
"CODEX_HOME",
|
|
59357
|
+
"XDG_CONFIG_HOME",
|
|
59358
|
+
"XDG_DATA_HOME",
|
|
59359
|
+
"SSL_CERT_FILE",
|
|
59360
|
+
"NIX_SSL_CERT_FILE",
|
|
59361
|
+
"NODE_EXTRA_CA_CERTS"
|
|
59362
|
+
];
|
|
59363
|
+
function remoteHarnessRunnerJoinPayload(config) {
|
|
59364
|
+
return {
|
|
59365
|
+
clientName: "kandan-remote-codex-harness-worker",
|
|
59366
|
+
clientId: config.instanceId,
|
|
59367
|
+
connectionMode: "session_worker",
|
|
59368
|
+
runnerPid: process.pid,
|
|
59369
|
+
version: linzumiCliVersion,
|
|
59370
|
+
cwd: config.cwd,
|
|
59371
|
+
workspace: config.workspaceSlug,
|
|
59372
|
+
channel: config.channelSlug,
|
|
59373
|
+
capabilities: {
|
|
59374
|
+
codexAppServer: true,
|
|
59375
|
+
defaultAgentProvider: "codex",
|
|
59376
|
+
agentProviders: ["codex"],
|
|
59377
|
+
remoteCodexExecution: false,
|
|
59378
|
+
allowedCwdSuggestions: [],
|
|
59379
|
+
allowedCwdProjects: [],
|
|
59380
|
+
portForwarding: false,
|
|
59381
|
+
tcpForwarding: false,
|
|
59382
|
+
linzumiMcp: true
|
|
59383
|
+
}
|
|
59384
|
+
};
|
|
59385
|
+
}
|
|
59386
|
+
function defaultWaitUntilShutdown(cleanup) {
|
|
59387
|
+
return new Promise((resolve11, reject) => {
|
|
59388
|
+
const finish = () => {
|
|
59389
|
+
cleanup().then(resolve11, reject);
|
|
59390
|
+
};
|
|
59391
|
+
process.once("SIGINT", finish);
|
|
59392
|
+
process.once("SIGTERM", finish);
|
|
59393
|
+
});
|
|
59394
|
+
}
|
|
59395
|
+
function onceAsync(fn) {
|
|
59396
|
+
let promise;
|
|
59397
|
+
return () => {
|
|
59398
|
+
promise = promise ?? fn();
|
|
59399
|
+
return promise;
|
|
59400
|
+
};
|
|
59401
|
+
}
|
|
59402
|
+
function waitForCodexAppServerExit(child) {
|
|
59403
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
59404
|
+
return Promise.resolve({
|
|
59405
|
+
code: child.exitCode,
|
|
59406
|
+
signal: child.signalCode
|
|
59407
|
+
});
|
|
59408
|
+
}
|
|
59409
|
+
return new Promise((resolve11) => {
|
|
59410
|
+
child.once("exit", (code, signal) => {
|
|
59411
|
+
resolve11({ code, signal });
|
|
59412
|
+
});
|
|
59413
|
+
});
|
|
59414
|
+
}
|
|
59415
|
+
function requireObject(value) {
|
|
59416
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
59417
|
+
throw new Error("remote Codex harness worker config must be an object");
|
|
59418
|
+
}
|
|
59419
|
+
return value;
|
|
59420
|
+
}
|
|
59421
|
+
function requiredString2(input, key) {
|
|
59422
|
+
const value = input[key];
|
|
59423
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
59424
|
+
throw new Error(`remote Codex harness worker config missing ${key}`);
|
|
59425
|
+
}
|
|
59426
|
+
return value;
|
|
59427
|
+
}
|
|
59428
|
+
function requiredPositiveInteger(input, key) {
|
|
59429
|
+
const value = input[key];
|
|
59430
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
59431
|
+
throw new Error(`remote Codex harness worker config missing ${key}`);
|
|
59432
|
+
}
|
|
59433
|
+
return value;
|
|
59434
|
+
}
|
|
59435
|
+
function optionalStringField(input, key) {
|
|
59436
|
+
const value = input[key];
|
|
59437
|
+
if (value === void 0) {
|
|
59438
|
+
return {};
|
|
59439
|
+
}
|
|
59440
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
59441
|
+
throw new Error(`remote Codex harness worker config invalid ${key}`);
|
|
59442
|
+
}
|
|
59443
|
+
return { [key]: value };
|
|
59444
|
+
}
|
|
59445
|
+
function optionalBooleanField(input, key) {
|
|
59446
|
+
const value = input[key];
|
|
59447
|
+
if (value === void 0) {
|
|
59448
|
+
return {};
|
|
59449
|
+
}
|
|
59450
|
+
if (typeof value !== "boolean") {
|
|
59451
|
+
throw new Error(`remote Codex harness worker config invalid ${key}`);
|
|
59452
|
+
}
|
|
59453
|
+
return { [key]: value };
|
|
59454
|
+
}
|
|
59455
|
+
function optionalObjectField(input, key) {
|
|
59456
|
+
const value = input[key];
|
|
59457
|
+
if (value === void 0) {
|
|
59458
|
+
return {};
|
|
59459
|
+
}
|
|
59460
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
59461
|
+
throw new Error(`remote Codex harness worker config invalid ${key}`);
|
|
59462
|
+
}
|
|
59463
|
+
return { [key]: value };
|
|
59464
|
+
}
|
|
59465
|
+
|
|
58127
59466
|
// src/index.ts
|
|
58128
59467
|
init_userFacingErrors();
|
|
58129
59468
|
var flagDefinitions = /* @__PURE__ */ new Map([
|
|
@@ -58250,6 +59589,9 @@ async function main(args) {
|
|
|
58250
59589
|
case "commanderDaemon":
|
|
58251
59590
|
await runCommanderDaemonCommand(parsed.args);
|
|
58252
59591
|
return;
|
|
59592
|
+
case "remoteCodexHarnessWorker":
|
|
59593
|
+
await runRemoteCodexHarnessWorkerFromEnv();
|
|
59594
|
+
return;
|
|
58253
59595
|
case "agentRunner": {
|
|
58254
59596
|
const options = await parseAgentRunnerArgs(parsed.args);
|
|
58255
59597
|
await runLocalCodexRunner(withLocalMachineId(options));
|
|
@@ -58301,6 +59643,8 @@ function parseCommand(args) {
|
|
|
58301
59643
|
return ["daemon", "status", "wait", "stop"].includes(rest[0] ?? "") ? { command: "commanderDaemon", args: rest } : { command: "agentRunner", args: rest };
|
|
58302
59644
|
case "commander-daemon":
|
|
58303
59645
|
return { command: "commanderDaemon", args: ["daemon", ...rest] };
|
|
59646
|
+
case "remote-codex-harness-worker":
|
|
59647
|
+
return { command: "remoteCodexHarnessWorker", args: rest };
|
|
58304
59648
|
case "commander-status":
|
|
58305
59649
|
return { command: "commanderDaemon", args: ["status", ...rest] };
|
|
58306
59650
|
case "commander-wait":
|
|
@@ -58606,7 +59950,7 @@ async function parseStartRunnerArgs(args, deps = {
|
|
|
58606
59950
|
codexBin: requestedCodexBin,
|
|
58607
59951
|
codeServerBin: customCodeServerBin
|
|
58608
59952
|
});
|
|
58609
|
-
|
|
59953
|
+
assertRunnerConnectionDependencies(initialDependencyStatus);
|
|
58610
59954
|
const codexBin = initialDependencyStatus.codex.command;
|
|
58611
59955
|
const explicitToken = stringValue7(values, "token");
|
|
58612
59956
|
const authFilePath = stringValue7(values, "auth-file");
|
|
@@ -58652,7 +59996,7 @@ async function parseStartRunnerArgs(args, deps = {
|
|
|
58652
59996
|
codeServerBin: editorRuntime.codeServerBin,
|
|
58653
59997
|
editorRuntime: editorRuntime.status
|
|
58654
59998
|
});
|
|
58655
|
-
|
|
59999
|
+
assertRunnerConnectionDependencies(dependencyStatus);
|
|
58656
60000
|
const claudeCodeAvailable = await resolveClaudeCodeAvailability(deps, cwd);
|
|
58657
60001
|
return {
|
|
58658
60002
|
kandanUrl,
|
|
@@ -58664,6 +60008,7 @@ async function parseStartRunnerArgs(args, deps = {
|
|
|
58664
60008
|
cwd,
|
|
58665
60009
|
codexBin,
|
|
58666
60010
|
codexUrl: stringValue7(values, "codex-url"),
|
|
60011
|
+
launchSource: electronAutoConnectLaunchSource(),
|
|
58667
60012
|
launchTui: values.get("launch-tui") === true,
|
|
58668
60013
|
fast: values.get("fast") === true,
|
|
58669
60014
|
logFile: stringValue7(values, "log-file"),
|
|
@@ -58741,7 +60086,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
58741
60086
|
codexBin: requestedCodexBin,
|
|
58742
60087
|
codeServerBin: customCodeServerBin
|
|
58743
60088
|
});
|
|
58744
|
-
|
|
60089
|
+
assertRunnerConnectionDependencies(initialDependencyStatus);
|
|
58745
60090
|
const codexBin = initialDependencyStatus.codex.command;
|
|
58746
60091
|
const editorRuntime = await deps.resolveEditorRuntime({
|
|
58747
60092
|
kandanUrl,
|
|
@@ -58755,7 +60100,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
58755
60100
|
codeServerBin: editorRuntime.codeServerBin,
|
|
58756
60101
|
editorRuntime: editorRuntime.status
|
|
58757
60102
|
});
|
|
58758
|
-
|
|
60103
|
+
assertRunnerConnectionDependencies(dependencyStatus);
|
|
58759
60104
|
const claudeCodeAvailable = await resolveClaudeCodeAvailability(deps, cwd);
|
|
58760
60105
|
return {
|
|
58761
60106
|
kandanUrl,
|
|
@@ -58767,6 +60112,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
58767
60112
|
cwd,
|
|
58768
60113
|
codexBin,
|
|
58769
60114
|
codexUrl: stringValue7(values, "codex-url"),
|
|
60115
|
+
launchSource: electronAutoConnectLaunchSource(),
|
|
58770
60116
|
launchTui: values.get("launch-tui") === true,
|
|
58771
60117
|
fast: values.get("fast") === true,
|
|
58772
60118
|
logFile: stringValue7(values, "log-file"),
|
|
@@ -58785,7 +60131,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
58785
60131
|
};
|
|
58786
60132
|
}
|
|
58787
60133
|
function readAgentTokenTextFile(path2) {
|
|
58788
|
-
return
|
|
60134
|
+
return existsSync14(path2) ? readFileSync16(path2, "utf8") : void 0;
|
|
58789
60135
|
}
|
|
58790
60136
|
function rejectAgentRunnerTargetingFlags(values) {
|
|
58791
60137
|
const unsupportedFlags = [
|
|
@@ -58901,7 +60247,7 @@ async function parseRunnerArgs(args, deps = {
|
|
|
58901
60247
|
codexBin: requestedCodexBin,
|
|
58902
60248
|
codeServerBin: customCodeServerBin
|
|
58903
60249
|
});
|
|
58904
|
-
|
|
60250
|
+
assertRunnerConnectionDependencies(initialDependencyStatus);
|
|
58905
60251
|
const codexBin = initialDependencyStatus.codex.command;
|
|
58906
60252
|
const explicitToken = stringValue7(values, "token");
|
|
58907
60253
|
const token = await deps.resolveToken({
|
|
@@ -58928,7 +60274,7 @@ async function parseRunnerArgs(args, deps = {
|
|
|
58928
60274
|
codeServerBin: editorRuntime.codeServerBin,
|
|
58929
60275
|
editorRuntime: editorRuntime.status
|
|
58930
60276
|
});
|
|
58931
|
-
|
|
60277
|
+
assertRunnerConnectionDependencies(dependencyStatus);
|
|
58932
60278
|
const claudeCodeAvailable = await resolveClaudeCodeAvailability(deps, cwd);
|
|
58933
60279
|
return {
|
|
58934
60280
|
kandanUrl,
|
|
@@ -58939,6 +60285,7 @@ async function parseRunnerArgs(args, deps = {
|
|
|
58939
60285
|
cwd,
|
|
58940
60286
|
codexBin,
|
|
58941
60287
|
codexUrl: stringValue7(values, "codex-url"),
|
|
60288
|
+
launchSource: electronAutoConnectLaunchSource(),
|
|
58942
60289
|
launchTui: values.get("launch-tui") === true,
|
|
58943
60290
|
fast: values.get("fast") === true,
|
|
58944
60291
|
logFile: stringValue7(values, "log-file"),
|
|
@@ -58968,6 +60315,9 @@ function runnerRuntimeDefaultsFromValues(values) {
|
|
|
58968
60315
|
allowPortForwardingByDefault: true
|
|
58969
60316
|
};
|
|
58970
60317
|
}
|
|
60318
|
+
function electronAutoConnectLaunchSource() {
|
|
60319
|
+
return process.env.LINZUMI_ELECTRON_AUTO_CONNECT_RUNNER === "1" ? "electron_auto_connect" : void 0;
|
|
60320
|
+
}
|
|
58971
60321
|
function kandanUrlValue(values) {
|
|
58972
60322
|
const apiUrl = stringValue7(values, "api-url");
|
|
58973
60323
|
const linzumiUrl = stringValue7(values, "linzumi-url");
|