@equationalapplications/core-llm-wiki 4.14.0 → 4.15.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 +12 -0
- package/dist/{chunk-6FWG2DG4.mjs → chunk-J4GBC6CP.mjs} +103 -31
- package/dist/chunk-J4GBC6CP.mjs.map +1 -0
- package/dist/index.d.mts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +441 -45
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +343 -20
- package/dist/index.mjs.map +1 -1
- package/dist/{testing-CDIDE4Jd.d.mts → testing-NH1_Aigh.d.mts} +47 -3
- package/dist/{testing-CDIDE4Jd.d.ts → testing-NH1_Aigh.d.ts} +47 -3
- package/dist/testing.d.mts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +316 -244
- package/dist/testing.js.map +1 -1
- package/dist/testing.mjs +1 -1
- package/package.json +2 -2
- package/dist/chunk-6FWG2DG4.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { __privateAdd, EmbeddingService, SearchService, JobManager, PromptService, IngestionService, MaintenanceService, ImportExportService, RetrievalService, WriteService, __privateGet, __privateSet, normalizeSourceRef, normalizeSourceHash, generateId } from './chunk-
|
|
2
|
-
export { HOOK_TIMEOUT_MARKER, PromptService, PrunePartialFailureError, WikiBusyError, parseEmbedding } from './chunk-
|
|
3
|
-
import { buildConceptDocument, buildLogMd, buildIndexMd, buildRootIndexMd } from '@equationalapplications/core-okf';
|
|
1
|
+
import { __privateAdd, EmbeddingService, SearchService, JobManager, PromptService, IngestionService, MaintenanceService, ImportExportService, RetrievalService, WriteService, __privateGet, __privateSet, normalizeSourceRef, normalizeSourceHash, generateId } from './chunk-J4GBC6CP.mjs';
|
|
2
|
+
export { HOOK_TIMEOUT_MARKER, PromptService, PrunePartialFailureError, WikiBusyError, parseEmbedding } from './chunk-J4GBC6CP.mjs';
|
|
3
|
+
import { buildConceptDocument, buildLogMd, buildIndexMd, buildRootIndexMd, parseConcept, extractMarkdownLinks, parseLogMd } from '@equationalapplications/core-okf';
|
|
4
4
|
|
|
5
5
|
// src/db/schema.ts
|
|
6
6
|
async function setupDatabase(db, prefix) {
|
|
@@ -21,7 +21,8 @@ async function setupDatabase(db, prefix) {
|
|
|
21
21
|
access_count INTEGER NOT NULL DEFAULT 0,
|
|
22
22
|
deleted_at INTEGER,
|
|
23
23
|
embedding TEXT,
|
|
24
|
-
embedding_blob BLOB
|
|
24
|
+
embedding_blob BLOB,
|
|
25
|
+
okf_type TEXT
|
|
25
26
|
);
|
|
26
27
|
|
|
27
28
|
CREATE INDEX IF NOT EXISTS ${prefix}entries_entity_idx ON ${prefix}entries(entity_id);
|
|
@@ -38,11 +39,24 @@ async function setupDatabase(db, prefix) {
|
|
|
38
39
|
created_at INTEGER NOT NULL,
|
|
39
40
|
updated_at INTEGER NOT NULL,
|
|
40
41
|
resolved_at INTEGER,
|
|
41
|
-
deleted_at INTEGER
|
|
42
|
+
deleted_at INTEGER,
|
|
43
|
+
okf_type TEXT
|
|
42
44
|
);
|
|
43
45
|
|
|
44
46
|
CREATE INDEX IF NOT EXISTS ${prefix}tasks_entity_idx ON ${prefix}tasks(entity_id, status);
|
|
45
47
|
|
|
48
|
+
CREATE TABLE IF NOT EXISTS ${prefix}edges (
|
|
49
|
+
id TEXT PRIMARY KEY,
|
|
50
|
+
entity_id TEXT NOT NULL,
|
|
51
|
+
source_id TEXT NOT NULL,
|
|
52
|
+
target_id TEXT NOT NULL,
|
|
53
|
+
edge_type TEXT NOT NULL,
|
|
54
|
+
created_at INTEGER NOT NULL,
|
|
55
|
+
UNIQUE(entity_id, source_id, target_id, edge_type)
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
CREATE INDEX IF NOT EXISTS ${prefix}edges_entity_idx ON ${prefix}edges(entity_id);
|
|
59
|
+
|
|
46
60
|
CREATE TABLE IF NOT EXISTS ${prefix}events (
|
|
47
61
|
id TEXT PRIMARY KEY,
|
|
48
62
|
entity_id TEXT NOT NULL,
|
|
@@ -143,6 +157,32 @@ var MIGRATIONS = [
|
|
|
143
157
|
ON ${prefix}outbox (entity_id, created_at);
|
|
144
158
|
`);
|
|
145
159
|
}
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
version: 5,
|
|
163
|
+
description: "Add okf_type to entries/tasks for OKF type fidelity; create edges table for OKF graph import",
|
|
164
|
+
run: async (db, prefix) => {
|
|
165
|
+
for (const table of ["entries", "tasks"]) {
|
|
166
|
+
const cols = await db.getAllAsync(
|
|
167
|
+
`PRAGMA table_info(${prefix}${table})`
|
|
168
|
+
);
|
|
169
|
+
if (!cols.some((c) => c.name === "okf_type")) {
|
|
170
|
+
await db.execAsync(`ALTER TABLE ${prefix}${table} ADD COLUMN okf_type TEXT`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
await db.execAsync(`
|
|
174
|
+
CREATE TABLE IF NOT EXISTS ${prefix}edges (
|
|
175
|
+
id TEXT PRIMARY KEY,
|
|
176
|
+
entity_id TEXT NOT NULL,
|
|
177
|
+
source_id TEXT NOT NULL,
|
|
178
|
+
target_id TEXT NOT NULL,
|
|
179
|
+
edge_type TEXT NOT NULL,
|
|
180
|
+
created_at INTEGER NOT NULL,
|
|
181
|
+
UNIQUE(entity_id, source_id, target_id, edge_type)
|
|
182
|
+
);
|
|
183
|
+
CREATE INDEX IF NOT EXISTS ${prefix}edges_entity_idx ON ${prefix}edges (entity_id);
|
|
184
|
+
`);
|
|
185
|
+
}
|
|
146
186
|
}
|
|
147
187
|
];
|
|
148
188
|
for (let i = 1; i < MIGRATIONS.length; i++) {
|
|
@@ -194,7 +234,8 @@ function mapRowToFact(row) {
|
|
|
194
234
|
updated_at: Number(row.updated_at),
|
|
195
235
|
last_accessed_at: row.last_accessed_at === null || row.last_accessed_at === void 0 ? null : Number(row.last_accessed_at),
|
|
196
236
|
deleted_at: row.deleted_at != null ? Number(row.deleted_at) : null,
|
|
197
|
-
access_count: Number(row.access_count ?? 0)
|
|
237
|
+
access_count: Number(row.access_count ?? 0),
|
|
238
|
+
okf_type: row.okf_type ?? null
|
|
198
239
|
};
|
|
199
240
|
}
|
|
200
241
|
function normalizeEmbeddingBlobValue(blob) {
|
|
@@ -367,8 +408,8 @@ var EntryRepository = class extends BaseRepository {
|
|
|
367
408
|
`INSERT INTO ${this.prefix}entries (
|
|
368
409
|
id, entity_id, title, body, tags, confidence, source_type,
|
|
369
410
|
source_hash, source_ref, created_at, updated_at, last_accessed_at, access_count,
|
|
370
|
-
deleted_at, embedding_blob, embedding
|
|
371
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
411
|
+
deleted_at, embedding_blob, embedding, okf_type
|
|
412
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
372
413
|
ON CONFLICT(id) DO UPDATE SET
|
|
373
414
|
entity_id = excluded.entity_id,
|
|
374
415
|
title = excluded.title,
|
|
@@ -384,7 +425,8 @@ var EntryRepository = class extends BaseRepository {
|
|
|
384
425
|
access_count = excluded.access_count,
|
|
385
426
|
deleted_at = excluded.deleted_at,
|
|
386
427
|
embedding_blob = excluded.embedding_blob,
|
|
387
|
-
embedding = NULL
|
|
428
|
+
embedding = NULL,
|
|
429
|
+
okf_type = excluded.okf_type`,
|
|
388
430
|
[
|
|
389
431
|
fact.id,
|
|
390
432
|
fact.entity_id,
|
|
@@ -401,7 +443,8 @@ var EntryRepository = class extends BaseRepository {
|
|
|
401
443
|
fact.access_count,
|
|
402
444
|
fact.deleted_at ?? null,
|
|
403
445
|
embeddingBlob ?? null,
|
|
404
|
-
null
|
|
446
|
+
null,
|
|
447
|
+
fact.okf_type ?? null
|
|
405
448
|
]
|
|
406
449
|
);
|
|
407
450
|
return result;
|
|
@@ -966,7 +1009,8 @@ function mapRowToTask(row) {
|
|
|
966
1009
|
created_at: Number(row.created_at),
|
|
967
1010
|
updated_at: Number(row.updated_at),
|
|
968
1011
|
resolved_at: row.resolved_at != null ? Number(row.resolved_at) : null,
|
|
969
|
-
deleted_at: row.deleted_at != null ? Number(row.deleted_at) : null
|
|
1012
|
+
deleted_at: row.deleted_at != null ? Number(row.deleted_at) : null,
|
|
1013
|
+
okf_type: row.okf_type ?? null
|
|
970
1014
|
};
|
|
971
1015
|
}
|
|
972
1016
|
var TaskRepository = class extends BaseRepository {
|
|
@@ -1068,8 +1112,8 @@ var TaskRepository = class extends BaseRepository {
|
|
|
1068
1112
|
await executor.runAsync(
|
|
1069
1113
|
`INSERT INTO ${this.prefix}tasks (
|
|
1070
1114
|
id, entity_id, description, status, priority,
|
|
1071
|
-
created_at, updated_at, resolved_at, deleted_at
|
|
1072
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1115
|
+
created_at, updated_at, resolved_at, deleted_at, okf_type
|
|
1116
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1073
1117
|
ON CONFLICT(id) DO UPDATE SET
|
|
1074
1118
|
entity_id = excluded.entity_id,
|
|
1075
1119
|
description = excluded.description,
|
|
@@ -1077,7 +1121,8 @@ var TaskRepository = class extends BaseRepository {
|
|
|
1077
1121
|
priority = excluded.priority,
|
|
1078
1122
|
updated_at = excluded.updated_at,
|
|
1079
1123
|
resolved_at = excluded.resolved_at,
|
|
1080
|
-
deleted_at = excluded.deleted_at
|
|
1124
|
+
deleted_at = excluded.deleted_at,
|
|
1125
|
+
okf_type = excluded.okf_type`,
|
|
1081
1126
|
[
|
|
1082
1127
|
task.id,
|
|
1083
1128
|
task.entity_id,
|
|
@@ -1087,7 +1132,8 @@ var TaskRepository = class extends BaseRepository {
|
|
|
1087
1132
|
task.created_at,
|
|
1088
1133
|
now,
|
|
1089
1134
|
task.resolved_at ?? null,
|
|
1090
|
-
task.deleted_at ?? null
|
|
1135
|
+
task.deleted_at ?? null,
|
|
1136
|
+
task.okf_type ?? null
|
|
1091
1137
|
]
|
|
1092
1138
|
);
|
|
1093
1139
|
}
|
|
@@ -1309,6 +1355,53 @@ var EventRepository = class extends BaseRepository {
|
|
|
1309
1355
|
}
|
|
1310
1356
|
};
|
|
1311
1357
|
|
|
1358
|
+
// src/repositories/EdgeRepository.ts
|
|
1359
|
+
var EdgeRepository = class extends BaseRepository {
|
|
1360
|
+
/**
|
|
1361
|
+
* Insert an edge, silently skipping on primary-key or uniqueness conflicts.
|
|
1362
|
+
* Throws when the insert was skipped due to an id collision with a different edge tuple.
|
|
1363
|
+
*/
|
|
1364
|
+
async addIgnoreDuplicate(edge, tx) {
|
|
1365
|
+
const executor = this.getExecutor(tx);
|
|
1366
|
+
const result = await executor.runAsync(
|
|
1367
|
+
`INSERT OR IGNORE INTO ${this.prefix}edges (id, entity_id, source_id, target_id, edge_type, created_at)
|
|
1368
|
+
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
1369
|
+
[edge.id, edge.entity_id, edge.source_id, edge.target_id, edge.edge_type, edge.created_at]
|
|
1370
|
+
);
|
|
1371
|
+
if (result.changes > 0) return;
|
|
1372
|
+
const existing = await executor.getFirstAsync(
|
|
1373
|
+
`SELECT entity_id, source_id, target_id, edge_type FROM ${this.prefix}edges WHERE id = ?`,
|
|
1374
|
+
[edge.id]
|
|
1375
|
+
);
|
|
1376
|
+
if (!existing) return;
|
|
1377
|
+
if (String(existing.entity_id) !== edge.entity_id || String(existing.source_id) !== edge.source_id || String(existing.target_id) !== edge.target_id || String(existing.edge_type) !== edge.edge_type) {
|
|
1378
|
+
throw new Error(
|
|
1379
|
+
`Edge id collision: ${JSON.stringify(edge.id)} already exists with a different (entity_id, source_id, target_id, edge_type) tuple`
|
|
1380
|
+
);
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
async getByEntityId(entityId, tx) {
|
|
1384
|
+
const executor = this.getExecutor(tx);
|
|
1385
|
+
const rows = await executor.getAllAsync(
|
|
1386
|
+
`SELECT * FROM ${this.prefix}edges WHERE entity_id = ? ORDER BY created_at ASC`,
|
|
1387
|
+
[entityId]
|
|
1388
|
+
);
|
|
1389
|
+
return rows.map((row) => ({
|
|
1390
|
+
id: String(row.id),
|
|
1391
|
+
entity_id: String(row.entity_id),
|
|
1392
|
+
source_id: String(row.source_id),
|
|
1393
|
+
target_id: String(row.target_id),
|
|
1394
|
+
edge_type: String(row.edge_type),
|
|
1395
|
+
created_at: Number(row.created_at)
|
|
1396
|
+
}));
|
|
1397
|
+
}
|
|
1398
|
+
/** Hard delete — edges have no soft-delete concept, only presence/absence. `tx` is REQUIRED. */
|
|
1399
|
+
async bulkDeleteByEntityId(entityId, tx) {
|
|
1400
|
+
const executor = this.getExecutor(tx);
|
|
1401
|
+
await executor.runAsync(`DELETE FROM ${this.prefix}edges WHERE entity_id = ?`, [entityId]);
|
|
1402
|
+
}
|
|
1403
|
+
};
|
|
1404
|
+
|
|
1312
1405
|
// src/repositories/MetadataRepository.ts
|
|
1313
1406
|
var MetadataRepository = class extends BaseRepository {
|
|
1314
1407
|
// CHECKPOINTS TABLE METHODS
|
|
@@ -1410,6 +1503,7 @@ var MetadataRepository = class extends BaseRepository {
|
|
|
1410
1503
|
};
|
|
1411
1504
|
|
|
1412
1505
|
// src/WikiMemory.ts
|
|
1506
|
+
var TABLE_PREFIX_PATTERN = /^[A-Za-z][A-Za-z0-9_]{0,30}_$/;
|
|
1413
1507
|
var _testAccessNonTestEnvWarned;
|
|
1414
1508
|
var WikiMemory = class {
|
|
1415
1509
|
constructor(db, options) {
|
|
@@ -1417,11 +1511,17 @@ var WikiMemory = class {
|
|
|
1417
1511
|
__privateAdd(this, _testAccessNonTestEnvWarned, false);
|
|
1418
1512
|
this.db = db;
|
|
1419
1513
|
this.options = options;
|
|
1420
|
-
this.prefix = options.config?.tablePrefix
|
|
1514
|
+
this.prefix = options.config?.tablePrefix ?? "llm_wiki_";
|
|
1515
|
+
if (!TABLE_PREFIX_PATTERN.test(this.prefix)) {
|
|
1516
|
+
throw new Error(
|
|
1517
|
+
`Invalid tablePrefix: ${JSON.stringify(this.prefix)}. Must match ${TABLE_PREFIX_PATTERN} (letter, then alphanumeric/underscore, ending in "_", max 32 chars total).`
|
|
1518
|
+
);
|
|
1519
|
+
}
|
|
1421
1520
|
this.outboxRepo = new OutboxRepository(db, this.prefix, !!options.config?.enableOutbox);
|
|
1422
1521
|
this.entryRepo = new EntryRepository(db, this.prefix, this.outboxRepo);
|
|
1423
1522
|
this.taskRepo = new TaskRepository(db, this.prefix, this.outboxRepo);
|
|
1424
1523
|
this.eventRepo = new EventRepository(db, this.prefix);
|
|
1524
|
+
this.edgeRepo = new EdgeRepository(db, this.prefix);
|
|
1425
1525
|
this.metadataRepo = new MetadataRepository(db, this.prefix);
|
|
1426
1526
|
this.embeddingService = new EmbeddingService(this.db, this.options, this.entryRepo, this.metadataRepo);
|
|
1427
1527
|
this.searchService = new SearchService(this.entryRepo);
|
|
@@ -1455,6 +1555,7 @@ var WikiMemory = class {
|
|
|
1455
1555
|
this.entryRepo,
|
|
1456
1556
|
this.taskRepo,
|
|
1457
1557
|
this.eventRepo,
|
|
1558
|
+
this.edgeRepo,
|
|
1458
1559
|
this.metadataRepo,
|
|
1459
1560
|
this.searchService,
|
|
1460
1561
|
this.jobManager,
|
|
@@ -1471,6 +1572,7 @@ var WikiMemory = class {
|
|
|
1471
1572
|
this.writeService = new WriteService(
|
|
1472
1573
|
this.db,
|
|
1473
1574
|
this.options,
|
|
1575
|
+
this.entryRepo,
|
|
1474
1576
|
this.eventRepo,
|
|
1475
1577
|
this.metadataRepo,
|
|
1476
1578
|
this.jobManager,
|
|
@@ -1549,7 +1651,7 @@ var WikiMemory = class {
|
|
|
1549
1651
|
async hasChanged(entityId, sourceRef, sourceHash) {
|
|
1550
1652
|
const normalizedRef = normalizeSourceRef(sourceRef);
|
|
1551
1653
|
if (!normalizedRef) {
|
|
1552
|
-
throw new Error(`Invalid sourceRef:
|
|
1654
|
+
throw new Error(`Invalid sourceRef: ${JSON.stringify(sourceRef)}`);
|
|
1553
1655
|
}
|
|
1554
1656
|
const normalizedHash = normalizeSourceHash(sourceHash);
|
|
1555
1657
|
if (!normalizedHash) {
|
|
@@ -1914,7 +2016,7 @@ function formatMemoryDump(dump) {
|
|
|
1914
2016
|
}
|
|
1915
2017
|
function factFrontmatter(f) {
|
|
1916
2018
|
return {
|
|
1917
|
-
type: "fact",
|
|
2019
|
+
type: f.okf_type ?? "fact",
|
|
1918
2020
|
title: f.title,
|
|
1919
2021
|
tags: f.tags,
|
|
1920
2022
|
timestamp: new Date(f.updated_at).toISOString(),
|
|
@@ -1932,7 +2034,7 @@ function factFrontmatter(f) {
|
|
|
1932
2034
|
}
|
|
1933
2035
|
function taskFrontmatter(t) {
|
|
1934
2036
|
return {
|
|
1935
|
-
type: "task",
|
|
2037
|
+
type: t.okf_type ?? "task",
|
|
1936
2038
|
title: t.description,
|
|
1937
2039
|
timestamp: new Date(t.updated_at).toISOString(),
|
|
1938
2040
|
id: t.id,
|
|
@@ -2007,6 +2109,227 @@ function formatOkfBundle(dump) {
|
|
|
2007
2109
|
});
|
|
2008
2110
|
return { files };
|
|
2009
2111
|
}
|
|
2112
|
+
var CONFIDENCE_VALUES = /* @__PURE__ */ new Set(["certain", "inferred", "tentative"]);
|
|
2113
|
+
var SOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
2114
|
+
"user_stated",
|
|
2115
|
+
"librarian_inferred",
|
|
2116
|
+
"user_confirmed",
|
|
2117
|
+
"immutable_document"
|
|
2118
|
+
]);
|
|
2119
|
+
var TASK_STATUSES = /* @__PURE__ */ new Set(["pending", "in_progress", "done", "abandoned"]);
|
|
2120
|
+
var EVENT_TYPES = /* @__PURE__ */ new Set(["observation", "decision", "action", "outcome"]);
|
|
2121
|
+
function basenameMd(filePath) {
|
|
2122
|
+
const name = filePath.slice(filePath.lastIndexOf("/") + 1);
|
|
2123
|
+
return name.endsWith(".md") ? name.slice(0, -3) : name;
|
|
2124
|
+
}
|
|
2125
|
+
function isConceptFile(filePath) {
|
|
2126
|
+
if (!filePath.endsWith(".md")) return false;
|
|
2127
|
+
if (filePath.endsWith("/index.md") || filePath === "index.md") return false;
|
|
2128
|
+
if (filePath.endsWith("/log.md") || filePath === "log.md") return false;
|
|
2129
|
+
return true;
|
|
2130
|
+
}
|
|
2131
|
+
function isStructuralPath(filePath) {
|
|
2132
|
+
return filePath.endsWith("/index.md") || filePath === "index.md" || filePath.endsWith("/log.md") || filePath === "log.md";
|
|
2133
|
+
}
|
|
2134
|
+
function posixDirname(filePath) {
|
|
2135
|
+
const idx = filePath.lastIndexOf("/");
|
|
2136
|
+
return idx === -1 ? "" : filePath.slice(0, idx);
|
|
2137
|
+
}
|
|
2138
|
+
function resolveRelativePath(fromFile, linkPath) {
|
|
2139
|
+
const baseDir = posixDirname(fromFile);
|
|
2140
|
+
const segments = [...baseDir ? baseDir.split("/") : [], ...linkPath.split("/")];
|
|
2141
|
+
const resolved = [];
|
|
2142
|
+
for (const seg of segments) {
|
|
2143
|
+
if (seg === "" || seg === ".") continue;
|
|
2144
|
+
if (seg === "..") {
|
|
2145
|
+
resolved.pop();
|
|
2146
|
+
continue;
|
|
2147
|
+
}
|
|
2148
|
+
resolved.push(seg);
|
|
2149
|
+
}
|
|
2150
|
+
return resolved.join("/");
|
|
2151
|
+
}
|
|
2152
|
+
function addPathAliases(map, filePath, resolvedId) {
|
|
2153
|
+
map.set(filePath, resolvedId);
|
|
2154
|
+
const withoutDot = filePath.replace(/^\.\//, "");
|
|
2155
|
+
if (withoutDot !== filePath) map.set(withoutDot, resolvedId);
|
|
2156
|
+
const entityRelative = filePath.replace(/^entities\/[^/]+\//, "");
|
|
2157
|
+
if (entityRelative !== filePath) {
|
|
2158
|
+
map.set(entityRelative, resolvedId);
|
|
2159
|
+
map.set(`./${entityRelative}`, resolvedId);
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
function lookupResolvedId(map, path) {
|
|
2163
|
+
const normalized = path.replace(/^\.\//, "");
|
|
2164
|
+
return map.get(path) ?? map.get(normalized) ?? map.get(`./${normalized}`);
|
|
2165
|
+
}
|
|
2166
|
+
function stripLinkSuffix(linkPath) {
|
|
2167
|
+
const hashIdx = linkPath.indexOf("#");
|
|
2168
|
+
const queryIdx = linkPath.indexOf("?");
|
|
2169
|
+
if (hashIdx === -1 && queryIdx === -1) return linkPath;
|
|
2170
|
+
const cut = hashIdx === -1 ? queryIdx : queryIdx === -1 ? hashIdx : Math.min(hashIdx, queryIdx);
|
|
2171
|
+
return linkPath.slice(0, cut);
|
|
2172
|
+
}
|
|
2173
|
+
function resolveRoute(filePath, frontmatterType, options) {
|
|
2174
|
+
if (options?.typeMapping && Object.prototype.hasOwnProperty.call(options.typeMapping, frontmatterType)) {
|
|
2175
|
+
return options.typeMapping[frontmatterType];
|
|
2176
|
+
}
|
|
2177
|
+
if (filePath.includes("/facts/")) return "fact";
|
|
2178
|
+
if (filePath.includes("/tasks/")) return "task";
|
|
2179
|
+
return options?.defaultSchema ?? "fact";
|
|
2180
|
+
}
|
|
2181
|
+
function parseFrontmatterTimestamp(value, fallback) {
|
|
2182
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
2183
|
+
if (typeof value === "string") {
|
|
2184
|
+
const parsed = Date.parse(value);
|
|
2185
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
2186
|
+
}
|
|
2187
|
+
return fallback;
|
|
2188
|
+
}
|
|
2189
|
+
function unescapeLogSummary(summary) {
|
|
2190
|
+
return summary.replace(/\\\]/g, "]").replace(/\\\[/g, "[").replace(/\\\\/g, "\\");
|
|
2191
|
+
}
|
|
2192
|
+
var LOG_LINE_PATTERN = /^\(([^)]+)\)\s*(?:\[((?:\\.|[^\]])*)\]\(([^)]+)\)|(.+))$/;
|
|
2193
|
+
function parseLogEntryText(text) {
|
|
2194
|
+
const match = LOG_LINE_PATTERN.exec(text.trim());
|
|
2195
|
+
if (!match) return null;
|
|
2196
|
+
const [, rawType, linkedSummary, linkPath, plainSummary] = match;
|
|
2197
|
+
const event_type = EVENT_TYPES.has(rawType) ? rawType : "observation";
|
|
2198
|
+
if (linkPath) {
|
|
2199
|
+
return { event_type, summary: unescapeLogSummary(linkedSummary), linkPath };
|
|
2200
|
+
}
|
|
2201
|
+
return { event_type, summary: (plainSummary ?? "").trim() };
|
|
2202
|
+
}
|
|
2203
|
+
function frontmatterToFact(entityId, id, frontmatter, body, now) {
|
|
2204
|
+
const created_at = parseFrontmatterTimestamp(frontmatter.created_at, now);
|
|
2205
|
+
const updated_at = parseFrontmatterTimestamp(
|
|
2206
|
+
frontmatter.timestamp,
|
|
2207
|
+
parseFrontmatterTimestamp(frontmatter.updated_at, now)
|
|
2208
|
+
);
|
|
2209
|
+
return {
|
|
2210
|
+
id,
|
|
2211
|
+
entity_id: entityId,
|
|
2212
|
+
title: typeof frontmatter.title === "string" ? frontmatter.title : "",
|
|
2213
|
+
body,
|
|
2214
|
+
tags: Array.isArray(frontmatter.tags) ? frontmatter.tags.filter((t) => typeof t === "string") : [],
|
|
2215
|
+
confidence: CONFIDENCE_VALUES.has(String(frontmatter.confidence)) ? frontmatter.confidence : "tentative",
|
|
2216
|
+
source_type: SOURCE_TYPES.has(String(frontmatter.source_type)) ? frontmatter.source_type : "user_stated",
|
|
2217
|
+
source_hash: typeof frontmatter.source_hash === "string" ? frontmatter.source_hash : null,
|
|
2218
|
+
source_ref: typeof frontmatter.resource === "string" ? frontmatter.resource : null,
|
|
2219
|
+
created_at,
|
|
2220
|
+
updated_at,
|
|
2221
|
+
last_accessed_at: frontmatter.last_accessed_at != null ? parseFrontmatterTimestamp(frontmatter.last_accessed_at, now) : null,
|
|
2222
|
+
access_count: typeof frontmatter.access_count === "number" ? frontmatter.access_count : 0,
|
|
2223
|
+
deleted_at: frontmatter.deleted_at != null ? parseFrontmatterTimestamp(frontmatter.deleted_at, 0) : null,
|
|
2224
|
+
okf_type: frontmatter.type
|
|
2225
|
+
};
|
|
2226
|
+
}
|
|
2227
|
+
function frontmatterToTask(entityId, id, frontmatter, now) {
|
|
2228
|
+
const created_at = parseFrontmatterTimestamp(frontmatter.created_at, now);
|
|
2229
|
+
const updated_at = parseFrontmatterTimestamp(
|
|
2230
|
+
frontmatter.timestamp,
|
|
2231
|
+
parseFrontmatterTimestamp(frontmatter.updated_at, now)
|
|
2232
|
+
);
|
|
2233
|
+
return {
|
|
2234
|
+
id,
|
|
2235
|
+
entity_id: entityId,
|
|
2236
|
+
description: typeof frontmatter.title === "string" ? frontmatter.title : "",
|
|
2237
|
+
status: TASK_STATUSES.has(String(frontmatter.status)) ? frontmatter.status : "pending",
|
|
2238
|
+
priority: typeof frontmatter.priority === "number" ? frontmatter.priority : 0,
|
|
2239
|
+
created_at,
|
|
2240
|
+
updated_at,
|
|
2241
|
+
resolved_at: frontmatter.resolved_at != null ? parseFrontmatterTimestamp(frontmatter.resolved_at, now) : null,
|
|
2242
|
+
deleted_at: frontmatter.deleted_at != null ? parseFrontmatterTimestamp(frontmatter.deleted_at, 0) : null,
|
|
2243
|
+
okf_type: frontmatter.type
|
|
2244
|
+
};
|
|
2245
|
+
}
|
|
2246
|
+
function findLogMdPath(files) {
|
|
2247
|
+
return files.find((f) => f.path.endsWith("/log.md") || f.path === "log.md")?.path;
|
|
2248
|
+
}
|
|
2249
|
+
function parseOkfBundle(entityId, files, options) {
|
|
2250
|
+
const now = Date.now();
|
|
2251
|
+
const pathToResolvedId = /* @__PURE__ */ new Map();
|
|
2252
|
+
for (const file of files) {
|
|
2253
|
+
if (!isConceptFile(file.path)) continue;
|
|
2254
|
+
const { frontmatter } = parseConcept(file.content);
|
|
2255
|
+
const route = resolveRoute(file.path, frontmatter.type ?? "", options);
|
|
2256
|
+
if (route === "ignore") continue;
|
|
2257
|
+
const resolvedId = typeof frontmatter.id === "string" && frontmatter.id ? frontmatter.id : basenameMd(file.path);
|
|
2258
|
+
addPathAliases(pathToResolvedId, file.path, resolvedId);
|
|
2259
|
+
}
|
|
2260
|
+
const facts = [];
|
|
2261
|
+
const tasks = [];
|
|
2262
|
+
const edges = [];
|
|
2263
|
+
let logContent = null;
|
|
2264
|
+
const logMdPath = findLogMdPath(files);
|
|
2265
|
+
for (const file of files) {
|
|
2266
|
+
if (file.path.endsWith("/log.md") || file.path === "log.md") {
|
|
2267
|
+
logContent = file.content;
|
|
2268
|
+
continue;
|
|
2269
|
+
}
|
|
2270
|
+
if (!isConceptFile(file.path)) continue;
|
|
2271
|
+
const { frontmatter, body } = parseConcept(file.content);
|
|
2272
|
+
const route = resolveRoute(file.path, frontmatter.type ?? "", options);
|
|
2273
|
+
if (route === "ignore") continue;
|
|
2274
|
+
const resolvedId = typeof frontmatter.id === "string" && frontmatter.id ? frontmatter.id : basenameMd(file.path);
|
|
2275
|
+
if (route === "fact") {
|
|
2276
|
+
facts.push(frontmatterToFact(entityId, resolvedId, frontmatter, body, now));
|
|
2277
|
+
} else {
|
|
2278
|
+
tasks.push(frontmatterToTask(entityId, resolvedId, frontmatter, now));
|
|
2279
|
+
}
|
|
2280
|
+
const seenEdges = /* @__PURE__ */ new Set();
|
|
2281
|
+
for (const link of extractMarkdownLinks(body)) {
|
|
2282
|
+
const strippedPath = stripLinkSuffix(link.path);
|
|
2283
|
+
const directTargetId = lookupResolvedId(pathToResolvedId, strippedPath);
|
|
2284
|
+
const resolvedTargetPath = resolveRelativePath(file.path, strippedPath);
|
|
2285
|
+
if (isStructuralPath(strippedPath) || isStructuralPath(resolvedTargetPath)) continue;
|
|
2286
|
+
const targetId = directTargetId ?? lookupResolvedId(pathToResolvedId, resolvedTargetPath);
|
|
2287
|
+
if (!targetId) continue;
|
|
2288
|
+
const edgeKey = `${resolvedId}\0${targetId}\0${link.text}`;
|
|
2289
|
+
if (seenEdges.has(edgeKey)) continue;
|
|
2290
|
+
seenEdges.add(edgeKey);
|
|
2291
|
+
edges.push({
|
|
2292
|
+
id: generateId(),
|
|
2293
|
+
entity_id: entityId,
|
|
2294
|
+
source_id: resolvedId,
|
|
2295
|
+
target_id: targetId,
|
|
2296
|
+
edge_type: link.text,
|
|
2297
|
+
created_at: now
|
|
2298
|
+
});
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
const events = [];
|
|
2302
|
+
if (logContent != null) {
|
|
2303
|
+
const logPath = logMdPath ?? `entities/${entityId}/log.md`;
|
|
2304
|
+
for (const entry of parseLogMd(logContent)) {
|
|
2305
|
+
const parsed = parseLogEntryText(entry.text);
|
|
2306
|
+
if (!parsed) continue;
|
|
2307
|
+
let related_entry_id = null;
|
|
2308
|
+
if (parsed.linkPath) {
|
|
2309
|
+
const targetPath = resolveRelativePath(logPath, stripLinkSuffix(parsed.linkPath));
|
|
2310
|
+
if (!isStructuralPath(targetPath) && targetPath.includes("/facts/")) {
|
|
2311
|
+
related_entry_id = lookupResolvedId(pathToResolvedId, targetPath) ?? null;
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
const created_at = (/* @__PURE__ */ new Date(`${entry.date}T00:00:00.000Z`)).getTime();
|
|
2315
|
+
if (!Number.isFinite(created_at)) continue;
|
|
2316
|
+
events.push({
|
|
2317
|
+
id: generateId("evt_"),
|
|
2318
|
+
entity_id: entityId,
|
|
2319
|
+
event_type: parsed.event_type,
|
|
2320
|
+
summary: parsed.summary,
|
|
2321
|
+
related_entry_id,
|
|
2322
|
+
created_at
|
|
2323
|
+
});
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
return {
|
|
2327
|
+
generatedAt: now,
|
|
2328
|
+
entities: {
|
|
2329
|
+
[entityId]: { facts, tasks, events, edges }
|
|
2330
|
+
}
|
|
2331
|
+
};
|
|
2332
|
+
}
|
|
2010
2333
|
|
|
2011
2334
|
// src/librarianPrompt.ts
|
|
2012
2335
|
var DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT = `You are a careful memory synthesis assistant.
|
|
@@ -2052,6 +2375,6 @@ function createWiki(db, options) {
|
|
|
2052
2375
|
return new WikiMemory(db, options);
|
|
2053
2376
|
}
|
|
2054
2377
|
|
|
2055
|
-
export { DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT, WikiMemory, createWiki, formatContext, formatMemoryDump, formatOkfBundle, hydrateLibrarianPrompt, mapLibrarianOptionsToReadOptions, validateLibrarianPromptTemplate };
|
|
2378
|
+
export { DEFAULT_LIBRARIAN_SYNTHESIS_PROMPT, WikiMemory, createWiki, formatContext, formatMemoryDump, formatOkfBundle, hydrateLibrarianPrompt, mapLibrarianOptionsToReadOptions, parseOkfBundle, validateLibrarianPromptTemplate };
|
|
2056
2379
|
//# sourceMappingURL=index.mjs.map
|
|
2057
2380
|
//# sourceMappingURL=index.mjs.map
|