conare 0.1.0 → 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/dist/index.js +144 -55
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -281,6 +281,7 @@ import { homedir as homedir3 } from "node:os";
|
|
|
281
281
|
|
|
282
282
|
// src/ingest/shared.ts
|
|
283
283
|
import { existsSync as existsSync2, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
284
|
+
import { createHash } from "node:crypto";
|
|
284
285
|
import { join as join2 } from "node:path";
|
|
285
286
|
import { homedir as homedir2 } from "node:os";
|
|
286
287
|
var MANIFEST_PATH = join2(homedir2(), ".conare", "ingested.json");
|
|
@@ -290,6 +291,9 @@ function cleanText(raw) {
|
|
|
290
291
|
text = text.replace(/<attached-context[\s\S]*?<\/attached-context>/g, "");
|
|
291
292
|
return text.trim();
|
|
292
293
|
}
|
|
294
|
+
function createContentHash(content) {
|
|
295
|
+
return createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
296
|
+
}
|
|
293
297
|
function getIngested() {
|
|
294
298
|
try {
|
|
295
299
|
if (existsSync2(MANIFEST_PATH)) {
|
|
@@ -372,12 +376,13 @@ function ingestClaude() {
|
|
|
372
376
|
const projectsDir = join3(homedir3(), ".claude", "projects");
|
|
373
377
|
const memories = [];
|
|
374
378
|
const sessionIds = [];
|
|
375
|
-
let
|
|
379
|
+
let filtered = 0;
|
|
380
|
+
let deduped = 0;
|
|
376
381
|
let projectDirs;
|
|
377
382
|
try {
|
|
378
383
|
projectDirs = readdirSync2(projectsDir);
|
|
379
384
|
} catch {
|
|
380
|
-
return { memories, sessionIds, skipped };
|
|
385
|
+
return { memories, sessionIds, skipped: 0, filtered, deduped };
|
|
381
386
|
}
|
|
382
387
|
for (const projDir of projectDirs) {
|
|
383
388
|
const projPath = join3(projectsDir, projDir);
|
|
@@ -390,15 +395,11 @@ function ingestClaude() {
|
|
|
390
395
|
}
|
|
391
396
|
for (const file of files) {
|
|
392
397
|
const sessionId = basename(file, ".jsonl");
|
|
393
|
-
if (isIngested("claude", sessionId)) {
|
|
394
|
-
skipped++;
|
|
395
|
-
continue;
|
|
396
|
-
}
|
|
397
398
|
const raw = readFileSync2(join3(projPath, file), "utf-8");
|
|
398
399
|
const { turns, date } = parseSession(raw.split(`
|
|
399
400
|
`));
|
|
400
401
|
if (turns.length === 0) {
|
|
401
|
-
|
|
402
|
+
filtered++;
|
|
402
403
|
continue;
|
|
403
404
|
}
|
|
404
405
|
const header = `# Chat: ${project}${date ? ` | ${date}` : ""}`;
|
|
@@ -419,15 +420,29 @@ ${body}`;
|
|
|
419
420
|
content = content.slice(0, MAX_CONTENT) + `
|
|
420
421
|
|
|
421
422
|
[truncated]`;
|
|
423
|
+
const contentHash = createContentHash(content);
|
|
424
|
+
const dedupKey = `claude:${sessionId}`;
|
|
425
|
+
const fingerprint = `${dedupKey}:${contentHash}`;
|
|
426
|
+
if (isIngested("claude", fingerprint)) {
|
|
427
|
+
deduped++;
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
422
430
|
memories.push({
|
|
423
431
|
content,
|
|
424
432
|
containerTag: "claude-chats",
|
|
425
|
-
metadata: {
|
|
433
|
+
metadata: {
|
|
434
|
+
dedupKey,
|
|
435
|
+
contentHash,
|
|
436
|
+
source: "claude-code",
|
|
437
|
+
sessionId,
|
|
438
|
+
project,
|
|
439
|
+
date: date || "unknown"
|
|
440
|
+
}
|
|
426
441
|
});
|
|
427
442
|
sessionIds.push(sessionId);
|
|
428
443
|
}
|
|
429
444
|
}
|
|
430
|
-
return { memories, sessionIds, skipped };
|
|
445
|
+
return { memories, sessionIds, skipped: filtered + deduped, filtered, deduped };
|
|
431
446
|
}
|
|
432
447
|
|
|
433
448
|
// src/ingest/codex.ts
|
|
@@ -438,7 +453,8 @@ var MAX_CONTENT2 = 48000;
|
|
|
438
453
|
function ingestCodex() {
|
|
439
454
|
const memories = [];
|
|
440
455
|
const sessionIds = [];
|
|
441
|
-
let
|
|
456
|
+
let filtered = 0;
|
|
457
|
+
let deduped = 0;
|
|
442
458
|
const historyPath = join4(homedir4(), ".codex", "history.jsonl");
|
|
443
459
|
if (existsSync3(historyPath)) {
|
|
444
460
|
try {
|
|
@@ -458,10 +474,6 @@ function ingestCodex() {
|
|
|
458
474
|
}
|
|
459
475
|
}
|
|
460
476
|
for (const [sessionId, entries] of sessions) {
|
|
461
|
-
if (isIngested("codex", sessionId)) {
|
|
462
|
-
skipped++;
|
|
463
|
-
continue;
|
|
464
|
-
}
|
|
465
477
|
entries.sort((a, b) => a.ts - b.ts);
|
|
466
478
|
const date = new Date(entries[0].ts * 1000).toISOString().slice(0, 10);
|
|
467
479
|
const body = entries.map((e) => {
|
|
@@ -480,13 +492,20 @@ ${body}`;
|
|
|
480
492
|
|
|
481
493
|
[truncated]`;
|
|
482
494
|
if (content.length < 100) {
|
|
483
|
-
|
|
495
|
+
filtered++;
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
const contentHash = createContentHash(content);
|
|
499
|
+
const dedupKey = `codex:${sessionId}`;
|
|
500
|
+
const fingerprint = `${dedupKey}:${contentHash}`;
|
|
501
|
+
if (isIngested("codex", fingerprint)) {
|
|
502
|
+
deduped++;
|
|
484
503
|
continue;
|
|
485
504
|
}
|
|
486
505
|
memories.push({
|
|
487
506
|
content,
|
|
488
507
|
containerTag: "codex-chats",
|
|
489
|
-
metadata: { source: "codex", sessionId, date }
|
|
508
|
+
metadata: { dedupKey, contentHash, source: "codex", sessionId, date }
|
|
490
509
|
});
|
|
491
510
|
sessionIds.push(sessionId);
|
|
492
511
|
}
|
|
@@ -495,19 +514,22 @@ ${body}`;
|
|
|
495
514
|
const sessionsDir = join4(homedir4(), ".codex", "sessions");
|
|
496
515
|
if (existsSync3(sessionsDir)) {
|
|
497
516
|
try {
|
|
498
|
-
|
|
517
|
+
const stats = { filtered: 0, deduped: 0 };
|
|
518
|
+
walkCodexSessions(sessionsDir, memories, sessionIds, stats);
|
|
519
|
+
filtered += stats.filtered;
|
|
520
|
+
deduped += stats.deduped;
|
|
499
521
|
} catch {}
|
|
500
522
|
}
|
|
501
|
-
return { memories, sessionIds, skipped };
|
|
523
|
+
return { memories, sessionIds, skipped: filtered + deduped, filtered, deduped };
|
|
502
524
|
}
|
|
503
|
-
function walkCodexSessions(dir, memories, sessionIds,
|
|
525
|
+
function walkCodexSessions(dir, memories, sessionIds, stats) {
|
|
504
526
|
try {
|
|
505
527
|
for (const entry of readdirSync3(dir, { withFileTypes: true })) {
|
|
506
528
|
if (entry.isDirectory()) {
|
|
507
|
-
walkCodexSessions(join4(dir, entry.name), memories, sessionIds,
|
|
529
|
+
walkCodexSessions(join4(dir, entry.name), memories, sessionIds, stats);
|
|
508
530
|
} else if (entry.name.endsWith(".jsonl")) {
|
|
509
531
|
const sessionId = basename2(entry.name, ".jsonl");
|
|
510
|
-
if (
|
|
532
|
+
if (sessionIds.includes(sessionId))
|
|
511
533
|
continue;
|
|
512
534
|
try {
|
|
513
535
|
const lines = readFileSync3(join4(dir, entry.name), "utf-8").split(`
|
|
@@ -535,8 +557,10 @@ function walkCodexSessions(dir, memories, sessionIds, skipped) {
|
|
|
535
557
|
continue;
|
|
536
558
|
}
|
|
537
559
|
}
|
|
538
|
-
if (turns.length === 0)
|
|
560
|
+
if (turns.length === 0) {
|
|
561
|
+
stats.filtered++;
|
|
539
562
|
continue;
|
|
563
|
+
}
|
|
540
564
|
const body = turns.map((t) => t.length > 500 ? t.slice(0, 500) + "..." : t).join(`
|
|
541
565
|
|
|
542
566
|
---
|
|
@@ -549,10 +573,23 @@ ${body}`;
|
|
|
549
573
|
content = content.slice(0, MAX_CONTENT2) + `
|
|
550
574
|
|
|
551
575
|
[truncated]`;
|
|
576
|
+
const contentHash = createContentHash(content);
|
|
577
|
+
const dedupKey = `codex:${sessionId}`;
|
|
578
|
+
const fingerprint = `${dedupKey}:${contentHash}`;
|
|
579
|
+
if (isIngested("codex", fingerprint)) {
|
|
580
|
+
stats.deduped++;
|
|
581
|
+
continue;
|
|
582
|
+
}
|
|
552
583
|
memories.push({
|
|
553
584
|
content,
|
|
554
585
|
containerTag: "codex-chats",
|
|
555
|
-
metadata: {
|
|
586
|
+
metadata: {
|
|
587
|
+
dedupKey,
|
|
588
|
+
contentHash,
|
|
589
|
+
source: "codex-session",
|
|
590
|
+
sessionId,
|
|
591
|
+
date: date || "unknown"
|
|
592
|
+
}
|
|
556
593
|
});
|
|
557
594
|
sessionIds.push(sessionId);
|
|
558
595
|
} catch {}
|
|
@@ -620,17 +657,18 @@ function extractTurns(db, composerId, bubbleHeaders) {
|
|
|
620
657
|
async function ingestCursor(dbPath, wasmDir) {
|
|
621
658
|
const memories = [];
|
|
622
659
|
const sessionIds = [];
|
|
623
|
-
let
|
|
660
|
+
let filtered = 0;
|
|
661
|
+
let deduped = 0;
|
|
624
662
|
let fileSize;
|
|
625
663
|
try {
|
|
626
664
|
fileSize = statSync(dbPath).size;
|
|
627
665
|
} catch {
|
|
628
666
|
console.log(" Skipping Cursor: database not accessible");
|
|
629
|
-
return { memories, sessionIds, skipped };
|
|
667
|
+
return { memories, sessionIds, skipped: 0, filtered, deduped };
|
|
630
668
|
}
|
|
631
669
|
if (fileSize > MAX_DB_SIZE) {
|
|
632
670
|
console.log(` Skipping Cursor: database too large (${(fileSize / 1024 / 1024 / 1024).toFixed(1)}GB)`);
|
|
633
|
-
return { memories, sessionIds, skipped };
|
|
671
|
+
return { memories, sessionIds, skipped: 0, filtered, deduped };
|
|
634
672
|
}
|
|
635
673
|
if (fileSize > WARN_DB_SIZE) {
|
|
636
674
|
console.log(` Warning: large database (${(fileSize / 1024 / 1024).toFixed(0)}MB), loading into memory...`);
|
|
@@ -638,14 +676,14 @@ async function ingestCursor(dbPath, wasmDir) {
|
|
|
638
676
|
const initSqlJs = loadSqlJs(wasmDir);
|
|
639
677
|
if (!initSqlJs) {
|
|
640
678
|
console.log(" Skipping Cursor: sql.js not available");
|
|
641
|
-
return { memories, sessionIds, skipped };
|
|
679
|
+
return { memories, sessionIds, skipped: 0, filtered, deduped };
|
|
642
680
|
}
|
|
643
681
|
let db;
|
|
644
682
|
try {
|
|
645
683
|
db = await openDb(initSqlJs, dbPath, wasmDir);
|
|
646
684
|
} catch (e) {
|
|
647
685
|
console.log(` Skipping Cursor: cannot open database (${e.message})`);
|
|
648
|
-
return { memories, sessionIds, skipped };
|
|
686
|
+
return { memories, sessionIds, skipped: 0, filtered, deduped };
|
|
649
687
|
}
|
|
650
688
|
try {
|
|
651
689
|
let rows = [];
|
|
@@ -656,29 +694,25 @@ async function ingestCursor(dbPath, wasmDir) {
|
|
|
656
694
|
} catch {}
|
|
657
695
|
for (const [key, value] of rows) {
|
|
658
696
|
const composerId = key.replace("composerData:", "");
|
|
659
|
-
if (isIngested("cursor", composerId)) {
|
|
660
|
-
skipped++;
|
|
661
|
-
continue;
|
|
662
|
-
}
|
|
663
697
|
let parsed;
|
|
664
698
|
try {
|
|
665
699
|
parsed = JSON.parse(value);
|
|
666
700
|
if (!parsed || typeof parsed !== "object") {
|
|
667
|
-
|
|
701
|
+
filtered++;
|
|
668
702
|
continue;
|
|
669
703
|
}
|
|
670
704
|
} catch {
|
|
671
|
-
|
|
705
|
+
filtered++;
|
|
672
706
|
continue;
|
|
673
707
|
}
|
|
674
708
|
const bubbleHeaders = parsed.fullConversationHeadersOnly;
|
|
675
709
|
if (!Array.isArray(bubbleHeaders) || bubbleHeaders.length === 0) {
|
|
676
|
-
|
|
710
|
+
filtered++;
|
|
677
711
|
continue;
|
|
678
712
|
}
|
|
679
713
|
const turns = extractTurns(db, composerId, bubbleHeaders);
|
|
680
714
|
if (turns.length === 0) {
|
|
681
|
-
|
|
715
|
+
filtered++;
|
|
682
716
|
continue;
|
|
683
717
|
}
|
|
684
718
|
const sessionName = parsed.name || "Cursor Chat";
|
|
@@ -701,10 +735,24 @@ ${body}`;
|
|
|
701
735
|
content = content.slice(0, MAX_CONTENT3) + `
|
|
702
736
|
|
|
703
737
|
[truncated]`;
|
|
738
|
+
const contentHash = createContentHash(content);
|
|
739
|
+
const dedupKey = `cursor:${composerId}`;
|
|
740
|
+
const fingerprint = `${dedupKey}:${contentHash}`;
|
|
741
|
+
if (isIngested("cursor", fingerprint)) {
|
|
742
|
+
deduped++;
|
|
743
|
+
continue;
|
|
744
|
+
}
|
|
704
745
|
memories.push({
|
|
705
746
|
content,
|
|
706
747
|
containerTag: "cursor-chats",
|
|
707
|
-
metadata: {
|
|
748
|
+
metadata: {
|
|
749
|
+
dedupKey,
|
|
750
|
+
contentHash,
|
|
751
|
+
source: "cursor",
|
|
752
|
+
sessionId: composerId,
|
|
753
|
+
name: sessionName,
|
|
754
|
+
date
|
|
755
|
+
}
|
|
708
756
|
});
|
|
709
757
|
sessionIds.push(composerId);
|
|
710
758
|
}
|
|
@@ -713,11 +761,11 @@ ${body}`;
|
|
|
713
761
|
} finally {
|
|
714
762
|
db.close();
|
|
715
763
|
}
|
|
716
|
-
return { memories, sessionIds, skipped };
|
|
764
|
+
return { memories, sessionIds, skipped: filtered + deduped, filtered, deduped };
|
|
717
765
|
}
|
|
718
766
|
|
|
719
767
|
// src/ingest/codebase.ts
|
|
720
|
-
import { createHash } from "node:crypto";
|
|
768
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
721
769
|
import { readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync2, existsSync as existsSync4 } from "node:fs";
|
|
722
770
|
import { join as join6, relative, extname, resolve } from "node:path";
|
|
723
771
|
var DEFAULT_IGNORE = new Set([
|
|
@@ -884,6 +932,7 @@ ${content}
|
|
|
884
932
|
}
|
|
885
933
|
function indexCodebase(rootPath) {
|
|
886
934
|
const absRoot = resolve(rootPath);
|
|
935
|
+
const repoHash = createHash2("sha256").update(absRoot).digest("hex").slice(0, 12);
|
|
887
936
|
const gitignorePatterns = parseGitignore(absRoot);
|
|
888
937
|
const memories = [];
|
|
889
938
|
let fileCount = 0;
|
|
@@ -930,9 +979,10 @@ function indexCodebase(rootPath) {
|
|
|
930
979
|
continue;
|
|
931
980
|
}
|
|
932
981
|
const relPath = relative(absRoot, fullPath);
|
|
933
|
-
const contentHash =
|
|
934
|
-
const
|
|
935
|
-
|
|
982
|
+
const contentHash = createContentHash(raw);
|
|
983
|
+
const dedupKey = `codebase:${repoHash}:${relPath}`;
|
|
984
|
+
const fingerprint = `${dedupKey}:${contentHash}`;
|
|
985
|
+
if (isIngested("codebase", fingerprint)) {
|
|
936
986
|
skipped++;
|
|
937
987
|
continue;
|
|
938
988
|
}
|
|
@@ -941,9 +991,12 @@ function indexCodebase(rootPath) {
|
|
|
941
991
|
content,
|
|
942
992
|
containerTag: "codebase",
|
|
943
993
|
metadata: {
|
|
994
|
+
dedupKey,
|
|
995
|
+
contentHash,
|
|
944
996
|
source: "codebase-index",
|
|
997
|
+
repoHash,
|
|
945
998
|
filePath: relPath,
|
|
946
|
-
fileHash
|
|
999
|
+
fileHash: `${relPath}:${contentHash}`,
|
|
947
1000
|
language: langFromExt(ext)
|
|
948
1001
|
}
|
|
949
1002
|
});
|
|
@@ -956,7 +1009,7 @@ function indexCodebase(rootPath) {
|
|
|
956
1009
|
|
|
957
1010
|
// src/api.ts
|
|
958
1011
|
var API_URL = "https://mcp.conare.ai";
|
|
959
|
-
function createUploadBatches(memories, maxItems =
|
|
1012
|
+
function createUploadBatches(memories, maxItems = 20, maxChars = 400000) {
|
|
960
1013
|
const batches = [];
|
|
961
1014
|
let current = [];
|
|
962
1015
|
let currentChars = 0;
|
|
@@ -992,6 +1045,21 @@ async function validateKey(apiKey) {
|
|
|
992
1045
|
return { valid: false };
|
|
993
1046
|
}
|
|
994
1047
|
}
|
|
1048
|
+
async function getRemoteMemoryCount(apiKey) {
|
|
1049
|
+
try {
|
|
1050
|
+
const res = await fetch(`${API_URL}/api/containers`, {
|
|
1051
|
+
headers: { Authorization: `Bearer ${apiKey}` }
|
|
1052
|
+
});
|
|
1053
|
+
if (!res.ok)
|
|
1054
|
+
return null;
|
|
1055
|
+
const data = await res.json();
|
|
1056
|
+
if (!Array.isArray(data.containers))
|
|
1057
|
+
return 0;
|
|
1058
|
+
return data.containers.reduce((sum, container) => sum + (container.count || 0), 0);
|
|
1059
|
+
} catch {
|
|
1060
|
+
return null;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
995
1063
|
async function uploadItems(apiKey, items) {
|
|
996
1064
|
let retries = 4;
|
|
997
1065
|
while (retries > 0) {
|
|
@@ -1822,9 +1890,12 @@ async function confirmIndexCodebase() {
|
|
|
1822
1890
|
}
|
|
1823
1891
|
|
|
1824
1892
|
// src/index.ts
|
|
1825
|
-
function
|
|
1893
|
+
function getManifestFingerprint(memory) {
|
|
1826
1894
|
const metadata = memory.metadata;
|
|
1827
|
-
|
|
1895
|
+
if (metadata?.dedupKey && metadata?.contentHash) {
|
|
1896
|
+
return `${metadata.dedupKey}:${metadata.contentHash}`;
|
|
1897
|
+
}
|
|
1898
|
+
return metadata?.dedupKey || metadata?.sessionId || metadata?.fileHash || null;
|
|
1828
1899
|
}
|
|
1829
1900
|
function printMissingKeyError() {
|
|
1830
1901
|
console.error("Error: no API key configured.");
|
|
@@ -1864,6 +1935,14 @@ function renderProgressSummary(success, failed, noun) {
|
|
|
1864
1935
|
return `\r \x1B[32m✓\x1B[0m [\x1B[36m${bar}\x1B[0m] ${success} ${noun}, ${failed} failed (${pct}%)${" ".repeat(12)}
|
|
1865
1936
|
`;
|
|
1866
1937
|
}
|
|
1938
|
+
function renderDiscoverySummary(discovered, filtered, deduped) {
|
|
1939
|
+
const parts = [`${discovered} ingestible`];
|
|
1940
|
+
if (filtered > 0)
|
|
1941
|
+
parts.push(`${filtered} filtered`);
|
|
1942
|
+
if (deduped > 0)
|
|
1943
|
+
parts.push(`${deduped} already imported`);
|
|
1944
|
+
return parts.join(", ");
|
|
1945
|
+
}
|
|
1867
1946
|
function parseArgs() {
|
|
1868
1947
|
const args = process.argv.slice(2);
|
|
1869
1948
|
let key = "";
|
|
@@ -1987,6 +2066,16 @@ async function main() {
|
|
|
1987
2066
|
console.log(auth.email ? `OK (${auth.email})` : "OK");
|
|
1988
2067
|
saveApiKey(apiKey);
|
|
1989
2068
|
console.log();
|
|
2069
|
+
if (!opts.force && !opts.dryRun) {
|
|
2070
|
+
const remoteMemoryCount = await getRemoteMemoryCount(apiKey);
|
|
2071
|
+
const localManifest = getIngested();
|
|
2072
|
+
const localManifestCount = Object.values(localManifest).reduce((sum, entries) => sum + entries.length, 0);
|
|
2073
|
+
if (remoteMemoryCount === 0 && localManifestCount > 0) {
|
|
2074
|
+
clearIngested();
|
|
2075
|
+
console.log("Remote account is empty; cleared stale local ingestion history.");
|
|
2076
|
+
console.log("");
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
1990
2079
|
if (!opts.wasmDir && existsSync7(join9(process.cwd(), "node_modules", "sql.js"))) {
|
|
1991
2080
|
opts.wasmDir = join9(process.cwd(), "node_modules");
|
|
1992
2081
|
}
|
|
@@ -2046,7 +2135,7 @@ Nothing new to index.`);
|
|
|
2046
2135
|
process.stdout.write(`\r Uploading [\x1B[36m${bar}\x1B[0m] ${uploaded}/${total} (${pct}%)`);
|
|
2047
2136
|
});
|
|
2048
2137
|
process.stdout.write(renderProgressSummary(success, failed, "indexed"));
|
|
2049
|
-
const fileHashes = results.filter((result) => result.success).map((result) =>
|
|
2138
|
+
const fileHashes = results.filter((result) => result.success).map((result) => getManifestFingerprint(memories[result.index])).filter((key) => !!key);
|
|
2050
2139
|
markIngested("codebase", fileHashes);
|
|
2051
2140
|
printFailureSummary(results, memories);
|
|
2052
2141
|
}
|
|
@@ -2088,22 +2177,22 @@ Nothing new to index.`);
|
|
|
2088
2177
|
const shouldIngest = (name) => selectedSources.includes(name);
|
|
2089
2178
|
if (shouldIngest("claude") && tools.find((t) => t.name === "Claude Code")?.available) {
|
|
2090
2179
|
process.stdout.write("Ingesting Claude Code... ");
|
|
2091
|
-
const { memories,
|
|
2180
|
+
const { memories, filtered, deduped } = ingestClaude();
|
|
2092
2181
|
allMemories.push(...memories);
|
|
2093
|
-
console.log(
|
|
2182
|
+
console.log(renderDiscoverySummary(memories.length, filtered, deduped));
|
|
2094
2183
|
}
|
|
2095
2184
|
if (shouldIngest("codex") && tools.find((t) => t.name === "Codex")?.available) {
|
|
2096
2185
|
process.stdout.write("Ingesting Codex... ");
|
|
2097
|
-
const { memories,
|
|
2186
|
+
const { memories, filtered, deduped } = ingestCodex();
|
|
2098
2187
|
allMemories.push(...memories);
|
|
2099
|
-
console.log(
|
|
2188
|
+
console.log(renderDiscoverySummary(memories.length, filtered, deduped));
|
|
2100
2189
|
}
|
|
2101
2190
|
if (shouldIngest("cursor") && tools.find((t) => t.name === "Cursor")?.available) {
|
|
2102
2191
|
process.stdout.write("Ingesting Cursor... ");
|
|
2103
2192
|
const cursorTool = tools.find((t) => t.name === "Cursor");
|
|
2104
|
-
const { memories,
|
|
2193
|
+
const { memories, filtered, deduped } = await ingestCursor(cursorTool.path, opts.wasmDir);
|
|
2105
2194
|
allMemories.push(...memories);
|
|
2106
|
-
console.log(
|
|
2195
|
+
console.log(renderDiscoverySummary(memories.length, filtered, deduped));
|
|
2107
2196
|
}
|
|
2108
2197
|
console.log();
|
|
2109
2198
|
if (allMemories.length === 0) {
|
|
@@ -2137,7 +2226,7 @@ Nothing new to index.`);
|
|
|
2137
2226
|
if (!result.success)
|
|
2138
2227
|
continue;
|
|
2139
2228
|
const memory = allMemories[result.index];
|
|
2140
|
-
const key =
|
|
2229
|
+
const key = getManifestFingerprint(memory);
|
|
2141
2230
|
if (!key)
|
|
2142
2231
|
continue;
|
|
2143
2232
|
switch (memory.containerTag) {
|
|
@@ -2200,7 +2289,7 @@ Nothing new to index.`);
|
|
|
2200
2289
|
process.stdout.write(`\r Uploading [\x1B[36m${bar}\x1B[0m] ${uploaded}/${total} (${pct}%)`);
|
|
2201
2290
|
});
|
|
2202
2291
|
process.stdout.write(renderProgressSummary(success, failed, "indexed"));
|
|
2203
|
-
const fileHashes = results.filter((result) => result.success).map((result) =>
|
|
2292
|
+
const fileHashes = results.filter((result) => result.success).map((result) => getManifestFingerprint(memories[result.index])).filter((key) => !!key);
|
|
2204
2293
|
markIngested("codebase", fileHashes);
|
|
2205
2294
|
printFailureSummary(results, memories);
|
|
2206
2295
|
}
|