@linzumi/cli 0.0.74-beta → 0.0.76-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 +1522 -163
- 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.76-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,281 @@ 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, realpathSync as realpathSync5 } 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
|
+
const cwdRules = existingPathAliases(request.cwd).flatMap((path2) => [
|
|
16789
|
+
`(allow file-read* (subpath ${sandboxString(path2)}))`,
|
|
16790
|
+
`(allow file-write* (subpath ${sandboxString(path2)}))`
|
|
16791
|
+
]).join("\n");
|
|
16792
|
+
return [
|
|
16793
|
+
"(version 1)",
|
|
16794
|
+
"(deny default)",
|
|
16795
|
+
"(allow process*)",
|
|
16796
|
+
"(allow signal (target self))",
|
|
16797
|
+
"(allow sysctl-read)",
|
|
16798
|
+
"(allow file-read-metadata)",
|
|
16799
|
+
'(allow file-read-data (literal "/"))',
|
|
16800
|
+
'(allow file-read* (literal "/dev/null"))',
|
|
16801
|
+
'(allow file-read* (literal "/dev/random"))',
|
|
16802
|
+
'(allow file-read* (literal "/dev/urandom"))',
|
|
16803
|
+
readableRules,
|
|
16804
|
+
writableTempRules,
|
|
16805
|
+
cwdRules
|
|
16806
|
+
].join("\n");
|
|
16807
|
+
}
|
|
16808
|
+
function createBoundedOutputBuffer() {
|
|
16809
|
+
let bytes = 0;
|
|
16810
|
+
let output = "";
|
|
16811
|
+
let isTruncated = false;
|
|
16812
|
+
return {
|
|
16813
|
+
append: (chunk) => {
|
|
16814
|
+
const text2 = Buffer.isBuffer(chunk) ? chunk.toString("utf8") : chunk;
|
|
16815
|
+
const remaining = maxCapturedOutputBytes - bytes;
|
|
16816
|
+
if (remaining <= 0) {
|
|
16817
|
+
isTruncated = true;
|
|
16818
|
+
return;
|
|
16819
|
+
}
|
|
16820
|
+
const buffer = Buffer.from(text2, "utf8");
|
|
16821
|
+
if (buffer.byteLength <= remaining) {
|
|
16822
|
+
bytes += buffer.byteLength;
|
|
16823
|
+
output += text2;
|
|
16824
|
+
return;
|
|
16825
|
+
}
|
|
16826
|
+
bytes = maxCapturedOutputBytes;
|
|
16827
|
+
output += buffer.subarray(0, remaining).toString("utf8");
|
|
16828
|
+
isTruncated = true;
|
|
16829
|
+
},
|
|
16830
|
+
value: () => output,
|
|
16831
|
+
truncated: () => isTruncated
|
|
16832
|
+
};
|
|
16833
|
+
}
|
|
16834
|
+
function normalizedSandboxKind(value) {
|
|
16835
|
+
switch (value) {
|
|
16836
|
+
case void 0:
|
|
16837
|
+
case "":
|
|
16838
|
+
return void 0;
|
|
16839
|
+
case "bubblewrap":
|
|
16840
|
+
case "macos-seatbelt":
|
|
16841
|
+
return value;
|
|
16842
|
+
default:
|
|
16843
|
+
throw new Error(`unsupported remote Codex sandbox: ${value}`);
|
|
16844
|
+
}
|
|
16845
|
+
}
|
|
16846
|
+
function requiredSandboxBin(kind, env) {
|
|
16847
|
+
const value = env.LINZUMI_REMOTE_CODEX_SANDBOX_BIN;
|
|
16848
|
+
if (value === void 0 || value.trim() === "") {
|
|
16849
|
+
throw new Error(`LINZUMI_REMOTE_CODEX_SANDBOX_BIN is required for ${kind}`);
|
|
16850
|
+
}
|
|
16851
|
+
if (!isAbsolute3(value)) {
|
|
16852
|
+
throw new Error("LINZUMI_REMOTE_CODEX_SANDBOX_BIN must be absolute");
|
|
16853
|
+
}
|
|
16854
|
+
return value;
|
|
16855
|
+
}
|
|
16856
|
+
function parentDirs(path2) {
|
|
16857
|
+
const parts = path2.split("/").filter((part) => part !== "");
|
|
16858
|
+
const parents = parts.slice(0, -1);
|
|
16859
|
+
return parents.map(
|
|
16860
|
+
(_part, index) => `/${parents.slice(0, index + 1).join("/")}`
|
|
16861
|
+
);
|
|
16862
|
+
}
|
|
16863
|
+
function uniqueStrings2(values) {
|
|
16864
|
+
return Array.from(new Set(values));
|
|
16865
|
+
}
|
|
16866
|
+
function existingPathAliases(path2) {
|
|
16867
|
+
return uniqueStrings2([path2, realpathSync5(path2)]);
|
|
16868
|
+
}
|
|
16869
|
+
function sandboxString(value) {
|
|
16870
|
+
return JSON.stringify(value);
|
|
16871
|
+
}
|
|
16872
|
+
var maxCapturedOutputBytes, linuxReadOnlyRoots, macosReadOnlyRoots, macosWritableTempRoots;
|
|
16873
|
+
var init_remoteCodexSandboxRunner = __esm({
|
|
16874
|
+
"src/remoteCodexSandboxRunner.ts"() {
|
|
16875
|
+
"use strict";
|
|
16876
|
+
maxCapturedOutputBytes = 512 * 1024;
|
|
16877
|
+
linuxReadOnlyRoots = [
|
|
16878
|
+
"/bin",
|
|
16879
|
+
"/etc/pki",
|
|
16880
|
+
"/etc/ssl",
|
|
16881
|
+
"/lib",
|
|
16882
|
+
"/lib64",
|
|
16883
|
+
"/nix/store",
|
|
16884
|
+
"/usr",
|
|
16885
|
+
"/usr/local"
|
|
16886
|
+
];
|
|
16887
|
+
macosReadOnlyRoots = [
|
|
16888
|
+
"/System",
|
|
16889
|
+
"/Library",
|
|
16890
|
+
"/etc",
|
|
16891
|
+
"/private/etc",
|
|
16892
|
+
"/usr",
|
|
16893
|
+
"/bin",
|
|
16894
|
+
"/sbin",
|
|
16895
|
+
"/opt/homebrew",
|
|
16896
|
+
"/nix/store"
|
|
16897
|
+
];
|
|
16898
|
+
macosWritableTempRoots = ["/tmp", "/private/tmp"];
|
|
16899
|
+
}
|
|
16900
|
+
});
|
|
16901
|
+
|
|
16138
16902
|
// src/runner.ts
|
|
16139
|
-
import { spawn as
|
|
16903
|
+
import { spawn as spawn8, spawnSync as spawnSync4 } from "node:child_process";
|
|
16140
16904
|
import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
|
|
16141
16905
|
import {
|
|
16142
16906
|
chmodSync as chmodSync2,
|
|
@@ -16144,13 +16908,13 @@ import {
|
|
|
16144
16908
|
mkdirSync as mkdirSync9,
|
|
16145
16909
|
mkdtempSync as mkdtempSync4,
|
|
16146
16910
|
readdirSync as readdirSync2,
|
|
16147
|
-
realpathSync as
|
|
16911
|
+
realpathSync as realpathSync6,
|
|
16148
16912
|
rmSync as rmSync4,
|
|
16149
16913
|
statSync
|
|
16150
16914
|
} from "node:fs";
|
|
16151
16915
|
import { createServer as createServer3 } from "node:http";
|
|
16152
16916
|
import { hostname as hostname2, tmpdir as tmpdir3 } from "node:os";
|
|
16153
|
-
import { dirname as
|
|
16917
|
+
import { dirname as dirname10, isAbsolute as isAbsolute4, join as join14, resolve as resolve7 } from "node:path";
|
|
16154
16918
|
async function runLocalCodexRunner(options) {
|
|
16155
16919
|
const log = makeRunnerLogger(options);
|
|
16156
16920
|
const cleanup = {
|
|
@@ -16173,6 +16937,7 @@ async function runLocalCodexRunner(options) {
|
|
|
16173
16937
|
cwd: options.cwd,
|
|
16174
16938
|
workspace: runnerWorkspaceSlug(options) ?? null,
|
|
16175
16939
|
linzumiUrl: options.kandanUrl,
|
|
16940
|
+
launchSource: options.launchSource,
|
|
16176
16941
|
configPath: options.runnerLockConfigPath
|
|
16177
16942
|
});
|
|
16178
16943
|
cleanup.actions.push(() => runnerLock.release());
|
|
@@ -16214,6 +16979,7 @@ async function runThreadCodexWorker(options) {
|
|
|
16214
16979
|
}
|
|
16215
16980
|
async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
16216
16981
|
const agentProviders = availableRunnerAgentProviders(options);
|
|
16982
|
+
const localCodexAppServerAvailable = hasLocalCodexAppServerCapability(options);
|
|
16217
16983
|
const allowedForwardPorts = options.allowedForwardPorts ?? [];
|
|
16218
16984
|
const liveForwardPorts = new Set(allowedForwardPorts);
|
|
16219
16985
|
const managedForwardPorts = /* @__PURE__ */ new Set();
|
|
@@ -16274,6 +17040,11 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
16274
17040
|
});
|
|
16275
17041
|
const startupAllowedCwds = normalizeAllowedCwds(options.allowedCwds);
|
|
16276
17042
|
const allowedCwds = { value: [...startupAllowedCwds] };
|
|
17043
|
+
const remoteCodexSandboxRunner = options.remoteCodexSandboxRunner ?? createConfiguredRemoteCodexSandboxRunner({
|
|
17044
|
+
env: process.env,
|
|
17045
|
+
platform: process.platform
|
|
17046
|
+
});
|
|
17047
|
+
const activeRemoteCodexExecRequests = /* @__PURE__ */ new Map();
|
|
16277
17048
|
const missingAllowedCwds = {
|
|
16278
17049
|
value: normalizeAllowedCwds(options.missingAllowedCwds ?? [])
|
|
16279
17050
|
};
|
|
@@ -16290,6 +17061,10 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
16290
17061
|
queuedCandidates: /* @__PURE__ */ new Map()
|
|
16291
17062
|
};
|
|
16292
17063
|
cleanup.actions.push(() => {
|
|
17064
|
+
for (const controller of activeRemoteCodexExecRequests.values()) {
|
|
17065
|
+
controller.abort(new Error("local runner stopped"));
|
|
17066
|
+
}
|
|
17067
|
+
activeRemoteCodexExecRequests.clear();
|
|
16293
17068
|
if (localEditorState.value.status === "running") {
|
|
16294
17069
|
localEditorState.value.process.kill("SIGINT");
|
|
16295
17070
|
localEditorState.value.collaboration?.process.kill("SIGINT");
|
|
@@ -16314,8 +17089,8 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
16314
17089
|
};
|
|
16315
17090
|
});
|
|
16316
17091
|
const capabilitiesPayload = () => ({
|
|
16317
|
-
codexAppServer:
|
|
16318
|
-
codexRemoteTui:
|
|
17092
|
+
codexAppServer: localCodexAppServerAvailable,
|
|
17093
|
+
codexRemoteTui: localCodexAppServerAvailable,
|
|
16319
17094
|
agentProviders,
|
|
16320
17095
|
defaultAgentProvider: "codex",
|
|
16321
17096
|
startInstance: allowedCwds.value.length > 0,
|
|
@@ -16331,6 +17106,8 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
16331
17106
|
portForwarding: liveForwardPorts.size > 0,
|
|
16332
17107
|
tcpForwarding: true,
|
|
16333
17108
|
linzumiMcp: true,
|
|
17109
|
+
remoteCodexExecution: remoteCodexSandboxRunner !== void 0 && allowedCwds.value.length > 0,
|
|
17110
|
+
remoteCodexExecutionStatus: remoteCodexSandboxRunner === void 0 ? "sandbox_unavailable" : allowedCwds.value.length > 0 ? "ready" : "cwd_unavailable",
|
|
16334
17111
|
allowedPorts: Array.from(liveForwardPorts).sort(
|
|
16335
17112
|
(left, right) => left - right
|
|
16336
17113
|
),
|
|
@@ -16380,18 +17157,15 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
16380
17157
|
const replacedRunners = replacementRunnerSummaries(
|
|
16381
17158
|
objectValue(joinResponse)?.replaced_runners
|
|
16382
17159
|
);
|
|
16383
|
-
const started = options.codexUrl === void 0 ? await startOwnedCodexAppServer(options) : void 0;
|
|
17160
|
+
const started = options.codexUrl === void 0 && localCodexAppServerAvailable ? await startOwnedCodexAppServer(options) : void 0;
|
|
16384
17161
|
if (started !== void 0) {
|
|
16385
17162
|
cleanup.actions.push(() => {
|
|
16386
17163
|
started.stop();
|
|
16387
17164
|
});
|
|
16388
17165
|
}
|
|
16389
17166
|
const codexUrl = options.codexUrl ?? started?.url;
|
|
16390
|
-
if (codexUrl === void 0) {
|
|
16391
|
-
throw new Error("missing codex app-server websocket URL");
|
|
16392
|
-
}
|
|
16393
17167
|
if (started !== void 0) {
|
|
16394
|
-
const appServerPort = explicitUrlPort(
|
|
17168
|
+
const appServerPort = explicitUrlPort(started.url);
|
|
16395
17169
|
if (appServerPort !== void 0) {
|
|
16396
17170
|
markCommanderManagedForwardPort(appServerPort, {
|
|
16397
17171
|
processName: "Codex app-server",
|
|
@@ -17081,15 +17855,20 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
17081
17855
|
};
|
|
17082
17856
|
void state.exited.then(handleExitAfterInitialStatus);
|
|
17083
17857
|
};
|
|
17084
|
-
const codex = await connectCodexAppServer(codexUrl);
|
|
17085
|
-
|
|
17858
|
+
const codex = codexUrl === void 0 ? void 0 : await connectCodexAppServer(codexUrl);
|
|
17859
|
+
if (codex !== void 0) {
|
|
17860
|
+
cleanup.actions.push(() => codex.close());
|
|
17861
|
+
}
|
|
17862
|
+
if (options.channelSession !== void 0 && codex === void 0) {
|
|
17863
|
+
throw new Error("channel session requires a Codex app-server connection");
|
|
17864
|
+
}
|
|
17086
17865
|
const seq = { value: 0 };
|
|
17087
17866
|
const discoveredCodexThreads = { value: [] };
|
|
17088
17867
|
const runtimeDefaults = runnerRuntimeDefaults(options);
|
|
17089
17868
|
const instancePayload = {
|
|
17090
17869
|
instanceId,
|
|
17091
17870
|
clientId,
|
|
17092
|
-
codexUrl,
|
|
17871
|
+
...codexUrl === void 0 ? {} : { codexUrl },
|
|
17093
17872
|
tuiLaunched: options.launchTui,
|
|
17094
17873
|
cwd: options.cwd,
|
|
17095
17874
|
hostname: runnerHost,
|
|
@@ -17108,7 +17887,7 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
17108
17887
|
workspace: runnerWorkspaceSlug(options) ?? null,
|
|
17109
17888
|
version: linzumiCliVersion,
|
|
17110
17889
|
instanceId,
|
|
17111
|
-
codexUrl,
|
|
17890
|
+
codexUrl: codexUrl ?? null,
|
|
17112
17891
|
replacedRunners
|
|
17113
17892
|
});
|
|
17114
17893
|
const channelSession = options.channelSession === void 0 ? void 0 : await attachChannelSession({
|
|
@@ -17422,6 +18201,8 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
17422
18201
|
options,
|
|
17423
18202
|
agentProviders,
|
|
17424
18203
|
allowedCwds,
|
|
18204
|
+
remoteCodexSandboxRunner,
|
|
18205
|
+
activeRemoteCodexExecRequests,
|
|
17425
18206
|
activeClaudeCodeSessions,
|
|
17426
18207
|
pendingClaudeCodeApprovals,
|
|
17427
18208
|
ensureClaudeCodeForwardPortSession,
|
|
@@ -17444,7 +18225,7 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
17444
18225
|
const heartbeatPayload = () => ({
|
|
17445
18226
|
instanceId,
|
|
17446
18227
|
clientId,
|
|
17447
|
-
codexUrl,
|
|
18228
|
+
...codexUrl === void 0 ? {} : { codexUrl },
|
|
17448
18229
|
cwd: options.cwd,
|
|
17449
18230
|
hostname: runnerHost,
|
|
17450
18231
|
workspace: runnerWorkspaceSlug(options) ?? null,
|
|
@@ -17476,10 +18257,13 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
17476
18257
|
);
|
|
17477
18258
|
cleanup.actions.push(() => forwardTcp.close());
|
|
17478
18259
|
const channelCodexThreadId = channelSession?.currentCodexThreadId();
|
|
17479
|
-
if (options.launchTui &&
|
|
18260
|
+
if (options.launchTui && codex === void 0) {
|
|
18261
|
+
throw new Error("Codex TUI requires a Codex app-server connection");
|
|
18262
|
+
}
|
|
18263
|
+
if (options.launchTui && codex !== void 0 && channelCodexThreadId !== void 0) {
|
|
17480
18264
|
await prepareCodexThreadForTuiResume(codex, channelCodexThreadId);
|
|
17481
18265
|
}
|
|
17482
|
-
const tui = options.launchTui ? launchCodexTui(
|
|
18266
|
+
const tui = options.launchTui && codexUrl !== void 0 ? launchCodexTui(
|
|
17483
18267
|
options.codexBin,
|
|
17484
18268
|
codexUrl,
|
|
17485
18269
|
options.cwd,
|
|
@@ -17492,7 +18276,7 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
17492
18276
|
tui.kill("SIGINT");
|
|
17493
18277
|
});
|
|
17494
18278
|
}
|
|
17495
|
-
codex
|
|
18279
|
+
codex?.onNotification((notification) => {
|
|
17496
18280
|
seq.value += 1;
|
|
17497
18281
|
const params = notification.params ?? {};
|
|
17498
18282
|
const logPayload = codexNotificationConsoleLogPayload(
|
|
@@ -17747,6 +18531,8 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
|
|
|
17747
18531
|
options,
|
|
17748
18532
|
agentProviders,
|
|
17749
18533
|
allowedCwds,
|
|
18534
|
+
remoteCodexSandboxRunner,
|
|
18535
|
+
activeRemoteCodexExecRequests,
|
|
17750
18536
|
activeClaudeCodeSessions,
|
|
17751
18537
|
pendingClaudeCodeApprovals,
|
|
17752
18538
|
ensureClaudeCodeForwardPortSession,
|
|
@@ -17831,6 +18617,8 @@ function controlThreadId(control) {
|
|
|
17831
18617
|
case "forward_tcp_open":
|
|
17832
18618
|
case "forward_tcp_send":
|
|
17833
18619
|
case "forward_tcp_close":
|
|
18620
|
+
case "remote_codex_exec":
|
|
18621
|
+
case "remote_codex_exec_cancel":
|
|
17834
18622
|
case "update_thread_interaction_access": {
|
|
17835
18623
|
const threadId = stringValue(control.threadId)?.trim();
|
|
17836
18624
|
return threadId === void 0 || threadId === "" ? void 0 : threadId;
|
|
@@ -17940,9 +18728,15 @@ function replacementRunnerSummaries(value) {
|
|
|
17940
18728
|
});
|
|
17941
18729
|
}
|
|
17942
18730
|
function makeRunnerLogger(options) {
|
|
18731
|
+
const consoleReporter = options.launchTui && options.consoleReporter === void 0 ? void 0 : (event, payload) => {
|
|
18732
|
+
if (!options.launchTui) {
|
|
18733
|
+
reportRunnerConsoleEvent(event, payload);
|
|
18734
|
+
}
|
|
18735
|
+
options.consoleReporter?.(event, payload);
|
|
18736
|
+
};
|
|
17943
18737
|
return createRunnerLogger(
|
|
17944
18738
|
options.logFile ?? defaultRunnerLogFile(),
|
|
17945
|
-
|
|
18739
|
+
consoleReporter
|
|
17946
18740
|
);
|
|
17947
18741
|
}
|
|
17948
18742
|
function installCleanupHandlers(close) {
|
|
@@ -17971,7 +18765,7 @@ function launchCodexTui(codexBin, codexUrl, cwd, codexThreadId, session, fast) {
|
|
|
17971
18765
|
cwd,
|
|
17972
18766
|
purpose: "codex.tui"
|
|
17973
18767
|
});
|
|
17974
|
-
const child =
|
|
18768
|
+
const child = spawn8(codexBin, args, {
|
|
17975
18769
|
cwd,
|
|
17976
18770
|
env: process.env,
|
|
17977
18771
|
stdio: "inherit"
|
|
@@ -18098,7 +18892,29 @@ async function resumeCodexThreadForReconnect(codex, codexThreadId, resumeOverrid
|
|
|
18098
18892
|
);
|
|
18099
18893
|
}
|
|
18100
18894
|
}
|
|
18101
|
-
async function applyControl(codex, kandan, topic, instanceId, options, agentProviders, allowedCwds, activeClaudeCodeSessions, pendingClaudeCodeApprovals, ensureClaudeCodeForwardPortSession, disposeClaudeCodeForwardPortSession, control, log, onStartedThread, onThreadProcessStart) {
|
|
18895
|
+
async function applyControl(codex, kandan, topic, instanceId, options, agentProviders, allowedCwds, remoteCodexSandboxRunner, activeRemoteCodexExecRequests, activeClaudeCodeSessions, pendingClaudeCodeApprovals, ensureClaudeCodeForwardPortSession, disposeClaudeCodeForwardPortSession, control, log, onStartedThread, onThreadProcessStart) {
|
|
18896
|
+
if (codex === void 0) {
|
|
18897
|
+
switch (control.type) {
|
|
18898
|
+
case "remote_codex_exec":
|
|
18899
|
+
case "remote_codex_exec_cancel":
|
|
18900
|
+
return await applyRemoteCodexExecControl(
|
|
18901
|
+
control,
|
|
18902
|
+
instanceId,
|
|
18903
|
+
allowedCwds.value,
|
|
18904
|
+
remoteCodexSandboxRunner,
|
|
18905
|
+
activeRemoteCodexExecRequests,
|
|
18906
|
+
log
|
|
18907
|
+
);
|
|
18908
|
+
default:
|
|
18909
|
+
return {
|
|
18910
|
+
instanceId,
|
|
18911
|
+
controlType: control.type,
|
|
18912
|
+
requestId: "requestId" in control ? stringValue(control.requestId) ?? null : null,
|
|
18913
|
+
ok: false,
|
|
18914
|
+
error: "agent_provider_unavailable:codex"
|
|
18915
|
+
};
|
|
18916
|
+
}
|
|
18917
|
+
}
|
|
18102
18918
|
switch (control.type) {
|
|
18103
18919
|
case "start_instance": {
|
|
18104
18920
|
const cwd = resolveAllowedCwd(control.cwd, allowedCwds.value);
|
|
@@ -18597,6 +19413,26 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
|
|
|
18597
19413
|
case "suggest_tasks": {
|
|
18598
19414
|
return suggestRunnerTasks(control, options, allowedCwds.value);
|
|
18599
19415
|
}
|
|
19416
|
+
case "remote_codex_exec": {
|
|
19417
|
+
return await applyRemoteCodexExecControl(
|
|
19418
|
+
control,
|
|
19419
|
+
instanceId,
|
|
19420
|
+
allowedCwds.value,
|
|
19421
|
+
remoteCodexSandboxRunner,
|
|
19422
|
+
activeRemoteCodexExecRequests,
|
|
19423
|
+
log
|
|
19424
|
+
);
|
|
19425
|
+
}
|
|
19426
|
+
case "remote_codex_exec_cancel": {
|
|
19427
|
+
return await applyRemoteCodexExecControl(
|
|
19428
|
+
control,
|
|
19429
|
+
instanceId,
|
|
19430
|
+
allowedCwds.value,
|
|
19431
|
+
remoteCodexSandboxRunner,
|
|
19432
|
+
activeRemoteCodexExecRequests,
|
|
19433
|
+
log
|
|
19434
|
+
);
|
|
19435
|
+
}
|
|
18600
19436
|
case "start_turn": {
|
|
18601
19437
|
const response = await codex.request("turn/start", {
|
|
18602
19438
|
threadId: control.threadId,
|
|
@@ -18769,6 +19605,55 @@ async function applyControl(codex, kandan, topic, instanceId, options, agentProv
|
|
|
18769
19605
|
return { instanceId, controlType: control.type, skipped: true };
|
|
18770
19606
|
}
|
|
18771
19607
|
}
|
|
19608
|
+
async function applyRemoteCodexExecControl(control, instanceId, allowedCwds, remoteCodexSandboxRunner, activeRemoteCodexExecRequests, log) {
|
|
19609
|
+
switch (control.type) {
|
|
19610
|
+
case "remote_codex_exec": {
|
|
19611
|
+
const requestId = stringValue(control.requestId)?.trim();
|
|
19612
|
+
const abortController = new AbortController();
|
|
19613
|
+
if (requestId !== void 0 && requestId !== "") {
|
|
19614
|
+
activeRemoteCodexExecRequests.set(requestId, abortController);
|
|
19615
|
+
}
|
|
19616
|
+
const result = await handleRemoteCodexExecControl(control, {
|
|
19617
|
+
instanceId,
|
|
19618
|
+
allowedCwds,
|
|
19619
|
+
sandboxRunner: remoteCodexSandboxRunner,
|
|
19620
|
+
abortSignal: abortController.signal
|
|
19621
|
+
});
|
|
19622
|
+
if (requestId !== void 0 && requestId !== "") {
|
|
19623
|
+
activeRemoteCodexExecRequests.delete(requestId);
|
|
19624
|
+
}
|
|
19625
|
+
log("remote_codex_exec.handled", {
|
|
19626
|
+
requestId: stringValue(control.requestId) ?? null,
|
|
19627
|
+
ok: result.ok === true,
|
|
19628
|
+
error: typeof result.error === "string" ? result.error : null
|
|
19629
|
+
});
|
|
19630
|
+
return result;
|
|
19631
|
+
}
|
|
19632
|
+
case "remote_codex_exec_cancel": {
|
|
19633
|
+
const requestId = stringValue(control.requestId)?.trim();
|
|
19634
|
+
if (requestId === void 0 || requestId === "") {
|
|
19635
|
+
return {
|
|
19636
|
+
instanceId,
|
|
19637
|
+
controlType: control.type,
|
|
19638
|
+
ok: false,
|
|
19639
|
+
error: "request_id_required"
|
|
19640
|
+
};
|
|
19641
|
+
}
|
|
19642
|
+
const activeRequest = activeRemoteCodexExecRequests.get(requestId);
|
|
19643
|
+
if (activeRequest !== void 0) {
|
|
19644
|
+
activeRequest.abort(new Error("remote_codex_exec_cancelled"));
|
|
19645
|
+
activeRemoteCodexExecRequests.delete(requestId);
|
|
19646
|
+
}
|
|
19647
|
+
return {
|
|
19648
|
+
instanceId,
|
|
19649
|
+
controlType: control.type,
|
|
19650
|
+
requestId,
|
|
19651
|
+
ok: true,
|
|
19652
|
+
cancelled: activeRequest !== void 0
|
|
19653
|
+
};
|
|
19654
|
+
}
|
|
19655
|
+
}
|
|
19656
|
+
}
|
|
18772
19657
|
function startInstanceFailureReason(stage, error) {
|
|
18773
19658
|
const detail = truncateFailureDetail(
|
|
18774
19659
|
error instanceof Error ? error.message : String(error)
|
|
@@ -18901,6 +19786,18 @@ function availableRunnerAgentProviders(options) {
|
|
|
18901
19786
|
return ["codex"];
|
|
18902
19787
|
}
|
|
18903
19788
|
}
|
|
19789
|
+
function hasLocalCodexAppServerCapability(options) {
|
|
19790
|
+
if (options.codexUrl !== void 0) {
|
|
19791
|
+
return true;
|
|
19792
|
+
}
|
|
19793
|
+
switch (options.dependencyStatus?.codex.available) {
|
|
19794
|
+
case false:
|
|
19795
|
+
return false;
|
|
19796
|
+
case true:
|
|
19797
|
+
case void 0:
|
|
19798
|
+
return true;
|
|
19799
|
+
}
|
|
19800
|
+
}
|
|
18904
19801
|
function startInstanceAgentProvider(control) {
|
|
18905
19802
|
const value = stringValue(control.agentProvider)?.trim();
|
|
18906
19803
|
switch (value) {
|
|
@@ -20362,7 +21259,7 @@ async function spawnLocalThreadRunnerProcess(options) {
|
|
|
20362
21259
|
cwd: options.cwd,
|
|
20363
21260
|
purpose: "linzumi.thread_runner"
|
|
20364
21261
|
});
|
|
20365
|
-
const child =
|
|
21262
|
+
const child = spawn8(process.execPath, nodeArgs, {
|
|
20366
21263
|
cwd: options.cwd,
|
|
20367
21264
|
env,
|
|
20368
21265
|
stdio: ["inherit", "inherit", "inherit", "ipc"]
|
|
@@ -20477,7 +21374,7 @@ function threadRunnerScriptPath(scriptPath, cwd) {
|
|
|
20477
21374
|
"cannot fork thread runner without current CLI script path"
|
|
20478
21375
|
);
|
|
20479
21376
|
}
|
|
20480
|
-
return
|
|
21377
|
+
return isAbsolute4(scriptPath) ? scriptPath : resolve7(cwd, scriptPath);
|
|
20481
21378
|
}
|
|
20482
21379
|
function threadRunnerLoaderExecArgv(execArgv, index = 0) {
|
|
20483
21380
|
const current = execArgv[index];
|
|
@@ -20812,7 +21709,7 @@ function configuredAllowedCwds(values, options = {}) {
|
|
|
20812
21709
|
if (options.createMissing === true) {
|
|
20813
21710
|
mkdirSync9(absolutePath, { recursive: true });
|
|
20814
21711
|
}
|
|
20815
|
-
const realPath =
|
|
21712
|
+
const realPath = realpathSync6(absolutePath);
|
|
20816
21713
|
allowedCwds.push(
|
|
20817
21714
|
...realPath === absolutePath ? [realPath] : [realPath, absolutePath]
|
|
20818
21715
|
);
|
|
@@ -20859,7 +21756,7 @@ function browseRunnerDirectory(control, options) {
|
|
|
20859
21756
|
const requestId = stringValue(control.requestId) ?? null;
|
|
20860
21757
|
const requestedPath = stringValue(control.path) ?? currentHomeDirectory();
|
|
20861
21758
|
try {
|
|
20862
|
-
const currentPath =
|
|
21759
|
+
const currentPath = realpathSync6(resolve7(expandUserPath(requestedPath)));
|
|
20863
21760
|
const stats = statSync(currentPath);
|
|
20864
21761
|
if (!stats.isDirectory()) {
|
|
20865
21762
|
return {
|
|
@@ -20870,7 +21767,7 @@ function browseRunnerDirectory(control, options) {
|
|
|
20870
21767
|
error: "not_directory"
|
|
20871
21768
|
};
|
|
20872
21769
|
}
|
|
20873
|
-
const parent =
|
|
21770
|
+
const parent = dirname10(currentPath);
|
|
20874
21771
|
const entries = readdirSync2(currentPath, { withFileTypes: true }).filter((entry) => entry.isDirectory()).filter((entry) => visibleRunnerDirectoryEntryName(entry.name)).map((entry) => {
|
|
20875
21772
|
const path2 = join14(currentPath, entry.name);
|
|
20876
21773
|
return {
|
|
@@ -20982,7 +21879,7 @@ function createRunnerProject(control, options, allowedCwds) {
|
|
|
20982
21879
|
error: cleanupError === void 0 ? `git_init_failed:${gitFailure}` : `git_init_cleanup_failed:${cleanupError}`
|
|
20983
21880
|
};
|
|
20984
21881
|
}
|
|
20985
|
-
const projectRealPath =
|
|
21882
|
+
const projectRealPath = realpathSync6(projectPath);
|
|
20986
21883
|
const persistedAllowedCwds = addAllowedCwdForLinzumiUrl(
|
|
20987
21884
|
projectRealPath,
|
|
20988
21885
|
options.kandanUrl
|
|
@@ -21090,6 +21987,7 @@ var init_runner = __esm({
|
|
|
21090
21987
|
init_linzumiContext();
|
|
21091
21988
|
init_localCapabilities();
|
|
21092
21989
|
init_localConfig();
|
|
21990
|
+
init_remoteCodexExecutionContext();
|
|
21093
21991
|
init_helloLinzumiProject();
|
|
21094
21992
|
init_localForwarding();
|
|
21095
21993
|
init_localEditor();
|
|
@@ -21109,6 +22007,7 @@ var init_runner = __esm({
|
|
|
21109
22007
|
init_threadCodexWorkerIpc();
|
|
21110
22008
|
init_signupTaskSuggestions();
|
|
21111
22009
|
init_userFacingErrors();
|
|
22010
|
+
init_remoteCodexSandboxRunner();
|
|
21112
22011
|
THREAD_RUNNER_READY_TIMEOUT_MS = 3e4;
|
|
21113
22012
|
claudeSessionStoreSequenceHighWater = /* @__PURE__ */ new Map();
|
|
21114
22013
|
ClaudeCodeOutputPostError = class extends Error {
|
|
@@ -21122,9 +22021,9 @@ var init_runner = __esm({
|
|
|
21122
22021
|
});
|
|
21123
22022
|
|
|
21124
22023
|
// src/kandanTls.ts
|
|
21125
|
-
import { existsSync as
|
|
22024
|
+
import { existsSync as existsSync10, readFileSync as readFileSync11 } from "node:fs";
|
|
21126
22025
|
import { Agent } from "undici";
|
|
21127
|
-
import
|
|
22026
|
+
import WsWebSocket from "ws";
|
|
21128
22027
|
function kandanTlsTrustFromEnv() {
|
|
21129
22028
|
return kandanTlsTrustFromCaFile(process.env.KANDAN_TLS_CA_FILE);
|
|
21130
22029
|
}
|
|
@@ -21133,7 +22032,7 @@ function kandanTlsTrustFromCaFile(caFile) {
|
|
|
21133
22032
|
return void 0;
|
|
21134
22033
|
}
|
|
21135
22034
|
const trimmed = caFile.trim();
|
|
21136
|
-
if (!
|
|
22035
|
+
if (!existsSync10(trimmed)) {
|
|
21137
22036
|
throw new Error(`KANDAN_TLS_CA_FILE does not exist: ${trimmed}`);
|
|
21138
22037
|
}
|
|
21139
22038
|
const ca = readFileSync11(trimmed, "utf8");
|
|
@@ -39919,7 +40818,7 @@ var init_RemoveFileError = __esm({
|
|
|
39919
40818
|
});
|
|
39920
40819
|
|
|
39921
40820
|
// ../../node_modules/@inquirer/external-editor/dist/esm/index.js
|
|
39922
|
-
import { spawn as
|
|
40821
|
+
import { spawn as spawn10, spawnSync as spawnSync5 } from "child_process";
|
|
39923
40822
|
import { readFileSync as readFileSync14, unlinkSync as unlinkSync3, writeFileSync as writeFileSync10 } from "fs";
|
|
39924
40823
|
import path from "node:path";
|
|
39925
40824
|
import os from "node:os";
|
|
@@ -40075,7 +40974,7 @@ var init_esm5 = __esm({
|
|
|
40075
40974
|
}
|
|
40076
40975
|
launchEditorAsync(callback) {
|
|
40077
40976
|
try {
|
|
40078
|
-
const editorProcess =
|
|
40977
|
+
const editorProcess = spawn10(this.editor.bin, this.editor.args.concat([this.tempFile]), { stdio: "inherit" });
|
|
40079
40978
|
editorProcess.on("exit", (code) => {
|
|
40080
40979
|
this.lastExitStatus = code;
|
|
40081
40980
|
setImmediate(callback);
|
|
@@ -41409,9 +42308,9 @@ __export(signupFlow_exports, {
|
|
|
41409
42308
|
signupTaskSuggestionWaitMessageForTest: () => signupTaskSuggestionWaitMessageForTest,
|
|
41410
42309
|
toggleProjectPickerSelectionForTest: () => toggleProjectPickerSelectionForTest
|
|
41411
42310
|
});
|
|
41412
|
-
import { spawn as
|
|
42311
|
+
import { spawn as spawn11, spawnSync as spawnSync6 } from "node:child_process";
|
|
41413
42312
|
import {
|
|
41414
|
-
existsSync as
|
|
42313
|
+
existsSync as existsSync13,
|
|
41415
42314
|
constants as fsConstants,
|
|
41416
42315
|
mkdirSync as mkdirSync12,
|
|
41417
42316
|
mkdtempSync as mkdtempSync5,
|
|
@@ -41423,7 +42322,7 @@ import {
|
|
|
41423
42322
|
} from "node:fs";
|
|
41424
42323
|
import { access } from "node:fs/promises";
|
|
41425
42324
|
import { homedir as homedir12, tmpdir as tmpdir4 } from "node:os";
|
|
41426
|
-
import { delimiter as delimiter3, dirname as
|
|
42325
|
+
import { delimiter as delimiter3, dirname as dirname13, join as join17, resolve as resolve9 } from "node:path";
|
|
41427
42326
|
import { stdin as defaultStdin, stdout as defaultStdout } from "node:process";
|
|
41428
42327
|
import { emitKeypressEvents } from "node:readline";
|
|
41429
42328
|
function signupHelpText() {
|
|
@@ -41522,7 +42421,7 @@ function defaultSignupDraftStore(serviceUrl) {
|
|
|
41522
42421
|
const path2 = defaultSignupDraftPath(serviceUrl);
|
|
41523
42422
|
return {
|
|
41524
42423
|
read: () => {
|
|
41525
|
-
if (!
|
|
42424
|
+
if (!existsSync13(path2)) {
|
|
41526
42425
|
return void 0;
|
|
41527
42426
|
}
|
|
41528
42427
|
let parsed;
|
|
@@ -41537,7 +42436,7 @@ function defaultSignupDraftStore(serviceUrl) {
|
|
|
41537
42436
|
return comparableServiceUrl(parsed.serviceUrl) === comparableServiceUrl(serviceUrl) ? parsed : void 0;
|
|
41538
42437
|
},
|
|
41539
42438
|
write: (draft) => {
|
|
41540
|
-
mkdirSync12(
|
|
42439
|
+
mkdirSync12(dirname13(path2), { recursive: true });
|
|
41541
42440
|
writeFileSync11(path2, `${JSON.stringify(draft, null, 2)}
|
|
41542
42441
|
`, {
|
|
41543
42442
|
encoding: "utf8",
|
|
@@ -41551,7 +42450,7 @@ function defaultSignupDraftStore(serviceUrl) {
|
|
|
41551
42450
|
}
|
|
41552
42451
|
function defaultSignupDraftPath(serviceUrl) {
|
|
41553
42452
|
return join17(
|
|
41554
|
-
|
|
42453
|
+
dirname13(localConfigPath()),
|
|
41555
42454
|
`signup-draft.${localConfigScopeFileStem(serviceUrl)}.json`
|
|
41556
42455
|
);
|
|
41557
42456
|
}
|
|
@@ -41585,7 +42484,7 @@ function defaultSignupTaskCacheStore(serviceUrl) {
|
|
|
41585
42484
|
}
|
|
41586
42485
|
}
|
|
41587
42486
|
};
|
|
41588
|
-
mkdirSync12(
|
|
42487
|
+
mkdirSync12(dirname13(path2), { recursive: true });
|
|
41589
42488
|
writeFileSync11(path2, `${JSON.stringify(next, null, 2)}
|
|
41590
42489
|
`, {
|
|
41591
42490
|
encoding: "utf8",
|
|
@@ -41596,12 +42495,12 @@ function defaultSignupTaskCacheStore(serviceUrl) {
|
|
|
41596
42495
|
}
|
|
41597
42496
|
function defaultSignupTaskCachePath(serviceUrl) {
|
|
41598
42497
|
return join17(
|
|
41599
|
-
|
|
42498
|
+
dirname13(localConfigPath()),
|
|
41600
42499
|
`signup-task-cache.${localConfigScopeFileStem(serviceUrl)}.json`
|
|
41601
42500
|
);
|
|
41602
42501
|
}
|
|
41603
42502
|
function readSignupTaskCache(path2) {
|
|
41604
|
-
if (!
|
|
42503
|
+
if (!existsSync13(path2)) {
|
|
41605
42504
|
return { version: 1, entries: {} };
|
|
41606
42505
|
}
|
|
41607
42506
|
let parsed;
|
|
@@ -42916,7 +43815,7 @@ async function openUrlInBrowser(url) {
|
|
|
42916
43815
|
}
|
|
42917
43816
|
const [command, args] = process.platform === "darwin" ? ["open", [url]] : process.platform === "win32" ? ["cmd", ["/c", "start", "", url]] : ["xdg-open", [url]];
|
|
42918
43817
|
await new Promise((resolve11, reject) => {
|
|
42919
|
-
const child =
|
|
43818
|
+
const child = spawn11(command, args, { stdio: "ignore", detached: true });
|
|
42920
43819
|
child.once("spawn", () => {
|
|
42921
43820
|
child.unref();
|
|
42922
43821
|
resolve11();
|
|
@@ -44114,7 +45013,7 @@ function parseTaskSuggestionResponse2(response) {
|
|
|
44114
45013
|
}
|
|
44115
45014
|
function runProcess3(args) {
|
|
44116
45015
|
return new Promise((resolveProcess, rejectProcess) => {
|
|
44117
|
-
const child =
|
|
45016
|
+
const child = spawn11(args.command, [...args.args], {
|
|
44118
45017
|
cwd: args.cwd,
|
|
44119
45018
|
stdio: ["pipe", "ignore", "pipe"]
|
|
44120
45019
|
});
|
|
@@ -44156,7 +45055,7 @@ function runProcess3(args) {
|
|
|
44156
45055
|
}
|
|
44157
45056
|
function runProcessCapture(args) {
|
|
44158
45057
|
return new Promise((resolveProcess) => {
|
|
44159
|
-
const child =
|
|
45058
|
+
const child = spawn11(args.command, [...args.args], {
|
|
44160
45059
|
cwd: args.cwd,
|
|
44161
45060
|
stdio: ["ignore", "pipe", "ignore"]
|
|
44162
45061
|
});
|
|
@@ -44374,7 +45273,7 @@ function spawnSyncGitOutput(args, cwd) {
|
|
|
44374
45273
|
}
|
|
44375
45274
|
function probeToolWithArgs(command, args, cwd) {
|
|
44376
45275
|
return new Promise((resolve11) => {
|
|
44377
|
-
const child =
|
|
45276
|
+
const child = spawn11(command, [...args], {
|
|
44378
45277
|
cwd,
|
|
44379
45278
|
stdio: ["ignore", "pipe", "pipe"]
|
|
44380
45279
|
});
|
|
@@ -44412,7 +45311,7 @@ async function discoverCodeRoots(homeDir) {
|
|
|
44412
45311
|
const candidates = ["src", "code", "projects"].map(
|
|
44413
45312
|
(name) => join17(homeDir, name)
|
|
44414
45313
|
);
|
|
44415
|
-
return candidates.filter((path2) =>
|
|
45314
|
+
return candidates.filter((path2) => existsSync13(path2)).flatMap((path2) => discoveredProjectNames(path2));
|
|
44416
45315
|
}
|
|
44417
45316
|
function discoveredProjectNames(root) {
|
|
44418
45317
|
try {
|
|
@@ -44516,25 +45415,25 @@ function looksLikeProject(path2) {
|
|
|
44516
45415
|
"pnpm-lock.yaml",
|
|
44517
45416
|
"yarn.lock",
|
|
44518
45417
|
"package-lock.json"
|
|
44519
|
-
].some((name) =>
|
|
45418
|
+
].some((name) => existsSync13(join17(path2, name)));
|
|
44520
45419
|
}
|
|
44521
45420
|
function detectProjectLanguage(path2) {
|
|
44522
|
-
if (
|
|
45421
|
+
if (existsSync13(join17(path2, "pyproject.toml")) || existsSync13(join17(path2, "requirements.txt"))) {
|
|
44523
45422
|
return "Python";
|
|
44524
45423
|
}
|
|
44525
|
-
if (
|
|
45424
|
+
if (existsSync13(join17(path2, "Cargo.toml"))) {
|
|
44526
45425
|
return "Rust";
|
|
44527
45426
|
}
|
|
44528
|
-
if (
|
|
45427
|
+
if (existsSync13(join17(path2, "go.mod"))) {
|
|
44529
45428
|
return "Go";
|
|
44530
45429
|
}
|
|
44531
|
-
if (
|
|
45430
|
+
if (existsSync13(join17(path2, "mix.exs"))) {
|
|
44532
45431
|
return "Elixir";
|
|
44533
45432
|
}
|
|
44534
|
-
if (
|
|
45433
|
+
if (existsSync13(join17(path2, "tsconfig.json")) || packageJsonMentionsTypeScript(path2)) {
|
|
44535
45434
|
return "TypeScript";
|
|
44536
45435
|
}
|
|
44537
|
-
if (
|
|
45436
|
+
if (existsSync13(join17(path2, "package.json"))) {
|
|
44538
45437
|
return "JavaScript";
|
|
44539
45438
|
}
|
|
44540
45439
|
return "Project";
|
|
@@ -44550,7 +45449,7 @@ function packageJsonMentionsTypeScript(path2) {
|
|
|
44550
45449
|
}
|
|
44551
45450
|
}
|
|
44552
45451
|
function hasGitMetadata(path2) {
|
|
44553
|
-
return
|
|
45452
|
+
return existsSync13(join17(path2, ".git"));
|
|
44554
45453
|
}
|
|
44555
45454
|
function childDirectories(root) {
|
|
44556
45455
|
try {
|
|
@@ -44672,7 +45571,7 @@ secure mission control for all your agents on your computers
|
|
|
44672
45571
|
init_runner();
|
|
44673
45572
|
init_claudeCodeSession();
|
|
44674
45573
|
init_authCache();
|
|
44675
|
-
import { existsSync as
|
|
45574
|
+
import { existsSync as existsSync14, readFileSync as readFileSync16, realpathSync as realpathSync7 } from "node:fs";
|
|
44676
45575
|
import { homedir as homedir13 } from "node:os";
|
|
44677
45576
|
import { resolve as resolve10 } from "node:path";
|
|
44678
45577
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
@@ -44734,8 +45633,8 @@ init_kandanTls();
|
|
|
44734
45633
|
init_protocol();
|
|
44735
45634
|
init_json();
|
|
44736
45635
|
init_defaultUrls();
|
|
44737
|
-
import { existsSync as
|
|
44738
|
-
import { dirname as
|
|
45636
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync10, readFileSync as readFileSync12, writeFileSync as writeFileSync8 } from "node:fs";
|
|
45637
|
+
import { dirname as dirname11, join as join15 } from "node:path";
|
|
44739
45638
|
import { homedir as homedir10 } from "node:os";
|
|
44740
45639
|
async function runAgentCliCommand(args, deps = {
|
|
44741
45640
|
fetchImpl: fetch,
|
|
@@ -45453,10 +46352,10 @@ function authorizationHeaders(token) {
|
|
|
45453
46352
|
return { authorization: `Bearer ${token}` };
|
|
45454
46353
|
}
|
|
45455
46354
|
function readOptionalTextFile(path2) {
|
|
45456
|
-
return
|
|
46355
|
+
return existsSync11(path2) ? readFileSync12(path2, "utf8") : void 0;
|
|
45457
46356
|
}
|
|
45458
46357
|
function writeTextFile(path2, content) {
|
|
45459
|
-
mkdirSync10(
|
|
46358
|
+
mkdirSync10(dirname11(path2), { recursive: true });
|
|
45460
46359
|
writeFileSync8(path2, content);
|
|
45461
46360
|
}
|
|
45462
46361
|
function readStoredAgentTokenFile(path2, readTextFile = readOptionalTextFile) {
|
|
@@ -45544,7 +46443,7 @@ init_helloLinzumiProject();
|
|
|
45544
46443
|
// src/commanderDaemon.ts
|
|
45545
46444
|
init_runnerLogger();
|
|
45546
46445
|
import {
|
|
45547
|
-
existsSync as
|
|
46446
|
+
existsSync as existsSync12,
|
|
45548
46447
|
closeSync as closeSync2,
|
|
45549
46448
|
mkdirSync as mkdirSync11,
|
|
45550
46449
|
openSync as openSync3,
|
|
@@ -45553,8 +46452,8 @@ import {
|
|
|
45553
46452
|
writeFileSync as writeFileSync9
|
|
45554
46453
|
} from "node:fs";
|
|
45555
46454
|
import { homedir as homedir11 } from "node:os";
|
|
45556
|
-
import { dirname as
|
|
45557
|
-
import { execFileSync, spawn as
|
|
46455
|
+
import { dirname as dirname12, join as join16, resolve as resolve8 } from "node:path";
|
|
46456
|
+
import { execFileSync, spawn as spawn9 } from "node:child_process";
|
|
45558
46457
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
45559
46458
|
var connectedMarkers = ["Connected to Linzumi", "Runner connected:"];
|
|
45560
46459
|
function commanderStatusDir() {
|
|
@@ -45586,7 +46485,7 @@ function startCommanderDaemon(options) {
|
|
|
45586
46485
|
logFile
|
|
45587
46486
|
];
|
|
45588
46487
|
mkdirSync11(statusDir, { recursive: true });
|
|
45589
|
-
mkdirSync11(
|
|
46488
|
+
mkdirSync11(dirname12(logFile), { recursive: true });
|
|
45590
46489
|
const out = openSync3(logFile, "a");
|
|
45591
46490
|
const err = openSync3(logFile, "a");
|
|
45592
46491
|
writeCliAuditEvent(
|
|
@@ -45599,7 +46498,7 @@ function startCommanderDaemon(options) {
|
|
|
45599
46498
|
},
|
|
45600
46499
|
{ sessionId: options.runnerId }
|
|
45601
46500
|
);
|
|
45602
|
-
const child = (options.spawnImpl ??
|
|
46501
|
+
const child = (options.spawnImpl ?? spawn9)(nodeBin, command, {
|
|
45603
46502
|
detached: true,
|
|
45604
46503
|
stdio: ["ignore", out, err],
|
|
45605
46504
|
env: process.env
|
|
@@ -45638,7 +46537,7 @@ function startCommanderDaemon(options) {
|
|
|
45638
46537
|
}
|
|
45639
46538
|
function commanderDaemonStatus(runnerId, statusDir = commanderStatusDir(), processIdentityReader = readProcessIdentity) {
|
|
45640
46539
|
const statusFile = commanderStatusFile(runnerId, statusDir);
|
|
45641
|
-
if (!
|
|
46540
|
+
if (!existsSync12(statusFile)) {
|
|
45642
46541
|
return { status: "missing", runnerId, statusFile };
|
|
45643
46542
|
}
|
|
45644
46543
|
const record = parseRecord(readFileSync13(statusFile, "utf8"));
|
|
@@ -45646,7 +46545,7 @@ function commanderDaemonStatus(runnerId, statusDir = commanderStatusDir(), proce
|
|
|
45646
46545
|
}
|
|
45647
46546
|
async function waitForCommanderDaemon(options) {
|
|
45648
46547
|
const now = options.now ?? (() => Date.now());
|
|
45649
|
-
const readTextFile = options.readTextFile ?? ((path2) =>
|
|
46548
|
+
const readTextFile = options.readTextFile ?? ((path2) => existsSync12(path2) ? readFileSync13(path2, "utf8") : void 0);
|
|
45650
46549
|
const statusImpl = options.statusImpl ?? commanderDaemonStatus;
|
|
45651
46550
|
const deadline = now() + options.timeoutMs;
|
|
45652
46551
|
while (now() <= deadline) {
|
|
@@ -57610,6 +58509,8 @@ function createLinzumiMcpApiClient(options) {
|
|
|
57610
58509
|
sendChannelMessage: (params) => request("POST", `${apiPrefix}/channel-message`, params),
|
|
57611
58510
|
prepareMessageUploads: (params) => request("POST", `${apiPrefix}/message-uploads/prepare`, params),
|
|
57612
58511
|
attachMessageFiles: (params) => request("POST", `${apiPrefix}/message-files/attach`, params),
|
|
58512
|
+
prepareCustomEmoji: (params) => request("POST", `${apiPrefix}/custom-emoji/prepare`, params),
|
|
58513
|
+
renameCustomEmoji: (params) => request("POST", `${apiPrefix}/custom-emoji/rename`, params),
|
|
57613
58514
|
sendThreadReply: (params) => request("POST", `${apiPrefix}/thread-reply`, params),
|
|
57614
58515
|
sendDm: (params) => request("POST", `${apiPrefix}/dm`, params),
|
|
57615
58516
|
dmOwner: (params) => request("POST", `${apiPrefix}/dm-owner`, params),
|
|
@@ -57620,6 +58521,17 @@ function createLinzumiMcpApiClient(options) {
|
|
|
57620
58521
|
// src/mcpServer.ts
|
|
57621
58522
|
init_mcpConfig();
|
|
57622
58523
|
init_oauth();
|
|
58524
|
+
init_protocol();
|
|
58525
|
+
var maxCustomEmojiNameLength = 64;
|
|
58526
|
+
function normalizeCustomEmojiNameForSchema(value) {
|
|
58527
|
+
return value.trim().replace(/^:+/, "").replace(/:+$/, "").toLowerCase();
|
|
58528
|
+
}
|
|
58529
|
+
var customEmojiNameSchema = external_exports2.string().min(1).refine(
|
|
58530
|
+
(value) => normalizeCustomEmojiNameForSchema(value).length <= maxCustomEmojiNameLength,
|
|
58531
|
+
{
|
|
58532
|
+
message: `Custom emoji shortcode name must be at most ${maxCustomEmojiNameLength} characters after trimming surrounding colons.`
|
|
58533
|
+
}
|
|
58534
|
+
);
|
|
57623
58535
|
var mcpFlagDefinitions = /* @__PURE__ */ new Map([
|
|
57624
58536
|
["api-url", { kind: "value" }],
|
|
57625
58537
|
["token", { kind: "value" }],
|
|
@@ -57680,6 +58592,10 @@ Tools:
|
|
|
57680
58592
|
linzumi_dm_owner Send a plain-text DM to the configured owner username.
|
|
57681
58593
|
linzumi_get_vault_values
|
|
57682
58594
|
Request approved named vault values for a thread.
|
|
58595
|
+
linzumi_upload_custom_emoji
|
|
58596
|
+
Upload a local image as a workspace custom emoji.
|
|
58597
|
+
linzumi_rename_custom_emoji
|
|
58598
|
+
Rename an existing workspace custom emoji.
|
|
57683
58599
|
|
|
57684
58600
|
Auth:
|
|
57685
58601
|
Uses --token, LINZUMI_MCP_ACCESS_TOKEN, or cached local runner OAuth from linzumi auth.
|
|
@@ -57801,6 +58717,43 @@ async function runMcpServer(args) {
|
|
|
57801
58717
|
{},
|
|
57802
58718
|
async (params) => mcpJsonResult(await client.listVaultSecrets(params))
|
|
57803
58719
|
);
|
|
58720
|
+
server.tool(
|
|
58721
|
+
"linzumi_upload_custom_emoji",
|
|
58722
|
+
"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:.",
|
|
58723
|
+
{
|
|
58724
|
+
name: customEmojiNameSchema.describe(
|
|
58725
|
+
"Custom emoji shortcode name, with or without surrounding colons."
|
|
58726
|
+
),
|
|
58727
|
+
file: external_exports2.string().min(1).describe(
|
|
58728
|
+
"Local PNG/WebP/GIF/JPEG file path to upload. Prefer transparent PNG for generated emoji."
|
|
58729
|
+
),
|
|
58730
|
+
workspace: external_exports2.string().optional().describe("Workspace slug. Omit to use the authenticated token scope.")
|
|
58731
|
+
},
|
|
58732
|
+
async (params) => mcpJsonResult(
|
|
58733
|
+
await uploadCustomEmojiWithClient({
|
|
58734
|
+
client,
|
|
58735
|
+
cwd,
|
|
58736
|
+
kandanUrl,
|
|
58737
|
+
name: params.name,
|
|
58738
|
+
file: params.file,
|
|
58739
|
+
workspace: params.workspace
|
|
58740
|
+
})
|
|
58741
|
+
)
|
|
58742
|
+
);
|
|
58743
|
+
server.tool(
|
|
58744
|
+
"linzumi_rename_custom_emoji",
|
|
58745
|
+
"Rename an existing workspace custom emoji. The new name may include surrounding colons; Linzumi stores the normalized shortcode without colons.",
|
|
58746
|
+
{
|
|
58747
|
+
emoji_id: external_exports2.union([external_exports2.string(), external_exports2.number().int().positive()]).describe(
|
|
58748
|
+
"Workspace custom emoji id returned by linzumi_upload_custom_emoji or workspace emoji listings."
|
|
58749
|
+
),
|
|
58750
|
+
name: customEmojiNameSchema.describe(
|
|
58751
|
+
"New shortcode name, with or without surrounding colons."
|
|
58752
|
+
),
|
|
58753
|
+
workspace: external_exports2.string().optional().describe("Workspace slug. Omit to use the authenticated token scope.")
|
|
58754
|
+
},
|
|
58755
|
+
async (params) => mcpJsonResult(await client.renameCustomEmoji(params))
|
|
58756
|
+
);
|
|
57804
58757
|
server.tool(
|
|
57805
58758
|
"linzumi_dm_owner",
|
|
57806
58759
|
"Send a plain-text DM to the configured Commander owner. Requires dm.write and a visible owner username.",
|
|
@@ -57936,6 +58889,69 @@ async function uploadFilesWithClient(args) {
|
|
|
57936
58889
|
uploaded_file_ids: uploadedFileIds
|
|
57937
58890
|
});
|
|
57938
58891
|
}
|
|
58892
|
+
async function uploadCustomEmojiWithClient(args) {
|
|
58893
|
+
const file = await commanderUploadFileForPath(args.cwd, args.file);
|
|
58894
|
+
const prepare = await args.client.prepareCustomEmoji({
|
|
58895
|
+
...args.workspace === void 0 ? {} : { workspace: args.workspace },
|
|
58896
|
+
name: args.name,
|
|
58897
|
+
file_name: file.fileName,
|
|
58898
|
+
content_type: file.contentType,
|
|
58899
|
+
size_bytes: file.sizeBytes
|
|
58900
|
+
});
|
|
58901
|
+
const upload = objectValue(prepare.upload);
|
|
58902
|
+
const uploadUrl = stringValue(upload?.upload_url);
|
|
58903
|
+
const uploadMethod = stringValue(upload?.upload_method) ?? "PUT";
|
|
58904
|
+
if (uploadUrl === void 0) {
|
|
58905
|
+
throw new Error("Linzumi custom emoji prepare response missing upload_url");
|
|
58906
|
+
}
|
|
58907
|
+
const bytes = await readFile2(file.path);
|
|
58908
|
+
const uploadBody = bytes.buffer.slice(
|
|
58909
|
+
bytes.byteOffset,
|
|
58910
|
+
bytes.byteOffset + bytes.byteLength
|
|
58911
|
+
);
|
|
58912
|
+
const response = await fetch(
|
|
58913
|
+
resolveLinzumiUploadUrl(args.kandanUrl, uploadUrl),
|
|
58914
|
+
{
|
|
58915
|
+
method: uploadMethod,
|
|
58916
|
+
headers: { "content-type": file.contentType },
|
|
58917
|
+
body: uploadBody
|
|
58918
|
+
}
|
|
58919
|
+
);
|
|
58920
|
+
if (!response.ok) {
|
|
58921
|
+
const fallbackError = `${response.status} ${response.statusText}`;
|
|
58922
|
+
const responseText = await response.text();
|
|
58923
|
+
const trimmedResponseText = responseText.trim();
|
|
58924
|
+
const error = trimmedResponseText === "" ? fallbackError : (() => {
|
|
58925
|
+
try {
|
|
58926
|
+
const parsedError = JSON.parse(trimmedResponseText);
|
|
58927
|
+
return isJsonObject(parsedError) && typeof parsedError.error === "string" ? parsedError.error : trimmedResponseText;
|
|
58928
|
+
} catch {
|
|
58929
|
+
return trimmedResponseText;
|
|
58930
|
+
}
|
|
58931
|
+
})();
|
|
58932
|
+
throw new Error(`Linzumi custom emoji upload failed: ${error}`);
|
|
58933
|
+
}
|
|
58934
|
+
const parsed = await response.json();
|
|
58935
|
+
if (!isJsonObject(parsed)) {
|
|
58936
|
+
throw new Error("Linzumi custom emoji upload returned non-object JSON");
|
|
58937
|
+
}
|
|
58938
|
+
const emoji = objectValue(parsed.custom_emoji);
|
|
58939
|
+
if (emoji === void 0) {
|
|
58940
|
+
throw new Error(
|
|
58941
|
+
"Linzumi custom emoji upload response missing custom_emoji"
|
|
58942
|
+
);
|
|
58943
|
+
}
|
|
58944
|
+
return {
|
|
58945
|
+
ok: true,
|
|
58946
|
+
workspace: prepare.workspace,
|
|
58947
|
+
emoji,
|
|
58948
|
+
asset_id: stringValue(parsed.asset_id),
|
|
58949
|
+
id: integerValue(emoji?.id),
|
|
58950
|
+
name: stringValue(emoji?.name),
|
|
58951
|
+
shortcode: stringValue(emoji?.shortcode),
|
|
58952
|
+
image_url: stringValue(emoji?.image_url)
|
|
58953
|
+
};
|
|
58954
|
+
}
|
|
57939
58955
|
function targetWithDefaultThread(target, defaultThreadId) {
|
|
57940
58956
|
const existingThreadId = stringValue(target.thread_id);
|
|
57941
58957
|
if (existingThreadId !== void 0 || defaultThreadId === void 0) {
|
|
@@ -58124,6 +59140,338 @@ function required(values, key) {
|
|
|
58124
59140
|
return value;
|
|
58125
59141
|
}
|
|
58126
59142
|
|
|
59143
|
+
// src/remoteCodexHarnessWorker.ts
|
|
59144
|
+
init_channelSession();
|
|
59145
|
+
init_codexAppServer();
|
|
59146
|
+
init_phoenix();
|
|
59147
|
+
init_runnerLogger();
|
|
59148
|
+
init_userFacingErrors();
|
|
59149
|
+
init_version();
|
|
59150
|
+
var configEnvKey = "LINZUMI_REMOTE_CODEX_HARNESS_CONFIG_B64";
|
|
59151
|
+
var remoteHarnessEnvironmentId = "linzumi-remote-codex-harness";
|
|
59152
|
+
async function runRemoteCodexHarnessWorkerFromEnv(env = process.env) {
|
|
59153
|
+
await runRemoteCodexHarnessWorker(remoteCodexHarnessWorkerConfigFromEnv(env));
|
|
59154
|
+
}
|
|
59155
|
+
async function runRemoteCodexHarnessWorker(config, deps = {}) {
|
|
59156
|
+
const resolvedDeps = {
|
|
59157
|
+
startCodexAppServer,
|
|
59158
|
+
connectCodexAppServer,
|
|
59159
|
+
connectPhoenixClient,
|
|
59160
|
+
attachChannelSession,
|
|
59161
|
+
waitUntilShutdown: defaultWaitUntilShutdown,
|
|
59162
|
+
writeStdout: (chunk) => process.stdout.write(chunk),
|
|
59163
|
+
log: writeCliAuditEvent,
|
|
59164
|
+
...deps
|
|
59165
|
+
};
|
|
59166
|
+
const started = await resolvedDeps.startCodexAppServer(
|
|
59167
|
+
config.codexBin,
|
|
59168
|
+
config.workerCwd,
|
|
59169
|
+
{
|
|
59170
|
+
model: config.model,
|
|
59171
|
+
reasoningEffort: config.reasoningEffort,
|
|
59172
|
+
fast: config.fast,
|
|
59173
|
+
inheritEnv: false,
|
|
59174
|
+
env: remoteHarnessCodexEnv(process.env, config.execServerUrl)
|
|
59175
|
+
}
|
|
59176
|
+
);
|
|
59177
|
+
let kandan;
|
|
59178
|
+
let codex;
|
|
59179
|
+
let session;
|
|
59180
|
+
const cleanup = async () => {
|
|
59181
|
+
await session?.close();
|
|
59182
|
+
codex?.close();
|
|
59183
|
+
kandan?.close();
|
|
59184
|
+
started.stop();
|
|
59185
|
+
};
|
|
59186
|
+
const cleanupOnce = onceAsync(cleanup);
|
|
59187
|
+
try {
|
|
59188
|
+
codex = await resolvedDeps.connectCodexAppServer(started.url);
|
|
59189
|
+
await registerExecServerEnvironment(codex, config.execServerUrl);
|
|
59190
|
+
kandan = await resolvedDeps.connectPhoenixClient(
|
|
59191
|
+
config.kandanUrl,
|
|
59192
|
+
config.token
|
|
59193
|
+
);
|
|
59194
|
+
const runnerTopic = `local_runner:${config.runnerId}`;
|
|
59195
|
+
const runnerJoinPayload = () => remoteHarnessRunnerJoinPayload(config);
|
|
59196
|
+
const pendingControls = [];
|
|
59197
|
+
const controlDispatcher = { value: void 0 };
|
|
59198
|
+
kandan.onControl((control) => {
|
|
59199
|
+
const dispatcher = controlDispatcher.value;
|
|
59200
|
+
if (dispatcher === void 0) {
|
|
59201
|
+
pendingControls.push(control);
|
|
59202
|
+
return;
|
|
59203
|
+
}
|
|
59204
|
+
dispatcher(control);
|
|
59205
|
+
});
|
|
59206
|
+
await kandan.join(runnerTopic, runnerJoinPayload(), {
|
|
59207
|
+
rejoinPayload: runnerJoinPayload
|
|
59208
|
+
});
|
|
59209
|
+
session = await resolvedDeps.attachChannelSession({
|
|
59210
|
+
kandan,
|
|
59211
|
+
codex,
|
|
59212
|
+
topic: runnerTopic,
|
|
59213
|
+
instanceId: config.instanceId,
|
|
59214
|
+
options: {
|
|
59215
|
+
kandanUrl: config.kandanUrl,
|
|
59216
|
+
token: config.token,
|
|
59217
|
+
runnerId: config.runnerId,
|
|
59218
|
+
cwd: config.cwd,
|
|
59219
|
+
codexBin: config.codexBin,
|
|
59220
|
+
fast: config.fast,
|
|
59221
|
+
launchTui: false,
|
|
59222
|
+
enablePortForwardWatch: false,
|
|
59223
|
+
channelSession: {
|
|
59224
|
+
workspaceSlug: config.workspaceSlug,
|
|
59225
|
+
channelSlug: config.channelSlug,
|
|
59226
|
+
kandanThreadId: config.kandanThreadId,
|
|
59227
|
+
rootSeq: config.rootSeq,
|
|
59228
|
+
startCodexThread: true,
|
|
59229
|
+
linzumiContext: config.linzumiContext,
|
|
59230
|
+
listenUser: config.listenUser,
|
|
59231
|
+
model: config.model,
|
|
59232
|
+
reasoningEffort: config.reasoningEffort,
|
|
59233
|
+
sandbox: config.sandbox,
|
|
59234
|
+
approvalPolicy: config.approvalPolicy,
|
|
59235
|
+
codexEnvironmentId: remoteHarnessEnvironmentId,
|
|
59236
|
+
allowPortForwardingByDefault: config.allowPortForwardingByDefault
|
|
59237
|
+
}
|
|
59238
|
+
},
|
|
59239
|
+
log: resolvedDeps.log
|
|
59240
|
+
});
|
|
59241
|
+
kandan.onReconnect(() => session?.handleKandanReconnect());
|
|
59242
|
+
const dispatchControl = (control) => {
|
|
59243
|
+
const liveSession = session;
|
|
59244
|
+
const liveKandan = kandan;
|
|
59245
|
+
if (liveSession === void 0 || liveKandan === void 0) {
|
|
59246
|
+
pendingControls.push(control);
|
|
59247
|
+
return;
|
|
59248
|
+
}
|
|
59249
|
+
void liveSession.handleControl(control).then(
|
|
59250
|
+
(response) => response === void 0 ? void 0 : liveKandan.push(runnerTopic, "codex_response", response)
|
|
59251
|
+
).catch(
|
|
59252
|
+
(error) => liveKandan.push(runnerTopic, "codex_error", {
|
|
59253
|
+
instanceId: config.instanceId,
|
|
59254
|
+
message: runnerActionErrorMessage(error)
|
|
59255
|
+
})
|
|
59256
|
+
).catch((error) => {
|
|
59257
|
+
resolvedDeps.log("remote_codex_harness.control_push_failed", {
|
|
59258
|
+
message: error instanceof Error ? error.message : String(error)
|
|
59259
|
+
});
|
|
59260
|
+
});
|
|
59261
|
+
};
|
|
59262
|
+
controlDispatcher.value = dispatchControl;
|
|
59263
|
+
pendingControls.splice(0).forEach(dispatchControl);
|
|
59264
|
+
codex.onNotification((notification) => {
|
|
59265
|
+
const params = notification.params ?? {};
|
|
59266
|
+
session?.handleCodexNotification(notification.method, params);
|
|
59267
|
+
});
|
|
59268
|
+
await session.startThreadMessageTurn({
|
|
59269
|
+
seq: config.sourceSeq,
|
|
59270
|
+
body: config.workDescription
|
|
59271
|
+
});
|
|
59272
|
+
resolvedDeps.writeStdout(
|
|
59273
|
+
`LINZUMI_REMOTE_CODEX_HARNESS_READY ${config.readyToken}
|
|
59274
|
+
`
|
|
59275
|
+
);
|
|
59276
|
+
const stopReason = await Promise.race([
|
|
59277
|
+
resolvedDeps.waitUntilShutdown(cleanupOnce).then(() => ({ type: "shutdown" })),
|
|
59278
|
+
waitForCodexAppServerExit(started.process).then((exit) => ({
|
|
59279
|
+
type: "codex_exit",
|
|
59280
|
+
exit
|
|
59281
|
+
}))
|
|
59282
|
+
]);
|
|
59283
|
+
if (stopReason.type === "codex_exit") {
|
|
59284
|
+
resolvedDeps.log("remote_codex_harness.codex_app_server_exited", {
|
|
59285
|
+
code: stopReason.exit.code,
|
|
59286
|
+
signal: stopReason.exit.signal
|
|
59287
|
+
});
|
|
59288
|
+
await cleanupOnce();
|
|
59289
|
+
}
|
|
59290
|
+
} catch (error) {
|
|
59291
|
+
await cleanupOnce();
|
|
59292
|
+
throw error;
|
|
59293
|
+
}
|
|
59294
|
+
}
|
|
59295
|
+
function remoteCodexHarnessWorkerConfigFromEnv(env) {
|
|
59296
|
+
const encoded = env[configEnvKey];
|
|
59297
|
+
if (encoded === void 0 || encoded.trim() === "") {
|
|
59298
|
+
throw new Error(`${configEnvKey} is required`);
|
|
59299
|
+
}
|
|
59300
|
+
return remoteCodexHarnessWorkerConfigFromJson(
|
|
59301
|
+
JSON.parse(Buffer.from(encoded, "base64url").toString("utf8"))
|
|
59302
|
+
);
|
|
59303
|
+
}
|
|
59304
|
+
function remoteCodexHarnessWorkerConfigFromJson(value) {
|
|
59305
|
+
const input = requireObject(value);
|
|
59306
|
+
const config = {
|
|
59307
|
+
kandanUrl: requiredString2(input, "kandanUrl"),
|
|
59308
|
+
token: requiredString2(input, "token"),
|
|
59309
|
+
runnerId: requiredString2(input, "runnerId"),
|
|
59310
|
+
instanceId: requiredString2(input, "instanceId"),
|
|
59311
|
+
workspaceSlug: requiredString2(input, "workspaceSlug"),
|
|
59312
|
+
channelSlug: requiredString2(input, "channelSlug"),
|
|
59313
|
+
kandanThreadId: requiredString2(input, "kandanThreadId"),
|
|
59314
|
+
rootSeq: requiredPositiveInteger(input, "rootSeq"),
|
|
59315
|
+
sourceSeq: requiredPositiveInteger(input, "sourceSeq"),
|
|
59316
|
+
cwd: requiredString2(input, "cwd"),
|
|
59317
|
+
workerCwd: requiredString2(input, "workerCwd"),
|
|
59318
|
+
workDescription: requiredString2(input, "workDescription"),
|
|
59319
|
+
readyToken: requiredString2(input, "readyToken"),
|
|
59320
|
+
codexBin: requiredString2(input, "codexBin"),
|
|
59321
|
+
execServerUrl: requiredString2(input, "execServerUrl"),
|
|
59322
|
+
listenUser: requiredString2(input, "listenUser"),
|
|
59323
|
+
...optionalStringField(input, "model"),
|
|
59324
|
+
...optionalStringField(input, "reasoningEffort"),
|
|
59325
|
+
...optionalStringField(input, "approvalPolicy"),
|
|
59326
|
+
...optionalStringField(input, "sandbox"),
|
|
59327
|
+
...optionalBooleanField(input, "fast"),
|
|
59328
|
+
...optionalBooleanField(input, "allowPortForwardingByDefault"),
|
|
59329
|
+
...optionalObjectField(input, "linzumiContext")
|
|
59330
|
+
};
|
|
59331
|
+
return config;
|
|
59332
|
+
}
|
|
59333
|
+
async function registerExecServerEnvironment(codex, execServerUrl) {
|
|
59334
|
+
const response = await codex.request("environment/add", {
|
|
59335
|
+
environmentId: remoteHarnessEnvironmentId,
|
|
59336
|
+
execServerUrl
|
|
59337
|
+
});
|
|
59338
|
+
assertJsonRpcOk(response, "environment/add");
|
|
59339
|
+
}
|
|
59340
|
+
function assertJsonRpcOk(response, method) {
|
|
59341
|
+
if ("error" in response) {
|
|
59342
|
+
throw new Error(`${method} failed: ${response.error.message}`);
|
|
59343
|
+
}
|
|
59344
|
+
}
|
|
59345
|
+
function remoteHarnessCodexEnv(sourceEnv, execServerUrl) {
|
|
59346
|
+
const env = {
|
|
59347
|
+
CODEX_EXEC_SERVER_URL: execServerUrl,
|
|
59348
|
+
LINZUMI_REMOTE_CODEX_HARNESS: "1"
|
|
59349
|
+
};
|
|
59350
|
+
for (const key of remoteHarnessCodexEnvAllowlist) {
|
|
59351
|
+
const value = sourceEnv[key];
|
|
59352
|
+
if (value !== void 0 && value.trim() !== "") {
|
|
59353
|
+
env[key] = value;
|
|
59354
|
+
}
|
|
59355
|
+
}
|
|
59356
|
+
return env;
|
|
59357
|
+
}
|
|
59358
|
+
var remoteHarnessCodexEnvAllowlist = [
|
|
59359
|
+
"PATH",
|
|
59360
|
+
"HOME",
|
|
59361
|
+
"TMPDIR",
|
|
59362
|
+
"SHELL",
|
|
59363
|
+
"USER",
|
|
59364
|
+
"LOGNAME",
|
|
59365
|
+
"CODEX_HOME",
|
|
59366
|
+
"XDG_CONFIG_HOME",
|
|
59367
|
+
"XDG_DATA_HOME",
|
|
59368
|
+
"SSL_CERT_FILE",
|
|
59369
|
+
"NIX_SSL_CERT_FILE",
|
|
59370
|
+
"NODE_EXTRA_CA_CERTS"
|
|
59371
|
+
];
|
|
59372
|
+
function remoteHarnessRunnerJoinPayload(config) {
|
|
59373
|
+
return {
|
|
59374
|
+
clientName: "kandan-remote-codex-harness-worker",
|
|
59375
|
+
clientId: config.instanceId,
|
|
59376
|
+
connectionMode: "session_worker",
|
|
59377
|
+
runnerPid: process.pid,
|
|
59378
|
+
version: linzumiCliVersion,
|
|
59379
|
+
cwd: config.cwd,
|
|
59380
|
+
workspace: config.workspaceSlug,
|
|
59381
|
+
channel: config.channelSlug,
|
|
59382
|
+
capabilities: {
|
|
59383
|
+
codexAppServer: true,
|
|
59384
|
+
defaultAgentProvider: "codex",
|
|
59385
|
+
agentProviders: ["codex"],
|
|
59386
|
+
remoteCodexExecution: false,
|
|
59387
|
+
allowedCwdSuggestions: [],
|
|
59388
|
+
allowedCwdProjects: [],
|
|
59389
|
+
portForwarding: false,
|
|
59390
|
+
tcpForwarding: false,
|
|
59391
|
+
linzumiMcp: true
|
|
59392
|
+
}
|
|
59393
|
+
};
|
|
59394
|
+
}
|
|
59395
|
+
function defaultWaitUntilShutdown(cleanup) {
|
|
59396
|
+
return new Promise((resolve11, reject) => {
|
|
59397
|
+
const finish = () => {
|
|
59398
|
+
cleanup().then(resolve11, reject);
|
|
59399
|
+
};
|
|
59400
|
+
process.once("SIGINT", finish);
|
|
59401
|
+
process.once("SIGTERM", finish);
|
|
59402
|
+
});
|
|
59403
|
+
}
|
|
59404
|
+
function onceAsync(fn) {
|
|
59405
|
+
let promise;
|
|
59406
|
+
return () => {
|
|
59407
|
+
promise = promise ?? fn();
|
|
59408
|
+
return promise;
|
|
59409
|
+
};
|
|
59410
|
+
}
|
|
59411
|
+
function waitForCodexAppServerExit(child) {
|
|
59412
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
59413
|
+
return Promise.resolve({
|
|
59414
|
+
code: child.exitCode,
|
|
59415
|
+
signal: child.signalCode
|
|
59416
|
+
});
|
|
59417
|
+
}
|
|
59418
|
+
return new Promise((resolve11) => {
|
|
59419
|
+
child.once("exit", (code, signal) => {
|
|
59420
|
+
resolve11({ code, signal });
|
|
59421
|
+
});
|
|
59422
|
+
});
|
|
59423
|
+
}
|
|
59424
|
+
function requireObject(value) {
|
|
59425
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
59426
|
+
throw new Error("remote Codex harness worker config must be an object");
|
|
59427
|
+
}
|
|
59428
|
+
return value;
|
|
59429
|
+
}
|
|
59430
|
+
function requiredString2(input, key) {
|
|
59431
|
+
const value = input[key];
|
|
59432
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
59433
|
+
throw new Error(`remote Codex harness worker config missing ${key}`);
|
|
59434
|
+
}
|
|
59435
|
+
return value;
|
|
59436
|
+
}
|
|
59437
|
+
function requiredPositiveInteger(input, key) {
|
|
59438
|
+
const value = input[key];
|
|
59439
|
+
if (!Number.isInteger(value) || value <= 0) {
|
|
59440
|
+
throw new Error(`remote Codex harness worker config missing ${key}`);
|
|
59441
|
+
}
|
|
59442
|
+
return value;
|
|
59443
|
+
}
|
|
59444
|
+
function optionalStringField(input, key) {
|
|
59445
|
+
const value = input[key];
|
|
59446
|
+
if (value === void 0) {
|
|
59447
|
+
return {};
|
|
59448
|
+
}
|
|
59449
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
59450
|
+
throw new Error(`remote Codex harness worker config invalid ${key}`);
|
|
59451
|
+
}
|
|
59452
|
+
return { [key]: value };
|
|
59453
|
+
}
|
|
59454
|
+
function optionalBooleanField(input, key) {
|
|
59455
|
+
const value = input[key];
|
|
59456
|
+
if (value === void 0) {
|
|
59457
|
+
return {};
|
|
59458
|
+
}
|
|
59459
|
+
if (typeof value !== "boolean") {
|
|
59460
|
+
throw new Error(`remote Codex harness worker config invalid ${key}`);
|
|
59461
|
+
}
|
|
59462
|
+
return { [key]: value };
|
|
59463
|
+
}
|
|
59464
|
+
function optionalObjectField(input, key) {
|
|
59465
|
+
const value = input[key];
|
|
59466
|
+
if (value === void 0) {
|
|
59467
|
+
return {};
|
|
59468
|
+
}
|
|
59469
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
59470
|
+
throw new Error(`remote Codex harness worker config invalid ${key}`);
|
|
59471
|
+
}
|
|
59472
|
+
return { [key]: value };
|
|
59473
|
+
}
|
|
59474
|
+
|
|
58127
59475
|
// src/index.ts
|
|
58128
59476
|
init_userFacingErrors();
|
|
58129
59477
|
var flagDefinitions = /* @__PURE__ */ new Map([
|
|
@@ -58250,6 +59598,9 @@ async function main(args) {
|
|
|
58250
59598
|
case "commanderDaemon":
|
|
58251
59599
|
await runCommanderDaemonCommand(parsed.args);
|
|
58252
59600
|
return;
|
|
59601
|
+
case "remoteCodexHarnessWorker":
|
|
59602
|
+
await runRemoteCodexHarnessWorkerFromEnv();
|
|
59603
|
+
return;
|
|
58253
59604
|
case "agentRunner": {
|
|
58254
59605
|
const options = await parseAgentRunnerArgs(parsed.args);
|
|
58255
59606
|
await runLocalCodexRunner(withLocalMachineId(options));
|
|
@@ -58301,6 +59652,8 @@ function parseCommand(args) {
|
|
|
58301
59652
|
return ["daemon", "status", "wait", "stop"].includes(rest[0] ?? "") ? { command: "commanderDaemon", args: rest } : { command: "agentRunner", args: rest };
|
|
58302
59653
|
case "commander-daemon":
|
|
58303
59654
|
return { command: "commanderDaemon", args: ["daemon", ...rest] };
|
|
59655
|
+
case "remote-codex-harness-worker":
|
|
59656
|
+
return { command: "remoteCodexHarnessWorker", args: rest };
|
|
58304
59657
|
case "commander-status":
|
|
58305
59658
|
return { command: "commanderDaemon", args: ["status", ...rest] };
|
|
58306
59659
|
case "commander-wait":
|
|
@@ -58397,7 +59750,7 @@ function runPathsCommand(args) {
|
|
|
58397
59750
|
if (pathValue === void 0 || pathValue.trim() === "") {
|
|
58398
59751
|
throw new Error("missing path for linzumi paths add");
|
|
58399
59752
|
}
|
|
58400
|
-
const trustedPath =
|
|
59753
|
+
const trustedPath = realpathSync7(resolve10(expandUserPath(pathValue)));
|
|
58401
59754
|
if (linzumiUrl === void 0) {
|
|
58402
59755
|
addAllowedCwd(pathValue);
|
|
58403
59756
|
} else {
|
|
@@ -58606,7 +59959,7 @@ async function parseStartRunnerArgs(args, deps = {
|
|
|
58606
59959
|
codexBin: requestedCodexBin,
|
|
58607
59960
|
codeServerBin: customCodeServerBin
|
|
58608
59961
|
});
|
|
58609
|
-
|
|
59962
|
+
assertRunnerConnectionDependencies(initialDependencyStatus);
|
|
58610
59963
|
const codexBin = initialDependencyStatus.codex.command;
|
|
58611
59964
|
const explicitToken = stringValue7(values, "token");
|
|
58612
59965
|
const authFilePath = stringValue7(values, "auth-file");
|
|
@@ -58652,7 +60005,7 @@ async function parseStartRunnerArgs(args, deps = {
|
|
|
58652
60005
|
codeServerBin: editorRuntime.codeServerBin,
|
|
58653
60006
|
editorRuntime: editorRuntime.status
|
|
58654
60007
|
});
|
|
58655
|
-
|
|
60008
|
+
assertRunnerConnectionDependencies(dependencyStatus);
|
|
58656
60009
|
const claudeCodeAvailable = await resolveClaudeCodeAvailability(deps, cwd);
|
|
58657
60010
|
return {
|
|
58658
60011
|
kandanUrl,
|
|
@@ -58664,6 +60017,7 @@ async function parseStartRunnerArgs(args, deps = {
|
|
|
58664
60017
|
cwd,
|
|
58665
60018
|
codexBin,
|
|
58666
60019
|
codexUrl: stringValue7(values, "codex-url"),
|
|
60020
|
+
launchSource: electronAutoConnectLaunchSource(),
|
|
58667
60021
|
launchTui: values.get("launch-tui") === true,
|
|
58668
60022
|
fast: values.get("fast") === true,
|
|
58669
60023
|
logFile: stringValue7(values, "log-file"),
|
|
@@ -58741,7 +60095,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
58741
60095
|
codexBin: requestedCodexBin,
|
|
58742
60096
|
codeServerBin: customCodeServerBin
|
|
58743
60097
|
});
|
|
58744
|
-
|
|
60098
|
+
assertRunnerConnectionDependencies(initialDependencyStatus);
|
|
58745
60099
|
const codexBin = initialDependencyStatus.codex.command;
|
|
58746
60100
|
const editorRuntime = await deps.resolveEditorRuntime({
|
|
58747
60101
|
kandanUrl,
|
|
@@ -58755,7 +60109,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
58755
60109
|
codeServerBin: editorRuntime.codeServerBin,
|
|
58756
60110
|
editorRuntime: editorRuntime.status
|
|
58757
60111
|
});
|
|
58758
|
-
|
|
60112
|
+
assertRunnerConnectionDependencies(dependencyStatus);
|
|
58759
60113
|
const claudeCodeAvailable = await resolveClaudeCodeAvailability(deps, cwd);
|
|
58760
60114
|
return {
|
|
58761
60115
|
kandanUrl,
|
|
@@ -58767,6 +60121,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
58767
60121
|
cwd,
|
|
58768
60122
|
codexBin,
|
|
58769
60123
|
codexUrl: stringValue7(values, "codex-url"),
|
|
60124
|
+
launchSource: electronAutoConnectLaunchSource(),
|
|
58770
60125
|
launchTui: values.get("launch-tui") === true,
|
|
58771
60126
|
fast: values.get("fast") === true,
|
|
58772
60127
|
logFile: stringValue7(values, "log-file"),
|
|
@@ -58785,7 +60140,7 @@ async function parseAgentRunnerArgs(args, deps = {
|
|
|
58785
60140
|
};
|
|
58786
60141
|
}
|
|
58787
60142
|
function readAgentTokenTextFile(path2) {
|
|
58788
|
-
return
|
|
60143
|
+
return existsSync14(path2) ? readFileSync16(path2, "utf8") : void 0;
|
|
58789
60144
|
}
|
|
58790
60145
|
function rejectAgentRunnerTargetingFlags(values) {
|
|
58791
60146
|
const unsupportedFlags = [
|
|
@@ -58901,7 +60256,7 @@ async function parseRunnerArgs(args, deps = {
|
|
|
58901
60256
|
codexBin: requestedCodexBin,
|
|
58902
60257
|
codeServerBin: customCodeServerBin
|
|
58903
60258
|
});
|
|
58904
|
-
|
|
60259
|
+
assertRunnerConnectionDependencies(initialDependencyStatus);
|
|
58905
60260
|
const codexBin = initialDependencyStatus.codex.command;
|
|
58906
60261
|
const explicitToken = stringValue7(values, "token");
|
|
58907
60262
|
const token = await deps.resolveToken({
|
|
@@ -58928,7 +60283,7 @@ async function parseRunnerArgs(args, deps = {
|
|
|
58928
60283
|
codeServerBin: editorRuntime.codeServerBin,
|
|
58929
60284
|
editorRuntime: editorRuntime.status
|
|
58930
60285
|
});
|
|
58931
|
-
|
|
60286
|
+
assertRunnerConnectionDependencies(dependencyStatus);
|
|
58932
60287
|
const claudeCodeAvailable = await resolveClaudeCodeAvailability(deps, cwd);
|
|
58933
60288
|
return {
|
|
58934
60289
|
kandanUrl,
|
|
@@ -58939,6 +60294,7 @@ async function parseRunnerArgs(args, deps = {
|
|
|
58939
60294
|
cwd,
|
|
58940
60295
|
codexBin,
|
|
58941
60296
|
codexUrl: stringValue7(values, "codex-url"),
|
|
60297
|
+
launchSource: electronAutoConnectLaunchSource(),
|
|
58942
60298
|
launchTui: values.get("launch-tui") === true,
|
|
58943
60299
|
fast: values.get("fast") === true,
|
|
58944
60300
|
logFile: stringValue7(values, "log-file"),
|
|
@@ -58968,6 +60324,9 @@ function runnerRuntimeDefaultsFromValues(values) {
|
|
|
58968
60324
|
allowPortForwardingByDefault: true
|
|
58969
60325
|
};
|
|
58970
60326
|
}
|
|
60327
|
+
function electronAutoConnectLaunchSource() {
|
|
60328
|
+
return process.env.LINZUMI_ELECTRON_AUTO_CONNECT_RUNNER === "1" ? "electron_auto_connect" : void 0;
|
|
60329
|
+
}
|
|
58971
60330
|
function kandanUrlValue(values) {
|
|
58972
60331
|
const apiUrl = stringValue7(values, "api-url");
|
|
58973
60332
|
const linzumiUrl = stringValue7(values, "linzumi-url");
|