@llmnesia/mcp 0.2.9 → 0.2.11
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/{chunk-BWEDXPNM.js → chunk-7ISC4REX.js} +162 -50
- package/dist/{chunk-YT6GNKKG.js → chunk-ZYE6VY6A.js} +1 -1
- package/dist/{cli-KHY7ADCU.js → cli-RQMFEW5J.js} +32 -32
- package/dist/cli.js +2 -2
- package/dist/llmnesia-claude-host.mjs +53 -7
- package/dist/llmnesia.mcpb +0 -0
- package/dist/mcp.js +286 -246
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -3,7 +3,7 @@ import { createRequire as __llmnesiaCreateRequire } from "node:module";
|
|
|
3
3
|
const require = __llmnesiaCreateRequire(import.meta.url);
|
|
4
4
|
import {
|
|
5
5
|
VERSION
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-ZYE6VY6A.js";
|
|
7
7
|
|
|
8
8
|
// src/config.ts
|
|
9
9
|
import { readFileSync } from "fs";
|
|
@@ -47,7 +47,7 @@ function expandHome(p) {
|
|
|
47
47
|
import { join as join2 } from "path";
|
|
48
48
|
import { readdir } from "fs/promises";
|
|
49
49
|
import { createHash } from "crypto";
|
|
50
|
-
var INDEX_FORMAT_VERSION =
|
|
50
|
+
var INDEX_FORMAT_VERSION = 7;
|
|
51
51
|
function indexDbFilename(version) {
|
|
52
52
|
return version === 1 ? "llmnesia.db" : `llmnesia-v${version}.db`;
|
|
53
53
|
}
|
|
@@ -217,6 +217,13 @@ function canonicalConversationDoc(c) {
|
|
|
217
217
|
observedAt: c.providerProject.observedAt
|
|
218
218
|
};
|
|
219
219
|
}
|
|
220
|
+
if (c.providerWorkspace) {
|
|
221
|
+
out.providerWorkspace = {
|
|
222
|
+
workspaceId: c.providerWorkspace.workspaceId,
|
|
223
|
+
source: c.providerWorkspace.source,
|
|
224
|
+
observedAt: c.providerWorkspace.observedAt
|
|
225
|
+
};
|
|
226
|
+
}
|
|
220
227
|
if (c.models && c.models.length > 0) out.models = [...c.models];
|
|
221
228
|
assignIfDefined(out, "modelMetadataUpdatedAt", c.modelMetadataUpdatedAt);
|
|
222
229
|
if (c.summary) {
|
|
@@ -396,7 +403,7 @@ var Corpus = class {
|
|
|
396
403
|
return this.enqueueWrite(async () => {
|
|
397
404
|
const canonical = canonicalizeMemory(memory);
|
|
398
405
|
const file = this.paths.memoryFile(canonical.memoryId);
|
|
399
|
-
const existing = await
|
|
406
|
+
const existing = await readMemoryIfExists(file);
|
|
400
407
|
if (existing) {
|
|
401
408
|
if (existing.source !== "agent") {
|
|
402
409
|
return { memoryId: canonical.memoryId, outcome: "refused" };
|
|
@@ -411,44 +418,48 @@ var Corpus = class {
|
|
|
411
418
|
}
|
|
412
419
|
/** Read a memory by memoryId, or null when it has never been written. */
|
|
413
420
|
async getMemory(memoryId) {
|
|
414
|
-
const record = await
|
|
421
|
+
const record = await readMemoryIfExists(this.paths.memoryFile(memoryId));
|
|
415
422
|
return record && record.memoryId === memoryId ? record : null;
|
|
416
423
|
}
|
|
417
424
|
/** Async-iterate every stored memory (used by the index rebuild). */
|
|
418
|
-
async *iterateMemories() {
|
|
425
|
+
async *iterateMemories(options = {}) {
|
|
419
426
|
let files;
|
|
420
427
|
try {
|
|
421
428
|
files = await fs.readdir(this.paths.memoriesDir);
|
|
422
|
-
} catch {
|
|
429
|
+
} catch (error) {
|
|
430
|
+
if (options.strict) throw error;
|
|
423
431
|
return;
|
|
424
432
|
}
|
|
425
433
|
for (const name of files.sort()) {
|
|
426
434
|
if (!name.endsWith(".json")) {
|
|
427
435
|
continue;
|
|
428
436
|
}
|
|
429
|
-
const
|
|
437
|
+
const file = join3(this.paths.memoriesDir, name);
|
|
438
|
+
const record = options.strict ? await readRequiredJson(file, isMemoryRecord) : await readJsonIfExists(file);
|
|
430
439
|
if (record?.memoryId) {
|
|
431
440
|
yield record;
|
|
432
441
|
}
|
|
433
442
|
}
|
|
434
443
|
}
|
|
435
444
|
/** Platform subdirectory names under conversations/. */
|
|
436
|
-
async listPlatforms() {
|
|
445
|
+
async listPlatforms(options = {}) {
|
|
437
446
|
try {
|
|
438
447
|
const entries = await fs.readdir(this.paths.conversationsDir, { withFileTypes: true });
|
|
439
448
|
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
440
|
-
} catch {
|
|
449
|
+
} catch (error) {
|
|
450
|
+
if (options.strict) throw error;
|
|
441
451
|
return [];
|
|
442
452
|
}
|
|
443
453
|
}
|
|
444
454
|
/** Async-iterate every stored conversation (used by reindex + stats). */
|
|
445
|
-
async *iterate() {
|
|
446
|
-
for (const platform of await this.listPlatforms()) {
|
|
455
|
+
async *iterate(options = {}) {
|
|
456
|
+
for (const platform of await this.listPlatforms(options)) {
|
|
447
457
|
const dir = this.paths.platformDir(platform);
|
|
448
458
|
let files;
|
|
449
459
|
try {
|
|
450
460
|
files = await fs.readdir(dir);
|
|
451
|
-
} catch {
|
|
461
|
+
} catch (error) {
|
|
462
|
+
if (options.strict) throw error;
|
|
452
463
|
continue;
|
|
453
464
|
}
|
|
454
465
|
const stems = /* @__PURE__ */ new Set();
|
|
@@ -459,7 +470,8 @@ var Corpus = class {
|
|
|
459
470
|
for (const stem of [...stems].sort()) {
|
|
460
471
|
const record = await readBestConversationFiles(
|
|
461
472
|
join3(dir, `${stem}.json.gz`),
|
|
462
|
-
join3(dir, `${stem}.json`)
|
|
473
|
+
join3(dir, `${stem}.json`),
|
|
474
|
+
options.strict
|
|
463
475
|
);
|
|
464
476
|
if (record) {
|
|
465
477
|
yield record;
|
|
@@ -622,6 +634,31 @@ async function readJsonIfExists(file) {
|
|
|
622
634
|
return null;
|
|
623
635
|
}
|
|
624
636
|
}
|
|
637
|
+
function isConversationRecord(value) {
|
|
638
|
+
if (!value || typeof value !== "object") return false;
|
|
639
|
+
const record = value;
|
|
640
|
+
const c = record.conversation;
|
|
641
|
+
return !!c && typeof c.docId === "string" && !!c.docId && typeof c.platform === "string" && typeof c.title === "string" && typeof c.url === "string" && Number.isFinite(c.createdAt) && Array.isArray(record.messages) && record.messages.every((m) => m && typeof m.text === "string" && typeof m.role === "string" && Number.isFinite(m.msgIndex));
|
|
642
|
+
}
|
|
643
|
+
function isMemoryRecord(value) {
|
|
644
|
+
if (!value || typeof value !== "object") return false;
|
|
645
|
+
const m = value;
|
|
646
|
+
return typeof m.memoryId === "string" && !!m.memoryId && typeof m.kind === "string" && typeof m.label === "string" && typeof m.text === "string" && typeof m.source === "string" && typeof m.enabled === "boolean" && typeof m.pinned === "boolean" && Number.isFinite(m.createdAt) && Number.isFinite(m.updatedAt);
|
|
647
|
+
}
|
|
648
|
+
async function readRequiredJson(file, validate, compressed = false) {
|
|
649
|
+
const raw = await fs.readFile(file);
|
|
650
|
+
const value = JSON.parse((compressed ? await gunzip(raw) : raw).toString("utf8"));
|
|
651
|
+
if (!validate(value)) throw new Error(`Invalid canonical record at ${file}`);
|
|
652
|
+
return value;
|
|
653
|
+
}
|
|
654
|
+
async function readMemoryIfExists(file) {
|
|
655
|
+
try {
|
|
656
|
+
return await readRequiredJson(file, isMemoryRecord);
|
|
657
|
+
} catch (error) {
|
|
658
|
+
if (error.code === "ENOENT") return null;
|
|
659
|
+
throw error;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
625
662
|
function serializeConversation(record) {
|
|
626
663
|
return `${JSON.stringify(canonicalizeConversation(record), null, 2)}
|
|
627
664
|
`;
|
|
@@ -637,7 +674,19 @@ async function readCompressedConversationIfExists(file) {
|
|
|
637
674
|
return null;
|
|
638
675
|
}
|
|
639
676
|
}
|
|
640
|
-
async function readBestConversationFiles(compressedFile, legacyFile) {
|
|
677
|
+
async function readBestConversationFiles(compressedFile, legacyFile, strict = false) {
|
|
678
|
+
if (strict) {
|
|
679
|
+
const copies = await Promise.allSettled([
|
|
680
|
+
readRequiredJson(compressedFile, isConversationRecord, true),
|
|
681
|
+
readRequiredJson(legacyFile, isConversationRecord)
|
|
682
|
+
]);
|
|
683
|
+
const valid = copies.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
|
|
684
|
+
if (valid.length > 0) return pickNewerConversation(valid[0], valid[1] ?? null);
|
|
685
|
+
throw new Error(
|
|
686
|
+
`Cannot rebuild the index: no readable conversation at ${compressedFile} or ${legacyFile}`,
|
|
687
|
+
{ cause: copies.find((result) => result.status === "rejected") }
|
|
688
|
+
);
|
|
689
|
+
}
|
|
641
690
|
const [compressed, legacy] = await Promise.all([
|
|
642
691
|
readCompressedConversationIfExists(compressedFile),
|
|
643
692
|
readPlainConversationIfExists(legacyFile)
|
|
@@ -658,6 +707,8 @@ function readBestConversationFilesSync(compressedFile, legacyFile) {
|
|
|
658
707
|
return pickNewerConversation(compressed, legacy);
|
|
659
708
|
}
|
|
660
709
|
function pickNewerConversation(a, b) {
|
|
710
|
+
if (!isConversationRecord(a)) a = null;
|
|
711
|
+
if (!isConversationRecord(b)) b = null;
|
|
661
712
|
if (!a) return b;
|
|
662
713
|
if (!b) return a;
|
|
663
714
|
const aChanged = a.conversation.corpusChangedAt ?? a.conversation.updatedAt ?? 0;
|
|
@@ -721,6 +772,21 @@ var EMPTY_REPORT = {
|
|
|
721
772
|
messages: 0,
|
|
722
773
|
malformedLines: 0
|
|
723
774
|
};
|
|
775
|
+
async function upsertIndexedConversation(corpus, record, index) {
|
|
776
|
+
const result = await corpus.upsert(record);
|
|
777
|
+
if (index) {
|
|
778
|
+
const saved = await corpus.getFromPlatform(record.conversation.platform, result.docId);
|
|
779
|
+
if (!saved) {
|
|
780
|
+
throw new Error(`Saved conversation '${result.docId}' could not be read for indexing`);
|
|
781
|
+
}
|
|
782
|
+
index.upsertConversation(saved, () => {
|
|
783
|
+
const current = corpus.getFromPlatformSync(record.conversation.platform, result.docId);
|
|
784
|
+
if (!current) throw new Error(`Saved conversation '${result.docId}' could not be read for indexing`);
|
|
785
|
+
return current;
|
|
786
|
+
});
|
|
787
|
+
}
|
|
788
|
+
return result;
|
|
789
|
+
}
|
|
724
790
|
async function ingestFile(corpus, file, index) {
|
|
725
791
|
const report = { ...EMPTY_REPORT };
|
|
726
792
|
let current = null;
|
|
@@ -730,11 +796,8 @@ async function ingestFile(corpus, file, index) {
|
|
|
730
796
|
return;
|
|
731
797
|
}
|
|
732
798
|
const record = { conversation: current, messages: buffered };
|
|
733
|
-
const result = await corpus
|
|
799
|
+
const result = await upsertIndexedConversation(corpus, record, index);
|
|
734
800
|
tally(report, result);
|
|
735
|
-
if (index && result.outcome !== "skipped") {
|
|
736
|
-
index.upsertConversation(record);
|
|
737
|
-
}
|
|
738
801
|
report.conversations += 1;
|
|
739
802
|
report.messages += buffered.length;
|
|
740
803
|
current = null;
|
|
@@ -771,9 +834,9 @@ async function ingestFile(corpus, file, index) {
|
|
|
771
834
|
}
|
|
772
835
|
continue;
|
|
773
836
|
}
|
|
774
|
-
if (type === "message"
|
|
837
|
+
if (type === "message") {
|
|
775
838
|
const docId = typeof record.docId === "string" ? record.docId : "";
|
|
776
|
-
if (docId !== current.docId) {
|
|
839
|
+
if (!current || docId !== current.docId) {
|
|
777
840
|
report.malformedLines += 1;
|
|
778
841
|
continue;
|
|
779
842
|
}
|
|
@@ -791,8 +854,9 @@ async function ingestFile(corpus, file, index) {
|
|
|
791
854
|
async function pendingInboxFiles(corpus) {
|
|
792
855
|
try {
|
|
793
856
|
return (await fs2.readdir(corpus.paths.inboxDir, { withFileTypes: true })).filter((e) => e.isFile() && isNdjson(e.name)).map((e) => e.name).sort();
|
|
794
|
-
} catch {
|
|
795
|
-
return [];
|
|
857
|
+
} catch (error) {
|
|
858
|
+
if (error.code === "ENOENT") return [];
|
|
859
|
+
throw error;
|
|
796
860
|
}
|
|
797
861
|
}
|
|
798
862
|
async function drainInbox(corpus, index, options = {}) {
|
|
@@ -1044,6 +1108,8 @@ CREATE TABLE IF NOT EXISTS conversations (
|
|
|
1044
1108
|
pinned INTEGER NOT NULL,
|
|
1045
1109
|
accountId TEXT,
|
|
1046
1110
|
accountLabel TEXT,
|
|
1111
|
+
providerProject TEXT,
|
|
1112
|
+
providerWorkspace TEXT,
|
|
1047
1113
|
models TEXT,
|
|
1048
1114
|
fingerprint TEXT NOT NULL
|
|
1049
1115
|
);
|
|
@@ -1113,14 +1179,14 @@ var SearchIndex = class {
|
|
|
1113
1179
|
deleteFts: this.db.prepare("DELETE FROM messages_fts WHERE rowid = ?"),
|
|
1114
1180
|
deleteMessageRows: this.db.prepare("DELETE FROM message_rows WHERE docId = ?"),
|
|
1115
1181
|
insertMessageRow: this.db.prepare(
|
|
1116
|
-
"INSERT INTO message_rows (docId, msgIndex, role) VALUES (?, ?, ?)"
|
|
1182
|
+
"INSERT INTO message_rows (docId, msgIndex, role) VALUES (?, ?, ?) RETURNING rowid"
|
|
1117
1183
|
),
|
|
1118
1184
|
insertFts: this.db.prepare("INSERT INTO messages_fts (rowid, text) VALUES (?, ?)"),
|
|
1119
1185
|
deleteConversation: this.db.prepare("DELETE FROM conversations WHERE docId = ?"),
|
|
1120
1186
|
insertConversation: this.db.prepare(
|
|
1121
1187
|
`INSERT INTO conversations
|
|
1122
|
-
(docId, platform, title, url, createdAt, updatedAt, messageCount, preview, pinned, accountId, accountLabel, models, fingerprint)
|
|
1123
|
-
VALUES (@docId, @platform, @title, @url, @createdAt, @updatedAt, @messageCount, @preview, @pinned, @accountId, @accountLabel, @models, @fingerprint)`
|
|
1188
|
+
(docId, platform, title, url, createdAt, updatedAt, messageCount, preview, pinned, accountId, accountLabel, providerProject, providerWorkspace, models, fingerprint)
|
|
1189
|
+
VALUES (@docId, @platform, @title, @url, @createdAt, @updatedAt, @messageCount, @preview, @pinned, @accountId, @accountLabel, @providerProject, @providerWorkspace, @models, @fingerprint)`
|
|
1124
1190
|
),
|
|
1125
1191
|
deleteMemoryFts: this.db.prepare("DELETE FROM memories_fts WHERE memoryId = ?"),
|
|
1126
1192
|
insertMemoryFts: this.db.prepare(
|
|
@@ -1139,6 +1205,9 @@ var SearchIndex = class {
|
|
|
1139
1205
|
FROM temp.snippet_fts WHERE snippet_fts MATCH ?`
|
|
1140
1206
|
)
|
|
1141
1207
|
};
|
|
1208
|
+
for (const statement of Object.values(this.stmts)) {
|
|
1209
|
+
statement.setReadBigInts(true);
|
|
1210
|
+
}
|
|
1142
1211
|
}
|
|
1143
1212
|
/** True when the stored format version was missing or stale — caller rebuilds. */
|
|
1144
1213
|
needsRebuild() {
|
|
@@ -1164,14 +1233,18 @@ var SearchIndex = class {
|
|
|
1164
1233
|
const orderBy = sort === "oldest" ? "createdAt ASC, updatedAt ASC" : sort === "newest" ? "createdAt DESC, updatedAt DESC" : "updatedAt DESC, createdAt DESC";
|
|
1165
1234
|
const rows = this.db.prepare(
|
|
1166
1235
|
`SELECT docId, platform, title, url, createdAt, updatedAt, messageCount, preview, pinned,
|
|
1167
|
-
accountId, accountLabel, models
|
|
1236
|
+
accountId, accountLabel, providerProject, providerWorkspace, models
|
|
1168
1237
|
FROM conversations ORDER BY ${orderBy} LIMIT ?`
|
|
1169
1238
|
).all(limit);
|
|
1170
1239
|
return rows.map((r) => {
|
|
1171
|
-
const { accountId, accountLabel, models, ...rest } = r;
|
|
1240
|
+
const { accountId, accountLabel, providerProject, providerWorkspace, models, ...rest } = r;
|
|
1172
1241
|
const entry = { ...rest, pinned: r.pinned === 1 };
|
|
1173
1242
|
if (accountId) entry.accountId = accountId;
|
|
1174
1243
|
if (accountLabel) entry.accountLabel = accountLabel;
|
|
1244
|
+
const project = parseObservation(providerProject);
|
|
1245
|
+
if (project) entry.providerProject = project;
|
|
1246
|
+
const workspace = parseObservation(providerWorkspace);
|
|
1247
|
+
if (workspace) entry.providerWorkspace = workspace;
|
|
1175
1248
|
const parsedModels = parseModels(models);
|
|
1176
1249
|
if (parsedModels.length > 0) entry.models = parsedModels;
|
|
1177
1250
|
return entry;
|
|
@@ -1195,7 +1268,7 @@ var SearchIndex = class {
|
|
|
1195
1268
|
* because its body is async and cannot be expressed as a sync callback.
|
|
1196
1269
|
*/
|
|
1197
1270
|
transaction(fn) {
|
|
1198
|
-
this.db.exec("BEGIN");
|
|
1271
|
+
this.db.exec("BEGIN IMMEDIATE");
|
|
1199
1272
|
try {
|
|
1200
1273
|
const result = fn();
|
|
1201
1274
|
this.db.exec("COMMIT");
|
|
@@ -1205,8 +1278,8 @@ var SearchIndex = class {
|
|
|
1205
1278
|
throw err;
|
|
1206
1279
|
}
|
|
1207
1280
|
}
|
|
1208
|
-
upsertConversation(record) {
|
|
1209
|
-
this.transaction(() => this.writeRecord(record));
|
|
1281
|
+
upsertConversation(record, readCurrent) {
|
|
1282
|
+
this.transaction(() => this.writeRecord(readCurrent ? readCurrent() : record));
|
|
1210
1283
|
}
|
|
1211
1284
|
upsertMemory(memory) {
|
|
1212
1285
|
this.transaction(() => this.writeMemory(memory));
|
|
@@ -1223,18 +1296,17 @@ var SearchIndex = class {
|
|
|
1223
1296
|
* reads, which the sync {@link transaction} helper cannot hold.
|
|
1224
1297
|
*/
|
|
1225
1298
|
async rebuildFrom(corpus) {
|
|
1226
|
-
this.corpus = corpus;
|
|
1227
|
-
this.db.exec("DELETE FROM messages_fts; DELETE FROM message_rows; DELETE FROM conversations;");
|
|
1228
|
-
this.db.exec("DELETE FROM memories_fts; DELETE FROM memories;");
|
|
1229
1299
|
let conversations = 0;
|
|
1230
1300
|
let memories = 0;
|
|
1231
|
-
this.db.exec("BEGIN");
|
|
1301
|
+
this.db.exec("BEGIN IMMEDIATE");
|
|
1232
1302
|
try {
|
|
1233
|
-
|
|
1303
|
+
this.db.exec("DELETE FROM messages_fts; DELETE FROM message_rows; DELETE FROM conversations;");
|
|
1304
|
+
this.db.exec("DELETE FROM memories_fts; DELETE FROM memories;");
|
|
1305
|
+
for await (const record of corpus.iterate({ strict: true })) {
|
|
1234
1306
|
this.writeRecord(record);
|
|
1235
1307
|
conversations += 1;
|
|
1236
1308
|
}
|
|
1237
|
-
for await (const memory of corpus.iterateMemories()) {
|
|
1309
|
+
for await (const memory of corpus.iterateMemories({ strict: true })) {
|
|
1238
1310
|
this.writeMemory(memory);
|
|
1239
1311
|
memories += 1;
|
|
1240
1312
|
}
|
|
@@ -1243,6 +1315,7 @@ var SearchIndex = class {
|
|
|
1243
1315
|
this.db.exec("ROLLBACK");
|
|
1244
1316
|
throw err;
|
|
1245
1317
|
}
|
|
1318
|
+
this.corpus = corpus;
|
|
1246
1319
|
return { conversations, memories };
|
|
1247
1320
|
}
|
|
1248
1321
|
// Replace a conversation's index rows. Caller supplies the transaction (the
|
|
@@ -1277,13 +1350,15 @@ var SearchIndex = class {
|
|
|
1277
1350
|
pinned: conversation.pinned ? 1 : 0,
|
|
1278
1351
|
accountId: conversation.accountId ?? null,
|
|
1279
1352
|
accountLabel: conversation.accountLabel ?? null,
|
|
1353
|
+
providerProject: observationJson(conversation.providerProject),
|
|
1354
|
+
providerWorkspace: observationJson(conversation.providerWorkspace),
|
|
1280
1355
|
models: conversation.models?.length ? JSON.stringify(conversation.models) : null,
|
|
1281
1356
|
fingerprint: fingerprintConversation(rec)
|
|
1282
1357
|
});
|
|
1283
1358
|
}
|
|
1284
1359
|
insertFtsRow(docId, msgIndex, role, text) {
|
|
1285
|
-
const inserted = this.stmts.insertMessageRow.
|
|
1286
|
-
this.stmts.insertFts.run(inserted.
|
|
1360
|
+
const inserted = this.stmts.insertMessageRow.get(docId, msgIndex, role);
|
|
1361
|
+
this.stmts.insertFts.run(inserted.rowid, text);
|
|
1287
1362
|
}
|
|
1288
1363
|
deleteFtsRows(docId) {
|
|
1289
1364
|
const rows = this.stmts.selectFtsRows.all(docId);
|
|
@@ -1339,11 +1414,19 @@ var SearchIndex = class {
|
|
|
1339
1414
|
clauses.push("c.createdAt <= @dateTo");
|
|
1340
1415
|
params.dateTo = filters.dateTo;
|
|
1341
1416
|
}
|
|
1342
|
-
|
|
1417
|
+
if (filters.providerProjectId) {
|
|
1418
|
+
clauses.push("json_extract(c.providerProject, '$.projectId') = @providerProjectId");
|
|
1419
|
+
params.providerProjectId = filters.providerProjectId;
|
|
1420
|
+
}
|
|
1421
|
+
if (filters.providerWorkspaceId) {
|
|
1422
|
+
clauses.push("json_extract(c.providerWorkspace, '$.workspaceId') = @providerWorkspaceId");
|
|
1423
|
+
params.providerWorkspaceId = filters.providerWorkspaceId;
|
|
1424
|
+
}
|
|
1343
1425
|
const sql = `
|
|
1344
1426
|
SELECT
|
|
1345
1427
|
c.docId, c.platform, c.title, c.url, c.createdAt, c.updatedAt,
|
|
1346
|
-
c.messageCount, c.preview, c.pinned, c.accountId, c.accountLabel,
|
|
1428
|
+
c.messageCount, c.preview, c.pinned, c.accountId, c.accountLabel,
|
|
1429
|
+
c.providerProject, c.providerWorkspace, c.models,
|
|
1347
1430
|
m.msgIndex AS msgIndex, m.role AS role,
|
|
1348
1431
|
bm25(messages_fts) AS bm25
|
|
1349
1432
|
FROM messages_fts
|
|
@@ -1351,16 +1434,18 @@ var SearchIndex = class {
|
|
|
1351
1434
|
JOIN conversations c ON c.docId = m.docId
|
|
1352
1435
|
WHERE ${clauses.join(" AND ")}
|
|
1353
1436
|
ORDER BY bm25
|
|
1354
|
-
LIMIT @scanCap
|
|
1355
1437
|
`;
|
|
1356
|
-
const rows = this.db.prepare(sql).all({ ...params, scanCap });
|
|
1357
1438
|
const seen = /* @__PURE__ */ new Set();
|
|
1439
|
+
const rows = [];
|
|
1440
|
+
for (const value of this.db.prepare(sql).iterate(params)) {
|
|
1441
|
+
const row = value;
|
|
1442
|
+
if (seen.has(row.docId)) continue;
|
|
1443
|
+
seen.add(row.docId);
|
|
1444
|
+
rows.push(row);
|
|
1445
|
+
if (rows.length >= limit) break;
|
|
1446
|
+
}
|
|
1358
1447
|
const hits = [];
|
|
1359
1448
|
for (const row of rows) {
|
|
1360
|
-
if (seen.has(row.docId)) {
|
|
1361
|
-
continue;
|
|
1362
|
-
}
|
|
1363
|
-
seen.add(row.docId);
|
|
1364
1449
|
const hit = {
|
|
1365
1450
|
docId: row.docId,
|
|
1366
1451
|
platform: row.platform,
|
|
@@ -1379,6 +1464,10 @@ var SearchIndex = class {
|
|
|
1379
1464
|
};
|
|
1380
1465
|
if (row.accountId) hit.accountId = row.accountId;
|
|
1381
1466
|
if (row.accountLabel) hit.accountLabel = row.accountLabel;
|
|
1467
|
+
const project = parseObservation(row.providerProject);
|
|
1468
|
+
if (project) hit.providerProject = project;
|
|
1469
|
+
const workspace = parseObservation(row.providerWorkspace);
|
|
1470
|
+
if (workspace) hit.providerWorkspace = workspace;
|
|
1382
1471
|
const models = parseModels(row.models);
|
|
1383
1472
|
if (models.length > 0) hit.models = models;
|
|
1384
1473
|
hits.push(hit);
|
|
@@ -1419,16 +1508,25 @@ var SearchIndex = class {
|
|
|
1419
1508
|
return row ? row.value : null;
|
|
1420
1509
|
}
|
|
1421
1510
|
setMeta(key, value) {
|
|
1422
|
-
|
|
1511
|
+
const statement = this.db.prepare(
|
|
1512
|
+
"INSERT INTO index_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value"
|
|
1513
|
+
);
|
|
1514
|
+
statement.setReadBigInts(true);
|
|
1515
|
+
statement.run(key, value);
|
|
1423
1516
|
}
|
|
1424
1517
|
};
|
|
1425
1518
|
async function openSearchIndex(corpus, options = {}) {
|
|
1426
1519
|
await corpus.init();
|
|
1427
1520
|
const index = new SearchIndex(corpus.paths.indexDbFile, corpus);
|
|
1428
|
-
|
|
1429
|
-
|
|
1521
|
+
try {
|
|
1522
|
+
if (options.autoBuild !== false && (index.needsRebuild() || index.count() === 0 && index.countMemories() === 0)) {
|
|
1523
|
+
await index.rebuildFrom(corpus);
|
|
1524
|
+
}
|
|
1525
|
+
return index;
|
|
1526
|
+
} catch (error) {
|
|
1527
|
+
index.close();
|
|
1528
|
+
throw error;
|
|
1430
1529
|
}
|
|
1431
|
-
return index;
|
|
1432
1530
|
}
|
|
1433
1531
|
async function deleteIndexDb(dbFile) {
|
|
1434
1532
|
for (const suffix of ["", "-wal", "-shm"]) {
|
|
@@ -1474,6 +1572,19 @@ function parseModels(value) {
|
|
|
1474
1572
|
return [];
|
|
1475
1573
|
}
|
|
1476
1574
|
}
|
|
1575
|
+
function observationJson(observation) {
|
|
1576
|
+
if (!observation) return null;
|
|
1577
|
+
return JSON.stringify(observation);
|
|
1578
|
+
}
|
|
1579
|
+
function parseObservation(value) {
|
|
1580
|
+
if (!value) return void 0;
|
|
1581
|
+
try {
|
|
1582
|
+
const parsed = JSON.parse(value);
|
|
1583
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : void 0;
|
|
1584
|
+
} catch {
|
|
1585
|
+
return void 0;
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1477
1588
|
|
|
1478
1589
|
// src/storageMaintenance.ts
|
|
1479
1590
|
import { promises as fs4 } from "fs";
|
|
@@ -2147,6 +2258,7 @@ export {
|
|
|
2147
2258
|
resolveCorpusDir,
|
|
2148
2259
|
staleIndexFiles,
|
|
2149
2260
|
Corpus,
|
|
2261
|
+
upsertIndexedConversation,
|
|
2150
2262
|
ingestFile,
|
|
2151
2263
|
pendingInboxFiles,
|
|
2152
2264
|
drainInbox,
|
|
@@ -17,17 +17,17 @@ import {
|
|
|
17
17
|
runtimeBinDir,
|
|
18
18
|
staleIndexFiles,
|
|
19
19
|
uninstallRuntime
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-7ISC4REX.js";
|
|
21
21
|
import {
|
|
22
22
|
VERSION,
|
|
23
23
|
__commonJS,
|
|
24
24
|
__require,
|
|
25
25
|
__toESM
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-ZYE6VY6A.js";
|
|
27
27
|
|
|
28
|
-
//
|
|
28
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/isexe/windows.js
|
|
29
29
|
var require_windows = __commonJS({
|
|
30
|
-
"
|
|
30
|
+
"../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/isexe/windows.js"(exports, module) {
|
|
31
31
|
"use strict";
|
|
32
32
|
module.exports = isexe;
|
|
33
33
|
isexe.sync = sync;
|
|
@@ -66,9 +66,9 @@ var require_windows = __commonJS({
|
|
|
66
66
|
}
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
//
|
|
69
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/isexe/mode.js
|
|
70
70
|
var require_mode = __commonJS({
|
|
71
|
-
"
|
|
71
|
+
"../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/isexe/mode.js"(exports, module) {
|
|
72
72
|
"use strict";
|
|
73
73
|
module.exports = isexe;
|
|
74
74
|
isexe.sync = sync;
|
|
@@ -100,9 +100,9 @@ var require_mode = __commonJS({
|
|
|
100
100
|
}
|
|
101
101
|
});
|
|
102
102
|
|
|
103
|
-
//
|
|
103
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/isexe/index.js
|
|
104
104
|
var require_isexe = __commonJS({
|
|
105
|
-
"
|
|
105
|
+
"../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/isexe/index.js"(exports, module) {
|
|
106
106
|
"use strict";
|
|
107
107
|
var fs = __require("fs");
|
|
108
108
|
var core;
|
|
@@ -156,9 +156,9 @@ var require_isexe = __commonJS({
|
|
|
156
156
|
}
|
|
157
157
|
});
|
|
158
158
|
|
|
159
|
-
//
|
|
159
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/which/which.js
|
|
160
160
|
var require_which = __commonJS({
|
|
161
|
-
"
|
|
161
|
+
"../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/which/which.js"(exports, module) {
|
|
162
162
|
"use strict";
|
|
163
163
|
var isWindows2 = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
|
|
164
164
|
var path = __require("path");
|
|
@@ -253,9 +253,9 @@ var require_which = __commonJS({
|
|
|
253
253
|
}
|
|
254
254
|
});
|
|
255
255
|
|
|
256
|
-
//
|
|
256
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/path-key/index.js
|
|
257
257
|
var require_path_key = __commonJS({
|
|
258
|
-
"
|
|
258
|
+
"../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/path-key/index.js"(exports, module) {
|
|
259
259
|
"use strict";
|
|
260
260
|
var pathKey = (options = {}) => {
|
|
261
261
|
const environment = options.env || process.env;
|
|
@@ -270,9 +270,9 @@ var require_path_key = __commonJS({
|
|
|
270
270
|
}
|
|
271
271
|
});
|
|
272
272
|
|
|
273
|
-
//
|
|
273
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/cross-spawn/lib/util/resolveCommand.js
|
|
274
274
|
var require_resolveCommand = __commonJS({
|
|
275
|
-
"
|
|
275
|
+
"../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/cross-spawn/lib/util/resolveCommand.js"(exports, module) {
|
|
276
276
|
"use strict";
|
|
277
277
|
var path = __require("path");
|
|
278
278
|
var which = require_which();
|
|
@@ -312,9 +312,9 @@ var require_resolveCommand = __commonJS({
|
|
|
312
312
|
}
|
|
313
313
|
});
|
|
314
314
|
|
|
315
|
-
//
|
|
315
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/cross-spawn/lib/util/escape.js
|
|
316
316
|
var require_escape = __commonJS({
|
|
317
|
-
"
|
|
317
|
+
"../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/cross-spawn/lib/util/escape.js"(exports, module) {
|
|
318
318
|
"use strict";
|
|
319
319
|
var metaCharsRegExp = /([()\][%!^"`<>&|;, *?])/g;
|
|
320
320
|
function escapeCommand(arg) {
|
|
@@ -337,17 +337,17 @@ var require_escape = __commonJS({
|
|
|
337
337
|
}
|
|
338
338
|
});
|
|
339
339
|
|
|
340
|
-
//
|
|
340
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/shebang-regex/index.js
|
|
341
341
|
var require_shebang_regex = __commonJS({
|
|
342
|
-
"
|
|
342
|
+
"../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/shebang-regex/index.js"(exports, module) {
|
|
343
343
|
"use strict";
|
|
344
344
|
module.exports = /^#!(.*)/;
|
|
345
345
|
}
|
|
346
346
|
});
|
|
347
347
|
|
|
348
|
-
//
|
|
348
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/shebang-command/index.js
|
|
349
349
|
var require_shebang_command = __commonJS({
|
|
350
|
-
"
|
|
350
|
+
"../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/shebang-command/index.js"(exports, module) {
|
|
351
351
|
"use strict";
|
|
352
352
|
var shebangRegex = require_shebang_regex();
|
|
353
353
|
module.exports = (string = "") => {
|
|
@@ -365,9 +365,9 @@ var require_shebang_command = __commonJS({
|
|
|
365
365
|
}
|
|
366
366
|
});
|
|
367
367
|
|
|
368
|
-
//
|
|
368
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/cross-spawn/lib/util/readShebang.js
|
|
369
369
|
var require_readShebang = __commonJS({
|
|
370
|
-
"
|
|
370
|
+
"../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/cross-spawn/lib/util/readShebang.js"(exports, module) {
|
|
371
371
|
"use strict";
|
|
372
372
|
var fs = __require("fs");
|
|
373
373
|
var shebangCommand = require_shebang_command();
|
|
@@ -387,9 +387,9 @@ var require_readShebang = __commonJS({
|
|
|
387
387
|
}
|
|
388
388
|
});
|
|
389
389
|
|
|
390
|
-
//
|
|
390
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/cross-spawn/lib/parse.js
|
|
391
391
|
var require_parse = __commonJS({
|
|
392
|
-
"
|
|
392
|
+
"../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/cross-spawn/lib/parse.js"(exports, module) {
|
|
393
393
|
"use strict";
|
|
394
394
|
var path = __require("path");
|
|
395
395
|
var resolveCommand = require_resolveCommand();
|
|
@@ -449,9 +449,9 @@ var require_parse = __commonJS({
|
|
|
449
449
|
}
|
|
450
450
|
});
|
|
451
451
|
|
|
452
|
-
//
|
|
452
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/cross-spawn/lib/enoent.js
|
|
453
453
|
var require_enoent = __commonJS({
|
|
454
|
-
"
|
|
454
|
+
"../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/cross-spawn/lib/enoent.js"(exports, module) {
|
|
455
455
|
"use strict";
|
|
456
456
|
var isWin = process.platform === "win32";
|
|
457
457
|
function notFoundError(original, syscall) {
|
|
@@ -499,9 +499,9 @@ var require_enoent = __commonJS({
|
|
|
499
499
|
}
|
|
500
500
|
});
|
|
501
501
|
|
|
502
|
-
//
|
|
502
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/cross-spawn/index.js
|
|
503
503
|
var require_cross_spawn = __commonJS({
|
|
504
|
-
"
|
|
504
|
+
"../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/cross-spawn/index.js"(exports, module) {
|
|
505
505
|
"use strict";
|
|
506
506
|
var cp = __require("child_process");
|
|
507
507
|
var parse = require_parse();
|
|
@@ -888,13 +888,13 @@ function parseArgs(argv) {
|
|
|
888
888
|
return { command: positionals[0], positionals: positionals.slice(1), options, flags };
|
|
889
889
|
}
|
|
890
890
|
|
|
891
|
-
//
|
|
891
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/chokidar/esm/index.js
|
|
892
892
|
import { stat as statcb } from "fs";
|
|
893
893
|
import { stat as stat4, readdir as readdir2 } from "fs/promises";
|
|
894
894
|
import { EventEmitter } from "events";
|
|
895
895
|
import * as sysPath2 from "path";
|
|
896
896
|
|
|
897
|
-
//
|
|
897
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/readdirp/esm/index.js
|
|
898
898
|
import { stat as stat2, lstat, readdir, realpath } from "fs/promises";
|
|
899
899
|
import { Readable } from "stream";
|
|
900
900
|
import { resolve as presolve, relative as prelative, join as pjoin, sep as psep } from "path";
|
|
@@ -1113,7 +1113,7 @@ function readdirp(root, options = {}) {
|
|
|
1113
1113
|
return new ReaddirpStream(options);
|
|
1114
1114
|
}
|
|
1115
1115
|
|
|
1116
|
-
//
|
|
1116
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/chokidar/esm/handler.js
|
|
1117
1117
|
import { watchFile, unwatchFile, watch as fs_watch } from "fs";
|
|
1118
1118
|
import { open, stat as stat3, lstat as lstat2, realpath as fsrealpath } from "fs/promises";
|
|
1119
1119
|
import * as sysPath from "path";
|
|
@@ -1869,7 +1869,7 @@ var NodeFsHandler = class {
|
|
|
1869
1869
|
}
|
|
1870
1870
|
};
|
|
1871
1871
|
|
|
1872
|
-
//
|
|
1872
|
+
// ../../../../Users/Kdog/Code-Projects/LLMnesia/node_modules/chokidar/esm/index.js
|
|
1873
1873
|
var SLASH = "/";
|
|
1874
1874
|
var SLASH_SLASH = "//";
|
|
1875
1875
|
var ONE_DOT = ".";
|