@plur-ai/core 0.3.1 → 0.4.1

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 CHANGED
@@ -1,4 +1,792 @@
1
- import "./chunk-2ZDO52B4.js";
1
+ import {
2
+ atomicWrite,
3
+ embeddingSearch,
4
+ engramSearchText,
5
+ ftsScore,
6
+ ftsTokenize,
7
+ getSyncStatus,
8
+ searchEngrams,
9
+ sync,
10
+ withLock
11
+ } from "./chunk-KMVQYBNP.js";
12
+ import {
13
+ __commonJS,
14
+ __require
15
+ } from "./chunk-2ZDO52B4.js";
16
+
17
+ // ../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/util.js
18
+ var require_util = __commonJS({
19
+ "../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/util.js"(exports) {
20
+ "use strict";
21
+ exports.getBooleanOption = (options, key) => {
22
+ let value = false;
23
+ if (key in options && typeof (value = options[key]) !== "boolean") {
24
+ throw new TypeError(`Expected the "${key}" option to be a boolean`);
25
+ }
26
+ return value;
27
+ };
28
+ exports.cppdb = /* @__PURE__ */ Symbol();
29
+ exports.inspect = /* @__PURE__ */ Symbol.for("nodejs.util.inspect.custom");
30
+ }
31
+ });
32
+
33
+ // ../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/sqlite-error.js
34
+ var require_sqlite_error = __commonJS({
35
+ "../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/sqlite-error.js"(exports, module) {
36
+ "use strict";
37
+ var descriptor = { value: "SqliteError", writable: true, enumerable: false, configurable: true };
38
+ function SqliteError(message, code) {
39
+ if (new.target !== SqliteError) {
40
+ return new SqliteError(message, code);
41
+ }
42
+ if (typeof code !== "string") {
43
+ throw new TypeError("Expected second argument to be a string");
44
+ }
45
+ Error.call(this, message);
46
+ descriptor.value = "" + message;
47
+ Object.defineProperty(this, "message", descriptor);
48
+ Error.captureStackTrace(this, SqliteError);
49
+ this.code = code;
50
+ }
51
+ Object.setPrototypeOf(SqliteError, Error);
52
+ Object.setPrototypeOf(SqliteError.prototype, Error.prototype);
53
+ Object.defineProperty(SqliteError.prototype, "name", descriptor);
54
+ module.exports = SqliteError;
55
+ }
56
+ });
57
+
58
+ // ../../node_modules/.pnpm/file-uri-to-path@1.0.0/node_modules/file-uri-to-path/index.js
59
+ var require_file_uri_to_path = __commonJS({
60
+ "../../node_modules/.pnpm/file-uri-to-path@1.0.0/node_modules/file-uri-to-path/index.js"(exports, module) {
61
+ "use strict";
62
+ var sep = __require("path").sep || "/";
63
+ module.exports = fileUriToPath;
64
+ function fileUriToPath(uri) {
65
+ if ("string" != typeof uri || uri.length <= 7 || "file://" != uri.substring(0, 7)) {
66
+ throw new TypeError("must pass in a file:// URI to convert to a file path");
67
+ }
68
+ var rest = decodeURI(uri.substring(7));
69
+ var firstSlash = rest.indexOf("/");
70
+ var host = rest.substring(0, firstSlash);
71
+ var path2 = rest.substring(firstSlash + 1);
72
+ if ("localhost" == host) host = "";
73
+ if (host) {
74
+ host = sep + sep + host;
75
+ }
76
+ path2 = path2.replace(/^(.+)\|/, "$1:");
77
+ if (sep == "\\") {
78
+ path2 = path2.replace(/\//g, "\\");
79
+ }
80
+ if (/^.+\:/.test(path2)) {
81
+ } else {
82
+ path2 = sep + path2;
83
+ }
84
+ return host + path2;
85
+ }
86
+ }
87
+ });
88
+
89
+ // ../../node_modules/.pnpm/bindings@1.5.0/node_modules/bindings/bindings.js
90
+ var require_bindings = __commonJS({
91
+ "../../node_modules/.pnpm/bindings@1.5.0/node_modules/bindings/bindings.js"(exports, module) {
92
+ "use strict";
93
+ var fs3 = __require("fs");
94
+ var path2 = __require("path");
95
+ var fileURLToPath = require_file_uri_to_path();
96
+ var join3 = path2.join;
97
+ var dirname = path2.dirname;
98
+ var exists = fs3.accessSync && function(path3) {
99
+ try {
100
+ fs3.accessSync(path3);
101
+ } catch (e) {
102
+ return false;
103
+ }
104
+ return true;
105
+ } || fs3.existsSync || path2.existsSync;
106
+ var defaults = {
107
+ arrow: process.env.NODE_BINDINGS_ARROW || " \u2192 ",
108
+ compiled: process.env.NODE_BINDINGS_COMPILED_DIR || "compiled",
109
+ platform: process.platform,
110
+ arch: process.arch,
111
+ nodePreGyp: "node-v" + process.versions.modules + "-" + process.platform + "-" + process.arch,
112
+ version: process.versions.node,
113
+ bindings: "bindings.node",
114
+ try: [
115
+ // node-gyp's linked version in the "build" dir
116
+ ["module_root", "build", "bindings"],
117
+ // node-waf and gyp_addon (a.k.a node-gyp)
118
+ ["module_root", "build", "Debug", "bindings"],
119
+ ["module_root", "build", "Release", "bindings"],
120
+ // Debug files, for development (legacy behavior, remove for node v0.9)
121
+ ["module_root", "out", "Debug", "bindings"],
122
+ ["module_root", "Debug", "bindings"],
123
+ // Release files, but manually compiled (legacy behavior, remove for node v0.9)
124
+ ["module_root", "out", "Release", "bindings"],
125
+ ["module_root", "Release", "bindings"],
126
+ // Legacy from node-waf, node <= 0.4.x
127
+ ["module_root", "build", "default", "bindings"],
128
+ // Production "Release" buildtype binary (meh...)
129
+ ["module_root", "compiled", "version", "platform", "arch", "bindings"],
130
+ // node-qbs builds
131
+ ["module_root", "addon-build", "release", "install-root", "bindings"],
132
+ ["module_root", "addon-build", "debug", "install-root", "bindings"],
133
+ ["module_root", "addon-build", "default", "install-root", "bindings"],
134
+ // node-pre-gyp path ./lib/binding/{node_abi}-{platform}-{arch}
135
+ ["module_root", "lib", "binding", "nodePreGyp", "bindings"]
136
+ ]
137
+ };
138
+ function bindings(opts) {
139
+ if (typeof opts == "string") {
140
+ opts = { bindings: opts };
141
+ } else if (!opts) {
142
+ opts = {};
143
+ }
144
+ Object.keys(defaults).map(function(i2) {
145
+ if (!(i2 in opts)) opts[i2] = defaults[i2];
146
+ });
147
+ if (!opts.module_root) {
148
+ opts.module_root = exports.getRoot(exports.getFileName());
149
+ }
150
+ if (path2.extname(opts.bindings) != ".node") {
151
+ opts.bindings += ".node";
152
+ }
153
+ var requireFunc = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
154
+ var tries = [], i = 0, l = opts.try.length, n, b, err;
155
+ for (; i < l; i++) {
156
+ n = join3.apply(
157
+ null,
158
+ opts.try[i].map(function(p) {
159
+ return opts[p] || p;
160
+ })
161
+ );
162
+ tries.push(n);
163
+ try {
164
+ b = opts.path ? requireFunc.resolve(n) : requireFunc(n);
165
+ if (!opts.path) {
166
+ b.path = n;
167
+ }
168
+ return b;
169
+ } catch (e) {
170
+ if (e.code !== "MODULE_NOT_FOUND" && e.code !== "QUALIFIED_PATH_RESOLUTION_FAILED" && !/not find/i.test(e.message)) {
171
+ throw e;
172
+ }
173
+ }
174
+ }
175
+ err = new Error(
176
+ "Could not locate the bindings file. Tried:\n" + tries.map(function(a) {
177
+ return opts.arrow + a;
178
+ }).join("\n")
179
+ );
180
+ err.tries = tries;
181
+ throw err;
182
+ }
183
+ module.exports = exports = bindings;
184
+ exports.getFileName = function getFileName(calling_file) {
185
+ var origPST = Error.prepareStackTrace, origSTL = Error.stackTraceLimit, dummy = {}, fileName;
186
+ Error.stackTraceLimit = 10;
187
+ Error.prepareStackTrace = function(e, st) {
188
+ for (var i = 0, l = st.length; i < l; i++) {
189
+ fileName = st[i].getFileName();
190
+ if (fileName !== __filename) {
191
+ if (calling_file) {
192
+ if (fileName !== calling_file) {
193
+ return;
194
+ }
195
+ } else {
196
+ return;
197
+ }
198
+ }
199
+ }
200
+ };
201
+ Error.captureStackTrace(dummy);
202
+ dummy.stack;
203
+ Error.prepareStackTrace = origPST;
204
+ Error.stackTraceLimit = origSTL;
205
+ var fileSchema = "file://";
206
+ if (fileName.indexOf(fileSchema) === 0) {
207
+ fileName = fileURLToPath(fileName);
208
+ }
209
+ return fileName;
210
+ };
211
+ exports.getRoot = function getRoot(file) {
212
+ var dir = dirname(file), prev;
213
+ while (true) {
214
+ if (dir === ".") {
215
+ dir = process.cwd();
216
+ }
217
+ if (exists(join3(dir, "package.json")) || exists(join3(dir, "node_modules"))) {
218
+ return dir;
219
+ }
220
+ if (prev === dir) {
221
+ throw new Error(
222
+ 'Could not find module root given file: "' + file + '". Do you have a `package.json` file? '
223
+ );
224
+ }
225
+ prev = dir;
226
+ dir = join3(dir, "..");
227
+ }
228
+ };
229
+ }
230
+ });
231
+
232
+ // ../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/wrappers.js
233
+ var require_wrappers = __commonJS({
234
+ "../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/wrappers.js"(exports) {
235
+ "use strict";
236
+ var { cppdb } = require_util();
237
+ exports.prepare = function prepare(sql) {
238
+ return this[cppdb].prepare(sql, this, false);
239
+ };
240
+ exports.exec = function exec(sql) {
241
+ this[cppdb].exec(sql);
242
+ return this;
243
+ };
244
+ exports.close = function close() {
245
+ this[cppdb].close();
246
+ return this;
247
+ };
248
+ exports.loadExtension = function loadExtension(...args) {
249
+ this[cppdb].loadExtension(...args);
250
+ return this;
251
+ };
252
+ exports.defaultSafeIntegers = function defaultSafeIntegers(...args) {
253
+ this[cppdb].defaultSafeIntegers(...args);
254
+ return this;
255
+ };
256
+ exports.unsafeMode = function unsafeMode(...args) {
257
+ this[cppdb].unsafeMode(...args);
258
+ return this;
259
+ };
260
+ exports.getters = {
261
+ name: {
262
+ get: function name() {
263
+ return this[cppdb].name;
264
+ },
265
+ enumerable: true
266
+ },
267
+ open: {
268
+ get: function open() {
269
+ return this[cppdb].open;
270
+ },
271
+ enumerable: true
272
+ },
273
+ inTransaction: {
274
+ get: function inTransaction() {
275
+ return this[cppdb].inTransaction;
276
+ },
277
+ enumerable: true
278
+ },
279
+ readonly: {
280
+ get: function readonly() {
281
+ return this[cppdb].readonly;
282
+ },
283
+ enumerable: true
284
+ },
285
+ memory: {
286
+ get: function memory() {
287
+ return this[cppdb].memory;
288
+ },
289
+ enumerable: true
290
+ }
291
+ };
292
+ }
293
+ });
294
+
295
+ // ../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/transaction.js
296
+ var require_transaction = __commonJS({
297
+ "../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/transaction.js"(exports, module) {
298
+ "use strict";
299
+ var { cppdb } = require_util();
300
+ var controllers = /* @__PURE__ */ new WeakMap();
301
+ module.exports = function transaction(fn) {
302
+ if (typeof fn !== "function") throw new TypeError("Expected first argument to be a function");
303
+ const db = this[cppdb];
304
+ const controller = getController(db, this);
305
+ const { apply } = Function.prototype;
306
+ const properties = {
307
+ default: { value: wrapTransaction(apply, fn, db, controller.default) },
308
+ deferred: { value: wrapTransaction(apply, fn, db, controller.deferred) },
309
+ immediate: { value: wrapTransaction(apply, fn, db, controller.immediate) },
310
+ exclusive: { value: wrapTransaction(apply, fn, db, controller.exclusive) },
311
+ database: { value: this, enumerable: true }
312
+ };
313
+ Object.defineProperties(properties.default.value, properties);
314
+ Object.defineProperties(properties.deferred.value, properties);
315
+ Object.defineProperties(properties.immediate.value, properties);
316
+ Object.defineProperties(properties.exclusive.value, properties);
317
+ return properties.default.value;
318
+ };
319
+ var getController = (db, self) => {
320
+ let controller = controllers.get(db);
321
+ if (!controller) {
322
+ const shared = {
323
+ commit: db.prepare("COMMIT", self, false),
324
+ rollback: db.prepare("ROLLBACK", self, false),
325
+ savepoint: db.prepare("SAVEPOINT ` _bs3. `", self, false),
326
+ release: db.prepare("RELEASE ` _bs3. `", self, false),
327
+ rollbackTo: db.prepare("ROLLBACK TO ` _bs3. `", self, false)
328
+ };
329
+ controllers.set(db, controller = {
330
+ default: Object.assign({ begin: db.prepare("BEGIN", self, false) }, shared),
331
+ deferred: Object.assign({ begin: db.prepare("BEGIN DEFERRED", self, false) }, shared),
332
+ immediate: Object.assign({ begin: db.prepare("BEGIN IMMEDIATE", self, false) }, shared),
333
+ exclusive: Object.assign({ begin: db.prepare("BEGIN EXCLUSIVE", self, false) }, shared)
334
+ });
335
+ }
336
+ return controller;
337
+ };
338
+ var wrapTransaction = (apply, fn, db, { begin, commit, rollback, savepoint, release, rollbackTo }) => function sqliteTransaction() {
339
+ let before, after, undo;
340
+ if (db.inTransaction) {
341
+ before = savepoint;
342
+ after = release;
343
+ undo = rollbackTo;
344
+ } else {
345
+ before = begin;
346
+ after = commit;
347
+ undo = rollback;
348
+ }
349
+ before.run();
350
+ try {
351
+ const result = apply.call(fn, this, arguments);
352
+ if (result && typeof result.then === "function") {
353
+ throw new TypeError("Transaction function cannot return a promise");
354
+ }
355
+ after.run();
356
+ return result;
357
+ } catch (ex) {
358
+ if (db.inTransaction) {
359
+ undo.run();
360
+ if (undo !== rollback) after.run();
361
+ }
362
+ throw ex;
363
+ }
364
+ };
365
+ }
366
+ });
367
+
368
+ // ../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/pragma.js
369
+ var require_pragma = __commonJS({
370
+ "../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/pragma.js"(exports, module) {
371
+ "use strict";
372
+ var { getBooleanOption, cppdb } = require_util();
373
+ module.exports = function pragma(source, options) {
374
+ if (options == null) options = {};
375
+ if (typeof source !== "string") throw new TypeError("Expected first argument to be a string");
376
+ if (typeof options !== "object") throw new TypeError("Expected second argument to be an options object");
377
+ const simple = getBooleanOption(options, "simple");
378
+ const stmt = this[cppdb].prepare(`PRAGMA ${source}`, this, true);
379
+ return simple ? stmt.pluck().get() : stmt.all();
380
+ };
381
+ }
382
+ });
383
+
384
+ // ../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/backup.js
385
+ var require_backup = __commonJS({
386
+ "../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/backup.js"(exports, module) {
387
+ "use strict";
388
+ var fs3 = __require("fs");
389
+ var path2 = __require("path");
390
+ var { promisify } = __require("util");
391
+ var { cppdb } = require_util();
392
+ var fsAccess = promisify(fs3.access);
393
+ module.exports = async function backup(filename, options) {
394
+ if (options == null) options = {};
395
+ if (typeof filename !== "string") throw new TypeError("Expected first argument to be a string");
396
+ if (typeof options !== "object") throw new TypeError("Expected second argument to be an options object");
397
+ filename = filename.trim();
398
+ const attachedName = "attached" in options ? options.attached : "main";
399
+ const handler = "progress" in options ? options.progress : null;
400
+ if (!filename) throw new TypeError("Backup filename cannot be an empty string");
401
+ if (filename === ":memory:") throw new TypeError('Invalid backup filename ":memory:"');
402
+ if (typeof attachedName !== "string") throw new TypeError('Expected the "attached" option to be a string');
403
+ if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string');
404
+ if (handler != null && typeof handler !== "function") throw new TypeError('Expected the "progress" option to be a function');
405
+ await fsAccess(path2.dirname(filename)).catch(() => {
406
+ throw new TypeError("Cannot save backup because the directory does not exist");
407
+ });
408
+ const isNewFile = await fsAccess(filename).then(() => false, () => true);
409
+ return runBackup(this[cppdb].backup(this, attachedName, filename, isNewFile), handler || null);
410
+ };
411
+ var runBackup = (backup, handler) => {
412
+ let rate = 0;
413
+ let useDefault = true;
414
+ return new Promise((resolve, reject) => {
415
+ setImmediate(function step() {
416
+ try {
417
+ const progress = backup.transfer(rate);
418
+ if (!progress.remainingPages) {
419
+ backup.close();
420
+ resolve(progress);
421
+ return;
422
+ }
423
+ if (useDefault) {
424
+ useDefault = false;
425
+ rate = 100;
426
+ }
427
+ if (handler) {
428
+ const ret = handler(progress);
429
+ if (ret !== void 0) {
430
+ if (typeof ret === "number" && ret === ret) rate = Math.max(0, Math.min(2147483647, Math.round(ret)));
431
+ else throw new TypeError("Expected progress callback to return a number or undefined");
432
+ }
433
+ }
434
+ setImmediate(step);
435
+ } catch (err) {
436
+ backup.close();
437
+ reject(err);
438
+ }
439
+ });
440
+ });
441
+ };
442
+ }
443
+ });
444
+
445
+ // ../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/serialize.js
446
+ var require_serialize = __commonJS({
447
+ "../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/serialize.js"(exports, module) {
448
+ "use strict";
449
+ var { cppdb } = require_util();
450
+ module.exports = function serialize(options) {
451
+ if (options == null) options = {};
452
+ if (typeof options !== "object") throw new TypeError("Expected first argument to be an options object");
453
+ const attachedName = "attached" in options ? options.attached : "main";
454
+ if (typeof attachedName !== "string") throw new TypeError('Expected the "attached" option to be a string');
455
+ if (!attachedName) throw new TypeError('The "attached" option cannot be an empty string');
456
+ return this[cppdb].serialize(attachedName);
457
+ };
458
+ }
459
+ });
460
+
461
+ // ../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/function.js
462
+ var require_function = __commonJS({
463
+ "../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/function.js"(exports, module) {
464
+ "use strict";
465
+ var { getBooleanOption, cppdb } = require_util();
466
+ module.exports = function defineFunction(name, options, fn) {
467
+ if (options == null) options = {};
468
+ if (typeof options === "function") {
469
+ fn = options;
470
+ options = {};
471
+ }
472
+ if (typeof name !== "string") throw new TypeError("Expected first argument to be a string");
473
+ if (typeof fn !== "function") throw new TypeError("Expected last argument to be a function");
474
+ if (typeof options !== "object") throw new TypeError("Expected second argument to be an options object");
475
+ if (!name) throw new TypeError("User-defined function name cannot be an empty string");
476
+ const safeIntegers = "safeIntegers" in options ? +getBooleanOption(options, "safeIntegers") : 2;
477
+ const deterministic = getBooleanOption(options, "deterministic");
478
+ const directOnly = getBooleanOption(options, "directOnly");
479
+ const varargs = getBooleanOption(options, "varargs");
480
+ let argCount = -1;
481
+ if (!varargs) {
482
+ argCount = fn.length;
483
+ if (!Number.isInteger(argCount) || argCount < 0) throw new TypeError("Expected function.length to be a positive integer");
484
+ if (argCount > 100) throw new RangeError("User-defined functions cannot have more than 100 arguments");
485
+ }
486
+ this[cppdb].function(fn, name, argCount, safeIntegers, deterministic, directOnly);
487
+ return this;
488
+ };
489
+ }
490
+ });
491
+
492
+ // ../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/aggregate.js
493
+ var require_aggregate = __commonJS({
494
+ "../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/aggregate.js"(exports, module) {
495
+ "use strict";
496
+ var { getBooleanOption, cppdb } = require_util();
497
+ module.exports = function defineAggregate(name, options) {
498
+ if (typeof name !== "string") throw new TypeError("Expected first argument to be a string");
499
+ if (typeof options !== "object" || options === null) throw new TypeError("Expected second argument to be an options object");
500
+ if (!name) throw new TypeError("User-defined function name cannot be an empty string");
501
+ const start = "start" in options ? options.start : null;
502
+ const step = getFunctionOption(options, "step", true);
503
+ const inverse = getFunctionOption(options, "inverse", false);
504
+ const result = getFunctionOption(options, "result", false);
505
+ const safeIntegers = "safeIntegers" in options ? +getBooleanOption(options, "safeIntegers") : 2;
506
+ const deterministic = getBooleanOption(options, "deterministic");
507
+ const directOnly = getBooleanOption(options, "directOnly");
508
+ const varargs = getBooleanOption(options, "varargs");
509
+ let argCount = -1;
510
+ if (!varargs) {
511
+ argCount = Math.max(getLength(step), inverse ? getLength(inverse) : 0);
512
+ if (argCount > 0) argCount -= 1;
513
+ if (argCount > 100) throw new RangeError("User-defined functions cannot have more than 100 arguments");
514
+ }
515
+ this[cppdb].aggregate(start, step, inverse, result, name, argCount, safeIntegers, deterministic, directOnly);
516
+ return this;
517
+ };
518
+ var getFunctionOption = (options, key, required) => {
519
+ const value = key in options ? options[key] : null;
520
+ if (typeof value === "function") return value;
521
+ if (value != null) throw new TypeError(`Expected the "${key}" option to be a function`);
522
+ if (required) throw new TypeError(`Missing required option "${key}"`);
523
+ return null;
524
+ };
525
+ var getLength = ({ length }) => {
526
+ if (Number.isInteger(length) && length >= 0) return length;
527
+ throw new TypeError("Expected function.length to be a positive integer");
528
+ };
529
+ }
530
+ });
531
+
532
+ // ../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/table.js
533
+ var require_table = __commonJS({
534
+ "../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/table.js"(exports, module) {
535
+ "use strict";
536
+ var { cppdb } = require_util();
537
+ module.exports = function defineTable(name, factory) {
538
+ if (typeof name !== "string") throw new TypeError("Expected first argument to be a string");
539
+ if (!name) throw new TypeError("Virtual table module name cannot be an empty string");
540
+ let eponymous = false;
541
+ if (typeof factory === "object" && factory !== null) {
542
+ eponymous = true;
543
+ factory = defer(parseTableDefinition(factory, "used", name));
544
+ } else {
545
+ if (typeof factory !== "function") throw new TypeError("Expected second argument to be a function or a table definition object");
546
+ factory = wrapFactory(factory);
547
+ }
548
+ this[cppdb].table(factory, name, eponymous);
549
+ return this;
550
+ };
551
+ function wrapFactory(factory) {
552
+ return function virtualTableFactory(moduleName, databaseName, tableName, ...args) {
553
+ const thisObject = {
554
+ module: moduleName,
555
+ database: databaseName,
556
+ table: tableName
557
+ };
558
+ const def = apply.call(factory, thisObject, args);
559
+ if (typeof def !== "object" || def === null) {
560
+ throw new TypeError(`Virtual table module "${moduleName}" did not return a table definition object`);
561
+ }
562
+ return parseTableDefinition(def, "returned", moduleName);
563
+ };
564
+ }
565
+ function parseTableDefinition(def, verb, moduleName) {
566
+ if (!hasOwnProperty.call(def, "rows")) {
567
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition without a "rows" property`);
568
+ }
569
+ if (!hasOwnProperty.call(def, "columns")) {
570
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition without a "columns" property`);
571
+ }
572
+ const rows = def.rows;
573
+ if (typeof rows !== "function" || Object.getPrototypeOf(rows) !== GeneratorFunctionPrototype) {
574
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "rows" property (should be a generator function)`);
575
+ }
576
+ let columns = def.columns;
577
+ if (!Array.isArray(columns) || !(columns = [...columns]).every((x) => typeof x === "string")) {
578
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "columns" property (should be an array of strings)`);
579
+ }
580
+ if (columns.length !== new Set(columns).size) {
581
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with duplicate column names`);
582
+ }
583
+ if (!columns.length) {
584
+ throw new RangeError(`Virtual table module "${moduleName}" ${verb} a table definition with zero columns`);
585
+ }
586
+ let parameters;
587
+ if (hasOwnProperty.call(def, "parameters")) {
588
+ parameters = def.parameters;
589
+ if (!Array.isArray(parameters) || !(parameters = [...parameters]).every((x) => typeof x === "string")) {
590
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "parameters" property (should be an array of strings)`);
591
+ }
592
+ } else {
593
+ parameters = inferParameters(rows);
594
+ }
595
+ if (parameters.length !== new Set(parameters).size) {
596
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with duplicate parameter names`);
597
+ }
598
+ if (parameters.length > 32) {
599
+ throw new RangeError(`Virtual table module "${moduleName}" ${verb} a table definition with more than the maximum number of 32 parameters`);
600
+ }
601
+ for (const parameter of parameters) {
602
+ if (columns.includes(parameter)) {
603
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with column "${parameter}" which was ambiguously defined as both a column and parameter`);
604
+ }
605
+ }
606
+ let safeIntegers = 2;
607
+ if (hasOwnProperty.call(def, "safeIntegers")) {
608
+ const bool = def.safeIntegers;
609
+ if (typeof bool !== "boolean") {
610
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "safeIntegers" property (should be a boolean)`);
611
+ }
612
+ safeIntegers = +bool;
613
+ }
614
+ let directOnly = false;
615
+ if (hasOwnProperty.call(def, "directOnly")) {
616
+ directOnly = def.directOnly;
617
+ if (typeof directOnly !== "boolean") {
618
+ throw new TypeError(`Virtual table module "${moduleName}" ${verb} a table definition with an invalid "directOnly" property (should be a boolean)`);
619
+ }
620
+ }
621
+ const columnDefinitions = [
622
+ ...parameters.map(identifier).map((str) => `${str} HIDDEN`),
623
+ ...columns.map(identifier)
624
+ ];
625
+ return [
626
+ `CREATE TABLE x(${columnDefinitions.join(", ")});`,
627
+ wrapGenerator(rows, new Map(columns.map((x, i) => [x, parameters.length + i])), moduleName),
628
+ parameters,
629
+ safeIntegers,
630
+ directOnly
631
+ ];
632
+ }
633
+ function wrapGenerator(generator, columnMap, moduleName) {
634
+ return function* virtualTable(...args) {
635
+ const output = args.map((x) => Buffer.isBuffer(x) ? Buffer.from(x) : x);
636
+ for (let i = 0; i < columnMap.size; ++i) {
637
+ output.push(null);
638
+ }
639
+ for (const row of generator(...args)) {
640
+ if (Array.isArray(row)) {
641
+ extractRowArray(row, output, columnMap.size, moduleName);
642
+ yield output;
643
+ } else if (typeof row === "object" && row !== null) {
644
+ extractRowObject(row, output, columnMap, moduleName);
645
+ yield output;
646
+ } else {
647
+ throw new TypeError(`Virtual table module "${moduleName}" yielded something that isn't a valid row object`);
648
+ }
649
+ }
650
+ };
651
+ }
652
+ function extractRowArray(row, output, columnCount, moduleName) {
653
+ if (row.length !== columnCount) {
654
+ throw new TypeError(`Virtual table module "${moduleName}" yielded a row with an incorrect number of columns`);
655
+ }
656
+ const offset = output.length - columnCount;
657
+ for (let i = 0; i < columnCount; ++i) {
658
+ output[i + offset] = row[i];
659
+ }
660
+ }
661
+ function extractRowObject(row, output, columnMap, moduleName) {
662
+ let count = 0;
663
+ for (const key of Object.keys(row)) {
664
+ const index = columnMap.get(key);
665
+ if (index === void 0) {
666
+ throw new TypeError(`Virtual table module "${moduleName}" yielded a row with an undeclared column "${key}"`);
667
+ }
668
+ output[index] = row[key];
669
+ count += 1;
670
+ }
671
+ if (count !== columnMap.size) {
672
+ throw new TypeError(`Virtual table module "${moduleName}" yielded a row with missing columns`);
673
+ }
674
+ }
675
+ function inferParameters({ length }) {
676
+ if (!Number.isInteger(length) || length < 0) {
677
+ throw new TypeError("Expected function.length to be a positive integer");
678
+ }
679
+ const params = [];
680
+ for (let i = 0; i < length; ++i) {
681
+ params.push(`$${i + 1}`);
682
+ }
683
+ return params;
684
+ }
685
+ var { hasOwnProperty } = Object.prototype;
686
+ var { apply } = Function.prototype;
687
+ var GeneratorFunctionPrototype = Object.getPrototypeOf(function* () {
688
+ });
689
+ var identifier = (str) => `"${str.replace(/"/g, '""')}"`;
690
+ var defer = (x) => () => x;
691
+ }
692
+ });
693
+
694
+ // ../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/inspect.js
695
+ var require_inspect = __commonJS({
696
+ "../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/methods/inspect.js"(exports, module) {
697
+ "use strict";
698
+ var DatabaseInspection = function Database2() {
699
+ };
700
+ module.exports = function inspect(depth, opts) {
701
+ return Object.assign(new DatabaseInspection(), this);
702
+ };
703
+ }
704
+ });
705
+
706
+ // ../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/database.js
707
+ var require_database = __commonJS({
708
+ "../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/database.js"(exports, module) {
709
+ "use strict";
710
+ var fs3 = __require("fs");
711
+ var path2 = __require("path");
712
+ var util = require_util();
713
+ var SqliteError = require_sqlite_error();
714
+ var DEFAULT_ADDON;
715
+ function Database2(filenameGiven, options) {
716
+ if (new.target == null) {
717
+ return new Database2(filenameGiven, options);
718
+ }
719
+ let buffer;
720
+ if (Buffer.isBuffer(filenameGiven)) {
721
+ buffer = filenameGiven;
722
+ filenameGiven = ":memory:";
723
+ }
724
+ if (filenameGiven == null) filenameGiven = "";
725
+ if (options == null) options = {};
726
+ if (typeof filenameGiven !== "string") throw new TypeError("Expected first argument to be a string");
727
+ if (typeof options !== "object") throw new TypeError("Expected second argument to be an options object");
728
+ if ("readOnly" in options) throw new TypeError('Misspelled option "readOnly" should be "readonly"');
729
+ if ("memory" in options) throw new TypeError('Option "memory" was removed in v7.0.0 (use ":memory:" filename instead)');
730
+ const filename = filenameGiven.trim();
731
+ const anonymous = filename === "" || filename === ":memory:";
732
+ const readonly = util.getBooleanOption(options, "readonly");
733
+ const fileMustExist = util.getBooleanOption(options, "fileMustExist");
734
+ const timeout = "timeout" in options ? options.timeout : 5e3;
735
+ const verbose = "verbose" in options ? options.verbose : null;
736
+ const nativeBinding = "nativeBinding" in options ? options.nativeBinding : null;
737
+ if (readonly && anonymous && !buffer) throw new TypeError("In-memory/temporary databases cannot be readonly");
738
+ if (!Number.isInteger(timeout) || timeout < 0) throw new TypeError('Expected the "timeout" option to be a positive integer');
739
+ if (timeout > 2147483647) throw new RangeError('Option "timeout" cannot be greater than 2147483647');
740
+ if (verbose != null && typeof verbose !== "function") throw new TypeError('Expected the "verbose" option to be a function');
741
+ if (nativeBinding != null && typeof nativeBinding !== "string" && typeof nativeBinding !== "object") throw new TypeError('Expected the "nativeBinding" option to be a string or addon object');
742
+ let addon;
743
+ if (nativeBinding == null) {
744
+ addon = DEFAULT_ADDON || (DEFAULT_ADDON = require_bindings()("better_sqlite3.node"));
745
+ } else if (typeof nativeBinding === "string") {
746
+ const requireFunc = typeof __non_webpack_require__ === "function" ? __non_webpack_require__ : __require;
747
+ addon = requireFunc(path2.resolve(nativeBinding).replace(/(\.node)?$/, ".node"));
748
+ } else {
749
+ addon = nativeBinding;
750
+ }
751
+ if (!addon.isInitialized) {
752
+ addon.setErrorConstructor(SqliteError);
753
+ addon.isInitialized = true;
754
+ }
755
+ if (!anonymous && !fs3.existsSync(path2.dirname(filename))) {
756
+ throw new TypeError("Cannot open database because the directory does not exist");
757
+ }
758
+ Object.defineProperties(this, {
759
+ [util.cppdb]: { value: new addon.Database(filename, filenameGiven, anonymous, readonly, fileMustExist, timeout, verbose || null, buffer || null) },
760
+ ...wrappers.getters
761
+ });
762
+ }
763
+ var wrappers = require_wrappers();
764
+ Database2.prototype.prepare = wrappers.prepare;
765
+ Database2.prototype.transaction = require_transaction();
766
+ Database2.prototype.pragma = require_pragma();
767
+ Database2.prototype.backup = require_backup();
768
+ Database2.prototype.serialize = require_serialize();
769
+ Database2.prototype.function = require_function();
770
+ Database2.prototype.aggregate = require_aggregate();
771
+ Database2.prototype.table = require_table();
772
+ Database2.prototype.loadExtension = wrappers.loadExtension;
773
+ Database2.prototype.exec = wrappers.exec;
774
+ Database2.prototype.close = wrappers.close;
775
+ Database2.prototype.defaultSafeIntegers = wrappers.defaultSafeIntegers;
776
+ Database2.prototype.unsafeMode = wrappers.unsafeMode;
777
+ Database2.prototype[util.inspect] = require_inspect();
778
+ module.exports = Database2;
779
+ }
780
+ });
781
+
782
+ // ../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/index.js
783
+ var require_lib = __commonJS({
784
+ "../../node_modules/.pnpm/better-sqlite3@11.10.0/node_modules/better-sqlite3/lib/index.js"(exports, module) {
785
+ "use strict";
786
+ module.exports = require_database();
787
+ module.exports.SqliteError = require_sqlite_error();
788
+ }
789
+ });
2
790
 
