@ccpocket/bridge 1.86.2 → 1.88.0
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/codex-process.d.ts +11 -0
- package/dist/codex-process.js +99 -1
- package/dist/codex-process.js.map +1 -1
- package/dist/codex-recovery.d.ts +35 -0
- package/dist/codex-recovery.js +121 -0
- package/dist/codex-recovery.js.map +1 -0
- package/dist/parser.d.ts +25 -0
- package/dist/parser.js +20 -0
- package/dist/parser.js.map +1 -1
- package/dist/performance-mode.d.ts +4 -0
- package/dist/performance-mode.js +58 -0
- package/dist/performance-mode.js.map +1 -0
- package/dist/session.js +3 -1
- package/dist/session.js.map +1 -1
- package/dist/sessions-index.js +138 -30
- package/dist/sessions-index.js.map +1 -1
- package/dist/websocket.d.ts +3 -0
- package/dist/websocket.js +103 -18
- package/dist/websocket.js.map +1 -1
- package/package.json +1 -1
package/dist/websocket.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { performanceMessage } from "./performance-mode.js";
|
|
1
2
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
3
|
import { execFile, execFileSync } from "node:child_process";
|
|
3
4
|
import { existsSync } from "node:fs";
|
|
@@ -104,6 +105,7 @@ const CODEX_USER_TURN_UUID_RE = /^codex:user-turn:(\d+)$/;
|
|
|
104
105
|
const OPT_IN_SERVER_MESSAGES = new Set([
|
|
105
106
|
"conversation_queue",
|
|
106
107
|
"goal_state",
|
|
108
|
+
"codex_recovery_state",
|
|
107
109
|
"guardian_approval",
|
|
108
110
|
"prompt_history_status",
|
|
109
111
|
"projects",
|
|
@@ -571,6 +573,16 @@ export class BridgeWebSocketServer {
|
|
|
571
573
|
deltaBatchMaxChars;
|
|
572
574
|
deltaBatches = new Map();
|
|
573
575
|
platform;
|
|
576
|
+
deliveryPreferences = new WeakMap();
|
|
577
|
+
activityTimes = new WeakMap();
|
|
578
|
+
performanceEnabled(ws, msg) {
|
|
579
|
+
const prefs = this.deliveryPreferences.get(ws);
|
|
580
|
+
if (!prefs || typeof msg.sessionId !== "string")
|
|
581
|
+
return false;
|
|
582
|
+
return Object.hasOwn(prefs.sessions, msg.sessionId)
|
|
583
|
+
? prefs.sessions[msg.sessionId]
|
|
584
|
+
: prefs.enabled;
|
|
585
|
+
}
|
|
574
586
|
clientSupportedServerMessages = new WeakMap();
|
|
575
587
|
clientProtocolVersions = new WeakMap();
|
|
576
588
|
rejectedProtocolClients = new WeakSet();
|
|
@@ -618,7 +630,15 @@ export class BridgeWebSocketServer {
|
|
|
618
630
|
else {
|
|
619
631
|
console.log("[ws] Push relay enabled (Firebase Anonymous Auth)");
|
|
620
632
|
}
|
|
621
|
-
this.wss = new WebSocketServer({
|
|
633
|
+
this.wss = new WebSocketServer({
|
|
634
|
+
server,
|
|
635
|
+
perMessageDeflate: {
|
|
636
|
+
serverNoContextTakeover: true,
|
|
637
|
+
clientNoContextTakeover: true,
|
|
638
|
+
threshold: 1024,
|
|
639
|
+
zlibDeflateOptions: { level: 3 },
|
|
640
|
+
},
|
|
641
|
+
});
|
|
622
642
|
this.sessionManager = new SessionManager((sessionId, msg) => {
|
|
623
643
|
this.broadcastSessionMessage(sessionId, msg);
|
|
624
644
|
}, imageStore, galleryStore,
|
|
@@ -1954,6 +1974,13 @@ export class BridgeWebSocketServer {
|
|
|
1954
1974
|
}
|
|
1955
1975
|
this.clientProtocolVersions.set(ws, selectedProtocolVersion);
|
|
1956
1976
|
this.clientSupportedServerMessages.set(ws, new Set(msg.supportedServerMessages ?? []));
|
|
1977
|
+
this.deliveryPreferences.set(ws, {
|
|
1978
|
+
enabled: msg.performanceMode ?? false,
|
|
1979
|
+
sessions: msg.sessionPerformanceModes ?? {},
|
|
1980
|
+
});
|
|
1981
|
+
if (msg.deliveryRevision !== undefined) {
|
|
1982
|
+
this.send(ws, { type: "performance_mode_state", deliveryRevision: msg.deliveryRevision });
|
|
1983
|
+
}
|
|
1957
1984
|
this.sendPromptHistoryStatus(ws);
|
|
1958
1985
|
return;
|
|
1959
1986
|
}
|
|
@@ -3104,6 +3131,21 @@ export class BridgeWebSocketServer {
|
|
|
3104
3131
|
console.log(`[ws] set_codex_speed(codex): serviceTier=${serviceTier}`);
|
|
3105
3132
|
break;
|
|
3106
3133
|
}
|
|
3134
|
+
case "set_codex_recovery":
|
|
3135
|
+
case "cancel_codex_recovery": {
|
|
3136
|
+
const session = this.resolveSession(msg.sessionId);
|
|
3137
|
+
if (!session || session.provider !== "codex") {
|
|
3138
|
+
this.send(ws, { type: "error", sessionId: msg.sessionId, errorCode: "codex_recovery_unsupported", message: "Automatic recovery requires an active Codex session." });
|
|
3139
|
+
break;
|
|
3140
|
+
}
|
|
3141
|
+
const process = session.process;
|
|
3142
|
+
if (msg.type === "set_codex_recovery")
|
|
3143
|
+
process.setRecoveryEnabled(msg.enabled);
|
|
3144
|
+
else
|
|
3145
|
+
process.cancelRecovery();
|
|
3146
|
+
this.send(ws, { type: "codex_recovery_state", sessionId: session.id, recovery: process.getRecoveryState() });
|
|
3147
|
+
break;
|
|
3148
|
+
}
|
|
3107
3149
|
case "get_goal": {
|
|
3108
3150
|
const session = this.resolveSession(msg.sessionId);
|
|
3109
3151
|
if (!session || session.provider !== "codex") {
|
|
@@ -6549,6 +6591,7 @@ export class BridgeWebSocketServer {
|
|
|
6549
6591
|
protocolVersion: BRIDGE_PROTOCOL_MAX_VERSION,
|
|
6550
6592
|
minimumProtocolVersion: BRIDGE_PROTOCOL_MIN_VERSION,
|
|
6551
6593
|
protocolCapabilities: [
|
|
6594
|
+
"performance_mode_v1",
|
|
6552
6595
|
"project_request_correlation_v1",
|
|
6553
6596
|
"session_context_v1",
|
|
6554
6597
|
],
|
|
@@ -6587,6 +6630,7 @@ export class BridgeWebSocketServer {
|
|
|
6587
6630
|
protocolVersion: BRIDGE_PROTOCOL_MAX_VERSION,
|
|
6588
6631
|
minimumProtocolVersion: BRIDGE_PROTOCOL_MIN_VERSION,
|
|
6589
6632
|
protocolCapabilities: [
|
|
6633
|
+
"performance_mode_v1",
|
|
6590
6634
|
"project_request_correlation_v1",
|
|
6591
6635
|
"session_context_v1",
|
|
6592
6636
|
],
|
|
@@ -6620,12 +6664,17 @@ export class BridgeWebSocketServer {
|
|
|
6620
6664
|
broadcastSessionMessage(sessionId, msg, exclude) {
|
|
6621
6665
|
if (this.shouldBatchDelta(msg, exclude)) {
|
|
6622
6666
|
this.trackSessionMessage(sessionId, msg);
|
|
6623
|
-
|
|
6667
|
+
let chunks;
|
|
6624
6668
|
for (const client of this.wss.clients) {
|
|
6625
6669
|
if (client.readyState !== WebSocket.OPEN)
|
|
6626
6670
|
continue;
|
|
6627
6671
|
if (!this.shouldSendToClient(client, msg))
|
|
6628
6672
|
continue;
|
|
6673
|
+
if (msg.type === "thinking_delta" && this.performanceEnabled(client, { sessionId })) {
|
|
6674
|
+
this.send(client, { ...msg, sessionId });
|
|
6675
|
+
continue;
|
|
6676
|
+
}
|
|
6677
|
+
chunks ??= this.splitDeltaText(msg.text);
|
|
6629
6678
|
this.queueDeltaForClient(client, sessionId, msg.type, chunks);
|
|
6630
6679
|
}
|
|
6631
6680
|
return;
|
|
@@ -6717,7 +6766,7 @@ export class BridgeWebSocketServer {
|
|
|
6717
6766
|
if (client.readyState !== WebSocket.OPEN)
|
|
6718
6767
|
return;
|
|
6719
6768
|
for (const msg of batch.messages) {
|
|
6720
|
-
|
|
6769
|
+
this.send(client, { ...msg, sessionId });
|
|
6721
6770
|
}
|
|
6722
6771
|
}
|
|
6723
6772
|
discardClientDeltaBatches(client) {
|
|
@@ -6858,9 +6907,9 @@ export class BridgeWebSocketServer {
|
|
|
6858
6907
|
}
|
|
6859
6908
|
}
|
|
6860
6909
|
async listWorkspaceFilteredCodexThreads(msg, matchesWorkspace, limit) {
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
const
|
|
6910
|
+
// A busy app-server can be blocked on a large thread/read or a running turn.
|
|
6911
|
+
// Discovery must remain independent so one session cannot hide the list.
|
|
6912
|
+
const process = await this.createStandaloneCodexProcess(undefined);
|
|
6864
6913
|
try {
|
|
6865
6914
|
const archivedIds = this.archiveStore.archivedIds();
|
|
6866
6915
|
const matchingThreads = [];
|
|
@@ -6892,12 +6941,19 @@ export class BridgeWebSocketServer {
|
|
|
6892
6941
|
}
|
|
6893
6942
|
cursor = result.nextCursor;
|
|
6894
6943
|
} while (matchingThreads.length < limit && cursor != null);
|
|
6895
|
-
const indexedById = await
|
|
6896
|
-
|
|
6944
|
+
const [indexedById, threadNames] = await Promise.all([
|
|
6945
|
+
getCodexSessionIndexMetadata(matchingThreads.map((thread) => thread.id)),
|
|
6946
|
+
loadCodexSessionNames(),
|
|
6947
|
+
]);
|
|
6948
|
+
return matchingThreads.map((thread) => this.enrichRecentSessionWorkspace({
|
|
6949
|
+
...codexThreadToRecentSession(thread, indexedById.get(thread.id)),
|
|
6950
|
+
...(threadNames.get(thread.id)
|
|
6951
|
+
? { name: threadNames.get(thread.id) }
|
|
6952
|
+
: {}),
|
|
6953
|
+
}));
|
|
6897
6954
|
}
|
|
6898
6955
|
finally {
|
|
6899
|
-
|
|
6900
|
-
process.stop();
|
|
6956
|
+
process.stop();
|
|
6901
6957
|
}
|
|
6902
6958
|
}
|
|
6903
6959
|
async listRecentSessionsRaw(msg) {
|
|
@@ -7319,9 +7375,7 @@ export class BridgeWebSocketServer {
|
|
|
7319
7375
|
async listRecentCodexThreads(msg) {
|
|
7320
7376
|
const limit = msg.limit ?? 20;
|
|
7321
7377
|
const offset = msg.offset ?? 0;
|
|
7322
|
-
const process = this.
|
|
7323
|
-
(await this.createStandaloneCodexProcess(msg.projectPath));
|
|
7324
|
-
const isStandalone = process !== this.getActiveCodexProcess();
|
|
7378
|
+
const process = await this.createStandaloneCodexProcess(msg.projectPath);
|
|
7325
7379
|
try {
|
|
7326
7380
|
const archivedIds = this.archiveStore.archivedIds();
|
|
7327
7381
|
const visibleThreads = [];
|
|
@@ -7349,17 +7403,23 @@ export class BridgeWebSocketServer {
|
|
|
7349
7403
|
hasServerMore = cursor != null;
|
|
7350
7404
|
} while (visibleThreads.length < targetCount && cursor != null);
|
|
7351
7405
|
const pageThreads = visibleThreads.slice(offset, offset + limit);
|
|
7352
|
-
const indexedById = await
|
|
7353
|
-
|
|
7406
|
+
const [indexedById, threadNames] = await Promise.all([
|
|
7407
|
+
getCodexSessionIndexMetadata(pageThreads.map((thread) => thread.id)),
|
|
7408
|
+
loadCodexSessionNames(),
|
|
7409
|
+
]);
|
|
7410
|
+
const sessions = pageThreads.map((thread) => ({
|
|
7411
|
+
...codexThreadToRecentSession(thread, indexedById.get(thread.id)),
|
|
7412
|
+
...(threadNames.get(thread.id)
|
|
7413
|
+
? { name: threadNames.get(thread.id) }
|
|
7414
|
+
: {}),
|
|
7415
|
+
}));
|
|
7354
7416
|
return {
|
|
7355
7417
|
sessions,
|
|
7356
7418
|
hasMore: hasServerMore || visibleThreads.length > offset + limit,
|
|
7357
7419
|
};
|
|
7358
7420
|
}
|
|
7359
7421
|
finally {
|
|
7360
|
-
|
|
7361
|
-
process.stop();
|
|
7362
|
-
}
|
|
7422
|
+
process.stop();
|
|
7363
7423
|
}
|
|
7364
7424
|
}
|
|
7365
7425
|
async createStandaloneCodexProcess(projectPath) {
|
|
@@ -7623,6 +7683,28 @@ export class BridgeWebSocketServer {
|
|
|
7623
7683
|
prepareServerMessageForClient(ws, msg) {
|
|
7624
7684
|
if (!this.shouldSendToClient(ws, msg))
|
|
7625
7685
|
return null;
|
|
7686
|
+
if (this.performanceEnabled(ws, msg)) {
|
|
7687
|
+
const projected = performanceMessage(msg);
|
|
7688
|
+
if (projected) {
|
|
7689
|
+
msg = projected;
|
|
7690
|
+
}
|
|
7691
|
+
else {
|
|
7692
|
+
const sessionId = msg.sessionId;
|
|
7693
|
+
const times = this.activityTimes.get(ws) ?? new Map();
|
|
7694
|
+
this.activityTimes.set(ws, times);
|
|
7695
|
+
const now = Date.now();
|
|
7696
|
+
if (now - (times.get(sessionId) ?? 0) < 1000)
|
|
7697
|
+
return null;
|
|
7698
|
+
times.set(sessionId, now);
|
|
7699
|
+
const historySeq = msg.historySeq;
|
|
7700
|
+
return {
|
|
7701
|
+
type: "session_activity",
|
|
7702
|
+
sessionId,
|
|
7703
|
+
historySeq: typeof historySeq === "number" ? historySeq : undefined,
|
|
7704
|
+
at: new Date(now).toISOString(),
|
|
7705
|
+
};
|
|
7706
|
+
}
|
|
7707
|
+
}
|
|
7626
7708
|
if (!("messages" in msg) || !Array.isArray(msg.messages))
|
|
7627
7709
|
return msg;
|
|
7628
7710
|
const messages = msg.messages;
|
|
@@ -7699,6 +7781,9 @@ export class BridgeWebSocketServer {
|
|
|
7699
7781
|
});
|
|
7700
7782
|
}
|
|
7701
7783
|
sendCodexGoalState(ws, sessionId, session) {
|
|
7784
|
+
const recovery = session.process.getRecoveryState?.();
|
|
7785
|
+
if (recovery)
|
|
7786
|
+
this.send(ws, { type: "codex_recovery_state", sessionId, recovery });
|
|
7702
7787
|
if (session.codexGoal === undefined)
|
|
7703
7788
|
return;
|
|
7704
7789
|
this.send(ws, {
|