agent-companion 0.1.1 → 0.1.2
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/bridge/server.mjs +189 -10
- package/package.json +1 -1
package/bridge/server.mjs
CHANGED
|
@@ -151,6 +151,11 @@ function normalizeState(value) {
|
|
|
151
151
|
return allowed.includes(value) ? value : "RUNNING";
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
+
function isDirectSessionId(value) {
|
|
155
|
+
const id = safeTrimmedText(value, 160);
|
|
156
|
+
return id.startsWith("codex:") || id.startsWith("claude:");
|
|
157
|
+
}
|
|
158
|
+
|
|
154
159
|
function normalizeCategory(value) {
|
|
155
160
|
const allowed = ["INFO", "ACTION", "INPUT", "ERROR"];
|
|
156
161
|
return allowed.includes(value) ? value : "INFO";
|
|
@@ -627,6 +632,170 @@ function extractClaudeSessionIdFromRun(run) {
|
|
|
627
632
|
return "";
|
|
628
633
|
}
|
|
629
634
|
|
|
635
|
+
function normalizeClaudeSessionId(value) {
|
|
636
|
+
const candidate = safeTrimmedText(value, 120).toLowerCase();
|
|
637
|
+
if (!candidate) return "";
|
|
638
|
+
if (/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(candidate)) {
|
|
639
|
+
return candidate;
|
|
640
|
+
}
|
|
641
|
+
return "";
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
function getLauncherRunUpdatedAt(run) {
|
|
645
|
+
return Math.max(
|
|
646
|
+
safeNumber(run?.endedAt, 0),
|
|
647
|
+
safeNumber(run?.startedAt, 0),
|
|
648
|
+
safeNumber(run?.createdAt, 0)
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
function resolveCanonicalSessionIdForDirectSession(sessionId) {
|
|
653
|
+
const directSessionId = safeTrimmedText(sessionId, 160);
|
|
654
|
+
if (!isDirectSessionId(directSessionId)) return directSessionId;
|
|
655
|
+
|
|
656
|
+
if (directSessionId.startsWith("codex:")) {
|
|
657
|
+
const threadId = directSessionId.slice("codex:".length).trim().toLowerCase();
|
|
658
|
+
if (!threadId) return directSessionId;
|
|
659
|
+
|
|
660
|
+
const mappedRun = [...launcherRuns.values()]
|
|
661
|
+
.slice()
|
|
662
|
+
.sort((a, b) => getLauncherRunUpdatedAt(b) - getLauncherRunUpdatedAt(a))
|
|
663
|
+
.find((run) => !isDirectSessionId(run?.sessionId) && extractCodexThreadIdFromRun(run) === threadId);
|
|
664
|
+
if (mappedRun?.sessionId) return mappedRun.sessionId;
|
|
665
|
+
|
|
666
|
+
const mappedThread = (Array.isArray(state.sessionThreads) ? state.sessionThreads : [])
|
|
667
|
+
.slice()
|
|
668
|
+
.sort((a, b) => safeNumber(b.updatedAt, 0) - safeNumber(a.updatedAt, 0))
|
|
669
|
+
.find(
|
|
670
|
+
(thread) =>
|
|
671
|
+
!isDirectSessionId(thread?.id) &&
|
|
672
|
+
safeTrimmedText(thread?.codexThreadId, 120).toLowerCase() === threadId
|
|
673
|
+
);
|
|
674
|
+
if (mappedThread?.id) return mappedThread.id;
|
|
675
|
+
|
|
676
|
+
return directSessionId;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
const claudeSessionId = normalizeClaudeSessionId(directSessionId.slice("claude:".length));
|
|
680
|
+
if (!claudeSessionId) return directSessionId;
|
|
681
|
+
|
|
682
|
+
const mappedRun = [...launcherRuns.values()]
|
|
683
|
+
.slice()
|
|
684
|
+
.sort((a, b) => getLauncherRunUpdatedAt(b) - getLauncherRunUpdatedAt(a))
|
|
685
|
+
.find((run) => !isDirectSessionId(run?.sessionId) && extractClaudeSessionIdFromRun(run) === claudeSessionId);
|
|
686
|
+
if (mappedRun?.sessionId) return mappedRun.sessionId;
|
|
687
|
+
|
|
688
|
+
const mappedThread = (Array.isArray(state.sessionThreads) ? state.sessionThreads : [])
|
|
689
|
+
.slice()
|
|
690
|
+
.sort((a, b) => safeNumber(b.updatedAt, 0) - safeNumber(a.updatedAt, 0))
|
|
691
|
+
.find(
|
|
692
|
+
(thread) =>
|
|
693
|
+
!isDirectSessionId(thread?.id) &&
|
|
694
|
+
normalizeClaudeSessionId(thread?.claudeSessionId) === claudeSessionId
|
|
695
|
+
);
|
|
696
|
+
if (mappedThread?.id) return mappedThread.id;
|
|
697
|
+
|
|
698
|
+
return directSessionId;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
function rewriteDirectScopedId(id, originalSessionId, canonicalSessionId) {
|
|
702
|
+
const text = safeTrimmedText(id, 240);
|
|
703
|
+
if (!text || !originalSessionId || !canonicalSessionId || originalSessionId === canonicalSessionId) {
|
|
704
|
+
return text || id;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
if (text === `pending:${originalSessionId}`) {
|
|
708
|
+
return `pending:${canonicalSessionId}`;
|
|
709
|
+
}
|
|
710
|
+
if (text === `event:${originalSessionId}`) {
|
|
711
|
+
return `event:${canonicalSessionId}`;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
const directPrefix = `direct:${originalSessionId}:`;
|
|
715
|
+
if (text.startsWith(directPrefix)) {
|
|
716
|
+
return `direct:${canonicalSessionId}:${text.slice(directPrefix.length)}`;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
return text;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
function canonicalizeDirectSnapshot(snapshot) {
|
|
723
|
+
if (!snapshot || typeof snapshot !== "object") return snapshot;
|
|
724
|
+
|
|
725
|
+
const sessionIdMap = new Map();
|
|
726
|
+
const sourceDirectSessionIds = new Set();
|
|
727
|
+
|
|
728
|
+
const remapSessionId = (value) => {
|
|
729
|
+
const sessionId = safeTrimmedText(value, 160);
|
|
730
|
+
if (!isDirectSessionId(sessionId)) return sessionId;
|
|
731
|
+
sourceDirectSessionIds.add(sessionId);
|
|
732
|
+
|
|
733
|
+
const existing = sessionIdMap.get(sessionId);
|
|
734
|
+
if (existing) return existing;
|
|
735
|
+
|
|
736
|
+
const canonical = resolveCanonicalSessionIdForDirectSession(sessionId) || sessionId;
|
|
737
|
+
sessionIdMap.set(sessionId, canonical);
|
|
738
|
+
return canonical;
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
const sessions = (Array.isArray(snapshot.sessions) ? snapshot.sessions : []).map((item) => {
|
|
742
|
+
const originalSessionId = safeTrimmedText(item?.id, 160);
|
|
743
|
+
const canonicalSessionId = remapSessionId(originalSessionId);
|
|
744
|
+
if (!originalSessionId || !canonicalSessionId || canonicalSessionId === originalSessionId) {
|
|
745
|
+
return item;
|
|
746
|
+
}
|
|
747
|
+
return { ...item, id: canonicalSessionId };
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
const pendingInputs = (Array.isArray(snapshot.pendingInputs) ? snapshot.pendingInputs : []).map((item) => {
|
|
751
|
+
const originalSessionId = safeTrimmedText(item?.sessionId, 160);
|
|
752
|
+
const canonicalSessionId = remapSessionId(originalSessionId);
|
|
753
|
+
if (!originalSessionId || !canonicalSessionId || canonicalSessionId === originalSessionId) {
|
|
754
|
+
return item;
|
|
755
|
+
}
|
|
756
|
+
return {
|
|
757
|
+
...item,
|
|
758
|
+
id: rewriteDirectScopedId(item?.id, originalSessionId, canonicalSessionId),
|
|
759
|
+
sessionId: canonicalSessionId
|
|
760
|
+
};
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
const events = (Array.isArray(snapshot.events) ? snapshot.events : []).map((item) => {
|
|
764
|
+
const originalSessionId = safeTrimmedText(item?.sessionId, 160);
|
|
765
|
+
const canonicalSessionId = remapSessionId(originalSessionId);
|
|
766
|
+
if (!originalSessionId || !canonicalSessionId || canonicalSessionId === originalSessionId) {
|
|
767
|
+
return item;
|
|
768
|
+
}
|
|
769
|
+
return {
|
|
770
|
+
...item,
|
|
771
|
+
id: rewriteDirectScopedId(item?.id, originalSessionId, canonicalSessionId),
|
|
772
|
+
sessionId: canonicalSessionId
|
|
773
|
+
};
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
const chatTurns = (Array.isArray(snapshot.chatTurns) ? snapshot.chatTurns : []).map((item) => {
|
|
777
|
+
const originalSessionId = safeTrimmedText(item?.sessionId, 160);
|
|
778
|
+
const canonicalSessionId = remapSessionId(originalSessionId);
|
|
779
|
+
if (!originalSessionId || !canonicalSessionId || canonicalSessionId === originalSessionId) {
|
|
780
|
+
return item;
|
|
781
|
+
}
|
|
782
|
+
return {
|
|
783
|
+
...item,
|
|
784
|
+
id: rewriteDirectScopedId(item?.id, originalSessionId, canonicalSessionId),
|
|
785
|
+
sessionId: canonicalSessionId
|
|
786
|
+
};
|
|
787
|
+
});
|
|
788
|
+
|
|
789
|
+
return {
|
|
790
|
+
...snapshot,
|
|
791
|
+
sessions,
|
|
792
|
+
pendingInputs,
|
|
793
|
+
events,
|
|
794
|
+
chatTurns,
|
|
795
|
+
directSourceSessionIds: [...sourceDirectSessionIds]
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
|
|
630
799
|
function buildContinueCommandFromThread(thread, prompt) {
|
|
631
800
|
const safePrompt = safeTrimmedText(prompt, 1500);
|
|
632
801
|
if (!safePrompt || !thread) return null;
|
|
@@ -1937,21 +2106,28 @@ function stopManagedService(service, signalInput) {
|
|
|
1937
2106
|
function mergeDirectSnapshot(snapshot) {
|
|
1938
2107
|
if (!snapshot || typeof snapshot !== "object") return;
|
|
1939
2108
|
|
|
2109
|
+
snapshot = canonicalizeDirectSnapshot(snapshot);
|
|
2110
|
+
|
|
1940
2111
|
const incomingDirectSessionIds = new Set(
|
|
1941
2112
|
(Array.isArray(snapshot.sessions) ? snapshot.sessions : [])
|
|
1942
2113
|
.map((item) => item?.id)
|
|
1943
|
-
.filter((id) => typeof id === "string")
|
|
2114
|
+
.filter((id) => typeof id === "string" && isDirectSessionId(id))
|
|
2115
|
+
);
|
|
2116
|
+
const incomingDirectSourceSessionIds = new Set(
|
|
2117
|
+
(Array.isArray(snapshot.directSourceSessionIds) ? snapshot.directSourceSessionIds : [])
|
|
2118
|
+
.map((item) => safeTrimmedText(item, 160))
|
|
2119
|
+
.filter(Boolean)
|
|
1944
2120
|
);
|
|
1945
2121
|
|
|
1946
|
-
if (incomingDirectSessionIds.size > 0) {
|
|
2122
|
+
if (incomingDirectSessionIds.size > 0 || incomingDirectSourceSessionIds.size > 0) {
|
|
1947
2123
|
state.sessions = state.sessions.filter((item) => {
|
|
1948
2124
|
const id = String(item?.id || "");
|
|
1949
|
-
if (!
|
|
2125
|
+
if (!isDirectSessionId(id)) return true;
|
|
1950
2126
|
return incomingDirectSessionIds.has(id);
|
|
1951
2127
|
});
|
|
1952
2128
|
state.sessionThreads = (Array.isArray(state.sessionThreads) ? state.sessionThreads : []).filter((item) => {
|
|
1953
2129
|
const id = String(item?.id || "");
|
|
1954
|
-
if (!
|
|
2130
|
+
if (!isDirectSessionId(id)) return true;
|
|
1955
2131
|
return incomingDirectSessionIds.has(id);
|
|
1956
2132
|
});
|
|
1957
2133
|
}
|
|
@@ -2802,11 +2978,14 @@ app.post("/api/import/snapshot", (req, res) => {
|
|
|
2802
2978
|
return res.json({ ok: true });
|
|
2803
2979
|
});
|
|
2804
2980
|
|
|
2981
|
+
function refreshDirectSnapshot() {
|
|
2982
|
+
withPersist(() => {
|
|
2983
|
+
const snapshot = collectDirectSnapshot();
|
|
2984
|
+
mergeDirectSnapshot(snapshot);
|
|
2985
|
+
});
|
|
2986
|
+
}
|
|
2987
|
+
|
|
2805
2988
|
app.listen(PORT, () => {
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
const snapshot = collectDirectSnapshot();
|
|
2809
|
-
mergeDirectSnapshot(snapshot);
|
|
2810
|
-
});
|
|
2811
|
-
}, DIRECT_SNAPSHOT_POLL_INTERVAL_MS);
|
|
2989
|
+
refreshDirectSnapshot();
|
|
2990
|
+
setInterval(refreshDirectSnapshot, DIRECT_SNAPSHOT_POLL_INTERVAL_MS);
|
|
2812
2991
|
});
|