3
791
  // src/storage.ts
4
792
  import { existsSync, mkdirSync } from "fs";
@@ -16,97 +804,70 @@ function detectPlurStorage(explicitPath) {
16
804
  candidates: join(root, "candidates.yaml"),
17
805
  packs: packsDir,
18
806
  exchange: join(root, "exchange"),
19
- config: join(root, "config.yaml")
807
+ config: join(root, "config.yaml"),
808
+ db: join(root, "engrams.db")
20
809
  };
21
810
  }
22
811
 
23
- // src/config.ts
24
- import { existsSync as existsSync2, readFileSync } from "fs";
25
- import yaml from "js-yaml";
26
-
27
- // src/schemas/config.ts
28
- import { z } from "zod";
29
- var PlurConfigSchema = z.object({
30
- auto_learn: z.boolean().default(true),
31
- auto_capture: z.boolean().default(true),
32
- injection_budget: z.number().default(2e3),
33
- decay_enabled: z.boolean().default(true),
34
- decay_threshold: z.number().default(0.15),
35
- packs: z.array(z.string()).default([]),
36
- injection: z.object({
37
- spread_cap: z.number().default(3),
38
- spread_budget: z.number().default(480),
39
- co_access: z.boolean().default(true)
40
- }).default({})
41
- }).partial();
42
-
43
- // src/config.ts
44
- function loadConfig(configPath) {
45
- if (!existsSync2(configPath)) return PlurConfigSchema.parse({});
46
- try {
47
- const raw = yaml.load(readFileSync(configPath, "utf8"));
48
- return PlurConfigSchema.parse(raw ?? {});
49
- } catch {
50
- return PlurConfigSchema.parse({});
51
- }
52
- }
812
+ // src/storage-indexed.ts
813
+ import { existsSync as existsSync3 } from "fs";
53
814
 
