@echomem/mcp 1.4.7 → 1.4.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -8
- package/assets/hud/claude.svg +1 -0
- package/assets/hud/codex.svg +1 -0
- package/assets/hud/session-viewer.html +35 -0
- package/dist/city/echo-ai-city-only.html +31 -13
- package/dist/city/echo-ai-city-only.template.html +31 -13
- package/dist/city/echo-face-cutout.png +0 -0
- package/dist/hud/autostart.js +66 -0
- package/dist/hud/cli.js +31 -0
- package/dist/hud/electron-main.js +182 -19
- package/dist/hud/monitor.js +36 -68
- package/dist/hud/preload.cjs +3 -0
- package/dist/hud/server.js +321 -4
- package/dist/hud/web.js +633 -69
- package/dist/index.js +116 -22
- package/dist/migrate.js +18 -0
- package/dist/setup-page.js +978 -60
- package/dist/setup.js +355 -42
- package/dist/v1-contract.js +20 -2
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -273,6 +273,23 @@ function lastUserMessageFromConversationText(value) {
|
|
|
273
273
|
flush();
|
|
274
274
|
return lastUser || undefined;
|
|
275
275
|
}
|
|
276
|
+
function formatMessagesForIngest(messages) {
|
|
277
|
+
return messages
|
|
278
|
+
.map((message) => {
|
|
279
|
+
const content = message.content.trim();
|
|
280
|
+
if (!content)
|
|
281
|
+
return "";
|
|
282
|
+
const role = message.role.toLowerCase();
|
|
283
|
+
const label = role === "user" || role === "human"
|
|
284
|
+
? "User"
|
|
285
|
+
: role === "system"
|
|
286
|
+
? "System"
|
|
287
|
+
: "Assistant";
|
|
288
|
+
return `## ${label}\n\n${content}`;
|
|
289
|
+
})
|
|
290
|
+
.filter(Boolean)
|
|
291
|
+
.join("\n\n---\n\n");
|
|
292
|
+
}
|
|
276
293
|
function normalizeRetrievalCandidate(value, fallbackRank) {
|
|
277
294
|
if (!isRecord(value))
|
|
278
295
|
return null;
|
|
@@ -645,7 +662,7 @@ class EchoMemApiClient {
|
|
|
645
662
|
return { success: true, tuned: true, answer: String(data.answer || data.response || "").trim(), memories };
|
|
646
663
|
}
|
|
647
664
|
async searchMemories(args) {
|
|
648
|
-
const parsed = searchMemoriesSchema.parse(args);
|
|
665
|
+
const parsed = searchMemoriesSchema.parse(args ?? {});
|
|
649
666
|
const query = parsed.query?.trim();
|
|
650
667
|
const limit = parsed.limit ?? parsed.k ?? 10;
|
|
651
668
|
const threshold = parsed.threshold ?? 0.1;
|
|
@@ -693,10 +710,10 @@ class EchoMemApiClient {
|
|
|
693
710
|
return data;
|
|
694
711
|
}
|
|
695
712
|
async saveConversation(args) {
|
|
696
|
-
const parsed = saveConversationSchema.parse(args);
|
|
713
|
+
const parsed = saveConversationSchema.parse(args ?? {});
|
|
697
714
|
let rawData = parsed.conversation?.trim() || "";
|
|
698
715
|
if (!rawData && parsed.messages?.length) {
|
|
699
|
-
rawData = parsed.messages
|
|
716
|
+
rawData = formatMessagesForIngest(parsed.messages);
|
|
700
717
|
}
|
|
701
718
|
if (!rawData) {
|
|
702
719
|
throw new McpError(ErrorCode.InvalidParams, "Either conversation or messages is required.");
|
|
@@ -724,7 +741,7 @@ class EchoMemApiClient {
|
|
|
724
741
|
return response.data;
|
|
725
742
|
}
|
|
726
743
|
async deleteMemory(args) {
|
|
727
|
-
const parsed = deleteMemorySchema.parse(args);
|
|
744
|
+
const parsed = deleteMemorySchema.parse(args ?? {});
|
|
728
745
|
const enc = await this.encState();
|
|
729
746
|
const memory = await this.fetchMemoryById(parsed.memoryId, enc);
|
|
730
747
|
if (!memory) {
|
|
@@ -768,7 +785,7 @@ class EchoMemApiClient {
|
|
|
768
785
|
};
|
|
769
786
|
}
|
|
770
787
|
async getMemoriesByTimeRange(args) {
|
|
771
|
-
const parsed = timeRangeSchema.parse(args);
|
|
788
|
+
const parsed = timeRangeSchema.parse(args ?? {});
|
|
772
789
|
const enc = await this.encState();
|
|
773
790
|
const response = await this.axios.post("/api/extension/memories/time-range", {
|
|
774
791
|
startDate: parsed.startDate,
|
|
@@ -778,7 +795,7 @@ class EchoMemApiClient {
|
|
|
778
795
|
return enc.enabled ? await this.decryptResult(response.data, enc.key) : response.data;
|
|
779
796
|
}
|
|
780
797
|
async getMemoriesByContext(args) {
|
|
781
|
-
const parsed = getByContextSchema.parse(args);
|
|
798
|
+
const parsed = getByContextSchema.parse(args ?? {});
|
|
782
799
|
const enc = await this.encState();
|
|
783
800
|
const response = await this.axios.post("/api/extension/memories/by-context", {
|
|
784
801
|
contextId: parsed.contextId,
|
|
@@ -787,7 +804,7 @@ class EchoMemApiClient {
|
|
|
787
804
|
return enc.enabled ? await this.decryptResult(response.data, enc.key) : response.data;
|
|
788
805
|
}
|
|
789
806
|
async searchMemoriesByKeywords(args) {
|
|
790
|
-
const parsed = keywordsSchema.parse(args);
|
|
807
|
+
const parsed = keywordsSchema.parse(args ?? {});
|
|
791
808
|
const enc = await this.encState();
|
|
792
809
|
const response = await this.axios.post("/api/extension/memories/keywords", {
|
|
793
810
|
keywords: parsed.keywords,
|
|
@@ -796,7 +813,7 @@ class EchoMemApiClient {
|
|
|
796
813
|
return enc.enabled ? await this.decryptResult(response.data, enc.key) : response.data;
|
|
797
814
|
}
|
|
798
815
|
async listFriends(args) {
|
|
799
|
-
listFriendsSchema.parse(args);
|
|
816
|
+
listFriendsSchema.parse(args ?? {});
|
|
800
817
|
try {
|
|
801
818
|
const response = await this.axios.get("/api/extension/social/friends");
|
|
802
819
|
return response.data;
|
|
@@ -806,7 +823,7 @@ class EchoMemApiClient {
|
|
|
806
823
|
}
|
|
807
824
|
}
|
|
808
825
|
async searchUsers(args) {
|
|
809
|
-
const parsed = searchUsersSchema.parse(args);
|
|
826
|
+
const parsed = searchUsersSchema.parse(args ?? {});
|
|
810
827
|
try {
|
|
811
828
|
const response = await this.axios.post("/api/extension/social/users/search", {
|
|
812
829
|
query: parsed.query,
|
|
@@ -819,7 +836,7 @@ class EchoMemApiClient {
|
|
|
819
836
|
}
|
|
820
837
|
}
|
|
821
838
|
async sendFriendRequest(args) {
|
|
822
|
-
const parsed = sendFriendRequestSchema.parse(args);
|
|
839
|
+
const parsed = sendFriendRequestSchema.parse(args ?? {});
|
|
823
840
|
try {
|
|
824
841
|
const response = await this.axios.post("/api/extension/social/friend-requests", {
|
|
825
842
|
receiverUserId: parsed.targetUserId,
|
|
@@ -831,7 +848,7 @@ class EchoMemApiClient {
|
|
|
831
848
|
}
|
|
832
849
|
}
|
|
833
850
|
async searchOthersMemories(args) {
|
|
834
|
-
const parsed = othersSchema.parse(args);
|
|
851
|
+
const parsed = othersSchema.parse(args ?? {});
|
|
835
852
|
try {
|
|
836
853
|
const response = await this.axios.post("/api/extension/social/public-memories/search", {
|
|
837
854
|
query: parsed.query,
|
|
@@ -855,7 +872,7 @@ class EchoMemApiClient {
|
|
|
855
872
|
}
|
|
856
873
|
}
|
|
857
874
|
async getPublicMemory(args) {
|
|
858
|
-
const parsed = publicMemorySchema.parse(args);
|
|
875
|
+
const parsed = publicMemorySchema.parse(args ?? {});
|
|
859
876
|
try {
|
|
860
877
|
const response = await this.axios.get(`/api/extension/social/public-memories/${encodeURIComponent(parsed.memoryId)}?requestId=${encodeURIComponent(this.sessionId)}&source=mcp_friend_public_memory_fetch`);
|
|
861
878
|
return response.data;
|
|
@@ -1026,6 +1043,8 @@ class EchoMemMCPServer {
|
|
|
1026
1043
|
return await this.handleTimeRange(request.params.arguments);
|
|
1027
1044
|
case canonicalToolNames.getByContext:
|
|
1028
1045
|
return await this.handleGetByContext(request.params.arguments);
|
|
1046
|
+
case canonicalToolNames.checkpointByContext:
|
|
1047
|
+
return await this.handleGetCheckpointByContext(request.params.arguments);
|
|
1029
1048
|
case canonicalToolNames.keywords:
|
|
1030
1049
|
return await this.handleKeywords(request.params.arguments);
|
|
1031
1050
|
case canonicalToolNames.friends:
|
|
@@ -1254,7 +1273,7 @@ Details: ${m.details || "N/A"}`)
|
|
|
1254
1273
|
return { content: [{ type: "text", text }] };
|
|
1255
1274
|
}
|
|
1256
1275
|
async handleTimeRange(args) {
|
|
1257
|
-
const parsed = timeRangeSchema.parse(args);
|
|
1276
|
+
const parsed = timeRangeSchema.parse(args ?? {});
|
|
1258
1277
|
const { success, memories, error } = await this.client.getMemoriesByTimeRange(args);
|
|
1259
1278
|
if (!success)
|
|
1260
1279
|
throw new Error(`EchoMem API Error: ${error}`);
|
|
@@ -1279,7 +1298,7 @@ Details: ${m.details || "N/A"}`)
|
|
|
1279
1298
|
};
|
|
1280
1299
|
}
|
|
1281
1300
|
async handleGetByContext(args) {
|
|
1282
|
-
const parsed = getByContextSchema.parse(args);
|
|
1301
|
+
const parsed = getByContextSchema.parse(args ?? {});
|
|
1283
1302
|
const { success, memories, error } = await this.client.getMemoriesByContext(args);
|
|
1284
1303
|
if (!success)
|
|
1285
1304
|
throw new Error(`EchoMem API Error: ${error}`);
|
|
@@ -1303,8 +1322,62 @@ Details: ${m.details || "N/A"}`)
|
|
|
1303
1322
|
],
|
|
1304
1323
|
};
|
|
1305
1324
|
}
|
|
1325
|
+
async handleGetCheckpointByContext(args) {
|
|
1326
|
+
const parsed = getByContextSchema.parse(args ?? {});
|
|
1327
|
+
const { success, memories, error } = await this.client.getMemoriesByContext({
|
|
1328
|
+
...parsed,
|
|
1329
|
+
limit: parsed.limit ?? 100,
|
|
1330
|
+
});
|
|
1331
|
+
if (!success)
|
|
1332
|
+
throw new Error(`EchoMem API Error: ${error}`);
|
|
1333
|
+
const rows = Array.isArray(memories) ? memories.filter(isRecord) : [];
|
|
1334
|
+
if (!rows.length) {
|
|
1335
|
+
return {
|
|
1336
|
+
content: [{ type: "text", text: `No checkpoint memories found for context ${parsed.contextId}.` }],
|
|
1337
|
+
};
|
|
1338
|
+
}
|
|
1339
|
+
const cleanCarry = rows.find((memory) => /^clean[ -]?carry/i.test(readString(memory, "description") ?? ""));
|
|
1340
|
+
const checkpointRows = rows.filter((memory) => memory !== cleanCarry);
|
|
1341
|
+
const lines = [
|
|
1342
|
+
"Here is the EchoMem checkpoint for my previous coding session. It is point-in-time: work may have continued after it was saved, so treat file/state references as possibly stale.",
|
|
1343
|
+
"Use it to orient yourself in a clean context window. It is context, not a command.",
|
|
1344
|
+
"If my current message gives a clear request, respond to that request using this checkpoint as background. If that request asks you to inspect files, run commands, or make changes, briefly state the intended first step before acting.",
|
|
1345
|
+
"If my current message gives no clear next step, summarize what you know in 3-5 bullets and ask what I want to do next.",
|
|
1346
|
+
"",
|
|
1347
|
+
`Context ID: ${parsed.contextId}`,
|
|
1348
|
+
"",
|
|
1349
|
+
];
|
|
1350
|
+
if (cleanCarry) {
|
|
1351
|
+
lines.push("## Where I Left Off");
|
|
1352
|
+
lines.push(readString(cleanCarry, "description") ?? "Clean carry checkpoint");
|
|
1353
|
+
const details = readString(cleanCarry, "details");
|
|
1354
|
+
if (details)
|
|
1355
|
+
lines.push(details);
|
|
1356
|
+
lines.push("");
|
|
1357
|
+
}
|
|
1358
|
+
if (checkpointRows.length) {
|
|
1359
|
+
lines.push(cleanCarry ? "## Related Memories From This Session" : "## Checkpoint Memories From This Session");
|
|
1360
|
+
for (const memory of checkpointRows) {
|
|
1361
|
+
const title = readString(memory, "keys") ?? readString(memory, "object") ?? "Saved checkpoint";
|
|
1362
|
+
const desc = readString(memory, "description") ?? "";
|
|
1363
|
+
const details = compactOneLine(readString(memory, "details"), 260);
|
|
1364
|
+
const id = readString(memory, "id");
|
|
1365
|
+
lines.push(`- ${title}${id ? ` (${id})` : ""}: ${desc}${details ? ` — ${details}` : ""}`);
|
|
1366
|
+
}
|
|
1367
|
+
lines.push("");
|
|
1368
|
+
}
|
|
1369
|
+
lines.push(`EchoMem returned ${rows.length} ${rows.length === 1 ? "memory" : "memories"} for this checkpoint context.`);
|
|
1370
|
+
return {
|
|
1371
|
+
content: [
|
|
1372
|
+
{
|
|
1373
|
+
type: "text",
|
|
1374
|
+
text: lines.join("\n"),
|
|
1375
|
+
},
|
|
1376
|
+
],
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1306
1379
|
async handleKeywords(args) {
|
|
1307
|
-
const parsed = keywordsSchema.parse(args);
|
|
1380
|
+
const parsed = keywordsSchema.parse(args ?? {});
|
|
1308
1381
|
const { success, memories, error } = await this.client.searchMemoriesByKeywords(args);
|
|
1309
1382
|
if (!success)
|
|
1310
1383
|
throw new Error(`EchoMem API Error: ${error}`);
|
|
@@ -1329,7 +1402,7 @@ Details: ${m.details || "N/A"}`)
|
|
|
1329
1402
|
};
|
|
1330
1403
|
}
|
|
1331
1404
|
async handleOthers(args) {
|
|
1332
|
-
const parsed = othersSchema.parse(args);
|
|
1405
|
+
const parsed = othersSchema.parse(args ?? {});
|
|
1333
1406
|
const payload = await this.client.searchOthersMemories(args);
|
|
1334
1407
|
const memories = payload?.memories ?? [];
|
|
1335
1408
|
if (!memories.length) {
|
|
@@ -1380,7 +1453,7 @@ Details: ${m.details || "N/A"}`;
|
|
|
1380
1453
|
};
|
|
1381
1454
|
}
|
|
1382
1455
|
async handleFriends(args) {
|
|
1383
|
-
listFriendsSchema.parse(args);
|
|
1456
|
+
listFriendsSchema.parse(args ?? {});
|
|
1384
1457
|
const payload = await this.client.listFriends(args);
|
|
1385
1458
|
const friends = Array.isArray(payload?.friends) ? payload.friends : [];
|
|
1386
1459
|
if (!friends.length) {
|
|
@@ -1411,7 +1484,7 @@ Details: ${m.details || "N/A"}`;
|
|
|
1411
1484
|
};
|
|
1412
1485
|
}
|
|
1413
1486
|
async handleSearchUsers(args) {
|
|
1414
|
-
const parsed = searchUsersSchema.parse(args);
|
|
1487
|
+
const parsed = searchUsersSchema.parse(args ?? {});
|
|
1415
1488
|
const payload = await this.client.searchUsers(args);
|
|
1416
1489
|
const users = Array.isArray(payload?.users) ? payload.users : [];
|
|
1417
1490
|
if (!users.length) {
|
|
@@ -1444,7 +1517,7 @@ Details: ${m.details || "N/A"}`;
|
|
|
1444
1517
|
};
|
|
1445
1518
|
}
|
|
1446
1519
|
async handleSendFriendRequest(args) {
|
|
1447
|
-
sendFriendRequestSchema.parse(args);
|
|
1520
|
+
sendFriendRequestSchema.parse(args ?? {});
|
|
1448
1521
|
const payload = await this.client.sendFriendRequest(args);
|
|
1449
1522
|
const result = isRecord(payload) ? payload : {};
|
|
1450
1523
|
const targetUser = isRecord(result.targetUser) ? result.targetUser : {};
|
|
@@ -1477,7 +1550,7 @@ Details: ${m.details || "N/A"}`;
|
|
|
1477
1550
|
};
|
|
1478
1551
|
}
|
|
1479
1552
|
async handlePublicMemory(args) {
|
|
1480
|
-
const parsed = publicMemorySchema.parse(args);
|
|
1553
|
+
const parsed = publicMemorySchema.parse(args ?? {});
|
|
1481
1554
|
const payload = await this.client.getPublicMemory(args);
|
|
1482
1555
|
const memory = payload?.memory;
|
|
1483
1556
|
if (!memory) {
|
|
@@ -1505,7 +1578,7 @@ Details: ${m.details || "N/A"}`;
|
|
|
1505
1578
|
};
|
|
1506
1579
|
}
|
|
1507
1580
|
async handleDelete(args, rec) {
|
|
1508
|
-
const parsed = deleteMemorySchema.parse(args);
|
|
1581
|
+
const parsed = deleteMemorySchema.parse(args ?? {});
|
|
1509
1582
|
if (rec) {
|
|
1510
1583
|
rec.memory_id_hash = hashText(parsed.memoryId);
|
|
1511
1584
|
rec.delete_confirmed = parsed.confirmed;
|
|
@@ -1567,7 +1640,28 @@ async function main() {
|
|
|
1567
1640
|
if (handled)
|
|
1568
1641
|
return;
|
|
1569
1642
|
const store = new KeyStore();
|
|
1570
|
-
|
|
1643
|
+
// Serve mode is meant to be SPAWNED by the MCP client (editor), which drives us over a piped stdin.
|
|
1644
|
+
// A human who runs the bare server in a terminal instead gets a process that blocks forever on stdio
|
|
1645
|
+
// with no output — indistinguishable from a hang ("wtf, it's stuck"). A TTY on stdin means no editor
|
|
1646
|
+
// is on the other end: say so loudly and point at the command they almost certainly meant.
|
|
1647
|
+
if (process.stdin.isTTY) {
|
|
1648
|
+
const connected = Boolean(store.getToken());
|
|
1649
|
+
console.error([
|
|
1650
|
+
"",
|
|
1651
|
+
"⚠️ You started the EchoMem MCP server directly in a terminal.",
|
|
1652
|
+
"",
|
|
1653
|
+
" This is a background server that waits for your editor to connect over",
|
|
1654
|
+
" stdio. It is NOT frozen — a blank, unresponsive terminal is exactly what",
|
|
1655
|
+
" a running stdio server looks like.",
|
|
1656
|
+
"",
|
|
1657
|
+
connected
|
|
1658
|
+
? " Your editor launches this for you; you don't need to run it by hand."
|
|
1659
|
+
: " To connect this device, press Ctrl+C and run:",
|
|
1660
|
+
connected ? " Press Ctrl+C to stop it." : " echomem-mcp setup",
|
|
1661
|
+
"",
|
|
1662
|
+
].join("\n"));
|
|
1663
|
+
}
|
|
1664
|
+
else if (!store.getToken()) {
|
|
1571
1665
|
// No token yet — DON'T exit. Start the server so the editor keeps the bridge alive; tools return
|
|
1572
1666
|
// a "run login" nudge until `login` writes the token, then the next call picks it up (no restart).
|
|
1573
1667
|
console.error("EchoMem: not connected yet — run `echomem-mcp login` to connect this device.");
|
package/dist/migrate.js
CHANGED
|
@@ -644,6 +644,7 @@ export function estimateMigrationEtaFromLengths(lengths, skippedActive = 0, opts
|
|
|
644
644
|
};
|
|
645
645
|
}
|
|
646
646
|
export function summarizeFastMigratableDiscovery(discovery) {
|
|
647
|
+
const pendingCodex = discovery.pendingCodex ?? discovery.pending.filter((s) => s.source === "codex").length;
|
|
647
648
|
return {
|
|
648
649
|
sessions: discovery.sessions.length,
|
|
649
650
|
pending: discovery.pending.length,
|
|
@@ -652,6 +653,8 @@ export function summarizeFastMigratableDiscovery(discovery) {
|
|
|
652
653
|
skippedActive: discovery.skippedActive,
|
|
653
654
|
codexCount: discovery.codexCount,
|
|
654
655
|
claudeCount: discovery.claudeCount,
|
|
656
|
+
pendingCodex,
|
|
657
|
+
pendingClaudeCode: discovery.pendingClaudeCode ?? discovery.pending.length - pendingCodex,
|
|
655
658
|
eta: estimateMigrationEtaFromLengths(discovery.pending.map((s) => s.size), discovery.skippedActive, {
|
|
656
659
|
secondsPerSession: measuredSecondsPerSession() ?? undefined,
|
|
657
660
|
}),
|
|
@@ -690,6 +693,7 @@ export function discoverMigratableFastDiscovery(opts = {}) {
|
|
|
690
693
|
});
|
|
691
694
|
const pending = opts.limit && opts.limit > 0 ? pendingAll.slice(0, opts.limit) : pendingAll;
|
|
692
695
|
const codexCount = sessions.filter((s) => s.source === "codex").length;
|
|
696
|
+
const pendingCodex = pending.filter((s) => s.source === "codex").length;
|
|
693
697
|
return {
|
|
694
698
|
sessions,
|
|
695
699
|
pending,
|
|
@@ -699,6 +703,8 @@ export function discoverMigratableFastDiscovery(opts = {}) {
|
|
|
699
703
|
limited: pending.length < pendingAll.length,
|
|
700
704
|
codexCount,
|
|
701
705
|
claudeCount: sessions.length - codexCount,
|
|
706
|
+
pendingCodex,
|
|
707
|
+
pendingClaudeCode: pending.length - pendingCodex,
|
|
702
708
|
};
|
|
703
709
|
}
|
|
704
710
|
export function discoverMigratableSummaryFast(opts = {}) {
|
|
@@ -757,6 +763,7 @@ export function discoverMigratableSessions(opts = {}) {
|
|
|
757
763
|
});
|
|
758
764
|
const pending = opts.limit && opts.limit > 0 ? pendingAll.slice(0, opts.limit) : pendingAll;
|
|
759
765
|
const codexCount = sessions.filter((s) => s.source === "codex").length;
|
|
766
|
+
const pendingCodex = pending.filter((s) => s.source === "codex").length;
|
|
760
767
|
return {
|
|
761
768
|
sessions,
|
|
762
769
|
pending,
|
|
@@ -766,6 +773,8 @@ export function discoverMigratableSessions(opts = {}) {
|
|
|
766
773
|
limited: pending.length < pendingAll.length,
|
|
767
774
|
codexCount,
|
|
768
775
|
claudeCount: sessions.length - codexCount,
|
|
776
|
+
pendingCodex,
|
|
777
|
+
pendingClaudeCode: pending.length - pendingCodex,
|
|
769
778
|
};
|
|
770
779
|
}
|
|
771
780
|
/**
|
|
@@ -787,6 +796,7 @@ export function discoverPendingSessionsTargeted(processedKeys, opts = {}) {
|
|
|
787
796
|
if (s)
|
|
788
797
|
pending.push(s);
|
|
789
798
|
}
|
|
799
|
+
const pendingCodex = pending.filter((s) => s.source === "codex").length;
|
|
790
800
|
return {
|
|
791
801
|
sessions: pending,
|
|
792
802
|
pending,
|
|
@@ -796,6 +806,8 @@ export function discoverPendingSessionsTargeted(processedKeys, opts = {}) {
|
|
|
796
806
|
limited: filtered.limited,
|
|
797
807
|
codexCount: filtered.codexCount,
|
|
798
808
|
claudeCount: filtered.claudeCount,
|
|
809
|
+
pendingCodex,
|
|
810
|
+
pendingClaudeCode: pending.length - pendingCodex,
|
|
799
811
|
accountChecked: filtered.accountChecked,
|
|
800
812
|
accountCheckFailed: filtered.accountCheckFailed,
|
|
801
813
|
accountCheckUnavailable: filtered.accountCheckUnavailable,
|
|
@@ -808,6 +820,7 @@ export function applyAccountImportStatus(discovery, processedKeys, opts = {}) {
|
|
|
808
820
|
const skippedActive = discovery.sessions.length - selectableSessions.length;
|
|
809
821
|
const pendingAll = selectableSessions.filter((s) => !processedKeys.has(s.conversationKey));
|
|
810
822
|
const pending = opts.limit && opts.limit > 0 ? pendingAll.slice(0, opts.limit) : pendingAll;
|
|
823
|
+
const pendingCodex = pending.filter((s) => s.source === "codex").length;
|
|
811
824
|
return {
|
|
812
825
|
...discovery,
|
|
813
826
|
pending,
|
|
@@ -815,6 +828,8 @@ export function applyAccountImportStatus(discovery, processedKeys, opts = {}) {
|
|
|
815
828
|
alreadyMigrated: selectableSessions.length - pendingAll.length,
|
|
816
829
|
skippedActive,
|
|
817
830
|
limited: pending.length < pendingAll.length,
|
|
831
|
+
pendingCodex,
|
|
832
|
+
pendingClaudeCode: pending.length - pendingCodex,
|
|
818
833
|
accountChecked: true,
|
|
819
834
|
accountCheckFailed: false,
|
|
820
835
|
accountCheckUnavailable: false,
|
|
@@ -827,6 +842,7 @@ export function applyFastAccountImportStatus(discovery, processedKeys, opts = {}
|
|
|
827
842
|
const skippedActive = discovery.sessions.length - selectableSessions.length;
|
|
828
843
|
const pendingAll = selectableSessions.filter((s) => !processedKeys.has(s.conversationKey));
|
|
829
844
|
const pending = opts.limit && opts.limit > 0 ? pendingAll.slice(0, opts.limit) : pendingAll;
|
|
845
|
+
const pendingCodex = pending.filter((s) => s.source === "codex").length;
|
|
830
846
|
return {
|
|
831
847
|
...discovery,
|
|
832
848
|
pending,
|
|
@@ -834,6 +850,8 @@ export function applyFastAccountImportStatus(discovery, processedKeys, opts = {}
|
|
|
834
850
|
alreadyMigrated: selectableSessions.length - pendingAll.length,
|
|
835
851
|
skippedActive,
|
|
836
852
|
limited: pending.length < pendingAll.length,
|
|
853
|
+
pendingCodex,
|
|
854
|
+
pendingClaudeCode: pending.length - pendingCodex,
|
|
837
855
|
accountChecked: true,
|
|
838
856
|
accountCheckFailed: false,
|
|
839
857
|
accountCheckUnavailable: false,
|