codex-to-im 1.0.60 → 1.0.62
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/daemon.mjs +304 -107
- package/dist/ui-server.mjs +117 -81
- package/package.json +1 -1
package/dist/daemon.mjs
CHANGED
|
@@ -324,9 +324,9 @@ __export(codex_provider_exports, {
|
|
|
324
324
|
CodexProvider: () => CodexProvider,
|
|
325
325
|
mapCodexUsage: () => mapCodexUsage
|
|
326
326
|
});
|
|
327
|
-
import
|
|
327
|
+
import fs17 from "node:fs";
|
|
328
328
|
import os4 from "node:os";
|
|
329
|
-
import
|
|
329
|
+
import path18 from "node:path";
|
|
330
330
|
function isRecord(value) {
|
|
331
331
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
332
332
|
}
|
|
@@ -543,13 +543,13 @@ var init_codex_provider = __esm({
|
|
|
543
543
|
{ type: "text", text: params.prompt }
|
|
544
544
|
];
|
|
545
545
|
for (const file of imageFiles) {
|
|
546
|
-
if (file.filePath &&
|
|
546
|
+
if (file.filePath && fs17.existsSync(file.filePath)) {
|
|
547
547
|
parts.push({ type: "local_image", path: file.filePath });
|
|
548
548
|
continue;
|
|
549
549
|
}
|
|
550
550
|
const ext = MIME_EXT[file.type] || ".png";
|
|
551
|
-
const tmpPath =
|
|
552
|
-
|
|
551
|
+
const tmpPath = path18.join(os4.tmpdir(), `cti-img-${Date.now()}-${Math.random().toString(36).slice(2)}${ext}`);
|
|
552
|
+
fs17.writeFileSync(tmpPath, Buffer.from(file.data, "base64"));
|
|
553
553
|
tempFiles.push(tmpPath);
|
|
554
554
|
parts.push({ type: "local_image", path: tmpPath });
|
|
555
555
|
}
|
|
@@ -715,7 +715,7 @@ var init_codex_provider = __esm({
|
|
|
715
715
|
} finally {
|
|
716
716
|
for (const tmp of tempFiles) {
|
|
717
717
|
try {
|
|
718
|
-
|
|
718
|
+
fs17.unlinkSync(tmp);
|
|
719
719
|
} catch {
|
|
720
720
|
}
|
|
721
721
|
}
|
|
@@ -845,9 +845,9 @@ var init_codex_provider = __esm({
|
|
|
845
845
|
});
|
|
846
846
|
|
|
847
847
|
// src/main.ts
|
|
848
|
-
import
|
|
849
|
-
import
|
|
850
|
-
import
|
|
848
|
+
import fs18 from "node:fs";
|
|
849
|
+
import path19 from "node:path";
|
|
850
|
+
import crypto11 from "node:crypto";
|
|
851
851
|
|
|
852
852
|
// src/lib/bridge/context.ts
|
|
853
853
|
var CONTEXT_KEY = "__bridge_context__";
|
|
@@ -3286,20 +3286,20 @@ ${trimmedResponse}`;
|
|
|
3286
3286
|
buffer = Buffer.concat(chunks);
|
|
3287
3287
|
} catch (streamErr) {
|
|
3288
3288
|
console.warn("[feishu-adapter] Stream read failed, falling back to writeFile:", streamErr instanceof Error ? streamErr.message : streamErr);
|
|
3289
|
-
const
|
|
3289
|
+
const fs19 = await import("fs");
|
|
3290
3290
|
const os5 = await import("os");
|
|
3291
|
-
const
|
|
3292
|
-
const tmpPath =
|
|
3291
|
+
const path20 = await import("path");
|
|
3292
|
+
const tmpPath = path20.join(os5.tmpdir(), `feishu-dl-${crypto3.randomUUID()}`);
|
|
3293
3293
|
try {
|
|
3294
3294
|
await res.writeFile(tmpPath);
|
|
3295
|
-
buffer =
|
|
3295
|
+
buffer = fs19.readFileSync(tmpPath);
|
|
3296
3296
|
if (buffer.length > MAX_FILE_SIZE) {
|
|
3297
3297
|
console.warn(`[feishu-adapter] Resource too large (>${MAX_FILE_SIZE} bytes), key: ${fileKey}`);
|
|
3298
3298
|
return null;
|
|
3299
3299
|
}
|
|
3300
3300
|
} finally {
|
|
3301
3301
|
try {
|
|
3302
|
-
|
|
3302
|
+
fs19.unlinkSync(tmpPath);
|
|
3303
3303
|
} catch {
|
|
3304
3304
|
}
|
|
3305
3305
|
}
|
|
@@ -10837,8 +10837,10 @@ var IGNORED_RESPONSE_ITEM_TYPES = /* @__PURE__ */ new Set([
|
|
|
10837
10837
|
"web_search_call"
|
|
10838
10838
|
]);
|
|
10839
10839
|
var IGNORED_TOP_LEVEL_TYPES = /* @__PURE__ */ new Set([
|
|
10840
|
+
"compacted",
|
|
10840
10841
|
"session_meta",
|
|
10841
|
-
"turn_context"
|
|
10842
|
+
"turn_context",
|
|
10843
|
+
"world_state"
|
|
10842
10844
|
]);
|
|
10843
10845
|
var TERMINAL_COMPLETION_EVENT_TYPES = /* @__PURE__ */ new Set([
|
|
10844
10846
|
"task_complete",
|
|
@@ -10865,6 +10867,10 @@ function extractTerminalCompletionText(payload) {
|
|
|
10865
10867
|
}
|
|
10866
10868
|
return "";
|
|
10867
10869
|
}
|
|
10870
|
+
function isSyntheticDesktopUserContext(text2) {
|
|
10871
|
+
const normalized = text2.trim();
|
|
10872
|
+
return normalized.startsWith("<environment_context>") && normalized.endsWith("</environment_context>");
|
|
10873
|
+
}
|
|
10868
10874
|
function isIgnoredMirrorLineKind(line) {
|
|
10869
10875
|
if (isSessionEventLine(line)) {
|
|
10870
10876
|
const payloadType = typeof line.payload?.type === "string" ? line.payload.type.trim() : "";
|
|
@@ -11177,7 +11183,7 @@ function pushDesktopMirrorEventRecord(records, parsed, rawLine, activeTurnId) {
|
|
|
11177
11183
|
}
|
|
11178
11184
|
if (parsed.payload?.type === "user_message") {
|
|
11179
11185
|
const text2 = extractNormalizedStructuredText(parsed.payload.message);
|
|
11180
|
-
if (!text2) return true;
|
|
11186
|
+
if (!text2 || isSyntheticDesktopUserContext(text2)) return true;
|
|
11181
11187
|
records.push({
|
|
11182
11188
|
signature,
|
|
11183
11189
|
type: "message",
|
|
@@ -11234,7 +11240,7 @@ function pushDesktopMirrorResponseRecord(records, parsed, rawLine, activeTurnId,
|
|
|
11234
11240
|
}
|
|
11235
11241
|
if (parsed.payload?.type === "message" && parsed.payload.role === "user") {
|
|
11236
11242
|
const text2 = extractDesktopMessageText(parsed);
|
|
11237
|
-
if (!text2) return true;
|
|
11243
|
+
if (!text2 || isSyntheticDesktopUserContext(text2)) return true;
|
|
11238
11244
|
const previous = records.at(-1);
|
|
11239
11245
|
if (previous?.type === "message" && previous.role === "user" && previous.content === text2 && previous.turnId === (activeTurnId || void 0)) {
|
|
11240
11246
|
return true;
|
|
@@ -11249,6 +11255,9 @@ function pushDesktopMirrorResponseRecord(records, parsed, rawLine, activeTurnId,
|
|
|
11249
11255
|
});
|
|
11250
11256
|
return true;
|
|
11251
11257
|
}
|
|
11258
|
+
if (parsed.payload?.type === "message") {
|
|
11259
|
+
return true;
|
|
11260
|
+
}
|
|
11252
11261
|
if (parsed.payload?.type === "tool_search_call") {
|
|
11253
11262
|
const toolId = extractNormalizedFreeText(parsed.payload.call_id) || signature;
|
|
11254
11263
|
records.push({
|
|
@@ -13165,6 +13174,10 @@ function filterSuppressedMirrorRecords(store, sessionId, records, config2, nowMs
|
|
|
13165
13174
|
break;
|
|
13166
13175
|
}
|
|
13167
13176
|
if (record.type === "message" && record.role === "user") {
|
|
13177
|
+
if (isSyntheticDesktopUserContext(record.content || "")) {
|
|
13178
|
+
handled = true;
|
|
13179
|
+
break;
|
|
13180
|
+
}
|
|
13168
13181
|
if (suppression.promptText && normalizedContent === suppression.promptText) {
|
|
13169
13182
|
suppression.awaitingPromptMatch = false;
|
|
13170
13183
|
suppression.droppingTurn = true;
|
|
@@ -16676,7 +16689,47 @@ async function runMirrorReconcileBatch(deps) {
|
|
|
16676
16689
|
}
|
|
16677
16690
|
|
|
16678
16691
|
// src/lib/bridge/mirror-runtime.ts
|
|
16692
|
+
var MIRROR_ORPHAN_PROCESS_PROBE_INTERVAL_MS = 6e4;
|
|
16679
16693
|
function createMirrorRuntime(getState2, options, deps) {
|
|
16694
|
+
const orphanProbeAt = /* @__PURE__ */ new Map();
|
|
16695
|
+
function isAtOrBefore(timestamp, boundary) {
|
|
16696
|
+
if (!timestamp) return true;
|
|
16697
|
+
const timestampMs = Date.parse(timestamp);
|
|
16698
|
+
const boundaryMs = Date.parse(boundary);
|
|
16699
|
+
if (Number.isFinite(timestampMs) && Number.isFinite(boundaryMs)) {
|
|
16700
|
+
return timestampMs <= boundaryMs;
|
|
16701
|
+
}
|
|
16702
|
+
return timestamp <= boundary;
|
|
16703
|
+
}
|
|
16704
|
+
function discardClaimedMirrorTurn(subscription, routeResult) {
|
|
16705
|
+
if (!routeResult.terminalClaimed) return;
|
|
16706
|
+
const claimedTurnId = routeResult.claimedTurnId;
|
|
16707
|
+
if (claimedTurnId) {
|
|
16708
|
+
const claimedStreamKey = buildMirrorStreamKey(subscription.sessionId, claimedTurnId, "");
|
|
16709
|
+
subscription.bufferedRecords = subscription.bufferedRecords.filter(
|
|
16710
|
+
(record) => record.turnId !== claimedTurnId
|
|
16711
|
+
);
|
|
16712
|
+
subscription.pendingDeliveries = subscription.pendingDeliveries.filter(
|
|
16713
|
+
(turn) => turn.streamKey !== claimedStreamKey
|
|
16714
|
+
);
|
|
16715
|
+
if (subscription.pendingTurn?.turnId === claimedTurnId) {
|
|
16716
|
+
deps.stopMirrorStreaming(subscription, "interrupted");
|
|
16717
|
+
subscription.pendingTurn = null;
|
|
16718
|
+
}
|
|
16719
|
+
}
|
|
16720
|
+
const claimedAt = routeResult.claimedAt;
|
|
16721
|
+
if (!claimedAt) return;
|
|
16722
|
+
const retainedAtOrBeforeClaim = [
|
|
16723
|
+
...subscription.bufferedRecords.map((record) => record.timestamp),
|
|
16724
|
+
...subscription.pendingDeliveries.map((turn) => turn.timestamp),
|
|
16725
|
+
...routeResult.unclaimed.map((record) => record.timestamp),
|
|
16726
|
+
...subscription.pendingTurn ? [subscription.pendingTurn.lastActivityAt] : []
|
|
16727
|
+
].some((timestamp) => isAtOrBefore(timestamp, claimedAt));
|
|
16728
|
+
if (retainedAtOrBeforeClaim) return;
|
|
16729
|
+
if (!subscription.lastDeliveredAt || !isAtOrBefore(claimedAt, subscription.lastDeliveredAt)) {
|
|
16730
|
+
subscription.lastDeliveredAt = claimedAt;
|
|
16731
|
+
}
|
|
16732
|
+
}
|
|
16680
16733
|
function closeMirrorWatcher(subscription) {
|
|
16681
16734
|
if (subscription.watcher) {
|
|
16682
16735
|
try {
|
|
@@ -16725,8 +16778,35 @@ function createMirrorRuntime(getState2, options, deps) {
|
|
|
16725
16778
|
deps.stopMirrorStreaming(existing);
|
|
16726
16779
|
closeMirrorWatcher(existing);
|
|
16727
16780
|
state.mirrorSubscriptions.delete(bindingId);
|
|
16781
|
+
orphanProbeAt.delete(bindingId);
|
|
16728
16782
|
deps.syncMirrorSessionStateSafe(existing.sessionId, "mirror subscription removal");
|
|
16729
16783
|
}
|
|
16784
|
+
async function finalizeOrphanedMirrorStream(subscription, snapshot, blocked, runtimeBusy, nowMs) {
|
|
16785
|
+
const pendingTurn = subscription.pendingTurn;
|
|
16786
|
+
if (!pendingTurn?.streamStarted || blocked || runtimeBusy) return null;
|
|
16787
|
+
const timeoutMs = options.streamOrphanTimeoutMs;
|
|
16788
|
+
const lastActivityMs = Date.parse(pendingTurn.lastActivityAt);
|
|
16789
|
+
if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || !Number.isFinite(lastActivityMs)) {
|
|
16790
|
+
return null;
|
|
16791
|
+
}
|
|
16792
|
+
const sourceActivityMs = Math.max(lastActivityMs, snapshot.mtimeMs);
|
|
16793
|
+
if (nowMs - sourceActivityMs < timeoutMs) return null;
|
|
16794
|
+
const lastProbeAt = orphanProbeAt.get(subscription.bindingId);
|
|
16795
|
+
if (typeof lastProbeAt === "number" && nowMs - lastProbeAt < MIRROR_ORPHAN_PROCESS_PROBE_INTERVAL_MS) {
|
|
16796
|
+
return null;
|
|
16797
|
+
}
|
|
16798
|
+
orphanProbeAt.set(subscription.bindingId, nowMs);
|
|
16799
|
+
if (!await deps.isThreadProcessDefinitelyGone(subscription.threadId)) return null;
|
|
16800
|
+
const finalized = flushTimedOutMirrorTurn(subscription, timeoutMs, nowMs);
|
|
16801
|
+
if (!finalized) return null;
|
|
16802
|
+
orphanProbeAt.delete(subscription.bindingId);
|
|
16803
|
+
const detail = "\u684C\u9762\u7EBF\u7A0B\u957F\u65F6\u95F4\u6CA1\u6709\u65B0\u8BB0\u5F55\uFF0C\u4E14\u672C\u673A\u672A\u627E\u5230\u5BF9\u5E94\u8FDB\u7A0B\uFF1B\u5DF2\u7ED3\u675F\u5B64\u7ACB\u7684\u6D41\u5F0F\u540C\u6B65\u3002";
|
|
16804
|
+
deps.recordOrphanedMirrorTurn(subscription.sessionId, detail);
|
|
16805
|
+
console.warn(
|
|
16806
|
+
`[bridge-manager] Finalized orphaned mirror turn ${pendingTurn.turnId || pendingTurn.streamKey} for thread ${subscription.threadId}`
|
|
16807
|
+
);
|
|
16808
|
+
return finalized;
|
|
16809
|
+
}
|
|
16730
16810
|
function clearDanglingMirrorThread(subscription, reason) {
|
|
16731
16811
|
const { store } = getBridgeContext();
|
|
16732
16812
|
const session = store.getSession(subscription.sessionId);
|
|
@@ -16784,6 +16864,7 @@ function createMirrorRuntime(getState2, options, deps) {
|
|
|
16784
16864
|
});
|
|
16785
16865
|
if (threadChanged || filePathChanged) {
|
|
16786
16866
|
deps.stopMirrorStreaming(existing);
|
|
16867
|
+
orphanProbeAt.delete(existing.bindingId);
|
|
16787
16868
|
}
|
|
16788
16869
|
watchMirrorFile(existing, filePath);
|
|
16789
16870
|
if (previousSessionId !== binding.codepilotSessionId) {
|
|
@@ -16864,7 +16945,14 @@ function createMirrorRuntime(getState2, options, deps) {
|
|
|
16864
16945
|
`[bridge-manager] Unhandled desktop mirror event for thread ${subscription.threadId}: ${kind}`
|
|
16865
16946
|
);
|
|
16866
16947
|
}
|
|
16867
|
-
const routeResult = deliverableRecords.length > 0 && deps.routeDesktopRecords ? await deps.routeDesktopRecords(subscription.sessionId, subscription.threadId, deliverableRecords) : {
|
|
16948
|
+
const routeResult = deliverableRecords.length > 0 && deps.routeDesktopRecords ? await deps.routeDesktopRecords(subscription.sessionId, subscription.threadId, deliverableRecords) : {
|
|
16949
|
+
claimed: [],
|
|
16950
|
+
unclaimed: deliverableRecords,
|
|
16951
|
+
terminalClaimed: false,
|
|
16952
|
+
claimedTurnId: null,
|
|
16953
|
+
claimedAt: null
|
|
16954
|
+
};
|
|
16955
|
+
discardClaimedMirrorTurn(subscription, routeResult);
|
|
16868
16956
|
const mirrorRecords = routeResult.unclaimed;
|
|
16869
16957
|
if (mirrorRecords.length > 0) {
|
|
16870
16958
|
deps.observeSessionHealthRecords(subscription.sessionId, subscription.threadId, mirrorRecords);
|
|
@@ -16876,6 +16964,20 @@ function createMirrorRuntime(getState2, options, deps) {
|
|
|
16876
16964
|
flushTimedOutTurn: (currentSubscription) => deps.flushTimedOutMirrorTurn(currentSubscription),
|
|
16877
16965
|
consumeBufferedTurns: (currentSubscription) => deps.consumeBufferedMirrorTurns(currentSubscription)
|
|
16878
16966
|
});
|
|
16967
|
+
const runtimeBusy = session.runtime_status === "running" || session.runtime_status === "queued";
|
|
16968
|
+
const orphanedTurn = await finalizeOrphanedMirrorStream(
|
|
16969
|
+
subscription,
|
|
16970
|
+
snapshot,
|
|
16971
|
+
blocked,
|
|
16972
|
+
runtimeBusy,
|
|
16973
|
+
Date.now()
|
|
16974
|
+
);
|
|
16975
|
+
if (orphanedTurn) {
|
|
16976
|
+
deliveryPlan.finalizedTurns.push(orphanedTurn);
|
|
16977
|
+
deliveryPlan.syncReason = "mirror reconcile delivered turns";
|
|
16978
|
+
} else if (!subscription.pendingTurn?.streamStarted) {
|
|
16979
|
+
orphanProbeAt.delete(subscription.bindingId);
|
|
16980
|
+
}
|
|
16879
16981
|
if (deliveryPlan.finalizedTurns.length > 0) {
|
|
16880
16982
|
enqueuePendingMirrorDeliveries(subscription, deliveryPlan.finalizedTurns);
|
|
16881
16983
|
}
|
|
@@ -17298,6 +17400,12 @@ async function probeCodexThreadProcess(threadId) {
|
|
|
17298
17400
|
};
|
|
17299
17401
|
}
|
|
17300
17402
|
}
|
|
17403
|
+
async function isCodexThreadProcessDefinitelyGone(threadId, probe = probeCodexThreadProcess) {
|
|
17404
|
+
const threadProbe = await probe(threadId);
|
|
17405
|
+
if (threadProbe.status !== "not_found") return false;
|
|
17406
|
+
const hostProbe = await probe("app-server");
|
|
17407
|
+
return hostProbe.status === "not_found";
|
|
17408
|
+
}
|
|
17301
17409
|
|
|
17302
17410
|
// src/lib/bridge/session-health-reducer.ts
|
|
17303
17411
|
var HEALTH_RECENT_PROGRESS_MS = 10 * 60 * 1e3;
|
|
@@ -17437,7 +17545,9 @@ function computeBaseDiagnosis(session, nowMs) {
|
|
|
17437
17545
|
const sdkSessionId = trimOrNull(session.sdk_session_id);
|
|
17438
17546
|
const lastProgressMs = parseIsoMs(lastProgressAt || void 0);
|
|
17439
17547
|
const previousStatus = session.health_status || "idle";
|
|
17440
|
-
|
|
17548
|
+
const terminalHealth = previousStatus === "completed" || previousStatus === "failed" || previousStatus === "aborted";
|
|
17549
|
+
const activeDesktopMirror = session.thread_origin === "desktop" && session.mirror_status === "watching" && isRunningHealthStatus(previousStatus);
|
|
17550
|
+
if (!isRunningRuntimeStatus(runtimeStatus) && !terminalHealth && !activeDesktopMirror) {
|
|
17441
17551
|
return {
|
|
17442
17552
|
sessionId: session.id,
|
|
17443
17553
|
checkedAt: null,
|
|
@@ -17525,6 +17635,12 @@ function applyProcessProbeDiagnosis(diagnosis, processProbe) {
|
|
|
17525
17635
|
processProbe: null
|
|
17526
17636
|
};
|
|
17527
17637
|
}
|
|
17638
|
+
if (!isRunningHealthStatus(diagnosis.healthStatus)) {
|
|
17639
|
+
return {
|
|
17640
|
+
...diagnosis,
|
|
17641
|
+
processProbe
|
|
17642
|
+
};
|
|
17643
|
+
}
|
|
17528
17644
|
if (processProbe.status === "alive") {
|
|
17529
17645
|
const healthStatus = diagnosis.activeToolName ? "waiting_tool" : "slow_observed";
|
|
17530
17646
|
const healthReason = diagnosis.activeToolName ? "\u68C0\u6D4B\u5230\u672C\u673A\u7EBF\u7A0B\u8FDB\u7A0B\u4ECD\u5728\u8FD0\u884C\uFF0C\u5F53\u524D\u66F4\u50CF\u662F\u957F\u65F6\u5DE5\u5177\u6267\u884C\u3002" : "\u68C0\u6D4B\u5230\u672C\u673A\u7EBF\u7A0B\u8FDB\u7A0B\u4ECD\u5728\u8FD0\u884C\uFF0C\u5F53\u524D\u66F4\u50CF\u662F\u957F\u65F6\u4EFB\u52A1\u3002";
|
|
@@ -17930,7 +18046,9 @@ async function routeDesktopRecords(sessionId, desktopThreadId, records, coordina
|
|
|
17930
18046
|
return {
|
|
17931
18047
|
claimed: [],
|
|
17932
18048
|
unclaimed: records,
|
|
17933
|
-
terminalClaimed: false
|
|
18049
|
+
terminalClaimed: false,
|
|
18050
|
+
claimedTurnId: null,
|
|
18051
|
+
claimedAt: null
|
|
17934
18052
|
};
|
|
17935
18053
|
}
|
|
17936
18054
|
const claim = await coordinator.claimDesktopTerminal(
|
|
@@ -17940,7 +18058,9 @@ async function routeDesktopRecords(sessionId, desktopThreadId, records, coordina
|
|
|
17940
18058
|
return {
|
|
17941
18059
|
claimed: [],
|
|
17942
18060
|
unclaimed: records,
|
|
17943
|
-
terminalClaimed: false
|
|
18061
|
+
terminalClaimed: false,
|
|
18062
|
+
claimedTurnId: null,
|
|
18063
|
+
claimedAt: null
|
|
17944
18064
|
};
|
|
17945
18065
|
}
|
|
17946
18066
|
const claimedTurnId = terminalRecord.turnId;
|
|
@@ -17949,7 +18069,9 @@ async function routeDesktopRecords(sessionId, desktopThreadId, records, coordina
|
|
|
17949
18069
|
return {
|
|
17950
18070
|
claimed,
|
|
17951
18071
|
unclaimed: records.filter((record) => !claimedSet.has(record.signature)),
|
|
17952
|
-
terminalClaimed: true
|
|
18072
|
+
terminalClaimed: true,
|
|
18073
|
+
claimedTurnId: claimedTurnId || null,
|
|
18074
|
+
claimedAt: terminalRecord.timestamp || null
|
|
17953
18075
|
};
|
|
17954
18076
|
}
|
|
17955
18077
|
|
|
@@ -18012,6 +18134,7 @@ var MIRROR_PROMPT_MATCH_GRACE_MS = 12e4;
|
|
|
18012
18134
|
var DESKTOP_TERMINAL_FINALIZATION_TIMEOUT_MS = 3e4;
|
|
18013
18135
|
var MIRROR_STREAM_STATUS_IDLE_START_MS = 18e4;
|
|
18014
18136
|
var MIRROR_STREAM_STATUS_HEARTBEAT_MS = 1e4;
|
|
18137
|
+
var MIRROR_STREAM_ORPHAN_TIMEOUT_MS = 30 * 6e4;
|
|
18015
18138
|
var MIRROR_TURN_BUFFER_TIMEOUT_MS = 10 * 6e4;
|
|
18016
18139
|
function describeUnknownError(error) {
|
|
18017
18140
|
if (error instanceof Error) {
|
|
@@ -18241,7 +18364,8 @@ var MIRROR_RUNTIME = createMirrorRuntime(getState, {
|
|
|
18241
18364
|
watchDebounceMs: MIRROR_WATCH_DEBOUNCE_MS,
|
|
18242
18365
|
danglingThreadRetryLimit: DANGLING_MIRROR_THREAD_RETRY_LIMIT,
|
|
18243
18366
|
failureSuspendThreshold: MIRROR_FAILURE_SUSPEND_THRESHOLD,
|
|
18244
|
-
failureSuspendMs: MIRROR_FAILURE_SUSPEND_MS
|
|
18367
|
+
failureSuspendMs: MIRROR_FAILURE_SUSPEND_MS,
|
|
18368
|
+
streamOrphanTimeoutMs: MIRROR_STREAM_ORPHAN_TIMEOUT_MS
|
|
18245
18369
|
}, {
|
|
18246
18370
|
nowIso: nowIso3,
|
|
18247
18371
|
describeUnknownError,
|
|
@@ -18251,6 +18375,10 @@ var MIRROR_RUNTIME = createMirrorRuntime(getState, {
|
|
|
18251
18375
|
observeSessionHealthRecords: (sessionId, threadId, records) => {
|
|
18252
18376
|
SESSION_HEALTH_RUNTIME.observeDesktopMirrorRecords(sessionId, threadId, records);
|
|
18253
18377
|
},
|
|
18378
|
+
recordOrphanedMirrorTurn: (sessionId, detail) => {
|
|
18379
|
+
SESSION_HEALTH_RUNTIME.recordInteractiveEnd(sessionId, "aborted", detail);
|
|
18380
|
+
},
|
|
18381
|
+
isThreadProcessDefinitelyGone: isCodexThreadProcessDefinitelyGone,
|
|
18254
18382
|
routeDesktopRecords: (sessionId, threadId, records) => routeDesktopRecords(
|
|
18255
18383
|
sessionId,
|
|
18256
18384
|
threadId,
|
|
@@ -18579,40 +18707,76 @@ function persistSdkSessionUpdate(sessionId, sdkSessionId, hasError) {
|
|
|
18579
18707
|
}
|
|
18580
18708
|
|
|
18581
18709
|
// src/store.ts
|
|
18710
|
+
import fs13 from "node:fs";
|
|
18711
|
+
import path15 from "node:path";
|
|
18712
|
+
import crypto10 from "node:crypto";
|
|
18713
|
+
|
|
18714
|
+
// src/atomic-file.ts
|
|
18715
|
+
import crypto9 from "node:crypto";
|
|
18582
18716
|
import fs12 from "node:fs";
|
|
18583
18717
|
import path14 from "node:path";
|
|
18584
|
-
|
|
18585
|
-
var
|
|
18586
|
-
|
|
18587
|
-
|
|
18588
|
-
|
|
18589
|
-
|
|
18590
|
-
|
|
18591
|
-
|
|
18592
|
-
|
|
18593
|
-
|
|
18594
|
-
|
|
18595
|
-
|
|
18596
|
-
|
|
18718
|
+
var RETRYABLE_RENAME_CODES = /* @__PURE__ */ new Set(["EACCES", "EBUSY", "EPERM"]);
|
|
18719
|
+
var WAIT_ARRAY2 = new Int32Array(new SharedArrayBuffer(4));
|
|
18720
|
+
function defaultSleepSync(delayMs) {
|
|
18721
|
+
Atomics.wait(WAIT_ARRAY2, 0, 0, Math.max(1, delayMs));
|
|
18722
|
+
}
|
|
18723
|
+
function isRetryableRenameError(error) {
|
|
18724
|
+
return RETRYABLE_RENAME_CODES.has(error?.code || "");
|
|
18725
|
+
}
|
|
18726
|
+
function renameFileWithRetrySync(source, destination, options = {}) {
|
|
18727
|
+
const maxAttempts = Math.max(1, options.maxAttempts ?? 8);
|
|
18728
|
+
const baseDelayMs = Math.max(1, options.baseDelayMs ?? 15);
|
|
18729
|
+
const renameSync = options.renameSync ?? fs12.renameSync;
|
|
18730
|
+
const sleepSync2 = options.sleepSync ?? defaultSleepSync;
|
|
18731
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
18732
|
+
try {
|
|
18733
|
+
renameSync(source, destination);
|
|
18734
|
+
return;
|
|
18735
|
+
} catch (error) {
|
|
18736
|
+
if (!isRetryableRenameError(error) || attempt === maxAttempts - 1) {
|
|
18737
|
+
throw error;
|
|
18738
|
+
}
|
|
18739
|
+
sleepSync2(Math.min(250, baseDelayMs * 2 ** attempt));
|
|
18740
|
+
}
|
|
18741
|
+
}
|
|
18597
18742
|
}
|
|
18598
|
-
function
|
|
18599
|
-
|
|
18743
|
+
function atomicWriteFileSync(filePath, data) {
|
|
18744
|
+
fs12.mkdirSync(path14.dirname(filePath), { recursive: true });
|
|
18745
|
+
const tmpPath = `${filePath}.${process.pid}.${crypto9.randomUUID()}.tmp`;
|
|
18600
18746
|
try {
|
|
18601
|
-
fs12.writeFileSync(
|
|
18602
|
-
|
|
18747
|
+
fs12.writeFileSync(tmpPath, data, "utf-8");
|
|
18748
|
+
renameFileWithRetrySync(tmpPath, filePath);
|
|
18603
18749
|
} finally {
|
|
18604
18750
|
try {
|
|
18605
|
-
fs12.rmSync(
|
|
18751
|
+
fs12.rmSync(tmpPath, { force: true });
|
|
18606
18752
|
} catch {
|
|
18607
18753
|
}
|
|
18608
18754
|
}
|
|
18609
18755
|
}
|
|
18756
|
+
|
|
18757
|
+
// src/store.ts
|
|
18758
|
+
var DATA_DIR2 = path15.join(CTI_HOME, "data");
|
|
18759
|
+
var MESSAGES_DIR = path15.join(DATA_DIR2, "messages");
|
|
18760
|
+
var SESSIONS_PATH = path15.join(DATA_DIR2, "sessions.json");
|
|
18761
|
+
var BINDINGS_PATH = path15.join(DATA_DIR2, "bindings.json");
|
|
18762
|
+
var PERMISSIONS_PATH = path15.join(DATA_DIR2, "permissions.json");
|
|
18763
|
+
var OFFSETS_PATH = path15.join(DATA_DIR2, "offsets.json");
|
|
18764
|
+
var DEDUP_PATH = path15.join(DATA_DIR2, "dedup.json");
|
|
18765
|
+
var AUDIT_PATH = path15.join(DATA_DIR2, "audit.json");
|
|
18766
|
+
var DEFAULT_DEDUP_TTL_MS = 5 * 60 * 1e3;
|
|
18767
|
+
var INBOUND_DEDUP_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
18768
|
+
function ensureDir2(dir) {
|
|
18769
|
+
fs13.mkdirSync(dir, { recursive: true });
|
|
18770
|
+
}
|
|
18771
|
+
function atomicWrite2(filePath, data) {
|
|
18772
|
+
atomicWriteFileSync(filePath, data);
|
|
18773
|
+
}
|
|
18610
18774
|
function dedupTtlMs(key) {
|
|
18611
18775
|
return key.startsWith("inbound:") ? INBOUND_DEDUP_TTL_MS : DEFAULT_DEDUP_TTL_MS;
|
|
18612
18776
|
}
|
|
18613
18777
|
function readJson2(filePath, fallback) {
|
|
18614
18778
|
try {
|
|
18615
|
-
const raw =
|
|
18779
|
+
const raw = fs13.readFileSync(filePath, "utf-8");
|
|
18616
18780
|
return JSON.parse(raw);
|
|
18617
18781
|
} catch (error) {
|
|
18618
18782
|
if (error.code === "ENOENT") return fallback;
|
|
@@ -18623,7 +18787,7 @@ function writeJson(filePath, data) {
|
|
|
18623
18787
|
atomicWrite2(filePath, JSON.stringify(data, null, 2));
|
|
18624
18788
|
}
|
|
18625
18789
|
function uuid() {
|
|
18626
|
-
return
|
|
18790
|
+
return crypto10.randomUUID();
|
|
18627
18791
|
}
|
|
18628
18792
|
function now() {
|
|
18629
18793
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -18786,14 +18950,14 @@ var JsonFileStore = class {
|
|
|
18786
18950
|
}
|
|
18787
18951
|
persistMessages(sessionId) {
|
|
18788
18952
|
const msgs = this.messages.get(sessionId) || [];
|
|
18789
|
-
writeJson(
|
|
18953
|
+
writeJson(path15.join(MESSAGES_DIR, `${sessionId}.json`), msgs);
|
|
18790
18954
|
}
|
|
18791
18955
|
loadMessages(sessionId) {
|
|
18792
18956
|
if (this.messages.has(sessionId)) {
|
|
18793
18957
|
return this.messages.get(sessionId);
|
|
18794
18958
|
}
|
|
18795
18959
|
const msgs = readJson2(
|
|
18796
|
-
|
|
18960
|
+
path15.join(MESSAGES_DIR, `${sessionId}.json`),
|
|
18797
18961
|
[]
|
|
18798
18962
|
);
|
|
18799
18963
|
this.messages.set(sessionId, msgs);
|
|
@@ -18816,7 +18980,7 @@ var JsonFileStore = class {
|
|
|
18816
18980
|
});
|
|
18817
18981
|
}
|
|
18818
18982
|
mutateMessages(sessionId, mutation) {
|
|
18819
|
-
const messagePath =
|
|
18983
|
+
const messagePath = path15.join(MESSAGES_DIR, `${sessionId}.json`);
|
|
18820
18984
|
return withFileLock(messagePath, () => {
|
|
18821
18985
|
const messages = readJson2(messagePath, []);
|
|
18822
18986
|
this.messages.set(sessionId, messages);
|
|
@@ -18975,7 +19139,7 @@ var JsonFileStore = class {
|
|
|
18975
19139
|
});
|
|
18976
19140
|
}
|
|
18977
19141
|
deleteSession(sessionId) {
|
|
18978
|
-
const messagePath =
|
|
19142
|
+
const messagePath = path15.join(MESSAGES_DIR, `${sessionId}.json`);
|
|
18979
19143
|
withFileLocks([SESSIONS_PATH, BINDINGS_PATH, messagePath], () => {
|
|
18980
19144
|
this.reloadSessions();
|
|
18981
19145
|
this.reloadBindings();
|
|
@@ -18987,7 +19151,7 @@ var JsonFileStore = class {
|
|
|
18987
19151
|
}
|
|
18988
19152
|
this.messages.delete(sessionId);
|
|
18989
19153
|
try {
|
|
18990
|
-
|
|
19154
|
+
fs13.rmSync(messagePath, { force: true });
|
|
18991
19155
|
} catch {
|
|
18992
19156
|
}
|
|
18993
19157
|
this.persistSessions();
|
|
@@ -19001,7 +19165,7 @@ var JsonFileStore = class {
|
|
|
19001
19165
|
});
|
|
19002
19166
|
}
|
|
19003
19167
|
getMessages(sessionId, opts) {
|
|
19004
|
-
const messagePath =
|
|
19168
|
+
const messagePath = path15.join(MESSAGES_DIR, `${sessionId}.json`);
|
|
19005
19169
|
const msgs = readJson2(messagePath, []);
|
|
19006
19170
|
this.messages.set(sessionId, msgs);
|
|
19007
19171
|
if (opts?.limit && opts.limit > 0) {
|
|
@@ -19242,8 +19406,8 @@ var PendingPermissions = class {
|
|
|
19242
19406
|
};
|
|
19243
19407
|
|
|
19244
19408
|
// src/logger.ts
|
|
19245
|
-
import
|
|
19246
|
-
import
|
|
19409
|
+
import fs14 from "node:fs";
|
|
19410
|
+
import path16 from "node:path";
|
|
19247
19411
|
import { inspect as inspect2 } from "node:util";
|
|
19248
19412
|
var MASK_PATTERNS = [
|
|
19249
19413
|
/(?:token|secret|password|api_key)["']?\s*[:=]\s*["']?([^\s"',]+)/gi,
|
|
@@ -19261,8 +19425,8 @@ function maskSecrets(text2) {
|
|
|
19261
19425
|
}
|
|
19262
19426
|
return result;
|
|
19263
19427
|
}
|
|
19264
|
-
var LOG_DIR =
|
|
19265
|
-
var LOG_PATH =
|
|
19428
|
+
var LOG_DIR = path16.join(CTI_HOME, "logs");
|
|
19429
|
+
var LOG_PATH = path16.join(LOG_DIR, "bridge.log");
|
|
19266
19430
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
19267
19431
|
var MAX_ROTATED = 3;
|
|
19268
19432
|
var logStream = null;
|
|
@@ -19283,11 +19447,11 @@ function formatLogArg(value) {
|
|
|
19283
19447
|
return String(value);
|
|
19284
19448
|
}
|
|
19285
19449
|
function openLogStream() {
|
|
19286
|
-
return
|
|
19450
|
+
return fs14.createWriteStream(LOG_PATH, { flags: "a" });
|
|
19287
19451
|
}
|
|
19288
19452
|
function rotateIfNeeded() {
|
|
19289
19453
|
try {
|
|
19290
|
-
const stat =
|
|
19454
|
+
const stat = fs14.statSync(LOG_PATH);
|
|
19291
19455
|
if (stat.size < MAX_LOG_SIZE) return;
|
|
19292
19456
|
} catch {
|
|
19293
19457
|
return;
|
|
@@ -19297,17 +19461,17 @@ function rotateIfNeeded() {
|
|
|
19297
19461
|
logStream = null;
|
|
19298
19462
|
}
|
|
19299
19463
|
const path32 = `${LOG_PATH}.${MAX_ROTATED}`;
|
|
19300
|
-
if (
|
|
19464
|
+
if (fs14.existsSync(path32)) fs14.unlinkSync(path32);
|
|
19301
19465
|
for (let i = MAX_ROTATED - 1; i >= 1; i--) {
|
|
19302
19466
|
const src = `${LOG_PATH}.${i}`;
|
|
19303
19467
|
const dst = `${LOG_PATH}.${i + 1}`;
|
|
19304
|
-
if (
|
|
19468
|
+
if (fs14.existsSync(src)) fs14.renameSync(src, dst);
|
|
19305
19469
|
}
|
|
19306
|
-
|
|
19470
|
+
fs14.renameSync(LOG_PATH, `${LOG_PATH}.1`);
|
|
19307
19471
|
logStream = openLogStream();
|
|
19308
19472
|
}
|
|
19309
19473
|
function setupLogger() {
|
|
19310
|
-
|
|
19474
|
+
fs14.mkdirSync(LOG_DIR, { recursive: true });
|
|
19311
19475
|
logStream = openLogStream();
|
|
19312
19476
|
const write = (level, args) => {
|
|
19313
19477
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -19323,13 +19487,13 @@ function setupLogger() {
|
|
|
19323
19487
|
}
|
|
19324
19488
|
|
|
19325
19489
|
// src/bridge-instance-lock.ts
|
|
19326
|
-
import
|
|
19327
|
-
import
|
|
19328
|
-
var runtimeDir =
|
|
19329
|
-
var bridgeInstanceLockFile =
|
|
19490
|
+
import fs15 from "node:fs";
|
|
19491
|
+
import path17 from "node:path";
|
|
19492
|
+
var runtimeDir = path17.join(CTI_HOME, "runtime");
|
|
19493
|
+
var bridgeInstanceLockFile = path17.join(runtimeDir, "bridge.instance.lock");
|
|
19330
19494
|
function readJsonFile(filePath, fallback) {
|
|
19331
19495
|
try {
|
|
19332
|
-
return JSON.parse(
|
|
19496
|
+
return JSON.parse(fs15.readFileSync(filePath, "utf-8"));
|
|
19333
19497
|
} catch {
|
|
19334
19498
|
return fallback;
|
|
19335
19499
|
}
|
|
@@ -19361,8 +19525,8 @@ function tryAcquireBridgeInstanceLock(options = {}) {
|
|
|
19361
19525
|
};
|
|
19362
19526
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
19363
19527
|
try {
|
|
19364
|
-
|
|
19365
|
-
|
|
19528
|
+
fs15.mkdirSync(path17.dirname(filePath), { recursive: true });
|
|
19529
|
+
fs15.writeFileSync(filePath, JSON.stringify(payload, null, 2), { encoding: "utf-8", flag: "wx" });
|
|
19366
19530
|
return { acquired: true };
|
|
19367
19531
|
} catch (error) {
|
|
19368
19532
|
const code2 = error.code;
|
|
@@ -19372,7 +19536,7 @@ function tryAcquireBridgeInstanceLock(options = {}) {
|
|
|
19372
19536
|
return { acquired: false, holderPid: existing2.pid };
|
|
19373
19537
|
}
|
|
19374
19538
|
try {
|
|
19375
|
-
|
|
19539
|
+
fs15.unlinkSync(filePath);
|
|
19376
19540
|
} catch {
|
|
19377
19541
|
}
|
|
19378
19542
|
}
|
|
@@ -19387,37 +19551,46 @@ function releaseBridgeInstanceLock(filePath = bridgeInstanceLockFile, ownerPid =
|
|
|
19387
19551
|
const existing = readBridgeInstanceLock(filePath);
|
|
19388
19552
|
if (!existing) {
|
|
19389
19553
|
try {
|
|
19390
|
-
|
|
19554
|
+
fs15.unlinkSync(filePath);
|
|
19391
19555
|
} catch {
|
|
19392
19556
|
}
|
|
19393
19557
|
return;
|
|
19394
19558
|
}
|
|
19395
19559
|
if (existing.pid !== ownerPid) return;
|
|
19396
19560
|
try {
|
|
19397
|
-
|
|
19561
|
+
fs15.unlinkSync(filePath);
|
|
19398
19562
|
} catch {
|
|
19399
19563
|
}
|
|
19400
19564
|
}
|
|
19401
19565
|
|
|
19402
|
-
// src/
|
|
19403
|
-
|
|
19404
|
-
|
|
19405
|
-
var PID_FILE = path18.join(RUNTIME_DIR, "bridge.pid");
|
|
19406
|
-
async function resolveProvider() {
|
|
19407
|
-
const { CodexProvider: CodexProvider2 } = await Promise.resolve().then(() => (init_codex_provider(), codex_provider_exports));
|
|
19408
|
-
return new CodexProvider2();
|
|
19409
|
-
}
|
|
19410
|
-
function writeStatus(info) {
|
|
19411
|
-
fs16.mkdirSync(RUNTIME_DIR, { recursive: true });
|
|
19566
|
+
// src/runtime-status.ts
|
|
19567
|
+
import fs16 from "node:fs";
|
|
19568
|
+
function writeRuntimeStatus(filePath, info, options = {}) {
|
|
19412
19569
|
let existing = {};
|
|
19413
19570
|
try {
|
|
19414
|
-
existing = JSON.parse(fs16.readFileSync(
|
|
19571
|
+
existing = JSON.parse(fs16.readFileSync(filePath, "utf-8"));
|
|
19415
19572
|
} catch {
|
|
19416
19573
|
}
|
|
19574
|
+
const existingRunId = typeof existing.runId === "string" ? existing.runId : "";
|
|
19575
|
+
if (options.expectedRunId && existingRunId && existingRunId !== options.expectedRunId && options.allowRunIdTakeover !== true) {
|
|
19576
|
+
return false;
|
|
19577
|
+
}
|
|
19417
19578
|
const merged = { ...existing, ...info };
|
|
19418
|
-
|
|
19419
|
-
|
|
19420
|
-
|
|
19579
|
+
atomicWriteFileSync(filePath, JSON.stringify(merged, null, 2));
|
|
19580
|
+
return true;
|
|
19581
|
+
}
|
|
19582
|
+
|
|
19583
|
+
// src/main.ts
|
|
19584
|
+
var RUNTIME_DIR = path19.join(CTI_HOME, "runtime");
|
|
19585
|
+
var STATUS_FILE = path19.join(RUNTIME_DIR, "status.json");
|
|
19586
|
+
var PID_FILE = path19.join(RUNTIME_DIR, "bridge.pid");
|
|
19587
|
+
var runId = crypto11.randomUUID();
|
|
19588
|
+
async function resolveProvider() {
|
|
19589
|
+
const { CodexProvider: CodexProvider2 } = await Promise.resolve().then(() => (init_codex_provider(), codex_provider_exports));
|
|
19590
|
+
return new CodexProvider2();
|
|
19591
|
+
}
|
|
19592
|
+
function writeStatus(info, options = {}) {
|
|
19593
|
+
return writeRuntimeStatus(STATUS_FILE, info, options);
|
|
19421
19594
|
}
|
|
19422
19595
|
function getRunningChannels() {
|
|
19423
19596
|
return getStatus().adapters.map((adapter) => adapter.channelType).sort();
|
|
@@ -19429,10 +19602,6 @@ async function main() {
|
|
|
19429
19602
|
const lockState = tryAcquireBridgeInstanceLock();
|
|
19430
19603
|
if (!lockState.acquired) {
|
|
19431
19604
|
const holderPid = lockState.holderPid;
|
|
19432
|
-
writeStatus({
|
|
19433
|
-
running: true,
|
|
19434
|
-
...Number.isFinite(holderPid) && holderPid ? { pid: holderPid } : {}
|
|
19435
|
-
});
|
|
19436
19605
|
console.log(
|
|
19437
19606
|
`[codex-to-im] Another bridge daemon is already running${holderPid ? ` (PID: ${holderPid})` : ""}. Exiting duplicate launcher.`
|
|
19438
19607
|
);
|
|
@@ -19444,9 +19613,15 @@ async function main() {
|
|
|
19444
19613
|
releaseBridgeInstanceLock(void 0, process.pid);
|
|
19445
19614
|
instanceLockHeld = false;
|
|
19446
19615
|
};
|
|
19616
|
+
writeStatus({
|
|
19617
|
+
running: false,
|
|
19618
|
+
pid: process.pid,
|
|
19619
|
+
runId,
|
|
19620
|
+
channels: [],
|
|
19621
|
+
adapters: []
|
|
19622
|
+
}, { expectedRunId: runId, allowRunIdTakeover: true });
|
|
19447
19623
|
const config2 = loadConfig();
|
|
19448
19624
|
setupLogger();
|
|
19449
|
-
const runId = crypto10.randomUUID();
|
|
19450
19625
|
console.log(`[codex-to-im] Starting bridge (run_id: ${runId})`);
|
|
19451
19626
|
const settings = configToSettings(config2);
|
|
19452
19627
|
const store = new JsonFileStore(settings, { dynamicSettings: true });
|
|
@@ -19462,8 +19637,8 @@ async function main() {
|
|
|
19462
19637
|
permissions: gateway,
|
|
19463
19638
|
lifecycle: {
|
|
19464
19639
|
onBridgeStart: () => {
|
|
19465
|
-
|
|
19466
|
-
|
|
19640
|
+
fs18.mkdirSync(RUNTIME_DIR, { recursive: true });
|
|
19641
|
+
fs18.writeFileSync(PID_FILE, String(process.pid), "utf-8");
|
|
19467
19642
|
const channels = getRunningChannels();
|
|
19468
19643
|
writeStatus({
|
|
19469
19644
|
running: true,
|
|
@@ -19472,7 +19647,7 @@ async function main() {
|
|
|
19472
19647
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
19473
19648
|
channels,
|
|
19474
19649
|
adapters: getAdapterStatuses()
|
|
19475
|
-
});
|
|
19650
|
+
}, { expectedRunId: runId });
|
|
19476
19651
|
console.log(`[codex-to-im] Bridge started (PID: ${process.pid}, channels: ${channels.join(", ")})`);
|
|
19477
19652
|
},
|
|
19478
19653
|
onBridgeAdaptersChanged: (channels) => {
|
|
@@ -19482,41 +19657,60 @@ async function main() {
|
|
|
19482
19657
|
runId,
|
|
19483
19658
|
channels,
|
|
19484
19659
|
adapters: getAdapterStatuses()
|
|
19485
|
-
});
|
|
19660
|
+
}, { expectedRunId: runId });
|
|
19486
19661
|
console.log(`[codex-to-im] Active channels updated: ${channels.join(", ") || "none"}`);
|
|
19487
19662
|
},
|
|
19488
19663
|
onBridgeStop: () => {
|
|
19489
19664
|
releaseInstanceLock();
|
|
19490
|
-
writeStatus({ running: false, channels: [], adapters: [] });
|
|
19665
|
+
writeStatus({ running: false, channels: [], adapters: [] }, { expectedRunId: runId });
|
|
19491
19666
|
console.log("[codex-to-im] Bridge stopped");
|
|
19492
19667
|
}
|
|
19493
19668
|
}
|
|
19494
19669
|
});
|
|
19495
19670
|
await start();
|
|
19496
19671
|
let shuttingDown = false;
|
|
19497
|
-
const shutdown = async (
|
|
19672
|
+
const shutdown = async (reason, exitCode = 0) => {
|
|
19498
19673
|
if (shuttingDown) return;
|
|
19499
19674
|
shuttingDown = true;
|
|
19500
|
-
const reason = signal ? `signal: ${signal}` : "shutdown requested";
|
|
19501
19675
|
console.log(`[codex-to-im] Shutting down (${reason})...`);
|
|
19502
19676
|
pendingPerms.denyAll();
|
|
19503
|
-
|
|
19504
|
-
|
|
19505
|
-
|
|
19506
|
-
|
|
19677
|
+
try {
|
|
19678
|
+
await stop();
|
|
19679
|
+
} catch (error) {
|
|
19680
|
+
console.error("[codex-to-im] Graceful bridge stop failed:", error instanceof Error ? error.stack || error.message : error);
|
|
19681
|
+
} finally {
|
|
19682
|
+
releaseInstanceLock();
|
|
19683
|
+
try {
|
|
19684
|
+
writeStatus({ running: false, lastExitReason: reason }, { expectedRunId: runId });
|
|
19685
|
+
} catch (error) {
|
|
19686
|
+
console.error("[codex-to-im] Failed to write final runtime status:", error instanceof Error ? error.message : error);
|
|
19687
|
+
}
|
|
19688
|
+
process.exit(exitCode);
|
|
19689
|
+
}
|
|
19507
19690
|
};
|
|
19508
|
-
process.on("SIGTERM", () =>
|
|
19509
|
-
|
|
19510
|
-
|
|
19691
|
+
process.on("SIGTERM", () => {
|
|
19692
|
+
void shutdown("signal: SIGTERM");
|
|
19693
|
+
});
|
|
19694
|
+
process.on("SIGINT", () => {
|
|
19695
|
+
void shutdown("signal: SIGINT");
|
|
19696
|
+
});
|
|
19697
|
+
process.on("SIGHUP", () => {
|
|
19698
|
+
void shutdown("signal: SIGHUP");
|
|
19699
|
+
});
|
|
19511
19700
|
process.on("unhandledRejection", (reason) => {
|
|
19512
19701
|
console.error("[codex-to-im] unhandledRejection:", reason instanceof Error ? reason.stack || reason.message : reason);
|
|
19513
|
-
writeStatus({
|
|
19702
|
+
writeStatus({
|
|
19703
|
+
running: true,
|
|
19704
|
+
pid: process.pid,
|
|
19705
|
+
runId,
|
|
19706
|
+
channels: getRunningChannels(),
|
|
19707
|
+
adapters: getAdapterStatuses(),
|
|
19708
|
+
lastExitReason: `unhandledRejection: ${reason instanceof Error ? reason.message : String(reason)}`
|
|
19709
|
+
}, { expectedRunId: runId });
|
|
19514
19710
|
});
|
|
19515
19711
|
process.on("uncaughtException", (err) => {
|
|
19516
19712
|
console.error("[codex-to-im] uncaughtException:", err.stack || err.message);
|
|
19517
|
-
|
|
19518
|
-
writeStatus({ running: false, lastExitReason: `uncaughtException: ${err.message}` });
|
|
19519
|
-
process.exit(1);
|
|
19713
|
+
void shutdown(`uncaughtException: ${err.message}`, 1);
|
|
19520
19714
|
});
|
|
19521
19715
|
process.on("beforeExit", (code2) => {
|
|
19522
19716
|
console.log(`[codex-to-im] beforeExit (code: ${code2})`);
|
|
@@ -19532,7 +19726,10 @@ main().catch((err) => {
|
|
|
19532
19726
|
console.error("[codex-to-im] Fatal error:", err instanceof Error ? err.stack || err.message : err);
|
|
19533
19727
|
releaseBridgeInstanceLock(void 0, process.pid);
|
|
19534
19728
|
try {
|
|
19535
|
-
writeStatus(
|
|
19729
|
+
writeStatus(
|
|
19730
|
+
{ running: false, lastExitReason: `fatal: ${err instanceof Error ? err.message : String(err)}` },
|
|
19731
|
+
{ expectedRunId: runId }
|
|
19732
|
+
);
|
|
19536
19733
|
} catch {
|
|
19537
19734
|
}
|
|
19538
19735
|
process.exit(1);
|
package/dist/ui-server.mjs
CHANGED
|
@@ -1572,10 +1572,10 @@ var require_segments = __commonJS({
|
|
|
1572
1572
|
const segs = getSegmentsFromString(data, Utils.isKanjiModeEnabled());
|
|
1573
1573
|
const nodes = buildNodes(segs);
|
|
1574
1574
|
const graph = buildGraph(nodes, version);
|
|
1575
|
-
const
|
|
1575
|
+
const path11 = dijkstra.find_path(graph.map, "start", "end");
|
|
1576
1576
|
const optimizedSegs = [];
|
|
1577
|
-
for (let i = 1; i <
|
|
1578
|
-
optimizedSegs.push(graph.table[
|
|
1577
|
+
for (let i = 1; i < path11.length - 1; i++) {
|
|
1578
|
+
optimizedSegs.push(graph.table[path11[i]].node);
|
|
1579
1579
|
}
|
|
1580
1580
|
return exports.fromArray(mergeSegments(optimizedSegs));
|
|
1581
1581
|
};
|
|
@@ -4011,7 +4011,7 @@ var require_utils2 = __commonJS({
|
|
|
4011
4011
|
// node_modules/qrcode/lib/renderer/png.js
|
|
4012
4012
|
var require_png2 = __commonJS({
|
|
4013
4013
|
"node_modules/qrcode/lib/renderer/png.js"(exports) {
|
|
4014
|
-
var
|
|
4014
|
+
var fs11 = __require("fs");
|
|
4015
4015
|
var PNG = require_png().PNG;
|
|
4016
4016
|
var Utils = require_utils2();
|
|
4017
4017
|
exports.render = function render(qrData, options) {
|
|
@@ -4052,7 +4052,7 @@ var require_png2 = __commonJS({
|
|
|
4052
4052
|
});
|
|
4053
4053
|
png.pack();
|
|
4054
4054
|
};
|
|
4055
|
-
exports.renderToFile = function renderToFile(
|
|
4055
|
+
exports.renderToFile = function renderToFile(path11, qrData, options, cb) {
|
|
4056
4056
|
if (typeof cb === "undefined") {
|
|
4057
4057
|
cb = options;
|
|
4058
4058
|
options = void 0;
|
|
@@ -4063,7 +4063,7 @@ var require_png2 = __commonJS({
|
|
|
4063
4063
|
called = true;
|
|
4064
4064
|
cb.apply(null, args);
|
|
4065
4065
|
};
|
|
4066
|
-
const stream =
|
|
4066
|
+
const stream = fs11.createWriteStream(path11);
|
|
4067
4067
|
stream.on("error", done);
|
|
4068
4068
|
stream.on("close", done);
|
|
4069
4069
|
exports.renderToFileStream(stream, qrData, options);
|
|
@@ -4125,14 +4125,14 @@ var require_utf8 = __commonJS({
|
|
|
4125
4125
|
}
|
|
4126
4126
|
return output;
|
|
4127
4127
|
};
|
|
4128
|
-
exports.renderToFile = function renderToFile(
|
|
4128
|
+
exports.renderToFile = function renderToFile(path11, qrData, options, cb) {
|
|
4129
4129
|
if (typeof cb === "undefined") {
|
|
4130
4130
|
cb = options;
|
|
4131
4131
|
options = void 0;
|
|
4132
4132
|
}
|
|
4133
|
-
const
|
|
4133
|
+
const fs11 = __require("fs");
|
|
4134
4134
|
const utf8 = exports.render(qrData, options);
|
|
4135
|
-
|
|
4135
|
+
fs11.writeFile(path11, utf8, cb);
|
|
4136
4136
|
};
|
|
4137
4137
|
}
|
|
4138
4138
|
});
|
|
@@ -4253,7 +4253,7 @@ var require_svg_tag = __commonJS({
|
|
|
4253
4253
|
return str;
|
|
4254
4254
|
}
|
|
4255
4255
|
function qrToPath(data, size, margin) {
|
|
4256
|
-
let
|
|
4256
|
+
let path11 = "";
|
|
4257
4257
|
let moveBy = 0;
|
|
4258
4258
|
let newRow = false;
|
|
4259
4259
|
let lineLength = 0;
|
|
@@ -4264,19 +4264,19 @@ var require_svg_tag = __commonJS({
|
|
|
4264
4264
|
if (data[i]) {
|
|
4265
4265
|
lineLength++;
|
|
4266
4266
|
if (!(i > 0 && col > 0 && data[i - 1])) {
|
|
4267
|
-
|
|
4267
|
+
path11 += newRow ? svgCmd("M", col + margin, 0.5 + row + margin) : svgCmd("m", moveBy, 0);
|
|
4268
4268
|
moveBy = 0;
|
|
4269
4269
|
newRow = false;
|
|
4270
4270
|
}
|
|
4271
4271
|
if (!(col + 1 < size && data[i + 1])) {
|
|
4272
|
-
|
|
4272
|
+
path11 += svgCmd("h", lineLength);
|
|
4273
4273
|
lineLength = 0;
|
|
4274
4274
|
}
|
|
4275
4275
|
} else {
|
|
4276
4276
|
moveBy++;
|
|
4277
4277
|
}
|
|
4278
4278
|
}
|
|
4279
|
-
return
|
|
4279
|
+
return path11;
|
|
4280
4280
|
}
|
|
4281
4281
|
exports.render = function render(qrData, options, cb) {
|
|
4282
4282
|
const opts = Utils.getOptions(options);
|
|
@@ -4284,10 +4284,10 @@ var require_svg_tag = __commonJS({
|
|
|
4284
4284
|
const data = qrData.modules.data;
|
|
4285
4285
|
const qrcodesize = size + opts.margin * 2;
|
|
4286
4286
|
const bg = !opts.color.light.a ? "" : "<path " + getColorAttrib(opts.color.light, "fill") + ' d="M0 0h' + qrcodesize + "v" + qrcodesize + 'H0z"/>';
|
|
4287
|
-
const
|
|
4287
|
+
const path11 = "<path " + getColorAttrib(opts.color.dark, "stroke") + ' d="' + qrToPath(data, size, opts.margin) + '"/>';
|
|
4288
4288
|
const viewBox = 'viewBox="0 0 ' + qrcodesize + " " + qrcodesize + '"';
|
|
4289
4289
|
const width = !opts.width ? "" : 'width="' + opts.width + '" height="' + opts.width + '" ';
|
|
4290
|
-
const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg +
|
|
4290
|
+
const svgTag = '<svg xmlns="http://www.w3.org/2000/svg" ' + width + viewBox + ' shape-rendering="crispEdges">' + bg + path11 + "</svg>\n";
|
|
4291
4291
|
if (typeof cb === "function") {
|
|
4292
4292
|
cb(null, svgTag);
|
|
4293
4293
|
}
|
|
@@ -4301,15 +4301,15 @@ var require_svg = __commonJS({
|
|
|
4301
4301
|
"node_modules/qrcode/lib/renderer/svg.js"(exports) {
|
|
4302
4302
|
var svgTagRenderer = require_svg_tag();
|
|
4303
4303
|
exports.render = svgTagRenderer.render;
|
|
4304
|
-
exports.renderToFile = function renderToFile(
|
|
4304
|
+
exports.renderToFile = function renderToFile(path11, qrData, options, cb) {
|
|
4305
4305
|
if (typeof cb === "undefined") {
|
|
4306
4306
|
cb = options;
|
|
4307
4307
|
options = void 0;
|
|
4308
4308
|
}
|
|
4309
|
-
const
|
|
4309
|
+
const fs11 = __require("fs");
|
|
4310
4310
|
const svgTag = exports.render(qrData, options);
|
|
4311
4311
|
const xmlStr = '<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">' + svgTag;
|
|
4312
|
-
|
|
4312
|
+
fs11.writeFile(path11, xmlStr, cb);
|
|
4313
4313
|
};
|
|
4314
4314
|
}
|
|
4315
4315
|
});
|
|
@@ -4467,8 +4467,8 @@ var require_server = __commonJS({
|
|
|
4467
4467
|
cb
|
|
4468
4468
|
};
|
|
4469
4469
|
}
|
|
4470
|
-
function getTypeFromFilename(
|
|
4471
|
-
return
|
|
4470
|
+
function getTypeFromFilename(path11) {
|
|
4471
|
+
return path11.slice((path11.lastIndexOf(".") - 1 >>> 0) + 2).toLowerCase();
|
|
4472
4472
|
}
|
|
4473
4473
|
function getRendererFromType(type) {
|
|
4474
4474
|
switch (type) {
|
|
@@ -4532,17 +4532,17 @@ var require_server = __commonJS({
|
|
|
4532
4532
|
const renderer = getRendererFromType(params.opts.type);
|
|
4533
4533
|
return render(renderer.renderToBuffer, text2, params);
|
|
4534
4534
|
};
|
|
4535
|
-
exports.toFile = function toFile(
|
|
4536
|
-
if (typeof
|
|
4535
|
+
exports.toFile = function toFile(path11, text2, opts, cb) {
|
|
4536
|
+
if (typeof path11 !== "string" || !(typeof text2 === "string" || typeof text2 === "object")) {
|
|
4537
4537
|
throw new Error("Invalid argument");
|
|
4538
4538
|
}
|
|
4539
4539
|
if (arguments.length < 3 && !canPromise()) {
|
|
4540
4540
|
throw new Error("Too few arguments provided");
|
|
4541
4541
|
}
|
|
4542
4542
|
const params = checkParams(text2, opts, cb);
|
|
4543
|
-
const type = params.opts.type || getTypeFromFilename(
|
|
4543
|
+
const type = params.opts.type || getTypeFromFilename(path11);
|
|
4544
4544
|
const renderer = getRendererFromType(type);
|
|
4545
|
-
const renderToFile = renderer.renderToFile.bind(null,
|
|
4545
|
+
const renderToFile = renderer.renderToFile.bind(null, path11);
|
|
4546
4546
|
return render(renderToFile, text2, params);
|
|
4547
4547
|
};
|
|
4548
4548
|
exports.toFileStream = function toFileStream(stream, text2, opts) {
|
|
@@ -4566,7 +4566,7 @@ var require_lib = __commonJS({
|
|
|
4566
4566
|
|
|
4567
4567
|
// src/ui-server.ts
|
|
4568
4568
|
import http from "node:http";
|
|
4569
|
-
import
|
|
4569
|
+
import crypto9 from "node:crypto";
|
|
4570
4570
|
import net from "node:net";
|
|
4571
4571
|
import os5 from "node:os";
|
|
4572
4572
|
|
|
@@ -6438,40 +6438,76 @@ function isCodexIntegrationInstalled() {
|
|
|
6438
6438
|
}
|
|
6439
6439
|
|
|
6440
6440
|
// src/store.ts
|
|
6441
|
+
import fs7 from "node:fs";
|
|
6442
|
+
import path7 from "node:path";
|
|
6443
|
+
import crypto5 from "node:crypto";
|
|
6444
|
+
|
|
6445
|
+
// src/atomic-file.ts
|
|
6446
|
+
import crypto4 from "node:crypto";
|
|
6441
6447
|
import fs6 from "node:fs";
|
|
6442
6448
|
import path6 from "node:path";
|
|
6443
|
-
|
|
6444
|
-
var
|
|
6445
|
-
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
6455
|
-
|
|
6449
|
+
var RETRYABLE_RENAME_CODES = /* @__PURE__ */ new Set(["EACCES", "EBUSY", "EPERM"]);
|
|
6450
|
+
var WAIT_ARRAY2 = new Int32Array(new SharedArrayBuffer(4));
|
|
6451
|
+
function defaultSleepSync(delayMs) {
|
|
6452
|
+
Atomics.wait(WAIT_ARRAY2, 0, 0, Math.max(1, delayMs));
|
|
6453
|
+
}
|
|
6454
|
+
function isRetryableRenameError(error) {
|
|
6455
|
+
return RETRYABLE_RENAME_CODES.has(error?.code || "");
|
|
6456
|
+
}
|
|
6457
|
+
function renameFileWithRetrySync(source, destination, options = {}) {
|
|
6458
|
+
const maxAttempts = Math.max(1, options.maxAttempts ?? 8);
|
|
6459
|
+
const baseDelayMs = Math.max(1, options.baseDelayMs ?? 15);
|
|
6460
|
+
const renameSync = options.renameSync ?? fs6.renameSync;
|
|
6461
|
+
const sleepSync2 = options.sleepSync ?? defaultSleepSync;
|
|
6462
|
+
for (let attempt = 0; attempt < maxAttempts; attempt += 1) {
|
|
6463
|
+
try {
|
|
6464
|
+
renameSync(source, destination);
|
|
6465
|
+
return;
|
|
6466
|
+
} catch (error) {
|
|
6467
|
+
if (!isRetryableRenameError(error) || attempt === maxAttempts - 1) {
|
|
6468
|
+
throw error;
|
|
6469
|
+
}
|
|
6470
|
+
sleepSync2(Math.min(250, baseDelayMs * 2 ** attempt));
|
|
6471
|
+
}
|
|
6472
|
+
}
|
|
6456
6473
|
}
|
|
6457
|
-
function
|
|
6458
|
-
|
|
6474
|
+
function atomicWriteFileSync(filePath, data) {
|
|
6475
|
+
fs6.mkdirSync(path6.dirname(filePath), { recursive: true });
|
|
6476
|
+
const tmpPath = `${filePath}.${process.pid}.${crypto4.randomUUID()}.tmp`;
|
|
6459
6477
|
try {
|
|
6460
|
-
fs6.writeFileSync(
|
|
6461
|
-
|
|
6478
|
+
fs6.writeFileSync(tmpPath, data, "utf-8");
|
|
6479
|
+
renameFileWithRetrySync(tmpPath, filePath);
|
|
6462
6480
|
} finally {
|
|
6463
6481
|
try {
|
|
6464
|
-
fs6.rmSync(
|
|
6482
|
+
fs6.rmSync(tmpPath, { force: true });
|
|
6465
6483
|
} catch {
|
|
6466
6484
|
}
|
|
6467
6485
|
}
|
|
6468
6486
|
}
|
|
6487
|
+
|
|
6488
|
+
// src/store.ts
|
|
6489
|
+
var DATA_DIR = path7.join(CTI_HOME, "data");
|
|
6490
|
+
var MESSAGES_DIR = path7.join(DATA_DIR, "messages");
|
|
6491
|
+
var SESSIONS_PATH = path7.join(DATA_DIR, "sessions.json");
|
|
6492
|
+
var BINDINGS_PATH = path7.join(DATA_DIR, "bindings.json");
|
|
6493
|
+
var PERMISSIONS_PATH = path7.join(DATA_DIR, "permissions.json");
|
|
6494
|
+
var OFFSETS_PATH = path7.join(DATA_DIR, "offsets.json");
|
|
6495
|
+
var DEDUP_PATH = path7.join(DATA_DIR, "dedup.json");
|
|
6496
|
+
var AUDIT_PATH = path7.join(DATA_DIR, "audit.json");
|
|
6497
|
+
var DEFAULT_DEDUP_TTL_MS = 5 * 60 * 1e3;
|
|
6498
|
+
var INBOUND_DEDUP_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
6499
|
+
function ensureDir(dir) {
|
|
6500
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
6501
|
+
}
|
|
6502
|
+
function atomicWrite(filePath, data) {
|
|
6503
|
+
atomicWriteFileSync(filePath, data);
|
|
6504
|
+
}
|
|
6469
6505
|
function dedupTtlMs(key) {
|
|
6470
6506
|
return key.startsWith("inbound:") ? INBOUND_DEDUP_TTL_MS : DEFAULT_DEDUP_TTL_MS;
|
|
6471
6507
|
}
|
|
6472
6508
|
function readJson(filePath, fallback) {
|
|
6473
6509
|
try {
|
|
6474
|
-
const raw =
|
|
6510
|
+
const raw = fs7.readFileSync(filePath, "utf-8");
|
|
6475
6511
|
return JSON.parse(raw);
|
|
6476
6512
|
} catch (error) {
|
|
6477
6513
|
if (error.code === "ENOENT") return fallback;
|
|
@@ -6482,7 +6518,7 @@ function writeJson(filePath, data) {
|
|
|
6482
6518
|
atomicWrite(filePath, JSON.stringify(data, null, 2));
|
|
6483
6519
|
}
|
|
6484
6520
|
function uuid() {
|
|
6485
|
-
return
|
|
6521
|
+
return crypto5.randomUUID();
|
|
6486
6522
|
}
|
|
6487
6523
|
function now() {
|
|
6488
6524
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -6645,14 +6681,14 @@ var JsonFileStore = class {
|
|
|
6645
6681
|
}
|
|
6646
6682
|
persistMessages(sessionId) {
|
|
6647
6683
|
const msgs = this.messages.get(sessionId) || [];
|
|
6648
|
-
writeJson(
|
|
6684
|
+
writeJson(path7.join(MESSAGES_DIR, `${sessionId}.json`), msgs);
|
|
6649
6685
|
}
|
|
6650
6686
|
loadMessages(sessionId) {
|
|
6651
6687
|
if (this.messages.has(sessionId)) {
|
|
6652
6688
|
return this.messages.get(sessionId);
|
|
6653
6689
|
}
|
|
6654
6690
|
const msgs = readJson(
|
|
6655
|
-
|
|
6691
|
+
path7.join(MESSAGES_DIR, `${sessionId}.json`),
|
|
6656
6692
|
[]
|
|
6657
6693
|
);
|
|
6658
6694
|
this.messages.set(sessionId, msgs);
|
|
@@ -6675,7 +6711,7 @@ var JsonFileStore = class {
|
|
|
6675
6711
|
});
|
|
6676
6712
|
}
|
|
6677
6713
|
mutateMessages(sessionId, mutation) {
|
|
6678
|
-
const messagePath =
|
|
6714
|
+
const messagePath = path7.join(MESSAGES_DIR, `${sessionId}.json`);
|
|
6679
6715
|
return withFileLock(messagePath, () => {
|
|
6680
6716
|
const messages = readJson(messagePath, []);
|
|
6681
6717
|
this.messages.set(sessionId, messages);
|
|
@@ -6834,7 +6870,7 @@ var JsonFileStore = class {
|
|
|
6834
6870
|
});
|
|
6835
6871
|
}
|
|
6836
6872
|
deleteSession(sessionId) {
|
|
6837
|
-
const messagePath =
|
|
6873
|
+
const messagePath = path7.join(MESSAGES_DIR, `${sessionId}.json`);
|
|
6838
6874
|
withFileLocks([SESSIONS_PATH, BINDINGS_PATH, messagePath], () => {
|
|
6839
6875
|
this.reloadSessions();
|
|
6840
6876
|
this.reloadBindings();
|
|
@@ -6846,7 +6882,7 @@ var JsonFileStore = class {
|
|
|
6846
6882
|
}
|
|
6847
6883
|
this.messages.delete(sessionId);
|
|
6848
6884
|
try {
|
|
6849
|
-
|
|
6885
|
+
fs7.rmSync(messagePath, { force: true });
|
|
6850
6886
|
} catch {
|
|
6851
6887
|
}
|
|
6852
6888
|
this.persistSessions();
|
|
@@ -6860,7 +6896,7 @@ var JsonFileStore = class {
|
|
|
6860
6896
|
});
|
|
6861
6897
|
}
|
|
6862
6898
|
getMessages(sessionId, opts) {
|
|
6863
|
-
const messagePath =
|
|
6899
|
+
const messagePath = path7.join(MESSAGES_DIR, `${sessionId}.json`);
|
|
6864
6900
|
const msgs = readJson(messagePath, []);
|
|
6865
6901
|
this.messages.set(sessionId, msgs);
|
|
6866
6902
|
if (opts?.limit && opts.limit > 0) {
|
|
@@ -7064,13 +7100,13 @@ var JsonFileStore = class {
|
|
|
7064
7100
|
|
|
7065
7101
|
// src/weixin-login.ts
|
|
7066
7102
|
var import_qrcode = __toESM(require_lib(), 1);
|
|
7067
|
-
import
|
|
7068
|
-
import
|
|
7069
|
-
import
|
|
7103
|
+
import fs9 from "node:fs";
|
|
7104
|
+
import path9 from "node:path";
|
|
7105
|
+
import crypto8 from "node:crypto";
|
|
7070
7106
|
import { spawn as spawn2 } from "node:child_process";
|
|
7071
7107
|
|
|
7072
7108
|
// src/adapters/weixin/weixin-api.ts
|
|
7073
|
-
import
|
|
7109
|
+
import crypto6 from "node:crypto";
|
|
7074
7110
|
|
|
7075
7111
|
// src/adapters/weixin/weixin-types.ts
|
|
7076
7112
|
var DEFAULT_BASE_URL = "https://ilinkai.weixin.qq.com";
|
|
@@ -7119,32 +7155,32 @@ async function pollLoginQrStatus(qrcode, baseUrl) {
|
|
|
7119
7155
|
}
|
|
7120
7156
|
|
|
7121
7157
|
// src/weixin-store.ts
|
|
7122
|
-
import
|
|
7123
|
-
import
|
|
7124
|
-
import
|
|
7125
|
-
var DATA_DIR2 =
|
|
7126
|
-
var ACCOUNTS_PATH =
|
|
7127
|
-
var CONTEXT_TOKENS_PATH =
|
|
7158
|
+
import fs8 from "node:fs";
|
|
7159
|
+
import crypto7 from "node:crypto";
|
|
7160
|
+
import path8 from "node:path";
|
|
7161
|
+
var DATA_DIR2 = path8.join(CTI_HOME, "data");
|
|
7162
|
+
var ACCOUNTS_PATH = path8.join(DATA_DIR2, "weixin-accounts.json");
|
|
7163
|
+
var CONTEXT_TOKENS_PATH = path8.join(DATA_DIR2, "weixin-context-tokens.json");
|
|
7128
7164
|
var DEFAULT_BASE_URL2 = "https://ilinkai.weixin.qq.com";
|
|
7129
7165
|
var DEFAULT_CDN_BASE_URL2 = "https://novac2c.cdn.weixin.qq.com/c2c";
|
|
7130
7166
|
function ensureDir2(dir) {
|
|
7131
|
-
|
|
7167
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
7132
7168
|
}
|
|
7133
7169
|
function atomicWrite2(filePath, data) {
|
|
7134
|
-
const tmpPath = `${filePath}.${process.pid}.${
|
|
7170
|
+
const tmpPath = `${filePath}.${process.pid}.${crypto7.randomUUID()}.tmp`;
|
|
7135
7171
|
try {
|
|
7136
|
-
|
|
7137
|
-
|
|
7172
|
+
fs8.writeFileSync(tmpPath, data, "utf-8");
|
|
7173
|
+
fs8.renameSync(tmpPath, filePath);
|
|
7138
7174
|
} finally {
|
|
7139
7175
|
try {
|
|
7140
|
-
|
|
7176
|
+
fs8.rmSync(tmpPath, { force: true });
|
|
7141
7177
|
} catch {
|
|
7142
7178
|
}
|
|
7143
7179
|
}
|
|
7144
7180
|
}
|
|
7145
7181
|
function readJson2(filePath, fallback) {
|
|
7146
7182
|
try {
|
|
7147
|
-
const raw =
|
|
7183
|
+
const raw = fs8.readFileSync(filePath, "utf-8");
|
|
7148
7184
|
return JSON.parse(raw);
|
|
7149
7185
|
} catch (error) {
|
|
7150
7186
|
if (error.code === "ENOENT") return fallback;
|
|
@@ -7236,11 +7272,11 @@ var MAX_REFRESHES = 3;
|
|
|
7236
7272
|
var QR_TTL_MS = 5 * 6e4;
|
|
7237
7273
|
var POLL_INTERVAL_MS = 3e3;
|
|
7238
7274
|
var WEB_SESSION_TTL_MS = 15 * 6e4;
|
|
7239
|
-
var RUNTIME_DIR =
|
|
7240
|
-
var HTML_PATH =
|
|
7275
|
+
var RUNTIME_DIR = path9.join(CTI_HOME, "runtime");
|
|
7276
|
+
var HTML_PATH = path9.join(RUNTIME_DIR, "weixin-login.html");
|
|
7241
7277
|
var webLoginSessions = /* @__PURE__ */ new Map();
|
|
7242
7278
|
function ensureRuntimeDir() {
|
|
7243
|
-
|
|
7279
|
+
fs9.mkdirSync(RUNTIME_DIR, { recursive: true });
|
|
7244
7280
|
}
|
|
7245
7281
|
function escapeHtml(text2) {
|
|
7246
7282
|
return text2.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
@@ -7553,7 +7589,7 @@ function buildWeixinLoginPopupHtml(sessionId) {
|
|
|
7553
7589
|
async function writeQrHtml(session) {
|
|
7554
7590
|
ensureRuntimeDir();
|
|
7555
7591
|
const qrSvg = await buildQrSvg(session.qrImageUrl);
|
|
7556
|
-
|
|
7592
|
+
fs9.writeFileSync(HTML_PATH, buildQrHtml(qrSvg), "utf-8");
|
|
7557
7593
|
}
|
|
7558
7594
|
function openQrHtml() {
|
|
7559
7595
|
try {
|
|
@@ -7742,7 +7778,7 @@ async function startWeixinLoginWebSession(options = {}) {
|
|
|
7742
7778
|
ensureRuntimeDir();
|
|
7743
7779
|
const config = options.config || {};
|
|
7744
7780
|
const seed = await createSession(0, config.baseUrl);
|
|
7745
|
-
const sessionId =
|
|
7781
|
+
const sessionId = crypto8.randomUUID();
|
|
7746
7782
|
const qrSvg = await buildQrSvg(seed.qrImageUrl);
|
|
7747
7783
|
const session = {
|
|
7748
7784
|
id: sessionId,
|
|
@@ -7814,7 +7850,7 @@ async function runWeixinLogin(config = {}) {
|
|
|
7814
7850
|
}
|
|
7815
7851
|
var isMainModule = (() => {
|
|
7816
7852
|
const entry = process.argv[1];
|
|
7817
|
-
return !!entry &&
|
|
7853
|
+
return !!entry && path9.resolve(entry) === path9.resolve(new URL(import.meta.url).pathname);
|
|
7818
7854
|
})();
|
|
7819
7855
|
if (isMainModule) {
|
|
7820
7856
|
runWeixinLogin().catch((err) => {
|
|
@@ -7824,11 +7860,11 @@ if (isMainModule) {
|
|
|
7824
7860
|
}
|
|
7825
7861
|
|
|
7826
7862
|
// src/codex-models.ts
|
|
7827
|
-
import
|
|
7863
|
+
import fs10 from "node:fs";
|
|
7828
7864
|
import os4 from "node:os";
|
|
7829
|
-
import
|
|
7830
|
-
var DEFAULT_CODEX_CONFIG_PATH =
|
|
7831
|
-
var DEFAULT_CODEX_MODELS_CACHE_PATH =
|
|
7865
|
+
import path10 from "node:path";
|
|
7866
|
+
var DEFAULT_CODEX_CONFIG_PATH = path10.join(os4.homedir(), ".codex", "config.toml");
|
|
7867
|
+
var DEFAULT_CODEX_MODELS_CACHE_PATH = path10.join(os4.homedir(), ".codex", "models_cache.json");
|
|
7832
7868
|
var REASONING_LEVEL_DESCRIPTIONS = {
|
|
7833
7869
|
low: "Fast responses with lighter reasoning",
|
|
7834
7870
|
medium: "Balances speed and reasoning depth for everyday tasks",
|
|
@@ -7877,7 +7913,7 @@ var KNOWN_CODEX_MODEL_FALLBACKS = [
|
|
|
7877
7913
|
];
|
|
7878
7914
|
function readConfiguredCodexModel(configPath = DEFAULT_CODEX_CONFIG_PATH) {
|
|
7879
7915
|
try {
|
|
7880
|
-
const raw =
|
|
7916
|
+
const raw = fs10.readFileSync(configPath, "utf-8");
|
|
7881
7917
|
let inSection = false;
|
|
7882
7918
|
for (const line of raw.split(/\r?\n/)) {
|
|
7883
7919
|
const trimmed = line.trim();
|
|
@@ -7921,7 +7957,7 @@ function parseSupportedReasoningLevels(value) {
|
|
|
7921
7957
|
}
|
|
7922
7958
|
function listCachedCodexModels(cachePath = DEFAULT_CODEX_MODELS_CACHE_PATH) {
|
|
7923
7959
|
try {
|
|
7924
|
-
const raw =
|
|
7960
|
+
const raw = fs10.readFileSync(cachePath, "utf-8");
|
|
7925
7961
|
const parsed = JSON.parse(raw);
|
|
7926
7962
|
if (!Array.isArray(parsed.models)) return [];
|
|
7927
7963
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -8220,14 +8256,14 @@ function channelToPayload(channel) {
|
|
|
8220
8256
|
};
|
|
8221
8257
|
}
|
|
8222
8258
|
function generateAccessToken() {
|
|
8223
|
-
return
|
|
8259
|
+
return crypto9.randomBytes(18).toString("base64url");
|
|
8224
8260
|
}
|
|
8225
8261
|
function timingSafeMatch(left, right) {
|
|
8226
8262
|
if (!left || !right) return false;
|
|
8227
8263
|
const leftBuffer = Buffer.from(left);
|
|
8228
8264
|
const rightBuffer = Buffer.from(right);
|
|
8229
8265
|
if (leftBuffer.length !== rightBuffer.length) return false;
|
|
8230
|
-
return
|
|
8266
|
+
return crypto9.timingSafeEqual(leftBuffer, rightBuffer);
|
|
8231
8267
|
}
|
|
8232
8268
|
function parseCookies(request) {
|
|
8233
8269
|
const header = request.headers.cookie;
|
package/package.json
CHANGED