@ccpocket/bridge 1.43.0 → 1.44.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 +17 -0
- package/dist/codex-process.js +38 -0
- package/dist/codex-process.js.map +1 -1
- package/dist/parser.d.ts +41 -0
- package/dist/parser.js +34 -0
- package/dist/parser.js.map +1 -1
- package/dist/session.d.ts +33 -2
- package/dist/session.js +136 -0
- package/dist/session.js.map +1 -1
- package/dist/websocket.js +157 -20
- package/dist/websocket.js.map +1 -1
- package/package.json +1 -1
package/dist/websocket.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
1
2
|
import { execFile, execFileSync } from "node:child_process";
|
|
2
3
|
import { existsSync } from "node:fs";
|
|
3
4
|
import { lstat, readFile, readlink, stat, unlink } from "node:fs/promises";
|
|
@@ -667,16 +668,8 @@ export class BridgeWebSocketServer {
|
|
|
667
668
|
return;
|
|
668
669
|
}
|
|
669
670
|
const text = msg.text;
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
!session.process.isWaitingForInput) {
|
|
673
|
-
this.send(ws, {
|
|
674
|
-
type: "input_rejected",
|
|
675
|
-
sessionId: session.id,
|
|
676
|
-
reason: "Process is busy",
|
|
677
|
-
});
|
|
678
|
-
break;
|
|
679
|
-
}
|
|
671
|
+
const codexSkills = msg.skills ?? (msg.skill ? [msg.skill] : []);
|
|
672
|
+
const codexMentions = msg.mentions ?? [];
|
|
680
673
|
// Snapshot busy state before dispatch. We prefer the actual enqueue
|
|
681
674
|
// result returned by SdkProcess sendInput* below, but keep this as a
|
|
682
675
|
// fallback for test doubles and async paths.
|
|
@@ -709,6 +702,50 @@ export class BridgeWebSocketServer {
|
|
|
709
702
|
if (imageRefs.length === 0)
|
|
710
703
|
imageRefs = undefined;
|
|
711
704
|
}
|
|
705
|
+
if (session.provider === "codex" &&
|
|
706
|
+
!session.process.isWaitingForInput) {
|
|
707
|
+
if (session.codexQueuedInput) {
|
|
708
|
+
this.send(ws, {
|
|
709
|
+
type: "input_rejected",
|
|
710
|
+
sessionId: session.id,
|
|
711
|
+
reason: "Queue is full",
|
|
712
|
+
});
|
|
713
|
+
break;
|
|
714
|
+
}
|
|
715
|
+
const queued = this.sessionManager.queueCodexInput(session.id, {
|
|
716
|
+
itemId: randomUUID(),
|
|
717
|
+
text,
|
|
718
|
+
createdAt: new Date().toISOString(),
|
|
719
|
+
...(images.length > 0 ? { imageCount: images.length, images } : {}),
|
|
720
|
+
...(imageRefs ? { imageRefs } : {}),
|
|
721
|
+
...(codexSkills.length > 0 ? { skills: codexSkills } : {}),
|
|
722
|
+
...(codexMentions.length > 0 ? { mentions: codexMentions } : {}),
|
|
723
|
+
});
|
|
724
|
+
if (!queued) {
|
|
725
|
+
this.send(ws, {
|
|
726
|
+
type: "input_rejected",
|
|
727
|
+
sessionId: session.id,
|
|
728
|
+
reason: "Queue is full",
|
|
729
|
+
});
|
|
730
|
+
break;
|
|
731
|
+
}
|
|
732
|
+
if (images.length > 0 && this.galleryStore && session.projectPath) {
|
|
733
|
+
for (const img of images) {
|
|
734
|
+
this.galleryStore
|
|
735
|
+
.addImageFromBase64(img.base64, img.mimeType, session.projectPath, msg.sessionId)
|
|
736
|
+
.catch((err) => {
|
|
737
|
+
console.warn(`[ws] Failed to persist queued image to gallery: ${err}`);
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
this.send(ws, {
|
|
742
|
+
type: "input_ack",
|
|
743
|
+
sessionId: session.id,
|
|
744
|
+
queued: true,
|
|
745
|
+
});
|
|
746
|
+
this.broadcastSessionList();
|
|
747
|
+
break;
|
|
748
|
+
}
|
|
712
749
|
session.history.push({
|
|
713
750
|
type: "user_input",
|
|
714
751
|
text,
|
|
@@ -734,13 +771,11 @@ export class BridgeWebSocketServer {
|
|
|
734
771
|
queued: false,
|
|
735
772
|
});
|
|
736
773
|
const codexProc = session.process;
|
|
737
|
-
const skills = msg.skills ?? (msg.skill ? [msg.skill] : []);
|
|
738
|
-
const mentions = msg.mentions ?? [];
|
|
739
774
|
if (images.length > 0) {
|
|
740
775
|
codexProc.sendInputStructured(text, {
|
|
741
776
|
images,
|
|
742
|
-
skills,
|
|
743
|
-
mentions,
|
|
777
|
+
skills: codexSkills,
|
|
778
|
+
mentions: codexMentions,
|
|
744
779
|
});
|
|
745
780
|
}
|
|
746
781
|
else if (msg.imageId && this.galleryStore) {
|
|
@@ -750,22 +785,31 @@ export class BridgeWebSocketServer {
|
|
|
750
785
|
if (imageData) {
|
|
751
786
|
codexProc.sendInputStructured(text, {
|
|
752
787
|
images: [imageData],
|
|
753
|
-
skills,
|
|
754
|
-
mentions,
|
|
788
|
+
skills: codexSkills,
|
|
789
|
+
mentions: codexMentions,
|
|
755
790
|
});
|
|
756
791
|
}
|
|
757
792
|
else {
|
|
758
793
|
console.warn(`[ws] Image not found: ${msg.imageId}`);
|
|
759
|
-
codexProc.sendInputStructured(text, {
|
|
794
|
+
codexProc.sendInputStructured(text, {
|
|
795
|
+
skills: codexSkills,
|
|
796
|
+
mentions: codexMentions,
|
|
797
|
+
});
|
|
760
798
|
}
|
|
761
799
|
})
|
|
762
800
|
.catch((err) => {
|
|
763
801
|
console.error(`[ws] Failed to load image: ${err}`);
|
|
764
|
-
codexProc.sendInputStructured(text, {
|
|
802
|
+
codexProc.sendInputStructured(text, {
|
|
803
|
+
skills: codexSkills,
|
|
804
|
+
mentions: codexMentions,
|
|
805
|
+
});
|
|
765
806
|
});
|
|
766
807
|
}
|
|
767
|
-
else if (
|
|
768
|
-
codexProc.sendInputStructured(text, {
|
|
808
|
+
else if (codexSkills.length > 0 || codexMentions.length > 0) {
|
|
809
|
+
codexProc.sendInputStructured(text, {
|
|
810
|
+
skills: codexSkills,
|
|
811
|
+
mentions: codexMentions,
|
|
812
|
+
});
|
|
769
813
|
}
|
|
770
814
|
else {
|
|
771
815
|
codexProc.sendInput(text);
|
|
@@ -841,6 +885,69 @@ export class BridgeWebSocketServer {
|
|
|
841
885
|
}
|
|
842
886
|
break;
|
|
843
887
|
}
|
|
888
|
+
case "update_queued_input": {
|
|
889
|
+
const session = this.resolveSession(msg.sessionId);
|
|
890
|
+
if (!session || session.provider !== "codex") {
|
|
891
|
+
this.send(ws, { type: "error", message: "No active Codex session." });
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
if (!msg.text.trim()) {
|
|
895
|
+
this.send(ws, {
|
|
896
|
+
type: "error",
|
|
897
|
+
message: "Queued message cannot be empty.",
|
|
898
|
+
});
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
const success = this.sessionManager.updateCodexQueuedInput(session.id, msg.itemId, msg.text, { skills: msg.skills ?? [], mentions: msg.mentions ?? [] });
|
|
902
|
+
if (!success) {
|
|
903
|
+
this.send(ws, {
|
|
904
|
+
type: "error",
|
|
905
|
+
message: "Queued message not found.",
|
|
906
|
+
errorCode: "queued_input_not_found",
|
|
907
|
+
});
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
this.broadcastSessionList();
|
|
911
|
+
break;
|
|
912
|
+
}
|
|
913
|
+
case "cancel_queued_input": {
|
|
914
|
+
const session = this.resolveSession(msg.sessionId);
|
|
915
|
+
if (!session || session.provider !== "codex") {
|
|
916
|
+
this.send(ws, { type: "error", message: "No active Codex session." });
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
const success = this.sessionManager.cancelCodexQueuedInput(session.id, msg.itemId);
|
|
920
|
+
if (!success) {
|
|
921
|
+
this.send(ws, {
|
|
922
|
+
type: "error",
|
|
923
|
+
message: "Queued message not found.",
|
|
924
|
+
errorCode: "queued_input_not_found",
|
|
925
|
+
});
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
this.broadcastSessionList();
|
|
929
|
+
break;
|
|
930
|
+
}
|
|
931
|
+
case "steer_queued_input": {
|
|
932
|
+
const session = this.resolveSession(msg.sessionId);
|
|
933
|
+
if (!session || session.provider !== "codex") {
|
|
934
|
+
this.send(ws, { type: "error", message: "No active Codex session." });
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
const result = await this.sessionManager.steerCodexQueuedInput(session.id, msg.itemId);
|
|
938
|
+
if (!result.ok) {
|
|
939
|
+
this.send(ws, {
|
|
940
|
+
type: "error",
|
|
941
|
+
message: result.error,
|
|
942
|
+
errorCode: result.error === "Queued message not found."
|
|
943
|
+
? "queued_input_not_found"
|
|
944
|
+
: "queued_input_steer_failed",
|
|
945
|
+
});
|
|
946
|
+
return;
|
|
947
|
+
}
|
|
948
|
+
this.broadcastSessionList();
|
|
949
|
+
break;
|
|
950
|
+
}
|
|
844
951
|
case "push_register": {
|
|
845
952
|
const locale = normalizePushLocale(msg.locale);
|
|
846
953
|
const privacyMode = msg.privacyMode === true;
|
|
@@ -958,6 +1065,11 @@ export class BridgeWebSocketServer {
|
|
|
958
1065
|
if (newCollaboration !== currentCollaboration) {
|
|
959
1066
|
process.setCollaborationMode(newCollaboration);
|
|
960
1067
|
}
|
|
1068
|
+
session.codexSettings = {
|
|
1069
|
+
...(session.codexSettings ?? {}),
|
|
1070
|
+
approvalPolicy: newApproval,
|
|
1071
|
+
approvalsReviewer: newReviewer,
|
|
1072
|
+
};
|
|
961
1073
|
session.lastActivityAt = new Date();
|
|
962
1074
|
this.broadcast({
|
|
963
1075
|
type: "system",
|
|
@@ -1473,6 +1585,31 @@ export class BridgeWebSocketServer {
|
|
|
1473
1585
|
status: session.status,
|
|
1474
1586
|
sessionId: msg.sessionId,
|
|
1475
1587
|
});
|
|
1588
|
+
if (session.provider === "codex") {
|
|
1589
|
+
const item = session.codexQueuedInput;
|
|
1590
|
+
this.send(ws, {
|
|
1591
|
+
type: "conversation_queue",
|
|
1592
|
+
sessionId: msg.sessionId,
|
|
1593
|
+
limit: 1,
|
|
1594
|
+
items: item
|
|
1595
|
+
? [
|
|
1596
|
+
{
|
|
1597
|
+
itemId: item.itemId,
|
|
1598
|
+
text: item.text,
|
|
1599
|
+
createdAt: item.createdAt,
|
|
1600
|
+
...(item.updatedAt ? { updatedAt: item.updatedAt } : {}),
|
|
1601
|
+
...(item.imageCount
|
|
1602
|
+
? { imageCount: item.imageCount }
|
|
1603
|
+
: {}),
|
|
1604
|
+
...(item.skills?.length ? { skills: item.skills } : {}),
|
|
1605
|
+
...(item.mentions?.length
|
|
1606
|
+
? { mentions: item.mentions }
|
|
1607
|
+
: {}),
|
|
1608
|
+
},
|
|
1609
|
+
]
|
|
1610
|
+
: [],
|
|
1611
|
+
});
|
|
1612
|
+
}
|
|
1476
1613
|
// Send cached slash commands so the client can restore them even when
|
|
1477
1614
|
// the original init/supported_commands message was evicted from the
|
|
1478
1615
|
// in-memory history (MAX_HISTORY_PER_SESSION overflow).
|