@plur-ai/core 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -265,10 +265,10 @@ declare const EngramSchema: z.ZodObject<{
265
265
  }, "strip", z.ZodTypeAny, {
266
266
  type: "behavioral" | "architectural" | "procedural" | "terminological";
267
267
  status: "active" | "dormant" | "retired" | "candidate";
268
+ scope: string;
268
269
  id: string;
269
270
  version: number;
270
271
  consolidated: boolean;
271
- scope: string;
272
272
  visibility: "private" | "public" | "template";
273
273
  statement: string;
274
274
  derivation_count: number;
@@ -359,8 +359,8 @@ declare const EngramSchema: z.ZodObject<{
359
359
  }, {
360
360
  type: "behavioral" | "architectural" | "procedural" | "terminological";
361
361
  status: "active" | "dormant" | "retired" | "candidate";
362
- id: string;
363
362
  scope: string;
363
+ id: string;
364
364
  statement: string;
365
365
  version?: number | undefined;
366
366
  consolidated?: boolean | undefined;
@@ -595,6 +595,23 @@ declare const EpisodeSchema: z.ZodObject<{
595
595
  }>;
596
596
  type Episode = z.infer<typeof EpisodeSchema>;
597
597
 
598
+ declare const StoreEntrySchema: z.ZodObject<{
599
+ path: z.ZodString;
600
+ scope: z.ZodString;
601
+ shared: z.ZodDefault<z.ZodBoolean>;
602
+ readonly: z.ZodDefault<z.ZodBoolean>;
603
+ }, "strip", z.ZodTypeAny, {
604
+ path: string;
605
+ scope: string;
606
+ shared: boolean;
607
+ readonly: boolean;
608
+ }, {
609
+ path: string;
610
+ scope: string;
611
+ shared?: boolean | undefined;
612
+ readonly?: boolean | undefined;
613
+ }>;
614
+ type StoreEntry = z.infer<typeof StoreEntrySchema>;
598
615
  declare const PlurConfigSchema: z.ZodObject<{
599
616
  auto_learn: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
600
617
  auto_capture: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
@@ -617,6 +634,22 @@ declare const PlurConfigSchema: z.ZodObject<{
617
634
  }>>>;
618
635
  allow_secrets: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
619
636
  index: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
637
+ stores: z.ZodOptional<z.ZodDefault<z.ZodArray<z.ZodObject<{
638
+ path: z.ZodString;
639
+ scope: z.ZodString;
640
+ shared: z.ZodDefault<z.ZodBoolean>;
641
+ readonly: z.ZodDefault<z.ZodBoolean>;
642
+ }, "strip", z.ZodTypeAny, {
643
+ path: string;
644
+ scope: string;
645
+ shared: boolean;
646
+ readonly: boolean;
647
+ }, {
648
+ path: string;
649
+ scope: string;
650
+ shared?: boolean | undefined;
651
+ readonly?: boolean | undefined;
652
+ }>, "many">>>;
620
653
  }, "strip", z.ZodTypeAny, {
621
654
  auto_learn?: boolean | undefined;
622
655
  auto_capture?: boolean | undefined;
@@ -631,6 +664,12 @@ declare const PlurConfigSchema: z.ZodObject<{
631
664
  } | undefined;
632
665
  allow_secrets?: boolean | undefined;
633
666
  index?: boolean | undefined;
667
+ stores?: {
668
+ path: string;
669
+ scope: string;
670
+ shared: boolean;
671
+ readonly: boolean;
672
+ }[] | undefined;
634
673
  }, {
635
674
  auto_learn?: boolean | undefined;
636
675
  auto_capture?: boolean | undefined;
@@ -645,6 +684,12 @@ declare const PlurConfigSchema: z.ZodObject<{
645
684
  } | undefined;
646
685
  allow_secrets?: boolean | undefined;
647
686
  index?: boolean | undefined;
687
+ stores?: {
688
+ path: string;
689
+ scope: string;
690
+ shared?: boolean | undefined;
691
+ readonly?: boolean | undefined;
692
+ }[] | undefined;
648
693
  }>;
649
694
  type PlurConfig = z.infer<typeof PlurConfigSchema>;
650
695
 
@@ -653,6 +698,20 @@ interface LearnContext {
653
698
  scope?: string;
654
699
  domain?: string;
655
700
  source?: string;
701
+ tags?: string[];
702
+ rationale?: string;
703
+ visibility?: 'private' | 'public' | 'template';
704
+ knowledge_anchors?: Array<{
705
+ path: string;
706
+ relevance?: string;
707
+ snippet?: string;
708
+ }>;
709
+ dual_coding?: {
710
+ example?: string;
711
+ analogy?: string;
712
+ };
713
+ abstract?: string | null;
714
+ derived_from?: string | null;
656
715
  }
657
716
  /**
658
717
  * Function that calls an LLM. Model-agnostic — consumer provides this.
@@ -680,6 +739,7 @@ interface InjectionResult {
680
739
  consider: string;
681
740
  count: number;
682
741
  tokens_used: number;
742
+ injected_ids: string[];
683
743
  }
684
744
  interface CaptureContext {
685
745
  agent?: string;
@@ -1268,6 +1328,8 @@ declare class Plur {
1268
1328
  recallExpanded(query: string, options: RecallOptions & {
1269
1329
  llm: LlmFunction;
1270
1330
  }): Promise<Engram[]>;
1331
+ /** Get a single engram by ID, regardless of status. Returns null if not found. */
1332
+ getById(id: string): Engram | null;
1271
1333
  /** List all active engrams, optionally filtered by scope/domain. No search — returns all matches. */
1272
1334
  list(options?: {
1273
1335
  scope?: string;
@@ -1283,7 +1345,7 @@ declare class Plur {
1283
1345
  /** Scored injection with embedding boost when available. Falls back to BM25 if embeddings not installed. */
1284
1346
  injectHybrid(task: string, options?: InjectOptions): Promise<InjectionResult>;
1285
1347
  private _formatInjection;
1286
- /** Update feedback_signals and adjust retrieval_strength. */
1348
+ /** Update feedback_signals and adjust retrieval_strength. Searches packs if not found in personal engrams. */
1287
1349
  feedback(id: string, signal: 'positive' | 'negative' | 'neutral'): void;
1288
1350
  /** Save extracted meta-engrams to the engram store. Skips IDs that already exist. */
1289
1351
  saveMetaEngrams(metas: Engram[]): {
@@ -1303,6 +1365,8 @@ declare class Plur {
1303
1365
  reindex(): void;
1304
1366
  /** Sync SQLite index after YAML write (no-op if index disabled) */
1305
1367
  private _syncIndex;
1368
+ /** Search packs for an engram by ID and apply feedback, writing back to the pack's engrams.yaml. */
1369
+ private _feedbackPack;
1306
1370
  /** Capture an episodic memory. */
1307
1371
  capture(summary: string, context?: CaptureContext): Episode;
1308
1372
  /** Query the episode timeline. */
@@ -1332,6 +1396,19 @@ declare class Plur {
1332
1396
  syncStatus(): SyncStatus;
1333
1397
  /** Return system health info. */
1334
1398
  status(): StatusResult;
1399
+ /** Register an additional engram store. */
1400
+ addStore(storePath: string, scope: string, options?: {
1401
+ shared?: boolean;
1402
+ readonly?: boolean;
1403
+ }): void;
1404
+ /** List all configured stores. */
1405
+ listStores(): Array<{
1406
+ path: string;
1407
+ scope: string;
1408
+ shared: boolean;
1409
+ readonly: boolean;
1410
+ engram_count: number;
1411
+ }>;
1335
1412
  }
1336
1413
 
1337
- export { type AlignmentResult, type Association, type CaptureContext, type DomainCoverage, DomainCoverageSchema, type Engram, type EngramCluster, type Episode, type EvidenceEntry, EvidenceEntrySchema, type ExtractOptions, type ExtractionResult, type Falsification, FalsificationSchema, type HierarchyPosition, HierarchyPositionSchema, IndexedStorage, type IngestCandidate, type IngestOptions, type InjectOptions, type InjectionResult, type KnowledgeAnchor, type LearnContext, type LlmFunction, type MemberAlignment, type MetaConfidence, MetaConfidenceSchema, type MetaField, MetaFieldSchema, PLATITUDE_PATTERNS, type PackManifest, Plur, type PlurConfig, type PlurPaths, type RecallOptions, type RelationalAnalysis, type RelationalTriple, SessionBreadcrumbs, type StatusResult, type StructuralTemplate, StructuralTemplateSchema, type SyncResult, type SyncStatus, type TimelineQuery, type TypedRole, type ValidationResult, type VersionCheckResult, alignCluster, analyzeStructure, checkForUpdate, classifyPolarity, clearVersionCache, clusterByStructure, computeConfidence, computeMetaConfidence, confidenceBand, detectPlurStorage, detectSecrets, engramSearchText, extractMetaEngrams, formulateMetaEngram, generateGuardrails, getCachedUpdateCheck, isPlatitude, organizeHierarchy, tokenSimilarity, validateMetaEngram };
1414
+ export { type AlignmentResult, type Association, type CaptureContext, type DomainCoverage, DomainCoverageSchema, type Engram, type EngramCluster, type Episode, type EvidenceEntry, EvidenceEntrySchema, type ExtractOptions, type ExtractionResult, type Falsification, FalsificationSchema, type HierarchyPosition, HierarchyPositionSchema, IndexedStorage, type IngestCandidate, type IngestOptions, type InjectOptions, type InjectionResult, type KnowledgeAnchor, type LearnContext, type LlmFunction, type MemberAlignment, type MetaConfidence, MetaConfidenceSchema, type MetaField, MetaFieldSchema, PLATITUDE_PATTERNS, type PackManifest, Plur, type PlurConfig, type PlurPaths, type RecallOptions, type RelationalAnalysis, type RelationalTriple, SessionBreadcrumbs, type StatusResult, type StoreEntry, type StructuralTemplate, StructuralTemplateSchema, type SyncResult, type SyncStatus, type TimelineQuery, type TypedRole, type ValidationResult, type VersionCheckResult, alignCluster, analyzeStructure, checkForUpdate, classifyPolarity, clearVersionCache, clusterByStructure, computeConfidence, computeMetaConfidence, confidenceBand, detectPlurStorage, detectSecrets, engramSearchText, extractMetaEngrams, formulateMetaEngram, generateGuardrails, getCachedUpdateCheck, isPlatitude, organizeHierarchy, tokenSimilarity, validateMetaEngram };
package/dist/index.js CHANGED
@@ -9,784 +9,11 @@ import {
9
9
  sync,
10
10
  withLock
11
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
- });
12
+ import "./chunk-2ZDO52B4.js";
460
13
 
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
- });
14
+ // src/index.ts
15
+ import * as fs3 from "fs";
16
+ import yaml5 from "js-yaml";
790
17
 
791
18
  // src/storage.ts
792
19
  import { existsSync, mkdirSync } from "fs";
@@ -811,6 +38,7 @@ function detectPlurStorage(explicitPath) {
811
38
 
812
39
  // src/storage-indexed.ts
813
40
  import { existsSync as existsSync3 } from "fs";
41
+ import { createRequire } from "module";
814
42
 
815
43
  // src/engrams.ts
816
44
  import * as fs from "fs";
@@ -1077,11 +305,12 @@ function generateEngramId(existing) {
1077
305
  }
1078
306
 
1079
307
  // src/storage-indexed.ts
308
+ var require2 = createRequire(import.meta.url);
1080
309
  var Database = null;
1081
310
  function getDatabase() {
1082
311
  if (!Database) {
1083
312
  try {
1084
- Database = require_lib();
313
+ Database = require2("better-sqlite3");
1085
314
  } catch {
1086
315
  throw new Error(
1087
316
  "better-sqlite3 is required for index: true. Install it with: npm install better-sqlite3"
@@ -1208,6 +437,12 @@ import yaml2 from "js-yaml";
1208
437
 
1209
438
  // src/schemas/config.ts
1210
439
  import { z as z3 } from "zod";
440
+ var StoreEntrySchema = z3.object({
441
+ path: z3.string(),
442
+ scope: z3.string(),
443
+ shared: z3.boolean().default(false),
444
+ readonly: z3.boolean().default(false)
445
+ });
1211
446
  var PlurConfigSchema = z3.object({
1212
447
  auto_learn: z3.boolean().default(true),
1213
448
  auto_capture: z3.boolean().default(true),
@@ -1221,7 +456,8 @@ var PlurConfigSchema = z3.object({
1221
456
  co_access: z3.boolean().default(true)
1222
457
  }).default({}),
1223
458
  allow_secrets: z3.boolean().default(false),
1224
- index: z3.boolean().default(false)
459
+ index: z3.boolean().default(false),
460
+ stores: z3.array(StoreEntrySchema).default([])
1225
461
  }).partial();
1226
462
 
1227
463
  // src/config.ts
@@ -2771,8 +2007,9 @@ var Plur = class {
2771
2007
  consolidated: false,
2772
2008
  type: context?.type ?? "behavioral",
2773
2009
  scope,
2774
- visibility: "private",
2010
+ visibility: context?.visibility ?? "private",
2775
2011
  statement,
2012
+ rationale: context?.rationale,
2776
2013
  source: context?.source,
2777
2014
  domain: context?.domain,
2778
2015
  activation: {
@@ -2782,13 +2019,18 @@ var Plur = class {
2782
2019
  last_accessed: now.slice(0, 10)
2783
2020
  },
2784
2021
  feedback_signals: { positive: 0, negative: 0, neutral: 0 },
2785
- knowledge_anchors: [],
2022
+ knowledge_anchors: (context?.knowledge_anchors ?? []).map((a) => ({
2023
+ path: a.path,
2024
+ relevance: a.relevance ?? "supporting",
2025
+ snippet: a.snippet
2026
+ })),
2786
2027
  associations: [],
2787
2028
  derivation_count: 1,
2788
- tags: [],
2029
+ tags: context?.tags ?? [],
2789
2030
  pack: null,
2790
- abstract: null,
2791
- derived_from: null,
2031
+ abstract: context?.abstract ?? null,
2032
+ derived_from: context?.derived_from ?? null,
2033
+ dual_coding: context?.dual_coding,
2792
2034
  polarity: null,
2793
2035
  relations: conflictIds.length > 0 ? {
2794
2036
  broader: [],
@@ -2849,6 +2091,11 @@ var Plur = class {
2849
2091
  this._reactivateResults(results);
2850
2092
  return results;
2851
2093
  }
2094
+ /** Get a single engram by ID, regardless of status. Returns null if not found. */
2095
+ getById(id) {
2096
+ const engrams = loadEngrams(this.paths.engrams);
2097
+ return engrams.find((e) => e.id === id) ?? null;
2098
+ }
2852
2099
  /** List all active engrams, optionally filtered by scope/domain. No search — returns all matches. */
2853
2100
  list(options) {
2854
2101
  return this._filterEngrams(options);
@@ -2986,20 +2233,26 @@ var Plur = class {
2986
2233
  const considerStr = formatEngrams(result.consider);
2987
2234
  const count = result.directives.length + result.constraints.length + result.consider.length;
2988
2235
  const tokensUsed = result.tokens_used.directives + result.tokens_used.consider;
2236
+ const injected_ids = [
2237
+ ...result.directives.map((e) => e.id),
2238
+ ...result.constraints.map((e) => e.id),
2239
+ ...result.consider.map((e) => e.id)
2240
+ ];
2989
2241
  return {
2990
2242
  directives: directivesStr,
2991
2243
  constraints: constraintsStr,
2992
2244
  consider: considerStr,
2993
2245
  count,
2994
- tokens_used: tokensUsed
2246
+ tokens_used: tokensUsed,
2247
+ injected_ids
2995
2248
  };
2996
2249
  }
2997
- /** Update feedback_signals and adjust retrieval_strength. */
2250
+ /** Update feedback_signals and adjust retrieval_strength. Searches packs if not found in personal engrams. */
2998
2251
  feedback(id, signal) {
2999
- withLock(this.paths.engrams, () => {
2252
+ const found = withLock(this.paths.engrams, () => {
3000
2253
  const engrams = loadEngrams(this.paths.engrams);
3001
2254
  const engram = engrams.find((e) => e.id === id);
3002
- if (!engram) throw new Error(`Engram not found: ${id}`);
2255
+ if (!engram) return false;
3003
2256
  if (!engram.feedback_signals) {
3004
2257
  engram.feedback_signals = { positive: 0, negative: 0, neutral: 0 };
3005
2258
  }
@@ -3011,7 +2264,10 @@ var Plur = class {
3011
2264
  }
3012
2265
  saveEngrams(this.paths.engrams, engrams);
3013
2266
  this._syncIndex();
2267
+ return true;
3014
2268
  });
2269
+ if (found) return;
2270
+ this._feedbackPack(id, signal);
3015
2271
  }
3016
2272
  /** Save extracted meta-engrams to the engram store. Skips IDs that already exist. */
3017
2273
  saveMetaEngrams(metas) {
@@ -3087,6 +2343,31 @@ var Plur = class {
3087
2343
  this.indexedStorage.syncFromYaml();
3088
2344
  }
3089
2345
  }
2346
+ /** Search packs for an engram by ID and apply feedback, writing back to the pack's engrams.yaml. */
2347
+ _feedbackPack(id, signal) {
2348
+ if (!fs3.existsSync(this.paths.packs)) throw new Error(`Engram not found: ${id}`);
2349
+ for (const entry of fs3.readdirSync(this.paths.packs)) {
2350
+ const packDir = `${this.paths.packs}/${entry}`;
2351
+ if (!fs3.statSync(packDir).isDirectory()) continue;
2352
+ const engramsPath = `${packDir}/engrams.yaml`;
2353
+ if (!fs3.existsSync(engramsPath)) continue;
2354
+ const engrams = loadEngrams(engramsPath);
2355
+ const engram = engrams.find((e) => e.id === id);
2356
+ if (!engram) continue;
2357
+ if (!engram.feedback_signals) {
2358
+ engram.feedback_signals = { positive: 0, negative: 0, neutral: 0 };
2359
+ }
2360
+ engram.feedback_signals[signal] += 1;
2361
+ if (signal === "positive") {
2362
+ engram.activation.retrieval_strength = Math.min(1, engram.activation.retrieval_strength + 0.05);
2363
+ } else if (signal === "negative") {
2364
+ engram.activation.retrieval_strength = Math.max(0, engram.activation.retrieval_strength - 0.1);
2365
+ }
2366
+ saveEngrams(engramsPath, engrams);
2367
+ return;
2368
+ }
2369
+ throw new Error(`Engram not found: ${id}`);
2370
+ }
3090
2371
  /** Capture an episodic memory. */
3091
2372
  capture(summary, context) {
3092
2373
  return captureEpisode(this.paths.episodes, summary, context);
@@ -3160,6 +2441,47 @@ var Plur = class {
3160
2441
  config: this.config
3161
2442
  };
3162
2443
  }
2444
+ /** Register an additional engram store. */
2445
+ addStore(storePath, scope, options) {
2446
+ const config = loadConfig(this.paths.config);
2447
+ const existing = config.stores?.find((s) => s.path === storePath);
2448
+ if (existing) return;
2449
+ const stores = [...config.stores ?? [], {
2450
+ path: storePath,
2451
+ scope,
2452
+ shared: options?.shared ?? false,
2453
+ readonly: options?.readonly ?? false
2454
+ }];
2455
+ let configData = {};
2456
+ try {
2457
+ const raw = fs3.readFileSync(this.paths.config, "utf8");
2458
+ if (raw) configData = yaml5.load(raw) ?? {};
2459
+ } catch {
2460
+ }
2461
+ configData.stores = stores;
2462
+ fs3.writeFileSync(this.paths.config, yaml5.dump(configData, { lineWidth: 120, noRefs: true }));
2463
+ this.config = loadConfig(this.paths.config);
2464
+ }
2465
+ /** List all configured stores. */
2466
+ listStores() {
2467
+ const stores = this.config.stores ?? [];
2468
+ const primary = {
2469
+ path: this.paths.engrams,
2470
+ scope: "global",
2471
+ shared: false,
2472
+ readonly: false,
2473
+ engram_count: loadEngrams(this.paths.engrams).filter((e) => e.status !== "retired").length
2474
+ };
2475
+ const additional = stores.map((s) => {
2476
+ let count = 0;
2477
+ try {
2478
+ count = loadEngrams(s.path).filter((e) => e.status !== "retired").length;
2479
+ } catch {
2480
+ }
2481
+ return { ...s, engram_count: count };
2482
+ });
2483
+ return [primary, ...additional];
2484
+ }
3163
2485
  };
3164
2486
  export {
3165
2487
  DomainCoverageSchema,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plur-ai/core",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",