@equationalapplications/expo-llm-wiki 2.2.0 → 2.3.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/README.md +122 -12
- package/dist/{WikiMemory-CjlQ68X0.d.mts → WikiMemory-ChQmVyvA.d.mts} +13 -1
- package/dist/{WikiMemory-CjlQ68X0.d.ts → WikiMemory-ChQmVyvA.d.ts} +13 -1
- package/dist/index.d.mts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +324 -39
- package/dist/index.mjs +323 -39
- package/dist/react/index.d.mts +30 -3
- package/dist/react/index.d.ts +30 -3
- package/dist/react/index.js +57 -3
- package/dist/react/index.mjs +56 -3
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -81,9 +81,64 @@ async function setupDatabase(db, prefix) {
|
|
|
81
81
|
heal_checkpoint INTEGER NOT NULL DEFAULT 0,
|
|
82
82
|
memory_checkpoint INTEGER NOT NULL DEFAULT 0
|
|
83
83
|
);
|
|
84
|
+
|
|
85
|
+
CREATE TABLE IF NOT EXISTS ${prefix}meta (
|
|
86
|
+
key TEXT PRIMARY KEY,
|
|
87
|
+
value TEXT NOT NULL
|
|
88
|
+
);
|
|
84
89
|
`);
|
|
85
90
|
}
|
|
86
91
|
|
|
92
|
+
// src/db/migrations.ts
|
|
93
|
+
var MIGRATIONS = [
|
|
94
|
+
{
|
|
95
|
+
version: 1,
|
|
96
|
+
description: "Rebuild FTS5 with porter unicode61 tokenizer",
|
|
97
|
+
run: async (db, prefix) => {
|
|
98
|
+
await db.withTransactionAsync(async () => {
|
|
99
|
+
await db.execAsync(`
|
|
100
|
+
DROP TRIGGER IF EXISTS ${prefix}entries_ai;
|
|
101
|
+
DROP TRIGGER IF EXISTS ${prefix}entries_ad;
|
|
102
|
+
DROP TRIGGER IF EXISTS ${prefix}entries_au;
|
|
103
|
+
DROP TABLE IF EXISTS ${prefix}entries_fts;
|
|
104
|
+
CREATE VIRTUAL TABLE ${prefix}entries_fts USING fts5(
|
|
105
|
+
title,
|
|
106
|
+
body,
|
|
107
|
+
tags,
|
|
108
|
+
content='${prefix}entries',
|
|
109
|
+
content_rowid='rowid',
|
|
110
|
+
tokenize='porter unicode61'
|
|
111
|
+
);
|
|
112
|
+
INSERT INTO ${prefix}entries_fts(rowid, title, body, tags)
|
|
113
|
+
SELECT rowid, title, body, tags FROM ${prefix}entries;
|
|
114
|
+
CREATE TRIGGER ${prefix}entries_ai AFTER INSERT ON ${prefix}entries BEGIN
|
|
115
|
+
INSERT INTO ${prefix}entries_fts(rowid, title, body, tags)
|
|
116
|
+
VALUES (new.rowid, new.title, new.body, new.tags);
|
|
117
|
+
END;
|
|
118
|
+
CREATE TRIGGER ${prefix}entries_ad AFTER DELETE ON ${prefix}entries BEGIN
|
|
119
|
+
INSERT INTO ${prefix}entries_fts(${prefix}entries_fts, rowid, title, body, tags)
|
|
120
|
+
VALUES ('delete', old.rowid, old.title, old.body, old.tags);
|
|
121
|
+
END;
|
|
122
|
+
CREATE TRIGGER ${prefix}entries_au AFTER UPDATE ON ${prefix}entries BEGIN
|
|
123
|
+
INSERT INTO ${prefix}entries_fts(${prefix}entries_fts, rowid, title, body, tags)
|
|
124
|
+
VALUES ('delete', old.rowid, old.title, old.body, old.tags);
|
|
125
|
+
INSERT INTO ${prefix}entries_fts(rowid, title, body, tags)
|
|
126
|
+
VALUES (new.rowid, new.title, new.body, new.tags);
|
|
127
|
+
END;
|
|
128
|
+
`);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
];
|
|
133
|
+
for (let i = 1; i < MIGRATIONS.length; i++) {
|
|
134
|
+
if (MIGRATIONS[i].version <= MIGRATIONS[i - 1].version) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
`migrations.ts: MIGRATIONS must be in strictly ascending version order. Found version ${MIGRATIONS[i].version} after ${MIGRATIONS[i - 1].version} at index ${i}.`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
var CURRENT_SCHEMA_VERSION = MIGRATIONS.length > 0 ? MIGRATIONS[MIGRATIONS.length - 1].version : 0;
|
|
141
|
+
|
|
87
142
|
// src/types.ts
|
|
88
143
|
var WikiBusyError = class extends Error {
|
|
89
144
|
operation;
|
|
@@ -344,45 +399,54 @@ var WikiMemory = class {
|
|
|
344
399
|
this.prefix = options.config?.tablePrefix || "llm_wiki_";
|
|
345
400
|
}
|
|
346
401
|
async setup() {
|
|
347
|
-
await
|
|
348
|
-
|
|
349
|
-
`
|
|
350
|
-
[`${this.prefix}entries_fts`]
|
|
402
|
+
const entriesExistedBeforeSetup = await this.db.getFirstAsync(
|
|
403
|
+
`SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
|
|
404
|
+
[`${this.prefix}entries`]
|
|
351
405
|
);
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
406
|
+
await setupDatabase(this.db, this.prefix);
|
|
407
|
+
let currentVersion;
|
|
408
|
+
if (!entriesExistedBeforeSetup) {
|
|
409
|
+
await this.db.runAsync(
|
|
410
|
+
`INSERT OR REPLACE INTO ${this.prefix}meta (key, value) VALUES ('schema_version', ?)`,
|
|
411
|
+
[String(CURRENT_SCHEMA_VERSION)]
|
|
412
|
+
);
|
|
413
|
+
currentVersion = CURRENT_SCHEMA_VERSION;
|
|
414
|
+
} else {
|
|
415
|
+
const metaRow = await this.db.getFirstAsync(
|
|
416
|
+
`SELECT value FROM ${this.prefix}meta WHERE key = 'schema_version'`
|
|
417
|
+
);
|
|
418
|
+
if (metaRow) {
|
|
419
|
+
currentVersion = parseInt(metaRow.value, 10);
|
|
420
|
+
if (!Number.isFinite(currentVersion)) currentVersion = 0;
|
|
421
|
+
} else {
|
|
422
|
+
const ftsMeta = await this.db.getFirstAsync(
|
|
423
|
+
`SELECT sql FROM sqlite_master WHERE type='table' AND name=?`,
|
|
424
|
+
[`${this.prefix}entries_fts`]
|
|
425
|
+
);
|
|
426
|
+
const hasPorter = /tokenize\s*=\s*['"]porter\s+unicode61['"]/i.test(ftsMeta?.sql ?? "");
|
|
427
|
+
currentVersion = hasPorter ? 1 : 0;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
for (const migration of MIGRATIONS) {
|
|
431
|
+
if (migration.version > currentVersion) {
|
|
432
|
+
await migration.run(this.db, this.prefix);
|
|
433
|
+
await this.db.runAsync(
|
|
434
|
+
`INSERT OR REPLACE INTO ${this.prefix}meta (key, value) VALUES ('schema_version', ?)`,
|
|
435
|
+
[String(migration.version)]
|
|
436
|
+
);
|
|
437
|
+
currentVersion = migration.version;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
if (entriesExistedBeforeSetup) {
|
|
441
|
+
const metaCheck = await this.db.getFirstAsync(
|
|
442
|
+
`SELECT value FROM ${this.prefix}meta WHERE key = 'schema_version'`
|
|
443
|
+
);
|
|
444
|
+
if (!metaCheck) {
|
|
445
|
+
await this.db.runAsync(
|
|
446
|
+
`INSERT OR REPLACE INTO ${this.prefix}meta (key, value) VALUES ('schema_version', ?)`,
|
|
447
|
+
[String(currentVersion)]
|
|
448
|
+
);
|
|
449
|
+
}
|
|
386
450
|
}
|
|
387
451
|
const rows = await this.db.getAllAsync(`
|
|
388
452
|
SELECT rowid, source_ref FROM ${this.prefix}entries
|
|
@@ -407,6 +471,101 @@ var WikiMemory = class {
|
|
|
407
471
|
}
|
|
408
472
|
});
|
|
409
473
|
}
|
|
474
|
+
async hasChanged(entityId, sourceRef, sourceHash) {
|
|
475
|
+
const normalizedRef = normalizeSourceRef(sourceRef);
|
|
476
|
+
if (!normalizedRef) {
|
|
477
|
+
throw new Error(`Invalid sourceRef: "${sourceRef}"`);
|
|
478
|
+
}
|
|
479
|
+
const normalizedHash = normalizeSourceHash(sourceHash);
|
|
480
|
+
if (!normalizedHash) {
|
|
481
|
+
throw new Error(`Invalid sourceHash: must be a 64-character hex string (normalized to lowercase)`);
|
|
482
|
+
}
|
|
483
|
+
const row = await this.db.getFirstAsync(
|
|
484
|
+
`SELECT source_hash FROM ${this.prefix}entries
|
|
485
|
+
WHERE entity_id = ? AND source_ref = ? AND deleted_at IS NULL
|
|
486
|
+
ORDER BY updated_at DESC
|
|
487
|
+
LIMIT 1`,
|
|
488
|
+
[entityId, normalizedRef]
|
|
489
|
+
);
|
|
490
|
+
if (!row) return true;
|
|
491
|
+
const normalizedStoredHash = row.source_hash ? normalizeSourceHash(row.source_hash) : null;
|
|
492
|
+
return normalizedStoredHash !== normalizedHash;
|
|
493
|
+
}
|
|
494
|
+
_pruneKey(entityId) {
|
|
495
|
+
return `${this.prefix}:${entityId}:prune`;
|
|
496
|
+
}
|
|
497
|
+
_validatePruneDuration(value, name) {
|
|
498
|
+
if (value !== null && value !== void 0 && (typeof value !== "number" || !isFinite(value) || value < 0)) {
|
|
499
|
+
throw new Error(`Invalid ${name}: must be a non-negative finite number or null`);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
async runPrune(entityId, options) {
|
|
503
|
+
const pruneKey = this._pruneKey(entityId);
|
|
504
|
+
const ingestPrefix = `${this.prefix}:${entityId}:`;
|
|
505
|
+
let isIngestRunning = false;
|
|
506
|
+
for (const k of this.activeIngestJobs) {
|
|
507
|
+
if (k.startsWith(ingestPrefix)) {
|
|
508
|
+
isIngestRunning = true;
|
|
509
|
+
break;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
let blockingOperation = null;
|
|
513
|
+
if (this.activeMaintenanceJobs.has(pruneKey)) {
|
|
514
|
+
blockingOperation = "prune";
|
|
515
|
+
} else if (this.activeMaintenanceJobs.has(this._librarianKey(entityId))) {
|
|
516
|
+
blockingOperation = "librarian";
|
|
517
|
+
} else if (this.activeMaintenanceJobs.has(this._healKey(entityId))) {
|
|
518
|
+
blockingOperation = "heal";
|
|
519
|
+
} else if (isIngestRunning) {
|
|
520
|
+
blockingOperation = "ingest";
|
|
521
|
+
}
|
|
522
|
+
if (blockingOperation !== null) {
|
|
523
|
+
throw new WikiBusyError(blockingOperation, entityId);
|
|
524
|
+
}
|
|
525
|
+
this.activeMaintenanceJobs.add(pruneKey);
|
|
526
|
+
try {
|
|
527
|
+
const retainSoftDeletedFor = options?.retainSoftDeletedFor !== void 0 ? options.retainSoftDeletedFor : this.options.config?.pruneRetainSoftDeletedFor ?? 7;
|
|
528
|
+
const retainEventsFor = options?.retainEventsFor !== void 0 ? options.retainEventsFor : this.options.config?.pruneEventsAfter ?? 30;
|
|
529
|
+
const vacuum = options?.vacuum ?? false;
|
|
530
|
+
this._validatePruneDuration(retainSoftDeletedFor, "retainSoftDeletedFor");
|
|
531
|
+
this._validatePruneDuration(retainEventsFor, "retainEventsFor");
|
|
532
|
+
const now = Date.now();
|
|
533
|
+
let deletedEntries = 0;
|
|
534
|
+
let deletedTasks = 0;
|
|
535
|
+
let deletedEvents = 0;
|
|
536
|
+
if (retainSoftDeletedFor !== null) {
|
|
537
|
+
const cutoff = now - retainSoftDeletedFor * 864e5;
|
|
538
|
+
const entryResult = await this.db.runAsync(
|
|
539
|
+
`DELETE FROM ${this.prefix}entries
|
|
540
|
+
WHERE entity_id = ? AND deleted_at IS NOT NULL AND deleted_at < ?`,
|
|
541
|
+
[entityId, cutoff]
|
|
542
|
+
);
|
|
543
|
+
deletedEntries = entryResult.changes;
|
|
544
|
+
const taskResult = await this.db.runAsync(
|
|
545
|
+
`DELETE FROM ${this.prefix}tasks
|
|
546
|
+
WHERE entity_id = ? AND deleted_at IS NOT NULL AND deleted_at < ?`,
|
|
547
|
+
[entityId, cutoff]
|
|
548
|
+
);
|
|
549
|
+
deletedTasks = taskResult.changes;
|
|
550
|
+
}
|
|
551
|
+
if (retainEventsFor !== null) {
|
|
552
|
+
const cutoff = now - retainEventsFor * 864e5;
|
|
553
|
+
const eventResult = await this.db.runAsync(
|
|
554
|
+
`DELETE FROM ${this.prefix}events
|
|
555
|
+
WHERE entity_id = ? AND created_at < ?`,
|
|
556
|
+
[entityId, cutoff]
|
|
557
|
+
);
|
|
558
|
+
deletedEvents = eventResult.changes;
|
|
559
|
+
}
|
|
560
|
+
if (vacuum) {
|
|
561
|
+
await this.db.execAsync(`PRAGMA wal_checkpoint(TRUNCATE)`);
|
|
562
|
+
await this.db.execAsync(`VACUUM`);
|
|
563
|
+
}
|
|
564
|
+
return { entries: deletedEntries, tasks: deletedTasks, events: deletedEvents };
|
|
565
|
+
} finally {
|
|
566
|
+
this.activeMaintenanceJobs.delete(pruneKey);
|
|
567
|
+
}
|
|
568
|
+
}
|
|
410
569
|
formatSearchQuery(query) {
|
|
411
570
|
const normalizeTokens = (value) => value.toLowerCase().replace(/[^a-z0-9\s]/g, "").split(/\s+/).filter((t) => t.length >= 3);
|
|
412
571
|
const baseTokens = normalizeTokens(query);
|
|
@@ -512,7 +671,7 @@ var WikiMemory = class {
|
|
|
512
671
|
if (memoryCheckpoint > count) memoryCheckpoint = 0;
|
|
513
672
|
if (count - memoryCheckpoint >= threshold) {
|
|
514
673
|
const jobKey = this._librarianKey(entityId);
|
|
515
|
-
if (!this.activeMaintenanceJobs.has(jobKey)) {
|
|
674
|
+
if (!this.activeMaintenanceJobs.has(jobKey) && !this.activeMaintenanceJobs.has(this._pruneKey(entityId))) {
|
|
516
675
|
this.activeMaintenanceJobs.add(jobKey);
|
|
517
676
|
this.runLibrarianThenMaybeHeal(entityId, count).catch(console.error).finally(() => this.activeMaintenanceJobs.delete(jobKey));
|
|
518
677
|
}
|
|
@@ -690,6 +849,9 @@ The following document anchors are provided for contradiction detection only. Do
|
|
|
690
849
|
if (this.activeMaintenanceJobs.has(jobKey)) {
|
|
691
850
|
throw new WikiBusyError("librarian", entityId);
|
|
692
851
|
}
|
|
852
|
+
if (this.activeMaintenanceJobs.has(this._pruneKey(entityId))) {
|
|
853
|
+
throw new WikiBusyError("prune", entityId);
|
|
854
|
+
}
|
|
693
855
|
this.activeMaintenanceJobs.add(jobKey);
|
|
694
856
|
try {
|
|
695
857
|
await this._doRunLibrarian(entityId);
|
|
@@ -702,6 +864,9 @@ The following document anchors are provided for contradiction detection only. Do
|
|
|
702
864
|
if (this.activeMaintenanceJobs.has(jobKey)) {
|
|
703
865
|
throw new WikiBusyError("heal", entityId);
|
|
704
866
|
}
|
|
867
|
+
if (this.activeMaintenanceJobs.has(this._pruneKey(entityId))) {
|
|
868
|
+
throw new WikiBusyError("prune", entityId);
|
|
869
|
+
}
|
|
705
870
|
this.activeMaintenanceJobs.add(jobKey);
|
|
706
871
|
try {
|
|
707
872
|
await this._doRunHeal(entityId);
|
|
@@ -952,6 +1117,9 @@ The following document anchors are provided for contradiction detection only. Do
|
|
|
952
1117
|
if (this.activeIngestJobs.has(jobKey)) {
|
|
953
1118
|
throw new WikiBusyError("ingest", entityId);
|
|
954
1119
|
}
|
|
1120
|
+
if (this.activeMaintenanceJobs.has(this._pruneKey(entityId))) {
|
|
1121
|
+
throw new WikiBusyError("prune", entityId);
|
|
1122
|
+
}
|
|
955
1123
|
this.activeIngestJobs.add(jobKey);
|
|
956
1124
|
try {
|
|
957
1125
|
const { chunks, truncated } = chunkText(params.documentChunk, maxChunkLength, chunkOverlap);
|
|
@@ -1089,6 +1257,121 @@ function formatMemoryDump(dump) {
|
|
|
1089
1257
|
};
|
|
1090
1258
|
}
|
|
1091
1259
|
|
|
1260
|
+
// src/utils/formatContext.ts
|
|
1261
|
+
function validateMaxOption(value, name) {
|
|
1262
|
+
if (!isFinite(value) || value < 0) {
|
|
1263
|
+
throw new Error(`Invalid ${name}: must be a non-negative finite number`);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
var CONFIDENCE_WEIGHT = {
|
|
1267
|
+
certain: 1,
|
|
1268
|
+
inferred: 0.6,
|
|
1269
|
+
tentative: 0.3
|
|
1270
|
+
};
|
|
1271
|
+
function scoreFactFor(fact, weights, now) {
|
|
1272
|
+
const confW = CONFIDENCE_WEIGHT[fact.confidence] ?? 0.3;
|
|
1273
|
+
const ageDays = (now - fact.updated_at) / 864e5;
|
|
1274
|
+
const recencyDecay = Math.exp(-ageDays / 30);
|
|
1275
|
+
return confW * weights.confidence + Math.log(1 + fact.access_count) * weights.accessCount + recencyDecay * weights.recency;
|
|
1276
|
+
}
|
|
1277
|
+
function renderFactMarkdown(fact, includeConfidence, includeTags) {
|
|
1278
|
+
const confPart = includeConfidence ? ` (${fact.confidence})` : "";
|
|
1279
|
+
const tagPart = includeTags && fact.tags.length > 0 ? ` [${fact.tags.join(", ")}]` : "";
|
|
1280
|
+
return `- **${fact.title}**${confPart}${tagPart}
|
|
1281
|
+
${fact.body.replace(/\n/g, "\n ")}`;
|
|
1282
|
+
}
|
|
1283
|
+
function renderFactPlain(fact, includeConfidence, includeTags) {
|
|
1284
|
+
const confPart = includeConfidence ? ` (${fact.confidence})` : "";
|
|
1285
|
+
const tagPart = includeTags && fact.tags.length > 0 ? ` [${fact.tags.join(", ")}]` : "";
|
|
1286
|
+
return `${fact.title}${confPart}${tagPart}: ${fact.body}`;
|
|
1287
|
+
}
|
|
1288
|
+
function renderTaskMarkdown(task) {
|
|
1289
|
+
return `- [P${task.priority}] ${task.description.replace(/\n/g, "\n ")} (${task.status})`;
|
|
1290
|
+
}
|
|
1291
|
+
function renderTaskPlain(task) {
|
|
1292
|
+
return `[P${task.priority}] ${task.description} (${task.status})`;
|
|
1293
|
+
}
|
|
1294
|
+
function renderEventMarkdown(event) {
|
|
1295
|
+
const ts = new Date(event.created_at).toISOString();
|
|
1296
|
+
return `- [${event.event_type} @ ${ts}] ${event.summary.replace(/\n/g, "\n ")}`;
|
|
1297
|
+
}
|
|
1298
|
+
function renderEventPlain(event) {
|
|
1299
|
+
const ts = new Date(event.created_at).toISOString();
|
|
1300
|
+
return `[${event.event_type} @ ${ts}] ${event.summary}`;
|
|
1301
|
+
}
|
|
1302
|
+
function formatContext(bundle, options) {
|
|
1303
|
+
const opts = {
|
|
1304
|
+
format: options?.format ?? "markdown",
|
|
1305
|
+
maxFacts: options?.maxFacts ?? 10,
|
|
1306
|
+
maxTasks: options?.maxTasks ?? 10,
|
|
1307
|
+
maxEvents: options?.maxEvents ?? 10,
|
|
1308
|
+
includeConfidence: options?.includeConfidence ?? true,
|
|
1309
|
+
includeTags: options?.includeTags ?? true,
|
|
1310
|
+
factWeights: {
|
|
1311
|
+
confidence: options?.factWeights?.confidence ?? 1,
|
|
1312
|
+
accessCount: options?.factWeights?.accessCount ?? 0.3,
|
|
1313
|
+
recency: options?.factWeights?.recency ?? 0.5
|
|
1314
|
+
}
|
|
1315
|
+
};
|
|
1316
|
+
validateMaxOption(opts.maxFacts, "maxFacts");
|
|
1317
|
+
validateMaxOption(opts.maxTasks, "maxTasks");
|
|
1318
|
+
validateMaxOption(opts.maxEvents, "maxEvents");
|
|
1319
|
+
const weights = opts.factWeights;
|
|
1320
|
+
const now = Date.now();
|
|
1321
|
+
const sortedFacts = [...bundle.facts].sort((a, b) => scoreFactFor(b, weights, now) - scoreFactFor(a, weights, now)).slice(0, opts.maxFacts);
|
|
1322
|
+
const sortedTasks = [...bundle.tasks].sort((a, b) => b.priority - a.priority || a.created_at - b.created_at).slice(0, opts.maxTasks);
|
|
1323
|
+
const sortedEvents = [...bundle.events].sort((a, b) => b.created_at - a.created_at).slice(0, opts.maxEvents);
|
|
1324
|
+
if (sortedFacts.length === 0 && sortedTasks.length === 0 && sortedEvents.length === 0) {
|
|
1325
|
+
return "";
|
|
1326
|
+
}
|
|
1327
|
+
const isMarkdown = opts.format === "markdown";
|
|
1328
|
+
const lines = [];
|
|
1329
|
+
if (isMarkdown) {
|
|
1330
|
+
lines.push("## Memory");
|
|
1331
|
+
if (sortedFacts.length > 0) {
|
|
1332
|
+
lines.push("");
|
|
1333
|
+
lines.push("### Known Facts");
|
|
1334
|
+
for (const fact of sortedFacts) {
|
|
1335
|
+
lines.push(renderFactMarkdown(fact, opts.includeConfidence, opts.includeTags));
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
if (sortedTasks.length > 0) {
|
|
1339
|
+
lines.push("");
|
|
1340
|
+
lines.push("### Open Tasks");
|
|
1341
|
+
for (const task of sortedTasks) {
|
|
1342
|
+
lines.push(renderTaskMarkdown(task));
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
if (sortedEvents.length > 0) {
|
|
1346
|
+
lines.push("");
|
|
1347
|
+
lines.push("### Recent Events");
|
|
1348
|
+
for (const event of sortedEvents) {
|
|
1349
|
+
lines.push(renderEventMarkdown(event));
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
} else {
|
|
1353
|
+
if (sortedFacts.length > 0) {
|
|
1354
|
+
lines.push("KNOWN FACTS:");
|
|
1355
|
+
for (const fact of sortedFacts) {
|
|
1356
|
+
lines.push(renderFactPlain(fact, opts.includeConfidence, opts.includeTags));
|
|
1357
|
+
}
|
|
1358
|
+
}
|
|
1359
|
+
if (sortedTasks.length > 0) {
|
|
1360
|
+
lines.push("OPEN TASKS:");
|
|
1361
|
+
for (const task of sortedTasks) {
|
|
1362
|
+
lines.push(renderTaskPlain(task));
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
if (sortedEvents.length > 0) {
|
|
1366
|
+
lines.push("RECENT EVENTS:");
|
|
1367
|
+
for (const event of sortedEvents) {
|
|
1368
|
+
lines.push(renderEventPlain(event));
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
return lines.join("\n");
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1092
1375
|
// src/index.ts
|
|
1093
1376
|
function createWiki(db, options) {
|
|
1094
1377
|
return new WikiMemory(db, options);
|
|
@@ -1097,5 +1380,6 @@ export {
|
|
|
1097
1380
|
WikiBusyError,
|
|
1098
1381
|
WikiMemory,
|
|
1099
1382
|
createWiki,
|
|
1383
|
+
formatContext,
|
|
1100
1384
|
formatMemoryDump
|
|
1101
1385
|
};
|
package/dist/react/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { c as WikiMemory, a as MemoryBundle, i as WikiEvent, M as MemoryDump } from '../WikiMemory-ChQmVyvA.mjs';
|
|
4
4
|
import 'expo-sqlite';
|
|
5
5
|
|
|
6
6
|
declare function WikiProvider({ wiki, children }: {
|
|
@@ -24,10 +24,30 @@ declare function useWikiWrite(): {
|
|
|
24
24
|
error: Error | null;
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
type MaintenanceResult = {
|
|
28
|
+
operation: 'librarian' | 'heal';
|
|
29
|
+
result: undefined;
|
|
30
|
+
} | {
|
|
31
|
+
operation: 'prune';
|
|
32
|
+
result: {
|
|
33
|
+
entries: number;
|
|
34
|
+
tasks: number;
|
|
35
|
+
events: number;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
27
38
|
declare function useWikiMaintenance(): {
|
|
28
39
|
runLibrarian: (entityId: string) => Promise<void>;
|
|
29
40
|
runHeal: (entityId: string) => Promise<void>;
|
|
30
|
-
|
|
41
|
+
runPrune: (entityId: string, options?: {
|
|
42
|
+
retainSoftDeletedFor?: number | null;
|
|
43
|
+
retainEventsFor?: number | null;
|
|
44
|
+
vacuum?: boolean;
|
|
45
|
+
}) => Promise<{
|
|
46
|
+
entries: number;
|
|
47
|
+
tasks: number;
|
|
48
|
+
events: number;
|
|
49
|
+
}>;
|
|
50
|
+
lastResult: MaintenanceResult | null;
|
|
31
51
|
isPending: boolean;
|
|
32
52
|
error: Error | null;
|
|
33
53
|
};
|
|
@@ -76,4 +96,11 @@ declare function useWikiExport(): {
|
|
|
76
96
|
error: Error | null;
|
|
77
97
|
};
|
|
78
98
|
|
|
79
|
-
|
|
99
|
+
declare function useWikiHasChanged(): {
|
|
100
|
+
execute: (entityId: string, sourceRef: string, sourceHash: string) => Promise<boolean>;
|
|
101
|
+
lastResult: boolean | null;
|
|
102
|
+
isPending: boolean;
|
|
103
|
+
error: Error | null;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export { type MaintenanceResult, WikiProvider, useMemoryRead, useWiki, useWikiExport, useWikiForget, useWikiHasChanged, useWikiIngest, useWikiMaintenance, useWikiWrite };
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { c as WikiMemory, a as MemoryBundle, i as WikiEvent, M as MemoryDump } from '../WikiMemory-ChQmVyvA.js';
|
|
4
4
|
import 'expo-sqlite';
|
|
5
5
|
|
|
6
6
|
declare function WikiProvider({ wiki, children }: {
|
|
@@ -24,10 +24,30 @@ declare function useWikiWrite(): {
|
|
|
24
24
|
error: Error | null;
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
+
type MaintenanceResult = {
|
|
28
|
+
operation: 'librarian' | 'heal';
|
|
29
|
+
result: undefined;
|
|
30
|
+
} | {
|
|
31
|
+
operation: 'prune';
|
|
32
|
+
result: {
|
|
33
|
+
entries: number;
|
|
34
|
+
tasks: number;
|
|
35
|
+
events: number;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
27
38
|
declare function useWikiMaintenance(): {
|
|
28
39
|
runLibrarian: (entityId: string) => Promise<void>;
|
|
29
40
|
runHeal: (entityId: string) => Promise<void>;
|
|
30
|
-
|
|
41
|
+
runPrune: (entityId: string, options?: {
|
|
42
|
+
retainSoftDeletedFor?: number | null;
|
|
43
|
+
retainEventsFor?: number | null;
|
|
44
|
+
vacuum?: boolean;
|
|
45
|
+
}) => Promise<{
|
|
46
|
+
entries: number;
|
|
47
|
+
tasks: number;
|
|
48
|
+
events: number;
|
|
49
|
+
}>;
|
|
50
|
+
lastResult: MaintenanceResult | null;
|
|
31
51
|
isPending: boolean;
|
|
32
52
|
error: Error | null;
|
|
33
53
|
};
|
|
@@ -76,4 +96,11 @@ declare function useWikiExport(): {
|
|
|
76
96
|
error: Error | null;
|
|
77
97
|
};
|
|
78
98
|
|
|
79
|
-
|
|
99
|
+
declare function useWikiHasChanged(): {
|
|
100
|
+
execute: (entityId: string, sourceRef: string, sourceHash: string) => Promise<boolean>;
|
|
101
|
+
lastResult: boolean | null;
|
|
102
|
+
isPending: boolean;
|
|
103
|
+
error: Error | null;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export { type MaintenanceResult, WikiProvider, useMemoryRead, useWiki, useWikiExport, useWikiForget, useWikiHasChanged, useWikiIngest, useWikiMaintenance, useWikiWrite };
|
package/dist/react/index.js
CHANGED
|
@@ -25,6 +25,7 @@ __export(react_exports, {
|
|
|
25
25
|
useWiki: () => useWiki,
|
|
26
26
|
useWikiExport: () => useWikiExport,
|
|
27
27
|
useWikiForget: () => useWikiForget,
|
|
28
|
+
useWikiHasChanged: () => useWikiHasChanged,
|
|
28
29
|
useWikiIngest: () => useWikiIngest,
|
|
29
30
|
useWikiMaintenance: () => useWikiMaintenance,
|
|
30
31
|
useWikiWrite: () => useWikiWrite
|
|
@@ -134,7 +135,7 @@ function useWikiMaintenance() {
|
|
|
134
135
|
setLastResult(null);
|
|
135
136
|
try {
|
|
136
137
|
await wikiRef.current.runLibrarian(entityId);
|
|
137
|
-
setLastResult(void 0);
|
|
138
|
+
setLastResult({ operation: "librarian", result: void 0 });
|
|
138
139
|
} catch (e) {
|
|
139
140
|
const err = e instanceof Error ? e : new Error(String(e));
|
|
140
141
|
setError(err);
|
|
@@ -151,7 +152,7 @@ function useWikiMaintenance() {
|
|
|
151
152
|
setLastResult(null);
|
|
152
153
|
try {
|
|
153
154
|
await wikiRef.current.runHeal(entityId);
|
|
154
|
-
setLastResult(void 0);
|
|
155
|
+
setLastResult({ operation: "heal", result: void 0 });
|
|
155
156
|
} catch (e) {
|
|
156
157
|
const err = e instanceof Error ? e : new Error(String(e));
|
|
157
158
|
setError(err);
|
|
@@ -161,7 +162,28 @@ function useWikiMaintenance() {
|
|
|
161
162
|
if (pendingCount.current === 0) setIsPending(false);
|
|
162
163
|
}
|
|
163
164
|
}, []);
|
|
164
|
-
|
|
165
|
+
const runPrune = (0, import_react4.useCallback)(
|
|
166
|
+
async (entityId, options) => {
|
|
167
|
+
setError(null);
|
|
168
|
+
pendingCount.current += 1;
|
|
169
|
+
setIsPending(true);
|
|
170
|
+
setLastResult(null);
|
|
171
|
+
try {
|
|
172
|
+
const result = await wikiRef.current.runPrune(entityId, options);
|
|
173
|
+
setLastResult({ operation: "prune", result });
|
|
174
|
+
return result;
|
|
175
|
+
} catch (e) {
|
|
176
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
177
|
+
setError(err);
|
|
178
|
+
throw err;
|
|
179
|
+
} finally {
|
|
180
|
+
pendingCount.current -= 1;
|
|
181
|
+
if (pendingCount.current === 0) setIsPending(false);
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
[]
|
|
185
|
+
);
|
|
186
|
+
return { runLibrarian, runHeal, runPrune, lastResult, isPending, error };
|
|
165
187
|
}
|
|
166
188
|
|
|
167
189
|
// src/react/useWikiIngest.ts
|
|
@@ -247,6 +269,37 @@ function useWikiExport() {
|
|
|
247
269
|
}, []);
|
|
248
270
|
return { execute, lastResult, isPending, error };
|
|
249
271
|
}
|
|
272
|
+
|
|
273
|
+
// src/react/useWikiHasChanged.ts
|
|
274
|
+
var import_react8 = require("react");
|
|
275
|
+
function useWikiHasChanged() {
|
|
276
|
+
const wiki = useWiki();
|
|
277
|
+
const wikiRef = (0, import_react8.useRef)(wiki);
|
|
278
|
+
wikiRef.current = wiki;
|
|
279
|
+
const [isPending, setIsPending] = (0, import_react8.useState)(false);
|
|
280
|
+
const [error, setError] = (0, import_react8.useState)(null);
|
|
281
|
+
const [lastResult, setLastResult] = (0, import_react8.useState)(null);
|
|
282
|
+
const execute = (0, import_react8.useCallback)(
|
|
283
|
+
async (entityId, sourceRef, sourceHash) => {
|
|
284
|
+
setError(null);
|
|
285
|
+
setIsPending(true);
|
|
286
|
+
setLastResult(null);
|
|
287
|
+
try {
|
|
288
|
+
const result = await wikiRef.current.hasChanged(entityId, sourceRef, sourceHash);
|
|
289
|
+
setLastResult(result);
|
|
290
|
+
return result;
|
|
291
|
+
} catch (e) {
|
|
292
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
293
|
+
setError(err);
|
|
294
|
+
throw err;
|
|
295
|
+
} finally {
|
|
296
|
+
setIsPending(false);
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
[]
|
|
300
|
+
);
|
|
301
|
+
return { execute, lastResult, isPending, error };
|
|
302
|
+
}
|
|
250
303
|
// Annotate the CommonJS export names for ESM import in node:
|
|
251
304
|
0 && (module.exports = {
|
|
252
305
|
WikiProvider,
|
|
@@ -254,6 +307,7 @@ function useWikiExport() {
|
|
|
254
307
|
useWiki,
|
|
255
308
|
useWikiExport,
|
|
256
309
|
useWikiForget,
|
|
310
|
+
useWikiHasChanged,
|
|
257
311
|
useWikiIngest,
|
|
258
312
|
useWikiMaintenance,
|
|
259
313
|
useWikiWrite
|