54
815
  // src/engrams.ts
55
816
  import * as fs from "fs";
56
- import * as yaml2 from "js-yaml";
817
+ import * as yaml from "js-yaml";
57
818
 
58
819
  // src/schemas/engram.ts
59
- import { z as z2 } from "zod";
60
- var ActivationSchema = z2.object({
61
- retrieval_strength: z2.number().min(0).max(1),
62
- storage_strength: z2.number().min(0).max(1),
63
- frequency: z2.number().int().min(0),
64
- last_accessed: z2.string()
820
+ import { z } from "zod";
821
+ var ActivationSchema = z.object({
822
+ retrieval_strength: z.number().min(0).max(1),
823
+ storage_strength: z.number().min(0).max(1),
824
+ frequency: z.number().int().min(0),
825
+ last_accessed: z.string()
65
826
  });
66
- var KnowledgeTypeSchema = z2.object({
67
- memory_class: z2.enum(["semantic", "episodic", "procedural", "metacognitive"]),
68
- cognitive_level: z2.enum(["remember", "understand", "apply", "analyze", "evaluate", "create"])
827
+ var KnowledgeTypeSchema = z.object({
828
+ memory_class: z.enum(["semantic", "episodic", "procedural", "metacognitive"]),
829
+ cognitive_level: z.enum(["remember", "understand", "apply", "analyze", "evaluate", "create"])
69
830
  });
70
- var KnowledgeAnchorSchema = z2.object({
71
- path: z2.string(),
72
- relevance: z2.enum(["primary", "supporting", "example"]).default("supporting"),
73
- snippet: z2.string().max(200).optional(),
74
- snippet_extracted_at: z2.string().optional()
831
+ var KnowledgeAnchorSchema = z.object({
832
+ path: z.string(),
833
+ relevance: z.enum(["primary", "supporting", "example"]).default("supporting"),
834
+ snippet: z.string().max(200).optional(),
835
+ snippet_extracted_at: z.string().optional()
75
836
  });
76
- var AssociationSchema = z2.object({
77
- target_type: z2.enum(["engram", "document"]),
78
- target: z2.string(),
79
- strength: z2.number().min(0).max(0.95),
80
- type: z2.enum(["semantic", "temporal", "causal", "co_accessed"]),
81
- updated_at: z2.string().optional()
837
+ var AssociationSchema = z.object({
838
+ target_type: z.enum(["engram", "document"]),
839
+ target: z.string(),
840
+ strength: z.number().min(0).max(0.95),
841
+ type: z.enum(["semantic", "temporal", "causal", "co_accessed"]),
842
+ updated_at: z.string().optional()
82
843
  });
83
- var DualCodingSchema = z2.object({
84
- example: z2.string().optional(),
85
- analogy: z2.string().optional()
844
+ var DualCodingSchema = z.object({
845
+ example: z.string().optional(),
846
+ analogy: z.string().optional()
86
847
  }).refine(
87
848
  (d) => d.example || d.analogy,
88
849
  "At least one of example or analogy must be provided"
89
850
  );
90
- var RelationsSchema = z2.object({
91
- broader: z2.array(z2.string()).default([]),
92
- narrower: z2.array(z2.string()).default([]),
93
- related: z2.array(z2.string()).default([]),
94
- conflicts: z2.array(z2.string()).default([])
851
+ var RelationsSchema = z.object({
852
+ broader: z.array(z.string()).default([]),
853
+ narrower: z.array(z.string()).default([]),
854
+ related: z.array(z.string()).default([]),
855
+ conflicts: z.array(z.string()).default([])
95
856
  });
96
- var ProvenanceSchema = z2.object({
97
- origin: z2.string(),
98
- chain: z2.array(z2.string()).default([]),
99
- signature: z2.string().nullable().default(null),
100
- license: z2.string().default("cc-by-sa-4.0")
857
+ var ProvenanceSchema = z.object({
858
+ origin: z.string(),
859
+ chain: z.array(z.string()).default([]),
860
+ signature: z.string().nullable().default(null),
861
+ license: z.string().default("cc-by-sa-4.0")
101
862
  });
102
- var FeedbackSignalsSchema = z2.object({
103
- positive: z2.number().int().default(0),
104
- negative: z2.number().int().default(0),
105
- neutral: z2.number().int().default(0)
863
+ var FeedbackSignalsSchema = z.object({
864
+ positive: z.number().int().default(0),
865
+ negative: z.number().int().default(0),
866
+ neutral: z.number().int().default(0)
106
867
  });
107
- var EntityRefSchema = z2.object({
108
- name: z2.string(),
109
- type: z2.enum([
868
+ var EntityRefSchema = z.object({
869
+ name: z.string(),
870
+ type: z.enum([
110
871
  "person",
111
872
  "organization",
112
873
  "technology",
@@ -118,56 +879,56 @@ var EntityRefSchema = z2.object({
118
879
  "standard",
119
880
  "other"
120
881
  ]),
121
- uri: z2.string().url().optional()
882
+ uri: z.string().url().optional()
122
883
  });
123
- var TemporalSchema = z2.object({
124
- learned_at: z2.string(),
125
- valid_from: z2.string().optional(),
126
- valid_until: z2.string().optional(),
127
- ingested_at: z2.string().optional()
884
+ var TemporalSchema = z.object({
885
+ learned_at: z.string(),
886
+ valid_from: z.string().optional(),
887
+ valid_until: z.string().optional(),
888
+ ingested_at: z.string().optional()
128
889
  });
129
- var UsageStatsSchema = z2.object({
130
- injections: z2.number().int().default(0),
131
- hits: z2.number().int().default(0),
132
- misses: z2.number().int().default(0),
133
- last_hit_at: z2.string().optional()
890
+ var UsageStatsSchema = z.object({
891
+ injections: z.number().int().default(0),
892
+ hits: z.number().int().default(0),
893
+ misses: z.number().int().default(0),
894
+ last_hit_at: z.string().optional()
134
895
  });
135
- var EpisodicFieldsSchema = z2.object({
136
- emotional_weight: z2.number().int().min(1).max(10).default(5),
137
- confidence: z2.number().int().min(1).max(10).default(5),
138
- trigger_context: z2.string().optional(),
139
- journal_ref: z2.string().optional()
896
+ var EpisodicFieldsSchema = z.object({
897
+ emotional_weight: z.number().int().min(1).max(10).default(5),
898
+ confidence: z.number().int().min(1).max(10).default(5),
899
+ trigger_context: z.string().optional(),
900
+ journal_ref: z.string().optional()
140
901
  });
141
- var ExchangeMetadataSchema = z2.object({
142
- fitness_score: z2.number().min(0).max(1).optional(),
143
- environmental_diversity: z2.number().int().default(0),
144
- adoption_count: z2.number().int().default(0),
145
- contradiction_rate: z2.number().min(0).max(1).default(0)
902
+ var ExchangeMetadataSchema = z.object({
903
+ fitness_score: z.number().min(0).max(1).optional(),
904
+ environmental_diversity: z.number().int().default(0),
905
+ adoption_count: z.number().int().default(0),
906
+ contradiction_rate: z.number().min(0).max(1).default(0)
146
907
  });
147
- var EngramSchema = z2.object({
908
+ var EngramSchema = z.object({
148
909
  // Identity
149
- id: z2.string().regex(/^(ENG|ABS)-[A-Za-z0-9-]+$/),
150
- version: z2.number().int().min(1).default(2),
151
- status: z2.enum(["active", "dormant", "retired", "candidate"]),
152
- consolidated: z2.boolean().default(false),
153
- type: z2.enum(["behavioral", "terminological", "procedural", "architectural"]),
154
- scope: z2.string(),
155
- visibility: z2.enum(["private", "public", "template"]).default("private"),
910
+ id: z.string().regex(/^(ENG|ABS|META)-[A-Za-z0-9-]+$/),
911
+ version: z.number().int().min(1).default(2),
912
+ status: z.enum(["active", "dormant", "retired", "candidate"]),
913
+ consolidated: z.boolean().default(false),
914
+ type: z.enum(["behavioral", "terminological", "procedural", "architectural"]),
915
+ scope: z.string(),
916
+ visibility: z.enum(["private", "public", "template"]).default("private"),
156
917
  // Content
157
- statement: z2.string().min(1),
158
- rationale: z2.string().optional(),
159
- contraindications: z2.array(z2.string()).optional(),
918
+ statement: z.string().min(1),
919
+ rationale: z.string().optional(),
920
+ contraindications: z.array(z.string()).optional(),
160
921
  // Lineage
161
- source: z2.string().optional(),
162
- source_patterns: z2.array(z2.string()).optional(),
163
- derivation_count: z2.number().int().min(0).default(1),
164
- pack: z2.string().nullable().default(null),
165
- abstract: z2.string().nullable().default(null),
166
- derived_from: z2.string().nullable().default(null),
922
+ source: z.string().optional(),
923
+ source_patterns: z.array(z.string()).optional(),
924
+ derivation_count: z.number().int().min(0).default(1),
925
+ pack: z.string().nullable().default(null),
926
+ abstract: z.string().nullable().default(null),
927
+ derived_from: z.string().nullable().default(null),
167
928
  // Classification
168
929
  knowledge_type: KnowledgeTypeSchema.optional(),
169
- domain: z2.string().optional(),
170
- tags: z2.array(z2.string()).default([]),
930
+ domain: z.string().optional(),
931
+ tags: z.array(z.string()).default([]),
171
932
  // Activation (ACT-R model)
172
933
  activation: ActivationSchema.default({
173
934
  retrieval_strength: 0.7,
@@ -177,8 +938,8 @@ var EngramSchema = z2.object({
177
938
  }),
178
939
  // Relations & grounding
179
940
  relations: RelationsSchema.optional(),
180
- associations: z2.array(AssociationSchema).default([]),
181
- knowledge_anchors: z2.array(KnowledgeAnchorSchema).default([]),
941
+ associations: z.array(AssociationSchema).default([]),
942
+ knowledge_anchors: z.array(KnowledgeAnchorSchema).default([]),
182
943
  dual_coding: DualCodingSchema.optional(),
183
944
  // Provenance
184
945
  provenance: ProvenanceSchema.optional(),
@@ -186,7 +947,7 @@ var EngramSchema = z2.object({
186
947
  feedback_signals: FeedbackSignalsSchema.default({ positive: 0, negative: 0, neutral: 0 }),
187
948
  // === NEW OPTIONAL FIELDS (v2.1) ===
188
949
  /** Typed entity references extracted from statement. Enables graph queries. */
189
- entities: z2.array(EntityRefSchema).optional(),
950
+ entities: z.array(EntityRefSchema).optional(),
190
951
  /** Temporal validity window. When is this knowledge true? */
191
952
  temporal: TemporalSchema.optional(),
192
953
  /** Automatic usage tracking. Injections, hits, misses. */
@@ -196,31 +957,33 @@ var EngramSchema = z2.object({
196
957
  /** Exchange marketplace metadata: fitness, adoption, diversity. */
197
958
  exchange: ExchangeMetadataSchema.optional(),
198
959
  /** Extensible key-value data for domain-specific fields. */
199
- structured_data: z2.record(z2.string(), z2.unknown()).optional()
960
+ structured_data: z.record(z.string(), z.unknown()).optional(),
961
+ /** Polarity classification: 'do' for directives, 'dont' for prohibitions, null for unclassified. */
962
+ polarity: z.enum(["do", "dont"]).nullable().default(null)
200
963
  });
201
964
 
202
965
  // src/schemas/pack.ts
203
- import { z as z3 } from "zod";
204
- var PackManifestSchema = z3.object({
205
- name: z3.string(),
206
- version: z3.string(),
207
- description: z3.string().optional(),
208
- creator: z3.string().optional(),
209
- license: z3.string().default("cc-by-sa-4.0"),
210
- tags: z3.array(z3.string()).default([]),
211
- metadata: z3.object({
212
- id: z3.string().optional(),
213
- injection_policy: z3.enum(["on_match", "on_request", "always"]).default("on_match"),
214
- match_terms: z3.array(z3.string()).default([]),
215
- domain: z3.string().optional(),
216
- engram_count: z3.number().optional()
966
+ import { z as z2 } from "zod";
967
+ var PackManifestSchema = z2.object({
968
+ name: z2.string(),
969
+ version: z2.string(),
970
+ description: z2.string().optional(),
971
+ creator: z2.string().optional(),
972
+ license: z2.string().default("cc-by-sa-4.0"),
973
+ tags: z2.array(z2.string()).default([]),
974
+ metadata: z2.object({
975
+ id: z2.string().optional(),
976
+ injection_policy: z2.enum(["on_match", "on_request", "always"]).default("on_match"),
977
+ match_terms: z2.array(z2.string()).default([]),
978
+ domain: z2.string().optional(),
979
+ engram_count: z2.number().optional()
217
980
  }).optional(),
218
- "x-datacore": z3.object({
219
- id: z3.string(),
220
- injection_policy: z3.enum(["on_match", "on_request"]),
221
- match_terms: z3.array(z3.string()).default([]),
222
- domain: z3.string().optional(),
223
- engram_count: z3.number().int().min(0)
981
+ "x-datacore": z2.object({
982
+ id: z2.string(),
983
+ injection_policy: z2.enum(["on_match", "on_request"]),
984
+ match_terms: z2.array(z2.string()).default([]),
985
+ domain: z2.string().optional(),
986
+ engram_count: z2.number().int().min(0)
224
987
  }).optional()
225
988
  });
226
989
 
@@ -243,173 +1006,11 @@ var logger = {
243
1006
  }
244
1007
  };
245
1008
 
246
- // src/sync.ts
247
- import { execFileSync } from "child_process";
248
- import { existsSync as existsSync3, writeFileSync, renameSync, mkdirSync as mkdirSync2 } from "fs";
249
- import { join as join2, dirname } from "path";
250
- var GITIGNORE = `# PLUR \u2014 derived/cache files (regenerated automatically)
251
- embeddings/
252
- .embeddings-cache.json
253
- *.db
254
- *.sqlite
255
- exchange/
256
- `;
257
- function git(args, cwd) {
258
- return execFileSync("git", args, { cwd, encoding: "utf8", timeout: 3e4 }).trim();
259
- }
260
- function gitSafe(args, cwd) {
261
- try {
262
- return git(args, cwd);
263
- } catch {
264
- return null;
265
- }
266
- }
267
- function isGitRepo(root) {
268
- return existsSync3(join2(root, ".git"));
269
- }
270
- function hasGitCli() {
271
- try {
272
- execFileSync("git", ["--version"], { encoding: "utf8", timeout: 5e3 });
273
- return true;
274
- } catch {
275
- return false;
276
- }
277
- }
278
- function getRemote(root) {
279
- return gitSafe(["remote", "get-url", "origin"], root);
280
- }
281
- function isDirty(root) {
282
- const status = gitSafe(["status", "--porcelain"], root);
283
- return status !== null && status.length > 0;
284
- }
285
- function countDiff(root, direction) {
286
- const tracking = gitSafe(["rev-parse", "--abbrev-ref", "@{u}"], root);
287
- if (!tracking) return 0;
288
- const flag = direction === "ahead" ? "--left-only" : "--right-only";
289
- const count = gitSafe(["rev-list", flag, "--count", "HEAD...@{u}"], root);
290
- return count ? parseInt(count, 10) : 0;
291
- }
292
- function getSyncStatus(root) {
293
- if (!isGitRepo(root)) {
294
- return { initialized: false, remote: null, dirty: false, branch: null, ahead: 0, behind: 0 };
295
- }
296
- const branch = gitSafe(["rev-parse", "--abbrev-ref", "HEAD"], root);
297
- const remote = getRemote(root);
298
- if (remote) gitSafe(["fetch", "origin", "--quiet"], root);
299
- return {
300
- initialized: true,
301
- remote,
302
- dirty: isDirty(root),
303
- branch,
304
- ahead: countDiff(root, "ahead"),
305
- behind: countDiff(root, "behind")
306
- };
307
- }
308
- function initRepo(root) {
309
- git(["init"], root);
310
- atomicWrite(join2(root, ".gitignore"), GITIGNORE);
311
- git(["add", "-A"], root);
312
- git(["commit", "-m", "Initial PLUR engram store"], root);
313
- }
314
- function commitChanges(root) {
315
- if (!isDirty(root)) return 0;
316
- git(["add", "-A"], root);
317
- const diff = gitSafe(["diff", "--cached", "--stat", "--shortstat"], root);
318
- const now = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace("T", " ");
319
- git(["commit", "-m", `plur sync ${now}`], root);
320
- const match = diff?.match(/(\d+) file/);
321
- return match ? parseInt(match[1], 10) : 1;
322
- }
323
- function hasConflictMarkers(root) {
324
- const result = gitSafe(["grep", "-l", "<<<<<<<"], root);
325
- return result !== null && result.length > 0;
326
- }
327
- function pullRebase(root) {
328
- const result = gitSafe(["pull", "--rebase", "origin", "main"], root);
329
- if (result !== null) return true;
330
- gitSafe(["rebase", "--abort"], root);
331
- const mergeResult = gitSafe(["pull", "origin", "main", "--no-edit"], root);
332
- if (mergeResult !== null) return true;
333
- if (hasConflictMarkers(root)) {
334
- gitSafe(["merge", "--abort"], root);
335
- throw new Error("Sync conflict: YAML files have merge conflicts that require manual resolution. Your local changes are preserved.");
336
- }
337
- git(["add", "-A"], root);
338
- gitSafe(["commit", "-m", "plur sync: merge conflict resolved (kept both)"], root);
339
- return true;
340
- }
341
- function sync(root, remote) {
342
- if (!hasGitCli()) {
343
- throw new Error("git is not installed. Install git to enable sync.");
344
- }
345
- if (!isGitRepo(root)) {
346
- initRepo(root);
347
- if (remote) {
348
- git(["remote", "add", "origin", remote], root);
349
- const branch = git(["rev-parse", "--abbrev-ref", "HEAD"], root);
350
- git(["push", "-u", "origin", branch], root);
351
- return { action: "initialized", message: `Initialized and pushed to ${remote}`, remote, files_changed: 0 };
352
- }
353
- return {
354
- action: "initialized",
355
- message: "Initialized local git repo. Call plur.sync with remote to enable cross-device sync.",
356
- remote: null,
357
- files_changed: 0
358
- };
359
- }
360
- const existingRemote = getRemote(root);
361
- if (remote && !existingRemote) {
362
- git(["remote", "add", "origin", remote], root);
363
- const filesChanged2 = commitChanges(root);
364
- const branch = git(["rev-parse", "--abbrev-ref", "HEAD"], root);
365
- git(["push", "-u", "origin", branch], root);
366
- return { action: "synced", message: `Remote added and pushed to ${remote}`, remote, files_changed: filesChanged2 };
367
- }
368
- if (!existingRemote) {
369
- const filesChanged2 = commitChanges(root);
370
- if (filesChanged2 === 0) {
371
- return { action: "up-to-date", message: 'No changes to commit. Add a remote with plur.sync({ remote: "..." }) to enable cross-device sync.', remote: null, files_changed: 0 };
372
- }
373
- return { action: "committed", message: `Committed ${filesChanged2} file(s) locally.`, remote: null, files_changed: filesChanged2 };
374
- }
375
- const filesChanged = commitChanges(root);
376
- gitSafe(["fetch", "origin", "--quiet"], root);
377
- const behind = countDiff(root, "behind");
378
- const aheadBefore = countDiff(root, "ahead");
379
- if (behind > 0) {
380
- pullRebase(root);
381
- }
382
- const aheadAfter = countDiff(root, "ahead");
383
- if (aheadAfter > 0) {
384
- gitSafe(["push", "origin"], root);
385
- }
386
- if (filesChanged === 0 && behind === 0 && aheadBefore === 0) {
387
- return { action: "up-to-date", message: "Already in sync.", remote: existingRemote, files_changed: 0 };
388
- }
389
- const parts = [];
390
- if (filesChanged > 0) parts.push(`${filesChanged} file(s) committed`);
391
- if (behind > 0) parts.push(`pulled ${behind} remote commit(s)`);
392
- if (aheadAfter === 0 && aheadBefore > 0) parts.push("pushed");
393
- return {
394
- action: "synced",
395
- message: `Synced. ${parts.join(", ")}.`,
396
- remote: existingRemote,
397
- files_changed: filesChanged
398
- };
399
- }
400
- function atomicWrite(filePath, content) {
401
- const dir = dirname(filePath);
402
- if (!existsSync3(dir)) mkdirSync2(dir, { recursive: true });
403
- const tmp = filePath + ".tmp";
404
- writeFileSync(tmp, content);
405
- renameSync(tmp, filePath);
406
- }
407
-
408
1009
  // src/engrams.ts
409
1010
  function loadEngrams(filePath) {
410
1011
  if (!fs.existsSync(filePath)) return [];
411
1012
  try {
412
- const raw = yaml2.load(fs.readFileSync(filePath, "utf8"));
1013
+ const raw = yaml.load(fs.readFileSync(filePath, "utf8"));
413
1014
  if (!raw?.engrams || !Array.isArray(raw.engrams)) return [];
414
1015
  const valid = [];
415
1016
  let skipped = 0;
@@ -426,14 +1027,14 @@ function loadEngrams(filePath) {
426
1027
  }
427
1028
  }
428
1029
  function saveEngrams(filePath, engrams) {
429
- const content = yaml2.dump({ engrams }, { lineWidth: 120, noRefs: true, quotingType: '"' });
1030
+ const content = yaml.dump({ engrams }, { lineWidth: 120, noRefs: true, quotingType: '"' });
430
1031
  atomicWrite(filePath, content);
431
1032
  }
432
1033
  function parseSkillMdFrontmatter(filePath) {
433
1034
  const content = fs.readFileSync(filePath, "utf8");
434
1035
  const match = content.match(/^---\n([\s\S]*?)\n---/);
435
1036
  if (!match) throw new Error(`No frontmatter found in ${filePath}`);
436
- return yaml2.load(match[1]);
1037
+ return yaml.load(match[1]);
437
1038
  }
438
1039
  function loadPack(packDir) {
439
1040
  const skillMdPath = `${packDir}/SKILL.md`;
@@ -443,7 +1044,7 @@ function loadPack(packDir) {
443
1044
  if (fs.existsSync(skillMdPath)) {
444
1045
  rawManifest = parseSkillMdFrontmatter(skillMdPath);
445
1046
  } else if (fs.existsSync(manifestYamlPath)) {
446
- rawManifest = yaml2.load(fs.readFileSync(manifestYamlPath, "utf8"));
1047
+ rawManifest = yaml.load(fs.readFileSync(manifestYamlPath, "utf8"));
447
1048
  } else {
448
1049
  throw new Error(`No SKILL.md or manifest.yaml found in ${packDir}`);
449
1050
  }
@@ -475,66 +1076,163 @@ function generateEngramId(existing) {
475
1076
  return `${prefix}${String(next).padStart(3, "0")}`;
476
1077
  }
477
1078
 
478
- // src/fts.ts
479
- var STOP_WORDS = /* @__PURE__ */ new Set([
480
- "the",
481
- "and",
482
- "for",
483
- "that",
484
- "this",
485
- "with",
486
- "from",
487
- "are",
488
- "was",
489
- "were",
490
- "been",
491
- "have",
492
- "has",
493
- "not",
494
- "but",
495
- "its",
496
- "you",
497
- "your",
498
- "can",
499
- "will",
500
- "should",
501
- "would",
502
- "could",
503
- "may",
504
- "might"
505
- ]);
506
- function ftsTokenize(text) {
507
- return text.toLowerCase().replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 2).filter((w) => !STOP_WORDS.has(w));
508
- }
509
- function engramSearchText(engram) {
510
- const parts = [engram.statement];
511
- if (engram.domain) parts.push(engram.domain.replace(/\./g, " "));
512
- if (engram.tags.length > 0) parts.push(engram.tags.join(" "));
513
- if (engram.entities) {
514
- for (const e of engram.entities) {
515
- parts.push(e.name);
516
- if (e.type !== "other") parts.push(e.type);
517
- }
518
- }
519
- if (engram.temporal) {
520
- if (engram.temporal.valid_from) parts.push(engram.temporal.valid_from);
521
- if (engram.temporal.valid_until) parts.push(engram.temporal.valid_until);
522
- }
523
- if (engram.rationale) parts.push(engram.rationale);
524
- return parts.join(" ");
525
- }
526
- function ftsScore(engram, queryTokens) {
527
- const allTerms = ftsTokenize(engramSearchText(engram));
528
- let matches = 0;
529
- for (const qt of queryTokens) {
530
- if (allTerms.some((t) => t.includes(qt) || qt.includes(t))) matches++;
1079
+ // src/storage-indexed.ts
1080
+ var Database = null;
1081
+ function getDatabase() {
1082
+ if (!Database) {
1083
+ try {
1084
+ Database = require_lib();
1085
+ } catch {
1086
+ throw new Error(
1087
+ "better-sqlite3 is required for index: true. Install it with: npm install better-sqlite3"
1088
+ );
1089
+ }
1090
+ }
1091
+ return Database;
1092
+ }
1093
+ var IndexedStorage = class {
1094
+ dbPath;
1095
+ engramsPath;
1096
+ db = null;
1097
+ constructor(engramsPath, dbPath) {
1098
+ this.engramsPath = engramsPath;
1099
+ this.dbPath = dbPath;
1100
+ }
1101
+ getDb() {
1102
+ if (!this.db) {
1103
+ const DB = getDatabase();
1104
+ this.db = new DB(this.dbPath);
1105
+ this.db.pragma("journal_mode = WAL");
1106
+ this.db.exec(`
1107
+ CREATE TABLE IF NOT EXISTS engrams (
1108
+ id TEXT PRIMARY KEY,
1109
+ status TEXT NOT NULL,
1110
+ scope TEXT NOT NULL,
1111
+ domain TEXT,
1112
+ last_accessed TEXT,
1113
+ data TEXT NOT NULL
1114
+ );
1115
+ CREATE INDEX IF NOT EXISTS idx_status ON engrams(status);
1116
+ CREATE INDEX IF NOT EXISTS idx_scope ON engrams(scope);
1117
+ CREATE INDEX IF NOT EXISTS idx_domain ON engrams(domain);
1118
+ `);
1119
+ }
1120
+ return this.db;
1121
+ }
1122
+ /** Load all engrams from SQLite index. Auto-rebuilds if db missing. */
1123
+ loadAll() {
1124
+ if (!existsSync3(this.dbPath)) {
1125
+ this.reindex();
1126
+ }
1127
+ const db = this.getDb();
1128
+ const rows = db.prepare("SELECT data FROM engrams").all();
1129
+ return rows.map((r) => JSON.parse(r.data));
1130
+ }
1131
+ /** Load engrams with SQL-level filtering. */
1132
+ loadFiltered(filter) {
1133
+ if (!existsSync3(this.dbPath)) {
1134
+ this.reindex();
1135
+ }
1136
+ const db = this.getDb();
1137
+ const conditions = [];
1138
+ const params = [];
1139
+ if (filter.status) {
1140
+ conditions.push("status = ?");
1141
+ params.push(filter.status);
1142
+ }
1143
+ if (filter.scope) {
1144
+ conditions.push("(scope = 'global' OR scope = ? OR scope LIKE ? || '%')");
1145
+ params.push(filter.scope, filter.scope);
1146
+ }
1147
+ if (filter.domain) {
1148
+ conditions.push("domain LIKE ? || '%'");
1149
+ params.push(filter.domain);
1150
+ }
1151
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1152
+ const rows = db.prepare(`SELECT data FROM engrams ${where}`).all(...params);
1153
+ return rows.map((r) => JSON.parse(r.data));
1154
+ }
1155
+ /** Count engrams with optional status filter. */
1156
+ count(filter) {
1157
+ if (!existsSync3(this.dbPath)) {
1158
+ this.reindex();
1159
+ }
1160
+ const db = this.getDb();
1161
+ if (filter?.status) {
1162
+ return db.prepare("SELECT COUNT(*) as c FROM engrams WHERE status = ?").get(filter.status).c;
1163
+ }
1164
+ return db.prepare("SELECT COUNT(*) as c FROM engrams").get().c;
1165
+ }
1166
+ /** Sync SQLite index from YAML source of truth. */
1167
+ syncFromYaml() {
1168
+ const engrams = loadEngrams(this.engramsPath);
1169
+ const db = this.getDb();
1170
+ const upsert = db.prepare(`
1171
+ INSERT OR REPLACE INTO engrams (id, status, scope, domain, last_accessed, data)
1172
+ VALUES (?, ?, ?, ?, ?, ?)
1173
+ `);
1174
+ const deleteStmt = db.prepare("DELETE FROM engrams WHERE id = ?");
1175
+ const yamlIds = new Set(engrams.map((e) => e.id));
1176
+ const dbIds = new Set(
1177
+ db.prepare("SELECT id FROM engrams").all().map((r) => r.id)
1178
+ );
1179
+ const tx = db.transaction(() => {
1180
+ for (const e of engrams) {
1181
+ upsert.run(e.id, e.status, e.scope, e.domain ?? null, e.activation.last_accessed, JSON.stringify(e));
1182
+ }
1183
+ for (const id of dbIds) {
1184
+ if (!yamlIds.has(id)) deleteStmt.run(id);
1185
+ }
1186
+ });
1187
+ tx();
1188
+ }
1189
+ /** Drop and rebuild the entire index from YAML. */
1190
+ reindex() {
1191
+ this.close();
1192
+ const db = this.getDb();
1193
+ db.exec("DELETE FROM engrams");
1194
+ this.syncFromYaml();
1195
+ }
1196
+ /** Close the database connection. */
1197
+ close() {
1198
+ if (this.db) {
1199
+ this.db.close();
1200
+ this.db = null;
1201
+ }
1202
+ }
1203
+ };
1204
+
1205
+ // src/config.ts
1206
+ import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
1207
+ import yaml2 from "js-yaml";
1208
+
1209
+ // src/schemas/config.ts
1210
+ import { z as z3 } from "zod";
1211
+ var PlurConfigSchema = z3.object({
1212
+ auto_learn: z3.boolean().default(true),
1213
+ auto_capture: z3.boolean().default(true),
1214
+ injection_budget: z3.number().default(2e3),
1215
+ decay_enabled: z3.boolean().default(true),
1216
+ decay_threshold: z3.number().default(0.15),
1217
+ packs: z3.array(z3.string()).default([]),
1218
+ injection: z3.object({
1219
+ spread_cap: z3.number().default(3),
1220
+ spread_budget: z3.number().default(480),
1221
+ co_access: z3.boolean().default(true)
1222
+ }).default({}),
1223
+ allow_secrets: z3.boolean().default(false),
1224
+ index: z3.boolean().default(false)
1225
+ }).partial();
1226
+
1227
+ // src/config.ts
1228
+ function loadConfig(configPath) {
1229
+ if (!existsSync4(configPath)) return PlurConfigSchema.parse({});
1230
+ try {
1231
+ const raw = yaml2.load(readFileSync2(configPath, "utf8"));
1232
+ return PlurConfigSchema.parse(raw ?? {});
1233
+ } catch {
1234
+ return PlurConfigSchema.parse({});
531
1235
  }
532
- return queryTokens.length > 0 ? matches / queryTokens.length : 0;
533
- }
534
- function searchEngrams(engrams, query, limit = 20) {
535
- const queryTokens = ftsTokenize(query);
536
- if (queryTokens.length === 0) return [];
537
- return engrams.map((e) => ({ engram: e, score: ftsScore(e, queryTokens) })).filter((r) => r.score > 0).sort((a, b) => b.score - a.score).slice(0, limit).map((r) => r.engram);
538
1236
  }
539
1237
 
540
1238
  // src/decay.ts
@@ -557,6 +1255,53 @@ function decayedCoAccessStrength(strength, daysSinceUpdate, lambda = 0.01) {
557
1255
  return floor + (strength - floor) * Math.exp(-lambda * daysSinceUpdate);
558
1256
  }
559
1257
 
1258
+ // src/polarity.ts
1259
+ var DONT_PATTERNS = [
1260
+ /\bnever\b/i,
1261
+ /\bdo\s+not\b/i,
1262
+ /\bdon'?t\b/i,
1263
+ /\bavoid\b/i,
1264
+ /\bmust\s+not\b/i,
1265
+ /\bshould\s+not\b/i,
1266
+ /\bNOT\b.*?\b(?:include|use|run|start|create|add|send|describe|reference|assume)\b/,
1267
+ /\bstop\b.*?\b(?:generating|iterating|doing|running|creating)\b/i
1268
+ ];
1269
+ function classifyPolarity(statement) {
1270
+ if (!statement || statement.length < 5) return null;
1271
+ const dotIndex = statement.indexOf(".");
1272
+ const firstSentence = statement.slice(0, dotIndex > 0 ? Math.min(dotIndex, 200) : 200);
1273
+ for (const pattern of DONT_PATTERNS) {
1274
+ if (pattern.test(firstSentence)) return "dont";
1275
+ }
1276
+ return null;
1277
+ }
1278
+
1279
+ // src/confidence.ts
1280
+ function computeConfidence(input) {
1281
+ const fb = input.feedback_signals ?? { positive: 0, negative: 0, neutral: 0 };
1282
+ const total = fb.positive + fb.negative + fb.neutral;
1283
+ if (total === 0) return 0.5;
1284
+ const netRatio = (fb.positive - fb.negative) / total;
1285
+ const dampening = 1 - 1 / (total + 1);
1286
+ const adjustedRatio = netRatio * dampening;
1287
+ const steepness = 2;
1288
+ const base = 1 / (1 + Math.exp(-steepness * adjustedRatio));
1289
+ const consolidationBonus = input.consolidated ? 0.05 : 0;
1290
+ return Math.min(1, Math.max(0, base + consolidationBonus));
1291
+ }
1292
+ function computeMetaConfidence(evidenceCount, domainCount, structuralDepth, validationRatio) {
1293
+ const evidenceSignal = Math.min(evidenceCount / 5, 1) * 0.25;
1294
+ const domainSignal = Math.min(domainCount / 3, 1) * 0.35;
1295
+ const depthSignal = Math.min(structuralDepth / 3, 1) * 0.2;
1296
+ const validationSignal = validationRatio * 0.2;
1297
+ return evidenceSignal + domainSignal + depthSignal + validationSignal;
1298
+ }
1299
+ function confidenceBand(score) {
1300
+ if (score >= 0.7) return "high";
1301
+ if (score >= 0.4) return "medium";
1302
+ return "low";
1303
+ }
1304
+
560
1305
  // src/inject.ts
561
1306
  var DEFAULT_MAX_TOKENS = 8e3;
562
1307
  var DEFAULT_MIN_RELEVANCE = 0.3;
@@ -614,7 +1359,7 @@ function stripAssociations(engram) {
614
1359
  }
615
1360
  function stripScoring(engram) {
616
1361
  const { keyword_match: _, raw_score: _r, score: _s, ...rest } = engram;
617
- return rest;
1362
+ return { ...rest, confidence_score: computeConfidence(engram) };
618
1363
  }
619
1364
  function scoreEngram(engram, promptLower, promptWords, packMatchTerms, scopeFilter, isPack) {
620
1365
  if (scopeFilter) {
@@ -650,6 +1395,8 @@ function scoreEngram(engram, promptLower, promptWords, packMatchTerms, scopeFilt
650
1395
  else if (netFeedback < 0) score *= Math.max(1 + netFeedback * 0.1, 0.5);
651
1396
  }
652
1397
  if (engram.consolidated) score *= 1.1;
1398
+ const emotionalWeight = engram.episodic?.emotional_weight ?? 5;
1399
+ score *= 1 + (emotionalWeight - 5) * 0.04;
653
1400
  return score;
654
1401
  }
655
1402
  function fillTokenBudget(scored, maxTokens) {
@@ -681,10 +1428,13 @@ function selectAndSpread(ctx, personalEngrams, packs, config, embeddingBoosts) {
681
1428
  const promptWords = new Set(promptLower.split(/\W+/).filter((w) => w.length > 2));
682
1429
  const maxTokens = ctx.maxTokens ?? DEFAULT_MAX_TOKENS;
683
1430
  const minRelevance = ctx.minRelevance ?? DEFAULT_MIN_RELEVANCE;
1431
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
684
1432
  const engramMap = /* @__PURE__ */ new Map();
685
1433
  const scored = [];
686
1434
  for (const engram of personalEngrams) {
687
1435
  if (engram.status !== "active") continue;
1436
+ if (engram.temporal?.valid_until && engram.temporal.valid_until < today) continue;
1437
+ if (engram.temporal?.valid_from && engram.temporal.valid_from > today) continue;
688
1438
  engramMap.set(engram.id, engram);
689
1439
  let raw = scoreEngram(engram, promptLower, promptWords, [], ctx.scope, false);
690
1440
  const embBoost = embeddingBoosts?.get(engram.id) ?? 0;
@@ -703,6 +1453,8 @@ function selectAndSpread(ctx, personalEngrams, packs, config, embeddingBoosts) {
703
1453
  const matchTerms = packMeta.match_terms;
704
1454
  for (const engram of pack.engrams) {
705
1455
  if (engram.status !== "active") continue;
1456
+ if (engram.temporal?.valid_until && engram.temporal.valid_until < today) continue;
1457
+ if (engram.temporal?.valid_from && engram.temporal.valid_from > today) continue;
706
1458
  engramMap.set(engram.id, engram);
707
1459
  let raw = scoreEngram(engram, promptLower, promptWords, matchTerms, ctx.scope, true);
708
1460
  const embBoost = embeddingBoosts?.get(engram.id) ?? 0;
@@ -750,6 +1502,7 @@ function selectAndSpread(ctx, personalEngrams, packs, config, embeddingBoosts) {
750
1502
  if (directives.length === 0 && dip19Pool.length === 0) {
751
1503
  return {
752
1504
  directives: [],
1505
+ constraints: [],
753
1506
  consider: [],
754
1507
  tokens_used: { directives: 0, consider: 0 }
755
1508
  };
@@ -787,11 +1540,22 @@ function selectAndSpread(ctx, personalEngrams, packs, config, embeddingBoosts) {
787
1540
  const allConsider = [...dip19Pool, ...spreadCandidates];
788
1541
  const agentDirectives = directives.map(stripAssociations);
789
1542
  const agentConsider = allConsider.map(stripAssociations);
790
- const wireDirectives = agentDirectives.map(stripScoring);
1543
+ const wireAll = agentDirectives.map(stripScoring);
791
1544
  const wireConsider = agentConsider.map(stripScoring);
1545
+ const wireDirectives = [];
1546
+ const wireConstraints = [];
1547
+ for (const wire of wireAll) {
1548
+ const polarity = wire.polarity ?? classifyPolarity(wire.statement);
1549
+ if (polarity === "dont") {
1550
+ wireConstraints.push(wire);
1551
+ } else {
1552
+ wireDirectives.push(wire);
1553
+ }
1554
+ }
792
1555
  const considerTokens = dip19PoolTokens + spreadTokens;
793
1556
  return {
794
1557
  directives: wireDirectives,
1558
+ constraints: wireConstraints,
795
1559
  consider: wireConsider,
796
1560
  tokens_used: { directives: directiveTokens, consider: considerTokens }
797
1561
  };
@@ -905,86 +1669,6 @@ Rules:
905
1669
  }
906
1670
  }
907
1671
 
908
- // src/embeddings.ts
909
- import { existsSync as existsSync6, readFileSync as readFileSync4, mkdirSync as mkdirSync3 } from "fs";
910
- import { join as join3 } from "path";
911
- import { createHash } from "crypto";
912
- var embedPipeline = null;
913
- var transformersUnavailable = false;
914
- async function getEmbedder() {
915
- if (transformersUnavailable) return null;
916
- if (!embedPipeline) {
917
- try {
918
- const { pipeline } = await import("./transformers.node-PH5YK5EA.js");
919
- embedPipeline = await pipeline("feature-extraction", "Xenova/bge-small-en-v1.5", {
920
- dtype: "fp32"
921
- });
922
- } catch {
923
- transformersUnavailable = true;
924
- return null;
925
- }
926
- }
927
- return embedPipeline;
928
- }
929
- async function embed(text) {
930
- const embedder = await getEmbedder();
931
- if (!embedder) return null;
932
- const result = await embedder(text, { pooling: "cls", normalize: true });
933
- return new Float32Array(result.data);
934
- }
935
- function cosineSimilarity(a, b) {
936
- let dot = 0;
937
- for (let i = 0; i < a.length; i++) dot += a[i] * b[i];
938
- return dot;
939
- }
940
- function loadCache(cachePath) {
941
- if (!existsSync6(cachePath)) return {};
942
- try {
943
- return JSON.parse(readFileSync4(cachePath, "utf8"));
944
- } catch {
945
- return {};
946
- }
947
- }
948
- function saveCache(cachePath, cache2) {
949
- const dir = cachePath.substring(0, cachePath.lastIndexOf("/"));
950
- if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
951
- atomicWrite(cachePath, JSON.stringify(cache2));
952
- }
953
- function hashStatement(statement) {
954
- return createHash("sha256").update(statement).digest("hex").slice(0, 16);
955
- }
956
- async function embeddingSearch(engrams, query, limit, storagePath) {
957
- if (engrams.length === 0) return [];
958
- const cachePath = storagePath ? join3(storagePath, ".embeddings-cache.json") : ".embeddings-cache.json";
959
- const cache2 = loadCache(cachePath);
960
- const queryEmbedding = await embed(query);
961
- if (!queryEmbedding) {
962
- return [];
963
- }
964
- const similarities = [];
965
- for (const engram of engrams) {
966
- const searchText = engramSearchText(engram);
967
- const hash = hashStatement(searchText);
968
- let engramEmbedding;
969
- if (cache2[engram.id]?.hash === hash) {
970
- engramEmbedding = new Float32Array(cache2[engram.id].embedding);
971
- } else {
972
- const emb = await embed(searchText);
973
- if (!emb) return [];
974
- engramEmbedding = emb;
975
- cache2[engram.id] = {
976
- hash,
977
- embedding: Array.from(engramEmbedding)
978
- };
979
- }
980
- const score = cosineSimilarity(queryEmbedding, engramEmbedding);
981
- similarities.push({ engram, score });
982
- }
983
- saveCache(cachePath, cache2);
984
- similarities.sort((a, b) => b.score - a.score);
985
- return similarities.slice(0, limit).map((s) => s.engram);
986
- }
987
-
988
1672
  // src/hybrid-search.ts
989
1673
  function rrfMerge(resultSets, k = 60) {
990
1674
  const scores = /* @__PURE__ */ new Map();
@@ -1183,6 +1867,818 @@ ${manifest.description || ""}
1183
1867
  return { path: outputDir, engram_count: engrams.length };
1184
1868
  }
1185
1869
 
1870
+ // src/secrets.ts
1871
+ var SECRET_PATTERNS = [
1872
+ { name: "aws_access_key", regex: /AKIA[0-9A-Z]{16}/ },
1873
+ { name: "aws_secret_key", regex: /(?:aws_secret_access_key|secret_access_key)\s*[=:]\s*[A-Za-z0-9/+=]{40}/i },
1874
+ { name: "generic_api_key", regex: /(?:^|[^a-z])(sk|pk)[-_][a-z0-9]{20,}/i },
1875
+ { name: "api_key_assignment", regex: /(?:api[_-]?key|api[_-]?secret|secret[_-]?key)\s*[=:]\s*\S{20,}/i },
1876
+ { name: "password_assignment", regex: /password\s*[=:]\s*\S{8,}/i },
1877
+ { name: "connection_string", regex: /(?:postgres|mysql|mongodb|redis):\/\/\S+/ },
1878
+ { name: "jwt", regex: /eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}/ },
1879
+ { name: "private_key", regex: /-----BEGIN\s+\S+\s+PRIVATE KEY-----/ },
1880
+ { name: "bearer_token", regex: /Bearer\s+[A-Za-z0-9._~+/=-]{20,}/ }
1881
+ ];
1882
+ function detectSecrets(text) {
1883
+ const matches = [];
1884
+ for (const { name, regex } of SECRET_PATTERNS) {
1885
+ const m = text.match(regex);
1886
+ if (m) {
1887
+ matches.push({ pattern: name, match: m[0].slice(0, 20) + "..." });
1888
+ }
1889
+ }
1890
+ return matches;
1891
+ }
1892
+
1893
+ // src/meta/sanitize.ts
1894
+ function sanitizeForPrompt(text) {
1895
+ return text.replace(/```/g, "~~~").replace(/\n{3,}/g, "\n\n").replace(/^(system|assistant|user):/gim, "$1 -").slice(0, 2e3);
1896
+ }
1897
+
1898
+ // src/meta/structural-analysis.ts
1899
+ var FAILURE_TAGS = /* @__PURE__ */ new Set(["correction", "mistake", "bug", "fix", "error", "wrong", "broken"]);
1900
+ var BATCH_SIZE = 5;
1901
+ function isFailureDriven(engram) {
1902
+ if (engram.tags.some((t) => FAILURE_TAGS.has(t.toLowerCase()))) return true;
1903
+ const fb = engram.feedback_signals;
1904
+ if (fb && fb.negative > fb.positive) return true;
1905
+ return false;
1906
+ }
1907
+ function prioritize(engrams) {
1908
+ return [...engrams].sort((a, b) => {
1909
+ const aFail = isFailureDriven(a) ? 0 : 1;
1910
+ const bFail = isFailureDriven(b) ? 0 : 1;
1911
+ if (aFail !== bFail) return aFail - bFail;
1912
+ const aFb = a.feedback_signals?.negative ?? 0;
1913
+ const bFb = b.feedback_signals?.negative ?? 0;
1914
+ return bFb - aFb;
1915
+ });
1916
+ }
1917
+ function buildPrompt(engrams) {
1918
+ const items = engrams.map((e, i) => {
1919
+ const parts = [` Statement: "${sanitizeForPrompt(e.statement)}"`];
1920
+ if (e.rationale) parts.push(` Rationale: "${sanitizeForPrompt(e.rationale)}"`);
1921
+ if (e.domain) parts.push(` Domain: "${e.domain}"`);
1922
+ return `Engram ${i + 1} (${e.id}):
1923
+ ${parts.join("\n")}`;
1924
+ }).join("\n\n");
1925
+ return `Given these learned lessons, extract relational structure for cross-domain transfer.
1926
+
1927
+ ${items}
1928
+
1929
+ For EACH engram, extract:
1930
+ 1. The GOAL the agent had (abstract type, not domain-specific)
1931
+ 2. Relational triples: subject (role + domain instance), predicate, object (role + domain instance), outcome
1932
+ 3. Use domain-GENERAL role types (e.g., "safety-metric" not "liquidation-price")
1933
+
1934
+ Return a JSON array with one object per engram:
1935
+ [{
1936
+ "engram_id": "ENG-...",
1937
+ "goal_context": "what the agent was trying to achieve (abstract)",
1938
+ "triples": [{ "subject": { "role": "...", "domain_instance": "..." }, "predicate": "...", "object": { "role": "...", "domain_instance": "..." }, "outcome": "..." }]
1939
+ }]
1940
+
1941
+ Rules:
1942
+ - Roles MUST be domain-general (e.g., "safety-metric" not "liquidation-price")
1943
+ - If a lesson is purely domain-specific with no transferable structure, return empty triples: []
1944
+ - Prefer causal chains over isolated attributes
1945
+ - Return ONLY valid JSON, no markdown fencing`;
1946
+ }
1947
+ async function analyzeStructure(engrams, llm) {
1948
+ const prioritized = prioritize(engrams.filter((e) => e.status === "active"));
1949
+ const results = [];
1950
+ for (let i = 0; i < prioritized.length; i += BATCH_SIZE) {
1951
+ const batch = prioritized.slice(i, i + BATCH_SIZE);
1952
+ const prompt = buildPrompt(batch);
1953
+ let parsed;
1954
+ try {
1955
+ const response = await llm(prompt);
1956
+ const cleaned = response.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
1957
+ parsed = JSON.parse(cleaned);
1958
+ } catch {
1959
+ try {
1960
+ const retryResponse = await llm(prompt + "\n\nIMPORTANT: Return ONLY raw JSON array, no text.");
1961
+ const cleaned = retryResponse.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
1962
+ parsed = JSON.parse(cleaned);
1963
+ } catch {
1964
+ continue;
1965
+ }
1966
+ }
1967
+ for (const item of parsed) {
1968
+ if (!item.triples || item.triples.length === 0) continue;
1969
+ const engram = batch.find((e) => e.id === item.engram_id) ?? batch[parsed.indexOf(item)];
1970
+ if (!engram) continue;
1971
+ results.push({
1972
+ engram_id: engram.id,
1973
+ triples: item.triples,
1974
+ goal_context: item.goal_context ?? "",
1975
+ is_failure_driven: isFailureDriven(engram),
1976
+ domain: engram.domain ?? "unknown",
1977
+ polarity: classifyPolarity(engram.statement) === "dont" ? "dont" : "do"
1978
+ });
1979
+ }
1980
+ }
1981
+ return results;
1982
+ }
1983
+
1984
+ // src/meta/similarity.ts
1985
+ function tokenSimilarity(a, b) {
1986
+ const wordsA = new Set(a.toLowerCase().split(/[\s\[\]→+\-]+/).filter((w) => w.length > 2));
1987
+ const wordsB = new Set(b.toLowerCase().split(/[\s\[\]→+\-]+/).filter((w) => w.length > 2));
1988
+ if (wordsA.size === 0 || wordsB.size === 0) return 0;
1989
+ let overlap = 0;
1990
+ for (const w of wordsA) {
1991
+ if (wordsB.has(w)) overlap++;
1992
+ }
1993
+ return overlap / Math.sqrt(wordsA.size * wordsB.size);
1994
+ }
1995
+
1996
+ // src/meta/clustering.ts
1997
+ function tripleToTemplate(triple) {
1998
+ const parts = [triple.subject.role, triple.predicate, triple.object.role];
1999
+ if (triple.outcome) parts.push("\u2192", triple.outcome);
2000
+ return parts.join(" ");
2001
+ }
2002
+ function analysisTemplate(analysis) {
2003
+ return analysis.triples.map(tripleToTemplate).join("; ");
2004
+ }
2005
+ async function computeSimilarityMatrix(templates) {
2006
+ const n = templates.length;
2007
+ const matrix = Array.from({ length: n }, () => Array(n).fill(0));
2008
+ try {
2009
+ const { embed, cosineSimilarity } = await import("./embeddings-2IODIQAF.js");
2010
+ const embeddings = [];
2011
+ for (const t of templates) {
2012
+ embeddings.push(await embed(t));
2013
+ }
2014
+ if (embeddings[0] !== null) {
2015
+ for (let i = 0; i < n; i++) {
2016
+ for (let j = i + 1; j < n; j++) {
2017
+ if (embeddings[i] && embeddings[j]) {
2018
+ const sim = cosineSimilarity(embeddings[i], embeddings[j]);
2019
+ matrix[i][j] = sim;
2020
+ matrix[j][i] = sim;
2021
+ }
2022
+ }
2023
+ }
2024
+ return { matrix, method: "embedding" };
2025
+ }
2026
+ } catch {
2027
+ }
2028
+ for (let i = 0; i < n; i++) {
2029
+ for (let j = i + 1; j < n; j++) {
2030
+ const sim = tokenSimilarity(templates[i], templates[j]);
2031
+ matrix[i][j] = sim;
2032
+ matrix[j][i] = sim;
2033
+ }
2034
+ }
2035
+ return { matrix, method: "token" };
2036
+ }
2037
+ var EMBEDDING_THRESHOLD = 0.65;
2038
+ var TOKEN_THRESHOLD = 0.35;
2039
+ async function clusterByStructure(analyses, threshold2) {
2040
+ if (analyses.length < 2) return [];
2041
+ const templates = analyses.map((a) => analysisTemplate(a));
2042
+ const { matrix, method } = await computeSimilarityMatrix(templates);
2043
+ const effectiveThreshold = threshold2 ?? (method === "embedding" ? EMBEDDING_THRESHOLD : TOKEN_THRESHOLD);
2044
+ const seenClusters = /* @__PURE__ */ new Set();
2045
+ const clusters = [];
2046
+ let clusterId = 0;
2047
+ for (let i = 0; i < analyses.length; i++) {
2048
+ const members = [analyses[i]];
2049
+ const memberIndices = [i];
2050
+ for (let j = 0; j < analyses.length; j++) {
2051
+ if (j === i) continue;
2052
+ if (matrix[i][j] >= effectiveThreshold) {
2053
+ members.push(analyses[j]);
2054
+ memberIndices.push(j);
2055
+ }
2056
+ }
2057
+ if (members.length < 2) continue;
2058
+ const memberKey = members.map((m) => m.engram_id).sort().join(",");
2059
+ if (seenClusters.has(memberKey)) continue;
2060
+ seenClusters.add(memberKey);
2061
+ const domains = [...new Set(members.map((m) => m.domain))];
2062
+ let totalSim = 0;
2063
+ let pairs = 0;
2064
+ for (let a = 0; a < memberIndices.length; a++) {
2065
+ for (let b = a + 1; b < memberIndices.length; b++) {
2066
+ totalSim += matrix[memberIndices[a]][memberIndices[b]];
2067
+ pairs++;
2068
+ }
2069
+ }
2070
+ clusters.push({
2071
+ cluster_id: `cluster-${clusterId++}`,
2072
+ members,
2073
+ domains,
2074
+ is_cross_domain: domains.length >= 2,
2075
+ cohesion: pairs > 0 ? totalSim / pairs : 0
2076
+ });
2077
+ }
2078
+ return clusters;
2079
+ }
2080
+
2081
+ // src/meta/platitudes.ts
2082
+ var PLATITUDE_PATTERNS = [
2083
+ "always be careful",
2084
+ "verify before acting",
2085
+ "plan ahead",
2086
+ "consider edge cases",
2087
+ "communicate clearly",
2088
+ "test thoroughly",
2089
+ "keep it simple",
2090
+ "document your work",
2091
+ "think before you act",
2092
+ "double check"
2093
+ ];
2094
+ function isPlatitude(statement) {
2095
+ const lower = statement.toLowerCase();
2096
+ return PLATITUDE_PATTERNS.some((p) => lower.includes(p)) || statement.length < 30;
2097
+ }
2098
+
2099
+ // src/meta/alignment.ts
2100
+ async function alignCluster(cluster, llm) {
2101
+ const tripleDescriptions = cluster.members.map((m) => {
2102
+ const domain = sanitizeForPrompt(m.domain);
2103
+ const triples = m.triples.map((t) => {
2104
+ const parts = [`${sanitizeForPrompt(t.subject.role)} ${sanitizeForPrompt(t.predicate)} ${sanitizeForPrompt(t.object.role)}`];
2105
+ if (t.outcome) parts.push(`\u2192 ${sanitizeForPrompt(t.outcome)}`);
2106
+ return parts.join(" ");
2107
+ }).join("; ");
2108
+ return `Domain ${domain} (${m.engram_id}): ${triples}`;
2109
+ }).join("\n");
2110
+ const prompt = `These lessons come from different domains but may share a common structural principle:
2111
+
2112
+ ${tripleDescriptions}
2113
+
2114
+ Tasks:
2115
+ 1. Is there a genuine common relational structure? (Not surface similarity, not a platitude)
2116
+ 2. Choose the structural frame that BEST captures the pattern:
2117
+ - "goal-constraint-outcome": [goal] + [constraint] \u2192 [outcome]
2118
+ - "feedback-loop": [action] \u2192 [effect] \u2192 [feeds back to action]
2119
+ - "causal-chain": [A] causes [B] causes [C]
2120
+ - "tradeoff": [optimizing X] at the expense of [Y]
2121
+ - "recursive": [pattern] contains smaller instances of [same pattern]
2122
+ - "freeform": describe the structure in your own terms
2123
+ 3. Express the common structure using your chosen frame
2124
+ 4. Rate structural depth (1-5): 1=surface, 3=causal chain, 5=deep systematic
2125
+ 5. For each member, rate alignment (0-1) and explain the mapping in one sentence
2126
+ 6. What does this structure PREDICT in a domain not listed above?
2127
+
2128
+ Return JSON:
2129
+ {
2130
+ "common_structure": {
2131
+ "goal_type": "...",
2132
+ "constraint_type": "...",
2133
+ "outcome_type": "...",
2134
+ "template": "...",
2135
+ "structure_type": "goal-constraint-outcome" | "feedback-loop" | "causal-chain" | "tradeoff" | "recursive" | "freeform",
2136
+ "freeform_structure": "..." (only if structure_type is "freeform")
2137
+ } | null,
2138
+ "structural_depth": N,
2139
+ "member_alignments": [{ "engram_id": "...", "alignment_score": N, "mapping_rationale": "..." }],
2140
+ "candidate_inferences": ["..."]
2141
+ }
2142
+
2143
+ If the commonality is shallow or trivially obvious (e.g., "mistakes happen", "always be careful"), return null for common_structure. We prefer no extraction over a false abstraction.
2144
+ Return ONLY valid JSON, no markdown fencing.`;
2145
+ try {
2146
+ const response = await llm(prompt);
2147
+ const cleaned = response.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
2148
+ if (cleaned === "null" || cleaned === '{"common_structure": null}') return null;
2149
+ const parsed = JSON.parse(cleaned);
2150
+ if (!parsed.common_structure) return null;
2151
+ if (parsed.structural_depth < 2) return null;
2152
+ if (isPlatitude(parsed.common_structure.template)) return null;
2153
+ if (parsed.common_structure.template.length < 30) return null;
2154
+ const alignments = parsed.member_alignments ?? [];
2155
+ const lowAlignments = alignments.filter((a) => a.alignment_score < 0.5);
2156
+ if (lowAlignments.length > alignments.length / 2) return null;
2157
+ return {
2158
+ cluster_id: cluster.cluster_id,
2159
+ common_structure: parsed.common_structure,
2160
+ member_alignments: alignments,
2161
+ structural_depth: parsed.structural_depth,
2162
+ systematicity: parsed.structural_depth,
2163
+ // Use depth as systematicity proxy
2164
+ candidate_inferences: parsed.candidate_inferences ?? []
2165
+ };
2166
+ } catch {
2167
+ return null;
2168
+ }
2169
+ }
2170
+
2171
+ // src/meta/formulation.ts
2172
+ var PIPELINE_VERSION = "1.0.0";
2173
+ function slugifyTemplate(template) {
2174
+ return template.toLowerCase().replace(/[\[\]→+]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
2175
+ }
2176
+ function isDuplicate(template, existingMetas) {
2177
+ for (const meta of existingMetas) {
2178
+ const metaField = meta.structured_data?.meta;
2179
+ if (!metaField?.structure?.template) continue;
2180
+ const sim = tokenSimilarity(template, metaField.structure.template);
2181
+ if (sim > 0.9) return meta;
2182
+ }
2183
+ return null;
2184
+ }
2185
+ async function formulateMetaEngram(alignment, llm, existingMetas = [], domains = []) {
2186
+ const { common_structure, member_alignments, structural_depth, candidate_inferences } = alignment;
2187
+ if (isPlatitude(common_structure.template)) return null;
2188
+ const memberSummary = member_alignments.map((m) => ` - ${m.engram_id}: ${sanitizeForPrompt(m.mapping_rationale)} (alignment: ${m.alignment_score})`).join("\n");
2189
+ const prompt = `Structural principle: ${sanitizeForPrompt(common_structure.template)}
2190
+ Goal type: ${common_structure.goal_type}
2191
+ Constraint type: ${common_structure.constraint_type}
2192
+ Outcome type: ${common_structure.outcome_type}
2193
+ Structural depth: ${structural_depth}
2194
+ Evidence from members:
2195
+ ${memberSummary}
2196
+ Candidate inferences: ${candidate_inferences.map(sanitizeForPrompt).join(", ")}
2197
+
2198
+ Generate:
2199
+ 1. A natural-language statement of this principle (1-2 sentences, precise, not generic)
2200
+ 2. Conditions under which it holds (expected_conditions)
2201
+ 3. Conditions under which it does NOT hold (expected_exceptions)
2202
+ 4. A concrete test: pick a domain NOT in the evidence list, describe a scenario where this principle predicts a specific outcome (test_prediction)
2203
+
2204
+ The statement must be specific enough to be FALSIFIABLE. If you cannot write falsification criteria, return null.
2205
+
2206
+ Return JSON:
2207
+ {
2208
+ "statement": "...",
2209
+ "falsification": {
2210
+ "expected_conditions": "...",
2211
+ "expected_exceptions": "...",
2212
+ "test_prediction": "..."
2213
+ }
2214
+ }
2215
+
2216
+ Or return null if the principle is too vague to falsify.
2217
+ Return ONLY valid JSON, no markdown fencing.`;
2218
+ let parsed;
2219
+ try {
2220
+ const response = await llm(prompt);
2221
+ const cleaned = response.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
2222
+ if (cleaned === "null") return null;
2223
+ parsed = JSON.parse(cleaned);
2224
+ } catch {
2225
+ return null;
2226
+ }
2227
+ if (!parsed || !parsed.statement || !parsed.falsification) return null;
2228
+ if (!parsed.falsification.expected_conditions || !parsed.falsification.expected_exceptions) return null;
2229
+ const duplicate = isDuplicate(common_structure.template, existingMetas);
2230
+ if (duplicate) {
2231
+ return null;
2232
+ }
2233
+ const evidenceCount = member_alignments.length;
2234
+ const domainCount = domains.length > 0 ? domains.length : 1;
2235
+ const validationRatio = 0;
2236
+ const composite = computeMetaConfidence(evidenceCount, domainCount, structural_depth, validationRatio);
2237
+ const slug = slugifyTemplate(common_structure.template);
2238
+ const id = `META-${slug}`;
2239
+ const evidence = member_alignments.map((ma) => ({
2240
+ engram_id: ma.engram_id,
2241
+ domain: "unknown",
2242
+ // Will be enriched by pipeline orchestrator
2243
+ mapping_rationale: ma.mapping_rationale,
2244
+ alignment_score: ma.alignment_score
2245
+ }));
2246
+ const metaField = {
2247
+ structure: common_structure,
2248
+ evidence,
2249
+ domain_coverage: {
2250
+ validated: [],
2251
+ failed: [],
2252
+ predicted: candidate_inferences
2253
+ },
2254
+ falsification: parsed.falsification,
2255
+ confidence: {
2256
+ evidence_count: evidenceCount,
2257
+ domain_count: domainCount,
2258
+ structural_depth,
2259
+ validation_ratio: validationRatio,
2260
+ composite
2261
+ },
2262
+ hierarchy: {
2263
+ level: domainCount >= 3 ? "top" : "mop",
2264
+ parent: null,
2265
+ children: []
2266
+ },
2267
+ pipeline_version: PIPELINE_VERSION
2268
+ };
2269
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2270
+ const engram = {
2271
+ id,
2272
+ version: 2,
2273
+ status: "active",
2274
+ consolidated: false,
2275
+ type: "behavioral",
2276
+ scope: "global",
2277
+ visibility: "private",
2278
+ statement: parsed.statement,
2279
+ domain: "meta",
2280
+ tags: ["meta-engram", common_structure.goal_type, common_structure.constraint_type],
2281
+ activation: {
2282
+ retrieval_strength: composite,
2283
+ storage_strength: 1,
2284
+ frequency: 0,
2285
+ last_accessed: now.slice(0, 10)
2286
+ },
2287
+ feedback_signals: { positive: 0, negative: 0, neutral: 0 },
2288
+ knowledge_anchors: [],
2289
+ associations: [],
2290
+ derivation_count: evidenceCount,
2291
+ pack: null,
2292
+ abstract: null,
2293
+ derived_from: null,
2294
+ polarity: null,
2295
+ knowledge_type: {
2296
+ memory_class: "metacognitive",
2297
+ cognitive_level: "evaluate"
2298
+ },
2299
+ structured_data: { meta: metaField }
2300
+ };
2301
+ return engram;
2302
+ }
2303
+
2304
+ // src/meta/validation.ts
2305
+ async function validateMetaEngram(meta, testEngrams, testDomain, llm) {
2306
+ const metaField = meta.structured_data?.meta;
2307
+ if (!metaField) {
2308
+ return {
2309
+ meta_engram_id: meta.id,
2310
+ test_domain: testDomain,
2311
+ prediction_held: false,
2312
+ matching_engram_id: null,
2313
+ alignment_score: 0,
2314
+ rationale: "Meta-engram has no meta field"
2315
+ };
2316
+ }
2317
+ const template = metaField.structure.template;
2318
+ const testEngramSummary = testEngrams.filter((e) => e.status === "active").slice(0, 10).map((e) => ` - [${e.id}] ${sanitizeForPrompt(e.statement)}`).join("\n");
2319
+ if (!testEngramSummary) {
2320
+ return {
2321
+ meta_engram_id: meta.id,
2322
+ test_domain: testDomain,
2323
+ prediction_held: false,
2324
+ matching_engram_id: null,
2325
+ alignment_score: 0,
2326
+ rationale: "No test engrams available for validation"
2327
+ };
2328
+ }
2329
+ const prompt = `Meta-engram structural principle: ${sanitizeForPrompt(template)}
2330
+ Meta-engram statement: ${sanitizeForPrompt(meta.statement)}
2331
+
2332
+ Test domain: ${testDomain}
2333
+ Test engrams from this domain:
2334
+ ${testEngramSummary}
2335
+
2336
+ Task: Does any of the test engrams instantiate or validate this structural principle?
2337
+
2338
+ If YES (a test engram matches):
2339
+ - prediction_held: true
2340
+ - matching_engram_id: the ID of the matching engram
2341
+ - alignment_score: 0.5-1.0 (how well the structural template maps)
2342
+ - rationale: one sentence explaining how the test engram maps to the template
2343
+
2344
+ If NO (no test engram matches):
2345
+ - prediction_held: false
2346
+ - matching_engram_id: null
2347
+ - alignment_score: 0
2348
+ - rationale: one sentence explaining WHY none of the test engrams match (e.g., "Test engrams cover X domain but none exhibit the structural pattern of [assumed independence] \u2192 [understated risk]")
2349
+
2350
+ Return JSON:
2351
+ {
2352
+ "prediction_held": true|false,
2353
+ "matching_engram_id": "ENG-..." | null,
2354
+ "alignment_score": 0.0-1.0,
2355
+ "rationale": "one sentence explanation \u2014 REQUIRED even when prediction_held is false"
2356
+ }
2357
+
2358
+ Return ONLY valid JSON, no markdown fencing.`;
2359
+ try {
2360
+ const response = await llm(prompt);
2361
+ const cleaned = response.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
2362
+ const parsed = JSON.parse(cleaned);
2363
+ const result = {
2364
+ meta_engram_id: meta.id,
2365
+ test_domain: testDomain,
2366
+ prediction_held: Boolean(parsed.prediction_held),
2367
+ matching_engram_id: parsed.matching_engram_id ?? null,
2368
+ alignment_score: typeof parsed.alignment_score === "number" ? parsed.alignment_score : 0,
2369
+ rationale: parsed.rationale ?? ""
2370
+ };
2371
+ if (result.prediction_held) {
2372
+ if (!metaField.domain_coverage.validated.includes(testDomain)) {
2373
+ metaField.domain_coverage.validated.push(testDomain);
2374
+ }
2375
+ } else {
2376
+ if (!metaField.domain_coverage.failed.includes(testDomain)) {
2377
+ metaField.domain_coverage.failed.push(testDomain);
2378
+ }
2379
+ }
2380
+ const passes = metaField.domain_coverage.validated.length;
2381
+ const total = passes + metaField.domain_coverage.failed.length;
2382
+ const validationRatio = total > 0 ? passes / total : 0;
2383
+ const updatedComposite = computeMetaConfidence(
2384
+ metaField.confidence.evidence_count,
2385
+ metaField.confidence.domain_count,
2386
+ metaField.confidence.structural_depth,
2387
+ validationRatio
2388
+ );
2389
+ metaField.confidence.validation_ratio = validationRatio;
2390
+ metaField.confidence.composite = updatedComposite;
2391
+ metaField.last_validated = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2392
+ const failedCount = metaField.domain_coverage.failed.length;
2393
+ if (failedCount >= 3) {
2394
+ if (metaField.hierarchy.level === "top") {
2395
+ metaField.hierarchy.level = "mop";
2396
+ } else {
2397
+ meta.status = "retired";
2398
+ }
2399
+ }
2400
+ return result;
2401
+ } catch {
2402
+ return {
2403
+ meta_engram_id: meta.id,
2404
+ test_domain: testDomain,
2405
+ prediction_held: false,
2406
+ matching_engram_id: null,
2407
+ alignment_score: 0,
2408
+ rationale: "LLM parsing failed during validation"
2409
+ };
2410
+ }
2411
+ }
2412
+
2413
+ // src/meta/hierarchy.ts
2414
+ var SUBSUMPTION_THRESHOLD = 0.75;
2415
+ function getMetaField(engram) {
2416
+ return engram.structured_data?.meta ?? null;
2417
+ }
2418
+ function getDomainCount(metaField) {
2419
+ const validated = metaField.domain_coverage.validated.length;
2420
+ const evidenceDomains = new Set(metaField.evidence.map((e) => e.domain)).size;
2421
+ return Math.max(validated, evidenceDomains, metaField.confidence.domain_count);
2422
+ }
2423
+ function organizeHierarchy(metaEngrams) {
2424
+ const metas = metaEngrams.filter((e) => getMetaField(e) !== null && e.id.startsWith("META-"));
2425
+ if (metas.length === 0) return metaEngrams;
2426
+ for (const meta of metas) {
2427
+ const mf = getMetaField(meta);
2428
+ mf.hierarchy.parent = null;
2429
+ mf.hierarchy.children = [];
2430
+ }
2431
+ for (let i = 0; i < metas.length; i++) {
2432
+ for (let j = 0; j < metas.length; j++) {
2433
+ if (i === j) continue;
2434
+ const mfI = getMetaField(metas[i]);
2435
+ const mfJ = getMetaField(metas[j]);
2436
+ const sim = tokenSimilarity(mfI.structure.template, mfJ.structure.template);
2437
+ if (sim < SUBSUMPTION_THRESHOLD) continue;
2438
+ const domainsI = getDomainCount(mfI);
2439
+ const domainsJ = getDomainCount(mfJ);
2440
+ if (domainsI > domainsJ) {
2441
+ if (!mfI.hierarchy.children.includes(metas[j].id)) {
2442
+ mfI.hierarchy.children.push(metas[j].id);
2443
+ }
2444
+ if (!mfJ.hierarchy.parent) {
2445
+ mfJ.hierarchy.parent = metas[i].id;
2446
+ } else {
2447
+ const currentParent = metas.find((m) => m.id === mfJ.hierarchy.parent);
2448
+ const currentParentMf = currentParent ? getMetaField(currentParent) : null;
2449
+ if (currentParentMf && getDomainCount(currentParentMf) < domainsI) {
2450
+ mfJ.hierarchy.parent = metas[i].id;
2451
+ }
2452
+ }
2453
+ }
2454
+ }
2455
+ }
2456
+ for (const meta of metas) {
2457
+ const mf = getMetaField(meta);
2458
+ const domains = getDomainCount(mf);
2459
+ if (domains >= 3 && !mf.hierarchy.parent) {
2460
+ mf.hierarchy.level = "top";
2461
+ } else {
2462
+ mf.hierarchy.level = "mop";
2463
+ }
2464
+ }
2465
+ return metaEngrams;
2466
+ }
2467
+
2468
+ // src/meta/pipeline.ts
2469
+ async function extractMetaEngrams(engrams, llm, options = {}) {
2470
+ const start = Date.now();
2471
+ const {
2472
+ run_validation = false,
2473
+ validation_engrams = [],
2474
+ existing_metas = [],
2475
+ min_cluster_size = 2
2476
+ } = options;
2477
+ let rejected_as_platitudes = 0;
2478
+ const analyses = await analyzeStructure(engrams, llm);
2479
+ const clusters = await clusterByStructure(analyses);
2480
+ const viableClusters = clusters.filter((c) => c.members.length >= min_cluster_size);
2481
+ const alignmentResults = await Promise.all(
2482
+ viableClusters.map((cluster) => alignCluster(cluster, llm))
2483
+ );
2484
+ const validAlignments = alignmentResults.filter((r) => r !== null);
2485
+ const formulated = [];
2486
+ for (const alignment of validAlignments) {
2487
+ const cluster = viableClusters.find((c) => c.cluster_id === alignment.cluster_id);
2488
+ const clusterDomains = cluster ? [...new Set(cluster.members.map((m) => m.domain))] : [];
2489
+ const meta = await formulateMetaEngram(alignment, llm, [...existing_metas, ...formulated], clusterDomains);
2490
+ if (meta === null) {
2491
+ rejected_as_platitudes++;
2492
+ } else {
2493
+ if (cluster) {
2494
+ const metaField = meta.structured_data?.meta;
2495
+ if (metaField) {
2496
+ const domainMap = new Map(cluster.members.map((m) => [m.engram_id, m.domain]));
2497
+ for (const ev of metaField.evidence) {
2498
+ if (domainMap.has(ev.engram_id)) {
2499
+ ev.domain = domainMap.get(ev.engram_id);
2500
+ }
2501
+ }
2502
+ metaField.domain_coverage.validated = clusterDomains;
2503
+ meta.domain = clusterDomains.length >= 3 ? "meta" : `meta.${clusterDomains[0] ?? "unknown"}`;
2504
+ }
2505
+ }
2506
+ formulated.push(meta);
2507
+ }
2508
+ }
2509
+ const validationResults = [];
2510
+ if (run_validation && validation_engrams.length > 0) {
2511
+ for (const meta of formulated) {
2512
+ const metaField = meta.structured_data?.meta;
2513
+ if (!metaField) continue;
2514
+ const evidenceDomains = new Set(metaField.evidence.map((e) => e.domain));
2515
+ const testEngrams = validation_engrams.filter((e) => !evidenceDomains.has(e.domain ?? ""));
2516
+ if (testEngrams.length > 0) {
2517
+ const byDomain = /* @__PURE__ */ new Map();
2518
+ for (const te of testEngrams) {
2519
+ const d = te.domain ?? "unknown";
2520
+ if (!byDomain.has(d)) byDomain.set(d, []);
2521
+ byDomain.get(d).push(te);
2522
+ }
2523
+ for (const [domain, domainEngrams] of byDomain) {
2524
+ const vr = await validateMetaEngram(meta, domainEngrams, domain, llm);
2525
+ validationResults.push(vr);
2526
+ }
2527
+ }
2528
+ }
2529
+ }
2530
+ const organized = organizeHierarchy(formulated);
2531
+ const duration_ms = Date.now() - start;
2532
+ return {
2533
+ engrams_analyzed: analyses.length,
2534
+ clusters_found: clusters.length,
2535
+ alignments_passed: validAlignments.length,
2536
+ meta_engrams_extracted: organized.length,
2537
+ rejected_as_platitudes,
2538
+ validation_results: validationResults,
2539
+ results: organized,
2540
+ duration_ms
2541
+ };
2542
+ }
2543
+
2544
+ // src/session-state.ts
2545
+ var SessionBreadcrumbs = class {
2546
+ toolCalls = [];
2547
+ engramsRecalled = [];
2548
+ recordToolCall(tool, args) {
2549
+ this.toolCalls.push({
2550
+ tool,
2551
+ args_keys: Object.keys(args).join(", "),
2552
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
2553
+ });
2554
+ }
2555
+ recordEngramRecalled(engramId) {
2556
+ if (!this.engramsRecalled.includes(engramId)) {
2557
+ this.engramsRecalled.push(engramId);
2558
+ }
2559
+ }
2560
+ getToolCalls() {
2561
+ return this.toolCalls;
2562
+ }
2563
+ getEngramsRecalled() {
2564
+ return this.engramsRecalled;
2565
+ }
2566
+ /**
2567
+ * Returns only engram IDs that have the META- prefix.
2568
+ * These represent meta-engrams injected into the session context.
2569
+ */
2570
+ getMetaEngramsRecalled() {
2571
+ return this.engramsRecalled.filter((id) => id.startsWith("META-"));
2572
+ }
2573
+ generateContinuationContext() {
2574
+ if (this.toolCalls.length === 0 && this.engramsRecalled.length === 0) return "";
2575
+ const lines = [];
2576
+ if (this.toolCalls.length > 0) {
2577
+ const uniqueTools = [...new Set(this.toolCalls.map((tc) => tc.tool))];
2578
+ lines.push(`Tools used: ${uniqueTools.join(", ")}`);
2579
+ lines.push(`Total tool calls: ${this.toolCalls.length}`);
2580
+ }
2581
+ if (this.engramsRecalled.length > 0) {
2582
+ lines.push(`Engrams recalled: ${this.engramsRecalled.length}`);
2583
+ const metaCount = this.getMetaEngramsRecalled().length;
2584
+ if (metaCount > 0) {
2585
+ lines.push(`Meta-engrams: ${metaCount}`);
2586
+ }
2587
+ }
2588
+ return lines.join("\n");
2589
+ }
2590
+ };
2591
+
2592
+ // src/guardrails.ts
2593
+ function generateGuardrails() {
2594
+ return `## PLUR Memory Guardrails
2595
+
2596
+ ### Verification Protocol
2597
+ When recalling facts that will drive actions (server IPs, file paths, API endpoints, credential locations):
2598
+ 1. State the recalled fact explicitly before acting on it
2599
+ 2. Include the engram ID or search that produced it
2600
+ 3. If no engram matches, say "No engram found \u2014 verifying from filesystem" and check directly
2601
+ 4. Never interpolate between two engrams to produce a "probably correct" composite
2602
+
2603
+ When the user corrects a recalled fact: call plur.learn immediately, then plur.feedback with negative signal on the wrong engram, before continuing the task.
2604
+
2605
+ ### Over-engineering Check
2606
+ Before proposing any new system, module, or architectural change:
2607
+ 1. What is the simplest version that solves the actual problem?
2608
+ 2. Is there an existing tool/pattern that already covers 80% of this?
2609
+ 3. Will this create maintenance burden disproportionate to its value?
2610
+
2611
+ If a task can be done in <20 lines of shell script, do that first.
2612
+
2613
+ ### Tool Selection Discipline
2614
+ Before invoking any external tool, apply the locality test:
2615
+ 1. Is the answer already in engrams? \u2192 plur.recall
2616
+ 2. Is the answer in the local filesystem? \u2192 Read/Grep/Glob
2617
+ 3. Is the answer derivable from context already loaded? \u2192 Just answer
2618
+ 4. Only if 1-3 fail \u2192 Use external tools
2619
+
2620
+ Meta-engrams flagged as "[structural transfer \u2014 untested in current domain]" are hypotheses, not rules. Test before applying.`;
2621
+ }
2622
+
2623
+ // src/schemas/meta-engram.ts
2624
+ import { z as z4 } from "zod";
2625
+ var StructuralTemplateSchema = z4.object({
2626
+ goal_type: z4.string().min(1),
2627
+ constraint_type: z4.string().min(1),
2628
+ outcome_type: z4.string().min(1),
2629
+ template: z4.string().min(1),
2630
+ /** Structural frame — declares which relational pattern this meta-engram uses.
2631
+ * Allows flexible analogy beyond rigid [goal]+[constraint]->[outcome]. */
2632
+ structure_type: z4.enum([
2633
+ "goal-constraint-outcome",
2634
+ "feedback-loop",
2635
+ "causal-chain",
2636
+ "recursive",
2637
+ "tradeoff",
2638
+ "freeform"
2639
+ ]).default("goal-constraint-outcome"),
2640
+ /** For patterns that don't fit the standard template fields — the LLM's own structural description */
2641
+ freeform_structure: z4.string().optional()
2642
+ });
2643
+ var EvidenceEntrySchema = z4.object({
2644
+ engram_id: z4.string(),
2645
+ domain: z4.string(),
2646
+ mapping_rationale: z4.string(),
2647
+ alignment_score: z4.number().min(0).max(1)
2648
+ });
2649
+ var FalsificationSchema = z4.object({
2650
+ expected_conditions: z4.string(),
2651
+ expected_exceptions: z4.string(),
2652
+ test_prediction: z4.string().optional()
2653
+ });
2654
+ var MetaConfidenceSchema = z4.object({
2655
+ evidence_count: z4.number().int().min(0),
2656
+ domain_count: z4.number().int().min(0),
2657
+ structural_depth: z4.number().int().min(1).max(5),
2658
+ validation_ratio: z4.number().min(0).max(1).default(0),
2659
+ composite: z4.number().min(0).max(1)
2660
+ });
2661
+ var DomainCoverageSchema = z4.object({
2662
+ validated: z4.array(z4.string()),
2663
+ failed: z4.array(z4.string()).default([]),
2664
+ predicted: z4.array(z4.string()).default([])
2665
+ });
2666
+ var HierarchyPositionSchema = z4.object({
2667
+ level: z4.enum(["mop", "top"]),
2668
+ parent: z4.string().nullable().default(null),
2669
+ children: z4.array(z4.string()).default([])
2670
+ });
2671
+ var MetaFieldSchema = z4.object({
2672
+ structure: StructuralTemplateSchema,
2673
+ evidence: z4.array(EvidenceEntrySchema).min(2),
2674
+ domain_coverage: DomainCoverageSchema,
2675
+ falsification: FalsificationSchema,
2676
+ confidence: MetaConfidenceSchema,
2677
+ hierarchy: HierarchyPositionSchema,
2678
+ pipeline_version: z4.string(),
2679
+ last_validated: z4.string().optional()
2680
+ });
2681
+
1186
2682
  // src/version-check.ts
1187
2683
  var cache = /* @__PURE__ */ new Map();
1188
2684
  async function checkForUpdate(packageName, currentVersion, onResult) {
@@ -1245,53 +2741,67 @@ var INGEST_PATTERNS = [
1245
2741
  var Plur = class {
1246
2742
  paths;
1247
2743
  config;
2744
+ indexedStorage = null;
1248
2745
  constructor(options) {
1249
2746
  this.paths = detectPlurStorage(options?.path);
1250
2747
  this.config = loadConfig(this.paths.config);
2748
+ if (this.config.index) {
2749
+ this.indexedStorage = new IndexedStorage(this.paths.engrams, this.paths.db);
2750
+ }
1251
2751
  }
1252
2752
  /** Create engram, detect conflicts, save. Returns the created engram. */
1253
2753
  learn(statement, context) {
1254
- const engrams = loadEngrams(this.paths.engrams);
1255
- const id = generateEngramId(engrams);
1256
- const scope = context?.scope ?? "global";
1257
- const now = (/* @__PURE__ */ new Date()).toISOString();
1258
- const conflictingEngrams = detectConflicts({ statement, scope }, engrams);
1259
- const conflictIds = conflictingEngrams.map((e) => e.id);
1260
- const engram = {
1261
- id,
1262
- version: 2,
1263
- status: "active",
1264
- consolidated: false,
1265
- type: context?.type ?? "behavioral",
1266
- scope,
1267
- visibility: "private",
1268
- statement,
1269
- source: context?.source,
1270
- domain: context?.domain,
1271
- activation: {
1272
- retrieval_strength: 0.7,
1273
- storage_strength: 1,
1274
- frequency: 0,
1275
- last_accessed: now.slice(0, 10)
1276
- },
1277
- feedback_signals: { positive: 0, negative: 0, neutral: 0 },
1278
- knowledge_anchors: [],
1279
- associations: [],
1280
- derivation_count: 1,
1281
- tags: [],
1282
- pack: null,
1283
- abstract: null,
1284
- derived_from: null,
1285
- relations: conflictIds.length > 0 ? {
1286
- broader: [],
1287
- narrower: [],
1288
- related: [],
1289
- conflicts: conflictIds
1290
- } : void 0
1291
- };
1292
- engrams.push(engram);
1293
- saveEngrams(this.paths.engrams, engrams);
1294
- return engram;
2754
+ if (!this.config.allow_secrets) {
2755
+ const secrets = detectSecrets(statement);
2756
+ if (secrets.length > 0) {
2757
+ throw new Error(`Secret detected in statement: ${secrets[0].pattern}. Use config.allow_secrets to override.`);
2758
+ }
2759
+ }
2760
+ return withLock(this.paths.engrams, () => {
2761
+ const engrams = loadEngrams(this.paths.engrams);
2762
+ const id = generateEngramId(engrams);
2763
+ const scope = context?.scope ?? "global";
2764
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2765
+ const conflictingEngrams = detectConflicts({ statement, scope }, engrams);
2766
+ const conflictIds = conflictingEngrams.map((e) => e.id);
2767
+ const engram = {
2768
+ id,
2769
+ version: 2,
2770
+ status: "active",
2771
+ consolidated: false,
2772
+ type: context?.type ?? "behavioral",
2773
+ scope,
2774
+ visibility: "private",
2775
+ statement,
2776
+ source: context?.source,
2777
+ domain: context?.domain,
2778
+ activation: {
2779
+ retrieval_strength: 0.7,
2780
+ storage_strength: 1,
2781
+ frequency: 0,
2782
+ last_accessed: now.slice(0, 10)
2783
+ },
2784
+ feedback_signals: { positive: 0, negative: 0, neutral: 0 },
2785
+ knowledge_anchors: [],
2786
+ associations: [],
2787
+ derivation_count: 1,
2788
+ tags: [],
2789
+ pack: null,
2790
+ abstract: null,
2791
+ derived_from: null,
2792
+ polarity: null,
2793
+ relations: conflictIds.length > 0 ? {
2794
+ broader: [],
2795
+ narrower: [],
2796
+ related: [],
2797
+ conflicts: conflictIds
2798
+ } : void 0
2799
+ };
2800
+ engrams.push(engram);
2801
+ saveEngrams(this.paths.engrams, engrams);
2802
+ this._syncIndex();
2803
+ return engram;
2804
+ });
1295
2805
  }
1296
2806
  /**
1297
2807
  * Search engrams, filter by scope/domain/strength, reactivate accessed.
@@ -1339,39 +2849,95 @@ var Plur = class {
1339
2849
  this._reactivateResults(results);
1340
2850
  return results;
1341
2851
  }
2852
+ /** List all active engrams, optionally filtered by scope/domain. No search — returns all matches. */
2853
+ list(options) {
2854
+ return this._filterEngrams(options);
2855
+ }
1342
2856
  /** Filter engrams by scope/domain/strength (shared by both modes) */
1343
2857
  _filterEngrams(options) {
1344
- let engrams = loadEngrams(this.paths.engrams);
1345
- engrams = engrams.filter((e) => e.status === "active");
1346
- if (options?.domain) {
1347
- engrams = engrams.filter((e) => e.domain?.startsWith(options.domain));
2858
+ let engrams;
2859
+ if (this.indexedStorage) {
2860
+ engrams = this.indexedStorage.loadFiltered({
2861
+ status: "active",
2862
+ scope: options?.scope,
2863
+ domain: options?.domain
2864
+ });
2865
+ } else {
2866
+ engrams = loadEngrams(this.paths.engrams);
2867
+ engrams = engrams.filter((e) => e.status === "active");
2868
+ if (options?.domain) {
2869
+ engrams = engrams.filter((e) => e.domain?.startsWith(options.domain));
2870
+ }
2871
+ if (options?.scope) {
2872
+ const scope = options.scope;
2873
+ engrams = engrams.filter(
2874
+ (e) => e.scope === "global" || e.scope === scope || e.scope.startsWith(scope)
2875
+ );
2876
+ }
1348
2877
  }
2878
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2879
+ engrams = engrams.filter((e) => {
2880
+ if (e.temporal?.valid_until && e.temporal.valid_until < today) return false;
2881
+ if (e.temporal?.valid_from && e.temporal.valid_from > today) return false;
2882
+ return true;
2883
+ });
1349
2884
  if (options?.min_strength !== void 0) {
1350
2885
  engrams = engrams.filter((e) => e.activation.retrieval_strength >= options.min_strength);
1351
2886
  }
1352
- if (options?.scope) {
1353
- const scope = options.scope;
1354
- engrams = engrams.filter(
1355
- (e) => e.scope === "global" || e.scope === scope || e.scope.startsWith(scope)
1356
- );
1357
- }
1358
2887
  return engrams;
1359
2888
  }
1360
- /** Reactivate accessed engrams (bump retrieval strength, frequency, last_accessed) */
2889
+ /** Reactivate accessed engrams and update co-access associations */
1361
2890
  _reactivateResults(results) {
1362
2891
  if (results.length === 0) return;
1363
- const allEngrams = loadEngrams(this.paths.engrams);
1364
- const resultIds = new Set(results.map((e) => e.id));
1365
- let modified = false;
1366
- for (const e of allEngrams) {
1367
- if (resultIds.has(e.id)) {
1368
- e.activation.retrieval_strength = reactivate(e.activation.retrieval_strength);
1369
- e.activation.last_accessed = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
1370
- e.activation.frequency += 1;
1371
- modified = true;
2892
+ withLock(this.paths.engrams, () => {
2893
+ const allEngrams = loadEngrams(this.paths.engrams);
2894
+ const resultIds = new Set(results.map((e) => e.id));
2895
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
2896
+ let modified = false;
2897
+ for (const e of allEngrams) {
2898
+ if (resultIds.has(e.id)) {
2899
+ e.activation.retrieval_strength = reactivate(e.activation.retrieval_strength);
2900
+ e.activation.last_accessed = today;
2901
+ e.activation.frequency += 1;
2902
+ modified = true;
2903
+ }
1372
2904
  }
1373
- }
1374
- if (modified) saveEngrams(this.paths.engrams, allEngrams);
2905
+ if (results.length >= 2 && this.config.injection?.co_access !== false) {
2906
+ const topHalf = results.slice(0, Math.max(2, Math.ceil(results.length / 2)));
2907
+ const topIds = topHalf.map((e) => e.id);
2908
+ for (const sourceId of topIds) {
2909
+ const source = allEngrams.find((e) => e.id === sourceId);
2910
+ if (!source) continue;
2911
+ for (const targetId of topIds) {
2912
+ if (targetId === sourceId) continue;
2913
+ const existing = source.associations.find(
2914
+ (a) => a.type === "co_accessed" && a.target === targetId
2915
+ );
2916
+ if (existing) {
2917
+ existing.strength = Math.min(0.95, existing.strength + 0.05);
2918
+ existing.updated_at = today;
2919
+ modified = true;
2920
+ } else {
2921
+ const coAccessCount = source.associations.filter((a) => a.type === "co_accessed").length;
2922
+ if (coAccessCount < 5) {
2923
+ source.associations.push({
2924
+ target_type: "engram",
2925
+ target: targetId,
2926
+ type: "co_accessed",
2927
+ strength: 0.3,
2928
+ updated_at: today
2929
+ });
2930
+ modified = true;
2931
+ }
2932
+ }
2933
+ }
2934
+ }
2935
+ }
2936
+ if (modified) {
2937
+ saveEngrams(this.paths.engrams, allEngrams);
2938
+ this._syncIndex();
2939
+ }
2940
+ });
1375
2941
  }
1376
2942
  /** Scored injection within token budget (BM25 only). Returns formatted strings. */
1377
2943
  inject(task, options) {
@@ -1416,11 +2982,13 @@ var Plur = class {
1416
2982
  return wires.map((e) => `[${e.id}] ${e.statement}`).join("\n");
1417
2983
  };
1418
2984
  const directivesStr = formatEngrams(result.directives);
2985
+ const constraintsStr = formatEngrams(result.constraints);
1419
2986
  const considerStr = formatEngrams(result.consider);
1420
- const count = result.directives.length + result.consider.length;
2987
+ const count = result.directives.length + result.constraints.length + result.consider.length;
1421
2988
  const tokensUsed = result.tokens_used.directives + result.tokens_used.consider;
1422
2989
  return {
1423
2990
  directives: directivesStr,
2991
+ constraints: constraintsStr,
1424
2992
  consider: considerStr,
1425
2993
  count,
1426
2994
  tokens_used: tokensUsed
@@ -1428,30 +2996,96 @@ var Plur = class {
1428
2996
  }
1429
2997
  /** Update feedback_signals and adjust retrieval_strength. */
1430
2998
  feedback(id, signal) {
1431
- const engrams = loadEngrams(this.paths.engrams);
1432
- const engram = engrams.find((e) => e.id === id);
1433
- if (!engram) throw new Error(`Engram not found: ${id}`);
1434
- if (!engram.feedback_signals) {
1435
- engram.feedback_signals = { positive: 0, negative: 0, neutral: 0 };
1436
- }
1437
- engram.feedback_signals[signal] += 1;
1438
- if (signal === "positive") {
1439
- engram.activation.retrieval_strength = Math.min(1, engram.activation.retrieval_strength + 0.05);
1440
- } else if (signal === "negative") {
1441
- engram.activation.retrieval_strength = Math.max(0, engram.activation.retrieval_strength - 0.1);
1442
- }
1443
- saveEngrams(this.paths.engrams, engrams);
2999
+ withLock(this.paths.engrams, () => {
3000
+ const engrams = loadEngrams(this.paths.engrams);
3001
+ const engram = engrams.find((e) => e.id === id);
3002
+ if (!engram) throw new Error(`Engram not found: ${id}`);
3003
+ if (!engram.feedback_signals) {
3004
+ engram.feedback_signals = { positive: 0, negative: 0, neutral: 0 };
3005
+ }
3006
+ engram.feedback_signals[signal] += 1;
3007
+ if (signal === "positive") {
3008
+ engram.activation.retrieval_strength = Math.min(1, engram.activation.retrieval_strength + 0.05);
3009
+ } else if (signal === "negative") {
3010
+ engram.activation.retrieval_strength = Math.max(0, engram.activation.retrieval_strength - 0.1);
3011
+ }
3012
+ saveEngrams(this.paths.engrams, engrams);
3013
+ this._syncIndex();
3014
+ });
3015
+ }
3016
+ /** Save extracted meta-engrams to the engram store. Skips IDs that already exist. */
3017
+ saveMetaEngrams(metas) {
3018
+ return withLock(this.paths.engrams, () => {
3019
+ const engrams = loadEngrams(this.paths.engrams);
3020
+ const existingIds = new Set(engrams.map((e) => e.id));
3021
+ let saved = 0;
3022
+ let skipped = 0;
3023
+ for (const meta of metas) {
3024
+ if (existingIds.has(meta.id)) {
3025
+ skipped++;
3026
+ } else {
3027
+ engrams.push(meta);
3028
+ saved++;
3029
+ }
3030
+ }
3031
+ if (saved > 0) {
3032
+ saveEngrams(this.paths.engrams, engrams);
3033
+ this._syncIndex();
3034
+ }
3035
+ return { saved, skipped };
3036
+ });
3037
+ }
3038
+ /** Update an existing engram in the store by ID. Returns true if found and updated. */
3039
+ updateEngram(updated) {
3040
+ return withLock(this.paths.engrams, () => {
3041
+ const engrams = loadEngrams(this.paths.engrams);
3042
+ const idx = engrams.findIndex((e) => e.id === updated.id);
3043
+ if (idx === -1) return false;
3044
+ engrams[idx] = updated;
3045
+ saveEngrams(this.paths.engrams, engrams);
3046
+ this._syncIndex();
3047
+ return true;
3048
+ });
1444
3049
  }
1445
3050
  /** Set engram status to 'retired'. */
1446
3051
  forget(id, reason) {
1447
- const engrams = loadEngrams(this.paths.engrams);
1448
- const engram = engrams.find((e) => e.id === id);
1449
- if (!engram) throw new Error(`Engram not found: ${id}`);
1450
- engram.status = "retired";
1451
- if (reason && !engram.rationale) {
1452
- engram.rationale = `Retired: ${reason}`;
3052
+ withLock(this.paths.engrams, () => {
3053
+ const engrams = loadEngrams(this.paths.engrams);
3054
+ const engram = engrams.find((e) => e.id === id);
3055
+ if (!engram) throw new Error(`Engram not found: ${id}`);
3056
+ engram.status = "retired";
3057
+ if (reason && !engram.rationale) {
3058
+ engram.rationale = `Retired: ${reason}`;
3059
+ }
3060
+ saveEngrams(this.paths.engrams, engrams);
3061
+ this._syncIndex();
3062
+ });
3063
+ }
3064
+ /** Remove retired engrams from storage. Returns count of removed and remaining. */
3065
+ compact() {
3066
+ return withLock(this.paths.engrams, () => {
3067
+ const engrams = loadEngrams(this.paths.engrams);
3068
+ const active = engrams.filter((e) => e.status !== "retired");
3069
+ const removed = engrams.length - active.length;
3070
+ if (removed > 0) {
3071
+ saveEngrams(this.paths.engrams, active);
3072
+ this._syncIndex();
3073
+ }
3074
+ return { removed, remaining: active.length };
3075
+ });
3076
+ }
3077
+ /** Rebuild SQLite index from YAML source of truth. Only works when index: true. */
3078
+ reindex() {
3079
+ if (!this.indexedStorage) {
3080
+ this.indexedStorage = new IndexedStorage(this.paths.engrams, this.paths.db);
3081
+ }
3082
+ this.indexedStorage.reindex();
3083
+ }
3084
+ /** Sync SQLite index after YAML write (no-op if index disabled) */
3085
+ _syncIndex() {
3086
+ if (this.indexedStorage) {
3087
+ this.indexedStorage.syncFromYaml();
1453
3088
  }
1454
- saveEngrams(this.paths.engrams, engrams);
1455
3089
  }
1456
3090
  /** Capture an episodic memory. */
1457
3091
  capture(summary, context) {
@@ -1472,6 +3106,7 @@ var Plur = class {
1472
3106
  const captured = match.slice(1).filter(Boolean).join(" ").trim();
1473
3107
  if (!captured || captured.length < 5) continue;
1474
3108
  if (seen.has(captured.toLowerCase())) continue;
3109
+ if (!this.config.allow_secrets && detectSecrets(captured).length > 0) continue;
1475
3110
  seen.add(captured.toLowerCase());
1476
3111
  candidates.push({
1477
3112
  statement: captured,
@@ -1527,10 +3162,35 @@ var Plur = class {
1527
3162
  }
1528
3163
  };
1529
3164
  export {
3165
+ DomainCoverageSchema,
3166
+ EvidenceEntrySchema,
3167
+ FalsificationSchema,
3168
+ HierarchyPositionSchema,
3169
+ IndexedStorage,
3170
+ MetaConfidenceSchema,
3171
+ MetaFieldSchema,
3172
+ PLATITUDE_PATTERNS,
1530
3173
  Plur,
3174
+ SessionBreadcrumbs,
3175
+ StructuralTemplateSchema,
3176
+ alignCluster,
3177
+ analyzeStructure,
1531
3178
  checkForUpdate,
3179
+ classifyPolarity,
1532
3180
  clearVersionCache,
3181
+ clusterByStructure,
3182
+ computeConfidence,
3183
+ computeMetaConfidence,
3184
+ confidenceBand,
1533
3185
  detectPlurStorage,
3186
+ detectSecrets,
1534
3187
  engramSearchText,
1535
- getCachedUpdateCheck
3188
+ extractMetaEngrams,
3189
+ formulateMetaEngram,
3190
+ generateGuardrails,
3191
+ getCachedUpdateCheck,
3192
+ isPlatitude,
3193
+ organizeHierarchy,
3194
+ tokenSimilarity,
3195
+ validateMetaEngram
1536
3196
  };