@plur-ai/core 0.3.0 → 0.4.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.js CHANGED
@@ -1,3 +1,13 @@
1
+ import {
2
+ atomicWrite,
3
+ embeddingSearch,
4
+ engramSearchText,
5
+ ftsScore,
6
+ ftsTokenize,
7
+ getSyncStatus,
8
+ searchEngrams,
9
+ sync
10
+ } from "./chunk-WPD4MPTT.js";
1
11
  import "./chunk-2ZDO52B4.js";
2
12
 
3
13
  // src/storage.ts
@@ -37,7 +47,8 @@ var PlurConfigSchema = z.object({
37
47
  spread_cap: z.number().default(3),
38
48
  spread_budget: z.number().default(480),
39
49
  co_access: z.boolean().default(true)
40
- }).default({})
50
+ }).default({}),
51
+ allow_secrets: z.boolean().default(false)
41
52
  }).partial();
42
53
 
43
54
  // src/config.ts
@@ -146,7 +157,7 @@ var ExchangeMetadataSchema = z2.object({
146
157
  });
147
158
  var EngramSchema = z2.object({
148
159
  // Identity
149
- id: z2.string().regex(/^(ENG|ABS)-[A-Za-z0-9-]+$/),
160
+ id: z2.string().regex(/^(ENG|ABS|META)-[A-Za-z0-9-]+$/),
150
161
  version: z2.number().int().min(1).default(2),
151
162
  status: z2.enum(["active", "dormant", "retired", "candidate"]),
152
163
  consolidated: z2.boolean().default(false),
@@ -196,7 +207,9 @@ var EngramSchema = z2.object({
196
207
  /** Exchange marketplace metadata: fitness, adoption, diversity. */
197
208
  exchange: ExchangeMetadataSchema.optional(),
198
209
  /** Extensible key-value data for domain-specific fields. */
199
- structured_data: z2.record(z2.string(), z2.unknown()).optional()
210
+ structured_data: z2.record(z2.string(), z2.unknown()).optional(),
211
+ /** Polarity classification: 'do' for directives, 'dont' for prohibitions, null for unclassified. */
212
+ polarity: z2.enum(["do", "dont"]).nullable().default(null)
200
213
  });
201
214
 
202
215
  // src/schemas/pack.ts
@@ -243,168 +256,6 @@ var logger = {
243
256
  }
244
257
  };
245
258
 
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
259
  // src/engrams.ts
409
260
  function loadEngrams(filePath) {
410
261
  if (!fs.existsSync(filePath)) return [];
@@ -475,68 +326,6 @@ function generateEngramId(existing) {
475
326
  return `${prefix}${String(next).padStart(3, "0")}`;
476
327
  }
477
328
 
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++;
531
- }
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
- }
539
-
540
329
  // src/decay.ts
541
330
  var DECAY_RATE = 0.05;
542
331
  var FLOOR = 0.05;
@@ -557,6 +346,53 @@ function decayedCoAccessStrength(strength, daysSinceUpdate, lambda = 0.01) {
557
346
  return floor + (strength - floor) * Math.exp(-lambda * daysSinceUpdate);
558
347
  }
559
348
 
349
+ // src/polarity.ts
350
+ var DONT_PATTERNS = [
351
+ /\bnever\b/i,
352
+ /\bdo\s+not\b/i,
353
+ /\bdon'?t\b/i,
354
+ /\bavoid\b/i,
355
+ /\bmust\s+not\b/i,
356
+ /\bshould\s+not\b/i,
357
+ /\bNOT\b.*?\b(?:include|use|run|start|create|add|send|describe|reference|assume)\b/,
358
+ /\bstop\b.*?\b(?:generating|iterating|doing|running|creating)\b/i
359
+ ];
360
+ function classifyPolarity(statement) {
361
+ if (!statement || statement.length < 5) return null;
362
+ const dotIndex = statement.indexOf(".");
363
+ const firstSentence = statement.slice(0, dotIndex > 0 ? Math.min(dotIndex, 200) : 200);
364
+ for (const pattern of DONT_PATTERNS) {
365
+ if (pattern.test(firstSentence)) return "dont";
366
+ }
367
+ return null;
368
+ }
369
+
370
+ // src/confidence.ts
371
+ function computeConfidence(input) {
372
+ const fb = input.feedback_signals ?? { positive: 0, negative: 0, neutral: 0 };
373
+ const total = fb.positive + fb.negative + fb.neutral;
374
+ if (total === 0) return 0.5;
375
+ const netRatio = (fb.positive - fb.negative) / total;
376
+ const dampening = 1 - 1 / (total + 1);
377
+ const adjustedRatio = netRatio * dampening;
378
+ const steepness = 2;
379
+ const base = 1 / (1 + Math.exp(-steepness * adjustedRatio));
380
+ const consolidationBonus = input.consolidated ? 0.05 : 0;
381
+ return Math.min(1, Math.max(0, base + consolidationBonus));
382
+ }
383
+ function computeMetaConfidence(evidenceCount, domainCount, structuralDepth, validationRatio) {
384
+ const evidenceSignal = Math.min(evidenceCount / 5, 1) * 0.25;
385
+ const domainSignal = Math.min(domainCount / 3, 1) * 0.35;
386
+ const depthSignal = Math.min(structuralDepth / 3, 1) * 0.2;
387
+ const validationSignal = validationRatio * 0.2;
388
+ return evidenceSignal + domainSignal + depthSignal + validationSignal;
389
+ }
390
+ function confidenceBand(score) {
391
+ if (score >= 0.7) return "high";
392
+ if (score >= 0.4) return "medium";
393
+ return "low";
394
+ }
395
+
560
396
  // src/inject.ts
561
397
  var DEFAULT_MAX_TOKENS = 8e3;
562
398
  var DEFAULT_MIN_RELEVANCE = 0.3;
@@ -614,7 +450,7 @@ function stripAssociations(engram) {
614
450
  }
615
451
  function stripScoring(engram) {
616
452
  const { keyword_match: _, raw_score: _r, score: _s, ...rest } = engram;
617
- return rest;
453
+ return { ...rest, confidence_score: computeConfidence(engram) };
618
454
  }
619
455
  function scoreEngram(engram, promptLower, promptWords, packMatchTerms, scopeFilter, isPack) {
620
456
  if (scopeFilter) {
@@ -650,6 +486,8 @@ function scoreEngram(engram, promptLower, promptWords, packMatchTerms, scopeFilt
650
486
  else if (netFeedback < 0) score *= Math.max(1 + netFeedback * 0.1, 0.5);
651
487
  }
652
488
  if (engram.consolidated) score *= 1.1;
489
+ const emotionalWeight = engram.episodic?.emotional_weight ?? 5;
490
+ score *= 1 + (emotionalWeight - 5) * 0.04;
653
491
  return score;
654
492
  }
655
493
  function fillTokenBudget(scored, maxTokens) {
@@ -681,10 +519,13 @@ function selectAndSpread(ctx, personalEngrams, packs, config, embeddingBoosts) {
681
519
  const promptWords = new Set(promptLower.split(/\W+/).filter((w) => w.length > 2));
682
520
  const maxTokens = ctx.maxTokens ?? DEFAULT_MAX_TOKENS;
683
521
  const minRelevance = ctx.minRelevance ?? DEFAULT_MIN_RELEVANCE;
522
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
684
523
  const engramMap = /* @__PURE__ */ new Map();
685
524
  const scored = [];
686
525
  for (const engram of personalEngrams) {
687
526
  if (engram.status !== "active") continue;
527
+ if (engram.temporal?.valid_until && engram.temporal.valid_until < today) continue;
528
+ if (engram.temporal?.valid_from && engram.temporal.valid_from > today) continue;
688
529
  engramMap.set(engram.id, engram);
689
530
  let raw = scoreEngram(engram, promptLower, promptWords, [], ctx.scope, false);
690
531
  const embBoost = embeddingBoosts?.get(engram.id) ?? 0;
@@ -703,6 +544,8 @@ function selectAndSpread(ctx, personalEngrams, packs, config, embeddingBoosts) {
703
544
  const matchTerms = packMeta.match_terms;
704
545
  for (const engram of pack.engrams) {
705
546
  if (engram.status !== "active") continue;
547
+ if (engram.temporal?.valid_until && engram.temporal.valid_until < today) continue;
548
+ if (engram.temporal?.valid_from && engram.temporal.valid_from > today) continue;
706
549
  engramMap.set(engram.id, engram);
707
550
  let raw = scoreEngram(engram, promptLower, promptWords, matchTerms, ctx.scope, true);
708
551
  const embBoost = embeddingBoosts?.get(engram.id) ?? 0;
@@ -750,6 +593,7 @@ function selectAndSpread(ctx, personalEngrams, packs, config, embeddingBoosts) {
750
593
  if (directives.length === 0 && dip19Pool.length === 0) {
751
594
  return {
752
595
  directives: [],
596
+ constraints: [],
753
597
  consider: [],
754
598
  tokens_used: { directives: 0, consider: 0 }
755
599
  };
@@ -787,18 +631,29 @@ function selectAndSpread(ctx, personalEngrams, packs, config, embeddingBoosts) {
787
631
  const allConsider = [...dip19Pool, ...spreadCandidates];
788
632
  const agentDirectives = directives.map(stripAssociations);
789
633
  const agentConsider = allConsider.map(stripAssociations);
790
- const wireDirectives = agentDirectives.map(stripScoring);
634
+ const wireAll = agentDirectives.map(stripScoring);
791
635
  const wireConsider = agentConsider.map(stripScoring);
636
+ const wireDirectives = [];
637
+ const wireConstraints = [];
638
+ for (const wire of wireAll) {
639
+ const polarity = wire.polarity ?? classifyPolarity(wire.statement);
640
+ if (polarity === "dont") {
641
+ wireConstraints.push(wire);
642
+ } else {
643
+ wireDirectives.push(wire);
644
+ }
645
+ }
792
646
  const considerTokens = dip19PoolTokens + spreadTokens;
793
647
  return {
794
648
  directives: wireDirectives,
649
+ constraints: wireConstraints,
795
650
  consider: wireConsider,
796
651
  tokens_used: { directives: directiveTokens, consider: considerTokens }
797
652
  };
798
653
  }
799
654
 
800
655
  // src/episodes.ts
801
- import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
656
+ import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
802
657
  import yaml3 from "js-yaml";
803
658
  function generateEpisodeId() {
804
659
  const ts = Date.now();
@@ -833,7 +688,7 @@ function queryTimeline(path2, query) {
833
688
  return episodes;
834
689
  }
835
690
  function loadEpisodes(path2) {
836
- if (!existsSync5(path2)) return [];
691
+ if (!existsSync4(path2)) return [];
837
692
  try {
838
693
  const raw = yaml3.load(readFileSync3(path2, "utf8"));
839
694
  return Array.isArray(raw) ? raw : [];
@@ -905,86 +760,6 @@ Rules:
905
760
  }
906
761
  }
907
762
 
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
763
  // src/hybrid-search.ts
989
764
  function rrfMerge(resultSets, k = 60) {
990
765
  const scores = /* @__PURE__ */ new Map();
@@ -1183,6 +958,818 @@ ${manifest.description || ""}
1183
958
  return { path: outputDir, engram_count: engrams.length };
1184
959
  }
1185
960
 
961
+ // src/secrets.ts
962
+ var SECRET_PATTERNS = [
963
+ { name: "aws_access_key", regex: /AKIA[0-9A-Z]{16}/ },
964
+ { name: "aws_secret_key", regex: /(?:aws_secret_access_key|secret_access_key)\s*[=:]\s*[A-Za-z0-9/+=]{40}/i },
965
+ { name: "generic_api_key", regex: /(?:^|[^a-z])(sk|pk)[-_][a-z0-9]{20,}/i },
966
+ { name: "api_key_assignment", regex: /(?:api[_-]?key|api[_-]?secret|secret[_-]?key)\s*[=:]\s*\S{20,}/i },
967
+ { name: "password_assignment", regex: /password\s*[=:]\s*\S{8,}/i },
968
+ { name: "connection_string", regex: /(?:postgres|mysql|mongodb|redis):\/\/\S+/ },
969
+ { name: "jwt", regex: /eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}/ },
970
+ { name: "private_key", regex: /-----BEGIN\s+\S+\s+PRIVATE KEY-----/ },
971
+ { name: "bearer_token", regex: /Bearer\s+[A-Za-z0-9._~+/=-]{20,}/ }
972
+ ];
973
+ function detectSecrets(text) {
974
+ const matches = [];
975
+ for (const { name, regex } of SECRET_PATTERNS) {
976
+ const m = text.match(regex);
977
+ if (m) {
978
+ matches.push({ pattern: name, match: m[0].slice(0, 20) + "..." });
979
+ }
980
+ }
981
+ return matches;
982
+ }
983
+
984
+ // src/meta/sanitize.ts
985
+ function sanitizeForPrompt(text) {
986
+ return text.replace(/```/g, "~~~").replace(/\n{3,}/g, "\n\n").replace(/^(system|assistant|user):/gim, "$1 -").slice(0, 2e3);
987
+ }
988
+
989
+ // src/meta/structural-analysis.ts
990
+ var FAILURE_TAGS = /* @__PURE__ */ new Set(["correction", "mistake", "bug", "fix", "error", "wrong", "broken"]);
991
+ var BATCH_SIZE = 5;
992
+ function isFailureDriven(engram) {
993
+ if (engram.tags.some((t) => FAILURE_TAGS.has(t.toLowerCase()))) return true;
994
+ const fb = engram.feedback_signals;
995
+ if (fb && fb.negative > fb.positive) return true;
996
+ return false;
997
+ }
998
+ function prioritize(engrams) {
999
+ return [...engrams].sort((a, b) => {
1000
+ const aFail = isFailureDriven(a) ? 0 : 1;
1001
+ const bFail = isFailureDriven(b) ? 0 : 1;
1002
+ if (aFail !== bFail) return aFail - bFail;
1003
+ const aFb = a.feedback_signals?.negative ?? 0;
1004
+ const bFb = b.feedback_signals?.negative ?? 0;
1005
+ return bFb - aFb;
1006
+ });
1007
+ }
1008
+ function buildPrompt(engrams) {
1009
+ const items = engrams.map((e, i) => {
1010
+ const parts = [` Statement: "${sanitizeForPrompt(e.statement)}"`];
1011
+ if (e.rationale) parts.push(` Rationale: "${sanitizeForPrompt(e.rationale)}"`);
1012
+ if (e.domain) parts.push(` Domain: "${e.domain}"`);
1013
+ return `Engram ${i + 1} (${e.id}):
1014
+ ${parts.join("\n")}`;
1015
+ }).join("\n\n");
1016
+ return `Given these learned lessons, extract relational structure for cross-domain transfer.
1017
+
1018
+ ${items}
1019
+
1020
+ For EACH engram, extract:
1021
+ 1. The GOAL the agent had (abstract type, not domain-specific)
1022
+ 2. Relational triples: subject (role + domain instance), predicate, object (role + domain instance), outcome
1023
+ 3. Use domain-GENERAL role types (e.g., "safety-metric" not "liquidation-price")
1024
+
1025
+ Return a JSON array with one object per engram:
1026
+ [{
1027
+ "engram_id": "ENG-...",
1028
+ "goal_context": "what the agent was trying to achieve (abstract)",
1029
+ "triples": [{ "subject": { "role": "...", "domain_instance": "..." }, "predicate": "...", "object": { "role": "...", "domain_instance": "..." }, "outcome": "..." }]
1030
+ }]
1031
+
1032
+ Rules:
1033
+ - Roles MUST be domain-general (e.g., "safety-metric" not "liquidation-price")
1034
+ - If a lesson is purely domain-specific with no transferable structure, return empty triples: []
1035
+ - Prefer causal chains over isolated attributes
1036
+ - Return ONLY valid JSON, no markdown fencing`;
1037
+ }
1038
+ async function analyzeStructure(engrams, llm) {
1039
+ const prioritized = prioritize(engrams.filter((e) => e.status === "active"));
1040
+ const results = [];
1041
+ for (let i = 0; i < prioritized.length; i += BATCH_SIZE) {
1042
+ const batch = prioritized.slice(i, i + BATCH_SIZE);
1043
+ const prompt = buildPrompt(batch);
1044
+ let parsed;
1045
+ try {
1046
+ const response = await llm(prompt);
1047
+ const cleaned = response.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
1048
+ parsed = JSON.parse(cleaned);
1049
+ } catch {
1050
+ try {
1051
+ const retryResponse = await llm(prompt + "\n\nIMPORTANT: Return ONLY raw JSON array, no text.");
1052
+ const cleaned = retryResponse.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
1053
+ parsed = JSON.parse(cleaned);
1054
+ } catch {
1055
+ continue;
1056
+ }
1057
+ }
1058
+ for (const item of parsed) {
1059
+ if (!item.triples || item.triples.length === 0) continue;
1060
+ const engram = batch.find((e) => e.id === item.engram_id) ?? batch[parsed.indexOf(item)];
1061
+ if (!engram) continue;
1062
+ results.push({
1063
+ engram_id: engram.id,
1064
+ triples: item.triples,
1065
+ goal_context: item.goal_context ?? "",
1066
+ is_failure_driven: isFailureDriven(engram),
1067
+ domain: engram.domain ?? "unknown",
1068
+ polarity: classifyPolarity(engram.statement) === "dont" ? "dont" : "do"
1069
+ });
1070
+ }
1071
+ }
1072
+ return results;
1073
+ }
1074
+
1075
+ // src/meta/similarity.ts
1076
+ function tokenSimilarity(a, b) {
1077
+ const wordsA = new Set(a.toLowerCase().split(/[\s\[\]→+\-]+/).filter((w) => w.length > 2));
1078
+ const wordsB = new Set(b.toLowerCase().split(/[\s\[\]→+\-]+/).filter((w) => w.length > 2));
1079
+ if (wordsA.size === 0 || wordsB.size === 0) return 0;
1080
+ let overlap = 0;
1081
+ for (const w of wordsA) {
1082
+ if (wordsB.has(w)) overlap++;
1083
+ }
1084
+ return overlap / Math.sqrt(wordsA.size * wordsB.size);
1085
+ }
1086
+
1087
+ // src/meta/clustering.ts
1088
+ function tripleToTemplate(triple) {
1089
+ const parts = [triple.subject.role, triple.predicate, triple.object.role];
1090
+ if (triple.outcome) parts.push("\u2192", triple.outcome);
1091
+ return parts.join(" ");
1092
+ }
1093
+ function analysisTemplate(analysis) {
1094
+ return analysis.triples.map(tripleToTemplate).join("; ");
1095
+ }
1096
+ async function computeSimilarityMatrix(templates) {
1097
+ const n = templates.length;
1098
+ const matrix = Array.from({ length: n }, () => Array(n).fill(0));
1099
+ try {
1100
+ const { embed, cosineSimilarity } = await import("./embeddings-Q76LNQ5B.js");
1101
+ const embeddings = [];
1102
+ for (const t of templates) {
1103
+ embeddings.push(await embed(t));
1104
+ }
1105
+ if (embeddings[0] !== null) {
1106
+ for (let i = 0; i < n; i++) {
1107
+ for (let j = i + 1; j < n; j++) {
1108
+ if (embeddings[i] && embeddings[j]) {
1109
+ const sim = cosineSimilarity(embeddings[i], embeddings[j]);
1110
+ matrix[i][j] = sim;
1111
+ matrix[j][i] = sim;
1112
+ }
1113
+ }
1114
+ }
1115
+ return { matrix, method: "embedding" };
1116
+ }
1117
+ } catch {
1118
+ }
1119
+ for (let i = 0; i < n; i++) {
1120
+ for (let j = i + 1; j < n; j++) {
1121
+ const sim = tokenSimilarity(templates[i], templates[j]);
1122
+ matrix[i][j] = sim;
1123
+ matrix[j][i] = sim;
1124
+ }
1125
+ }
1126
+ return { matrix, method: "token" };
1127
+ }
1128
+ var EMBEDDING_THRESHOLD = 0.65;
1129
+ var TOKEN_THRESHOLD = 0.35;
1130
+ async function clusterByStructure(analyses, threshold2) {
1131
+ if (analyses.length < 2) return [];
1132
+ const templates = analyses.map((a) => analysisTemplate(a));
1133
+ const { matrix, method } = await computeSimilarityMatrix(templates);
1134
+ const effectiveThreshold = threshold2 ?? (method === "embedding" ? EMBEDDING_THRESHOLD : TOKEN_THRESHOLD);
1135
+ const seenClusters = /* @__PURE__ */ new Set();
1136
+ const clusters = [];
1137
+ let clusterId = 0;
1138
+ for (let i = 0; i < analyses.length; i++) {
1139
+ const members = [analyses[i]];
1140
+ const memberIndices = [i];
1141
+ for (let j = 0; j < analyses.length; j++) {
1142
+ if (j === i) continue;
1143
+ if (matrix[i][j] >= effectiveThreshold) {
1144
+ members.push(analyses[j]);
1145
+ memberIndices.push(j);
1146
+ }
1147
+ }
1148
+ if (members.length < 2) continue;
1149
+ const memberKey = members.map((m) => m.engram_id).sort().join(",");
1150
+ if (seenClusters.has(memberKey)) continue;
1151
+ seenClusters.add(memberKey);
1152
+ const domains = [...new Set(members.map((m) => m.domain))];
1153
+ let totalSim = 0;
1154
+ let pairs = 0;
1155
+ for (let a = 0; a < memberIndices.length; a++) {
1156
+ for (let b = a + 1; b < memberIndices.length; b++) {
1157
+ totalSim += matrix[memberIndices[a]][memberIndices[b]];
1158
+ pairs++;
1159
+ }
1160
+ }
1161
+ clusters.push({
1162
+ cluster_id: `cluster-${clusterId++}`,
1163
+ members,
1164
+ domains,
1165
+ is_cross_domain: domains.length >= 2,
1166
+ cohesion: pairs > 0 ? totalSim / pairs : 0
1167
+ });
1168
+ }
1169
+ return clusters;
1170
+ }
1171
+
1172
+ // src/meta/platitudes.ts
1173
+ var PLATITUDE_PATTERNS = [
1174
+ "always be careful",
1175
+ "verify before acting",
1176
+ "plan ahead",
1177
+ "consider edge cases",
1178
+ "communicate clearly",
1179
+ "test thoroughly",
1180
+ "keep it simple",
1181
+ "document your work",
1182
+ "think before you act",
1183
+ "double check"
1184
+ ];
1185
+ function isPlatitude(statement) {
1186
+ const lower = statement.toLowerCase();
1187
+ return PLATITUDE_PATTERNS.some((p) => lower.includes(p)) || statement.length < 30;
1188
+ }
1189
+
1190
+ // src/meta/alignment.ts
1191
+ async function alignCluster(cluster, llm) {
1192
+ const tripleDescriptions = cluster.members.map((m) => {
1193
+ const domain = sanitizeForPrompt(m.domain);
1194
+ const triples = m.triples.map((t) => {
1195
+ const parts = [`${sanitizeForPrompt(t.subject.role)} ${sanitizeForPrompt(t.predicate)} ${sanitizeForPrompt(t.object.role)}`];
1196
+ if (t.outcome) parts.push(`\u2192 ${sanitizeForPrompt(t.outcome)}`);
1197
+ return parts.join(" ");
1198
+ }).join("; ");
1199
+ return `Domain ${domain} (${m.engram_id}): ${triples}`;
1200
+ }).join("\n");
1201
+ const prompt = `These lessons come from different domains but may share a common structural principle:
1202
+
1203
+ ${tripleDescriptions}
1204
+
1205
+ Tasks:
1206
+ 1. Is there a genuine common relational structure? (Not surface similarity, not a platitude)
1207
+ 2. Choose the structural frame that BEST captures the pattern:
1208
+ - "goal-constraint-outcome": [goal] + [constraint] \u2192 [outcome]
1209
+ - "feedback-loop": [action] \u2192 [effect] \u2192 [feeds back to action]
1210
+ - "causal-chain": [A] causes [B] causes [C]
1211
+ - "tradeoff": [optimizing X] at the expense of [Y]
1212
+ - "recursive": [pattern] contains smaller instances of [same pattern]
1213
+ - "freeform": describe the structure in your own terms
1214
+ 3. Express the common structure using your chosen frame
1215
+ 4. Rate structural depth (1-5): 1=surface, 3=causal chain, 5=deep systematic
1216
+ 5. For each member, rate alignment (0-1) and explain the mapping in one sentence
1217
+ 6. What does this structure PREDICT in a domain not listed above?
1218
+
1219
+ Return JSON:
1220
+ {
1221
+ "common_structure": {
1222
+ "goal_type": "...",
1223
+ "constraint_type": "...",
1224
+ "outcome_type": "...",
1225
+ "template": "...",
1226
+ "structure_type": "goal-constraint-outcome" | "feedback-loop" | "causal-chain" | "tradeoff" | "recursive" | "freeform",
1227
+ "freeform_structure": "..." (only if structure_type is "freeform")
1228
+ } | null,
1229
+ "structural_depth": N,
1230
+ "member_alignments": [{ "engram_id": "...", "alignment_score": N, "mapping_rationale": "..." }],
1231
+ "candidate_inferences": ["..."]
1232
+ }
1233
+
1234
+ 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.
1235
+ Return ONLY valid JSON, no markdown fencing.`;
1236
+ try {
1237
+ const response = await llm(prompt);
1238
+ const cleaned = response.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
1239
+ if (cleaned === "null" || cleaned === '{"common_structure": null}') return null;
1240
+ const parsed = JSON.parse(cleaned);
1241
+ if (!parsed.common_structure) return null;
1242
+ if (parsed.structural_depth < 2) return null;
1243
+ if (isPlatitude(parsed.common_structure.template)) return null;
1244
+ if (parsed.common_structure.template.length < 30) return null;
1245
+ const alignments = parsed.member_alignments ?? [];
1246
+ const lowAlignments = alignments.filter((a) => a.alignment_score < 0.5);
1247
+ if (lowAlignments.length > alignments.length / 2) return null;
1248
+ return {
1249
+ cluster_id: cluster.cluster_id,
1250
+ common_structure: parsed.common_structure,
1251
+ member_alignments: alignments,
1252
+ structural_depth: parsed.structural_depth,
1253
+ systematicity: parsed.structural_depth,
1254
+ // Use depth as systematicity proxy
1255
+ candidate_inferences: parsed.candidate_inferences ?? []
1256
+ };
1257
+ } catch {
1258
+ return null;
1259
+ }
1260
+ }
1261
+
1262
+ // src/meta/formulation.ts
1263
+ var PIPELINE_VERSION = "1.0.0";
1264
+ function slugifyTemplate(template) {
1265
+ return template.toLowerCase().replace(/[\[\]→+]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 60);
1266
+ }
1267
+ function isDuplicate(template, existingMetas) {
1268
+ for (const meta of existingMetas) {
1269
+ const metaField = meta.structured_data?.meta;
1270
+ if (!metaField?.structure?.template) continue;
1271
+ const sim = tokenSimilarity(template, metaField.structure.template);
1272
+ if (sim > 0.9) return meta;
1273
+ }
1274
+ return null;
1275
+ }
1276
+ async function formulateMetaEngram(alignment, llm, existingMetas = [], domains = []) {
1277
+ const { common_structure, member_alignments, structural_depth, candidate_inferences } = alignment;
1278
+ if (isPlatitude(common_structure.template)) return null;
1279
+ const memberSummary = member_alignments.map((m) => ` - ${m.engram_id}: ${sanitizeForPrompt(m.mapping_rationale)} (alignment: ${m.alignment_score})`).join("\n");
1280
+ const prompt = `Structural principle: ${sanitizeForPrompt(common_structure.template)}
1281
+ Goal type: ${common_structure.goal_type}
1282
+ Constraint type: ${common_structure.constraint_type}
1283
+ Outcome type: ${common_structure.outcome_type}
1284
+ Structural depth: ${structural_depth}
1285
+ Evidence from members:
1286
+ ${memberSummary}
1287
+ Candidate inferences: ${candidate_inferences.map(sanitizeForPrompt).join(", ")}
1288
+
1289
+ Generate:
1290
+ 1. A natural-language statement of this principle (1-2 sentences, precise, not generic)
1291
+ 2. Conditions under which it holds (expected_conditions)
1292
+ 3. Conditions under which it does NOT hold (expected_exceptions)
1293
+ 4. A concrete test: pick a domain NOT in the evidence list, describe a scenario where this principle predicts a specific outcome (test_prediction)
1294
+
1295
+ The statement must be specific enough to be FALSIFIABLE. If you cannot write falsification criteria, return null.
1296
+
1297
+ Return JSON:
1298
+ {
1299
+ "statement": "...",
1300
+ "falsification": {
1301
+ "expected_conditions": "...",
1302
+ "expected_exceptions": "...",
1303
+ "test_prediction": "..."
1304
+ }
1305
+ }
1306
+
1307
+ Or return null if the principle is too vague to falsify.
1308
+ Return ONLY valid JSON, no markdown fencing.`;
1309
+ let parsed;
1310
+ try {
1311
+ const response = await llm(prompt);
1312
+ const cleaned = response.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
1313
+ if (cleaned === "null") return null;
1314
+ parsed = JSON.parse(cleaned);
1315
+ } catch {
1316
+ return null;
1317
+ }
1318
+ if (!parsed || !parsed.statement || !parsed.falsification) return null;
1319
+ if (!parsed.falsification.expected_conditions || !parsed.falsification.expected_exceptions) return null;
1320
+ const duplicate = isDuplicate(common_structure.template, existingMetas);
1321
+ if (duplicate) {
1322
+ return null;
1323
+ }
1324
+ const evidenceCount = member_alignments.length;
1325
+ const domainCount = domains.length > 0 ? domains.length : 1;
1326
+ const validationRatio = 0;
1327
+ const composite = computeMetaConfidence(evidenceCount, domainCount, structural_depth, validationRatio);
1328
+ const slug = slugifyTemplate(common_structure.template);
1329
+ const id = `META-${slug}`;
1330
+ const evidence = member_alignments.map((ma) => ({
1331
+ engram_id: ma.engram_id,
1332
+ domain: "unknown",
1333
+ // Will be enriched by pipeline orchestrator
1334
+ mapping_rationale: ma.mapping_rationale,
1335
+ alignment_score: ma.alignment_score
1336
+ }));
1337
+ const metaField = {
1338
+ structure: common_structure,
1339
+ evidence,
1340
+ domain_coverage: {
1341
+ validated: [],
1342
+ failed: [],
1343
+ predicted: candidate_inferences
1344
+ },
1345
+ falsification: parsed.falsification,
1346
+ confidence: {
1347
+ evidence_count: evidenceCount,
1348
+ domain_count: domainCount,
1349
+ structural_depth,
1350
+ validation_ratio: validationRatio,
1351
+ composite
1352
+ },
1353
+ hierarchy: {
1354
+ level: domainCount >= 3 ? "top" : "mop",
1355
+ parent: null,
1356
+ children: []
1357
+ },
1358
+ pipeline_version: PIPELINE_VERSION
1359
+ };
1360
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1361
+ const engram = {
1362
+ id,
1363
+ version: 2,
1364
+ status: "active",
1365
+ consolidated: false,
1366
+ type: "behavioral",
1367
+ scope: "global",
1368
+ visibility: "private",
1369
+ statement: parsed.statement,
1370
+ domain: "meta",
1371
+ tags: ["meta-engram", common_structure.goal_type, common_structure.constraint_type],
1372
+ activation: {
1373
+ retrieval_strength: composite,
1374
+ storage_strength: 1,
1375
+ frequency: 0,
1376
+ last_accessed: now.slice(0, 10)
1377
+ },
1378
+ feedback_signals: { positive: 0, negative: 0, neutral: 0 },
1379
+ knowledge_anchors: [],
1380
+ associations: [],
1381
+ derivation_count: evidenceCount,
1382
+ pack: null,
1383
+ abstract: null,
1384
+ derived_from: null,
1385
+ polarity: null,
1386
+ knowledge_type: {
1387
+ memory_class: "metacognitive",
1388
+ cognitive_level: "evaluate"
1389
+ },
1390
+ structured_data: { meta: metaField }
1391
+ };
1392
+ return engram;
1393
+ }
1394
+
1395
+ // src/meta/validation.ts
1396
+ async function validateMetaEngram(meta, testEngrams, testDomain, llm) {
1397
+ const metaField = meta.structured_data?.meta;
1398
+ if (!metaField) {
1399
+ return {
1400
+ meta_engram_id: meta.id,
1401
+ test_domain: testDomain,
1402
+ prediction_held: false,
1403
+ matching_engram_id: null,
1404
+ alignment_score: 0,
1405
+ rationale: "Meta-engram has no meta field"
1406
+ };
1407
+ }
1408
+ const template = metaField.structure.template;
1409
+ const testEngramSummary = testEngrams.filter((e) => e.status === "active").slice(0, 10).map((e) => ` - [${e.id}] ${sanitizeForPrompt(e.statement)}`).join("\n");
1410
+ if (!testEngramSummary) {
1411
+ return {
1412
+ meta_engram_id: meta.id,
1413
+ test_domain: testDomain,
1414
+ prediction_held: false,
1415
+ matching_engram_id: null,
1416
+ alignment_score: 0,
1417
+ rationale: "No test engrams available for validation"
1418
+ };
1419
+ }
1420
+ const prompt = `Meta-engram structural principle: ${sanitizeForPrompt(template)}
1421
+ Meta-engram statement: ${sanitizeForPrompt(meta.statement)}
1422
+
1423
+ Test domain: ${testDomain}
1424
+ Test engrams from this domain:
1425
+ ${testEngramSummary}
1426
+
1427
+ Task: Does any of the test engrams instantiate or validate this structural principle?
1428
+
1429
+ If YES (a test engram matches):
1430
+ - prediction_held: true
1431
+ - matching_engram_id: the ID of the matching engram
1432
+ - alignment_score: 0.5-1.0 (how well the structural template maps)
1433
+ - rationale: one sentence explaining how the test engram maps to the template
1434
+
1435
+ If NO (no test engram matches):
1436
+ - prediction_held: false
1437
+ - matching_engram_id: null
1438
+ - alignment_score: 0
1439
+ - 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]")
1440
+
1441
+ Return JSON:
1442
+ {
1443
+ "prediction_held": true|false,
1444
+ "matching_engram_id": "ENG-..." | null,
1445
+ "alignment_score": 0.0-1.0,
1446
+ "rationale": "one sentence explanation \u2014 REQUIRED even when prediction_held is false"
1447
+ }
1448
+
1449
+ Return ONLY valid JSON, no markdown fencing.`;
1450
+ try {
1451
+ const response = await llm(prompt);
1452
+ const cleaned = response.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
1453
+ const parsed = JSON.parse(cleaned);
1454
+ const result = {
1455
+ meta_engram_id: meta.id,
1456
+ test_domain: testDomain,
1457
+ prediction_held: Boolean(parsed.prediction_held),
1458
+ matching_engram_id: parsed.matching_engram_id ?? null,
1459
+ alignment_score: typeof parsed.alignment_score === "number" ? parsed.alignment_score : 0,
1460
+ rationale: parsed.rationale ?? ""
1461
+ };
1462
+ if (result.prediction_held) {
1463
+ if (!metaField.domain_coverage.validated.includes(testDomain)) {
1464
+ metaField.domain_coverage.validated.push(testDomain);
1465
+ }
1466
+ } else {
1467
+ if (!metaField.domain_coverage.failed.includes(testDomain)) {
1468
+ metaField.domain_coverage.failed.push(testDomain);
1469
+ }
1470
+ }
1471
+ const passes = metaField.domain_coverage.validated.length;
1472
+ const total = passes + metaField.domain_coverage.failed.length;
1473
+ const validationRatio = total > 0 ? passes / total : 0;
1474
+ const updatedComposite = computeMetaConfidence(
1475
+ metaField.confidence.evidence_count,
1476
+ metaField.confidence.domain_count,
1477
+ metaField.confidence.structural_depth,
1478
+ validationRatio
1479
+ );
1480
+ metaField.confidence.validation_ratio = validationRatio;
1481
+ metaField.confidence.composite = updatedComposite;
1482
+ metaField.last_validated = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
1483
+ const failedCount = metaField.domain_coverage.failed.length;
1484
+ if (failedCount >= 3) {
1485
+ if (metaField.hierarchy.level === "top") {
1486
+ metaField.hierarchy.level = "mop";
1487
+ } else {
1488
+ meta.status = "retired";
1489
+ }
1490
+ }
1491
+ return result;
1492
+ } catch {
1493
+ return {
1494
+ meta_engram_id: meta.id,
1495
+ test_domain: testDomain,
1496
+ prediction_held: false,
1497
+ matching_engram_id: null,
1498
+ alignment_score: 0,
1499
+ rationale: "LLM parsing failed during validation"
1500
+ };
1501
+ }
1502
+ }
1503
+
1504
+ // src/meta/hierarchy.ts
1505
+ var SUBSUMPTION_THRESHOLD = 0.75;
1506
+ function getMetaField(engram) {
1507
+ return engram.structured_data?.meta ?? null;
1508
+ }
1509
+ function getDomainCount(metaField) {
1510
+ const validated = metaField.domain_coverage.validated.length;
1511
+ const evidenceDomains = new Set(metaField.evidence.map((e) => e.domain)).size;
1512
+ return Math.max(validated, evidenceDomains, metaField.confidence.domain_count);
1513
+ }
1514
+ function organizeHierarchy(metaEngrams) {
1515
+ const metas = metaEngrams.filter((e) => getMetaField(e) !== null && e.id.startsWith("META-"));
1516
+ if (metas.length === 0) return metaEngrams;
1517
+ for (const meta of metas) {
1518
+ const mf = getMetaField(meta);
1519
+ mf.hierarchy.parent = null;
1520
+ mf.hierarchy.children = [];
1521
+ }
1522
+ for (let i = 0; i < metas.length; i++) {
1523
+ for (let j = 0; j < metas.length; j++) {
1524
+ if (i === j) continue;
1525
+ const mfI = getMetaField(metas[i]);
1526
+ const mfJ = getMetaField(metas[j]);
1527
+ const sim = tokenSimilarity(mfI.structure.template, mfJ.structure.template);
1528
+ if (sim < SUBSUMPTION_THRESHOLD) continue;
1529
+ const domainsI = getDomainCount(mfI);
1530
+ const domainsJ = getDomainCount(mfJ);
1531
+ if (domainsI > domainsJ) {
1532
+ if (!mfI.hierarchy.children.includes(metas[j].id)) {
1533
+ mfI.hierarchy.children.push(metas[j].id);
1534
+ }
1535
+ if (!mfJ.hierarchy.parent) {
1536
+ mfJ.hierarchy.parent = metas[i].id;
1537
+ } else {
1538
+ const currentParent = metas.find((m) => m.id === mfJ.hierarchy.parent);
1539
+ const currentParentMf = currentParent ? getMetaField(currentParent) : null;
1540
+ if (currentParentMf && getDomainCount(currentParentMf) < domainsI) {
1541
+ mfJ.hierarchy.parent = metas[i].id;
1542
+ }
1543
+ }
1544
+ }
1545
+ }
1546
+ }
1547
+ for (const meta of metas) {
1548
+ const mf = getMetaField(meta);
1549
+ const domains = getDomainCount(mf);
1550
+ if (domains >= 3 && !mf.hierarchy.parent) {
1551
+ mf.hierarchy.level = "top";
1552
+ } else {
1553
+ mf.hierarchy.level = "mop";
1554
+ }
1555
+ }
1556
+ return metaEngrams;
1557
+ }
1558
+
1559
+ // src/meta/pipeline.ts
1560
+ async function extractMetaEngrams(engrams, llm, options = {}) {
1561
+ const start = Date.now();
1562
+ const {
1563
+ run_validation = false,
1564
+ validation_engrams = [],
1565
+ existing_metas = [],
1566
+ min_cluster_size = 2
1567
+ } = options;
1568
+ let rejected_as_platitudes = 0;
1569
+ const analyses = await analyzeStructure(engrams, llm);
1570
+ const clusters = await clusterByStructure(analyses);
1571
+ const viableClusters = clusters.filter((c) => c.members.length >= min_cluster_size);
1572
+ const alignmentResults = await Promise.all(
1573
+ viableClusters.map((cluster) => alignCluster(cluster, llm))
1574
+ );
1575
+ const validAlignments = alignmentResults.filter((r) => r !== null);
1576
+ const formulated = [];
1577
+ for (const alignment of validAlignments) {
1578
+ const cluster = viableClusters.find((c) => c.cluster_id === alignment.cluster_id);
1579
+ const clusterDomains = cluster ? [...new Set(cluster.members.map((m) => m.domain))] : [];
1580
+ const meta = await formulateMetaEngram(alignment, llm, [...existing_metas, ...formulated], clusterDomains);
1581
+ if (meta === null) {
1582
+ rejected_as_platitudes++;
1583
+ } else {
1584
+ if (cluster) {
1585
+ const metaField = meta.structured_data?.meta;
1586
+ if (metaField) {
1587
+ const domainMap = new Map(cluster.members.map((m) => [m.engram_id, m.domain]));
1588
+ for (const ev of metaField.evidence) {
1589
+ if (domainMap.has(ev.engram_id)) {
1590
+ ev.domain = domainMap.get(ev.engram_id);
1591
+ }
1592
+ }
1593
+ metaField.domain_coverage.validated = clusterDomains;
1594
+ meta.domain = clusterDomains.length >= 3 ? "meta" : `meta.${clusterDomains[0] ?? "unknown"}`;
1595
+ }
1596
+ }
1597
+ formulated.push(meta);
1598
+ }
1599
+ }
1600
+ const validationResults = [];
1601
+ if (run_validation && validation_engrams.length > 0) {
1602
+ for (const meta of formulated) {
1603
+ const metaField = meta.structured_data?.meta;
1604
+ if (!metaField) continue;
1605
+ const evidenceDomains = new Set(metaField.evidence.map((e) => e.domain));
1606
+ const testEngrams = validation_engrams.filter((e) => !evidenceDomains.has(e.domain ?? ""));
1607
+ if (testEngrams.length > 0) {
1608
+ const byDomain = /* @__PURE__ */ new Map();
1609
+ for (const te of testEngrams) {
1610
+ const d = te.domain ?? "unknown";
1611
+ if (!byDomain.has(d)) byDomain.set(d, []);
1612
+ byDomain.get(d).push(te);
1613
+ }
1614
+ for (const [domain, domainEngrams] of byDomain) {
1615
+ const vr = await validateMetaEngram(meta, domainEngrams, domain, llm);
1616
+ validationResults.push(vr);
1617
+ }
1618
+ }
1619
+ }
1620
+ }
1621
+ const organized = organizeHierarchy(formulated);
1622
+ const duration_ms = Date.now() - start;
1623
+ return {
1624
+ engrams_analyzed: analyses.length,
1625
+ clusters_found: clusters.length,
1626
+ alignments_passed: validAlignments.length,
1627
+ meta_engrams_extracted: organized.length,
1628
+ rejected_as_platitudes,
1629
+ validation_results: validationResults,
1630
+ results: organized,
1631
+ duration_ms
1632
+ };
1633
+ }
1634
+
1635
+ // src/session-state.ts
1636
+ var SessionBreadcrumbs = class {
1637
+ toolCalls = [];
1638
+ engramsRecalled = [];
1639
+ recordToolCall(tool, args) {
1640
+ this.toolCalls.push({
1641
+ tool,
1642
+ args_keys: Object.keys(args).join(", "),
1643
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1644
+ });
1645
+ }
1646
+ recordEngramRecalled(engramId) {
1647
+ if (!this.engramsRecalled.includes(engramId)) {
1648
+ this.engramsRecalled.push(engramId);
1649
+ }
1650
+ }
1651
+ getToolCalls() {
1652
+ return this.toolCalls;
1653
+ }
1654
+ getEngramsRecalled() {
1655
+ return this.engramsRecalled;
1656
+ }
1657
+ /**
1658
+ * Returns only engram IDs that have the META- prefix.
1659
+ * These represent meta-engrams injected into the session context.
1660
+ */
1661
+ getMetaEngramsRecalled() {
1662
+ return this.engramsRecalled.filter((id) => id.startsWith("META-"));
1663
+ }
1664
+ generateContinuationContext() {
1665
+ if (this.toolCalls.length === 0 && this.engramsRecalled.length === 0) return "";
1666
+ const lines = [];
1667
+ if (this.toolCalls.length > 0) {
1668
+ const uniqueTools = [...new Set(this.toolCalls.map((tc) => tc.tool))];
1669
+ lines.push(`Tools used: ${uniqueTools.join(", ")}`);
1670
+ lines.push(`Total tool calls: ${this.toolCalls.length}`);
1671
+ }
1672
+ if (this.engramsRecalled.length > 0) {
1673
+ lines.push(`Engrams recalled: ${this.engramsRecalled.length}`);
1674
+ const metaCount = this.getMetaEngramsRecalled().length;
1675
+ if (metaCount > 0) {
1676
+ lines.push(`Meta-engrams: ${metaCount}`);
1677
+ }
1678
+ }
1679
+ return lines.join("\n");
1680
+ }
1681
+ };
1682
+
1683
+ // src/guardrails.ts
1684
+ function generateGuardrails() {
1685
+ return `## PLUR Memory Guardrails
1686
+
1687
+ ### Verification Protocol
1688
+ When recalling facts that will drive actions (server IPs, file paths, API endpoints, credential locations):
1689
+ 1. State the recalled fact explicitly before acting on it
1690
+ 2. Include the engram ID or search that produced it
1691
+ 3. If no engram matches, say "No engram found \u2014 verifying from filesystem" and check directly
1692
+ 4. Never interpolate between two engrams to produce a "probably correct" composite
1693
+
1694
+ 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.
1695
+
1696
+ ### Over-engineering Check
1697
+ Before proposing any new system, module, or architectural change:
1698
+ 1. What is the simplest version that solves the actual problem?
1699
+ 2. Is there an existing tool/pattern that already covers 80% of this?
1700
+ 3. Will this create maintenance burden disproportionate to its value?
1701
+
1702
+ If a task can be done in <20 lines of shell script, do that first.
1703
+
1704
+ ### Tool Selection Discipline
1705
+ Before invoking any external tool, apply the locality test:
1706
+ 1. Is the answer already in engrams? \u2192 plur.recall
1707
+ 2. Is the answer in the local filesystem? \u2192 Read/Grep/Glob
1708
+ 3. Is the answer derivable from context already loaded? \u2192 Just answer
1709
+ 4. Only if 1-3 fail \u2192 Use external tools
1710
+
1711
+ Meta-engrams flagged as "[structural transfer \u2014 untested in current domain]" are hypotheses, not rules. Test before applying.`;
1712
+ }
1713
+
1714
+ // src/schemas/meta-engram.ts
1715
+ import { z as z4 } from "zod";
1716
+ var StructuralTemplateSchema = z4.object({
1717
+ goal_type: z4.string().min(1),
1718
+ constraint_type: z4.string().min(1),
1719
+ outcome_type: z4.string().min(1),
1720
+ template: z4.string().min(1),
1721
+ /** Structural frame — declares which relational pattern this meta-engram uses.
1722
+ * Allows flexible analogy beyond rigid [goal]+[constraint]->[outcome]. */
1723
+ structure_type: z4.enum([
1724
+ "goal-constraint-outcome",
1725
+ "feedback-loop",
1726
+ "causal-chain",
1727
+ "recursive",
1728
+ "tradeoff",
1729
+ "freeform"
1730
+ ]).default("goal-constraint-outcome"),
1731
+ /** For patterns that don't fit the standard template fields — the LLM's own structural description */
1732
+ freeform_structure: z4.string().optional()
1733
+ });
1734
+ var EvidenceEntrySchema = z4.object({
1735
+ engram_id: z4.string(),
1736
+ domain: z4.string(),
1737
+ mapping_rationale: z4.string(),
1738
+ alignment_score: z4.number().min(0).max(1)
1739
+ });
1740
+ var FalsificationSchema = z4.object({
1741
+ expected_conditions: z4.string(),
1742
+ expected_exceptions: z4.string(),
1743
+ test_prediction: z4.string().optional()
1744
+ });
1745
+ var MetaConfidenceSchema = z4.object({
1746
+ evidence_count: z4.number().int().min(0),
1747
+ domain_count: z4.number().int().min(0),
1748
+ structural_depth: z4.number().int().min(1).max(5),
1749
+ validation_ratio: z4.number().min(0).max(1).default(0),
1750
+ composite: z4.number().min(0).max(1)
1751
+ });
1752
+ var DomainCoverageSchema = z4.object({
1753
+ validated: z4.array(z4.string()),
1754
+ failed: z4.array(z4.string()).default([]),
1755
+ predicted: z4.array(z4.string()).default([])
1756
+ });
1757
+ var HierarchyPositionSchema = z4.object({
1758
+ level: z4.enum(["mop", "top"]),
1759
+ parent: z4.string().nullable().default(null),
1760
+ children: z4.array(z4.string()).default([])
1761
+ });
1762
+ var MetaFieldSchema = z4.object({
1763
+ structure: StructuralTemplateSchema,
1764
+ evidence: z4.array(EvidenceEntrySchema).min(2),
1765
+ domain_coverage: DomainCoverageSchema,
1766
+ falsification: FalsificationSchema,
1767
+ confidence: MetaConfidenceSchema,
1768
+ hierarchy: HierarchyPositionSchema,
1769
+ pipeline_version: z4.string(),
1770
+ last_validated: z4.string().optional()
1771
+ });
1772
+
1186
1773
  // src/version-check.ts
1187
1774
  var cache = /* @__PURE__ */ new Map();
1188
1775
  async function checkForUpdate(packageName, currentVersion, onResult) {
@@ -1251,6 +1838,12 @@ var Plur = class {
1251
1838
  }
1252
1839
  /** Create engram, detect conflicts, save. Returns the created engram. */
1253
1840
  learn(statement, context) {
1841
+ if (!this.config.allow_secrets) {
1842
+ const secrets = detectSecrets(statement);
1843
+ if (secrets.length > 0) {
1844
+ throw new Error(`Secret detected in statement: ${secrets[0].pattern}. Use config.allow_secrets to override.`);
1845
+ }
1846
+ }
1254
1847
  const engrams = loadEngrams(this.paths.engrams);
1255
1848
  const id = generateEngramId(engrams);
1256
1849
  const scope = context?.scope ?? "global";
@@ -1282,6 +1875,7 @@ var Plur = class {
1282
1875
  pack: null,
1283
1876
  abstract: null,
1284
1877
  derived_from: null,
1878
+ polarity: null,
1285
1879
  relations: conflictIds.length > 0 ? {
1286
1880
  broader: [],
1287
1881
  narrower: [],
@@ -1339,10 +1933,20 @@ var Plur = class {
1339
1933
  this._reactivateResults(results);
1340
1934
  return results;
1341
1935
  }
1936
+ /** List all active engrams, optionally filtered by scope/domain. No search — returns all matches. */
1937
+ list(options) {
1938
+ return this._filterEngrams(options);
1939
+ }
1342
1940
  /** Filter engrams by scope/domain/strength (shared by both modes) */
1343
1941
  _filterEngrams(options) {
1344
1942
  let engrams = loadEngrams(this.paths.engrams);
1345
1943
  engrams = engrams.filter((e) => e.status === "active");
1944
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
1945
+ engrams = engrams.filter((e) => {
1946
+ if (e.temporal?.valid_until && e.temporal.valid_until < today) return false;
1947
+ if (e.temporal?.valid_from && e.temporal.valid_from > today) return false;
1948
+ return true;
1949
+ });
1346
1950
  if (options?.domain) {
1347
1951
  engrams = engrams.filter((e) => e.domain?.startsWith(options.domain));
1348
1952
  }
@@ -1357,20 +1961,52 @@ var Plur = class {
1357
1961
  }
1358
1962
  return engrams;
1359
1963
  }
1360
- /** Reactivate accessed engrams (bump retrieval strength, frequency, last_accessed) */
1964
+ /** Reactivate accessed engrams and update co-access associations */
1361
1965
  _reactivateResults(results) {
1362
1966
  if (results.length === 0) return;
1363
1967
  const allEngrams = loadEngrams(this.paths.engrams);
1364
1968
  const resultIds = new Set(results.map((e) => e.id));
1969
+ const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
1365
1970
  let modified = false;
1366
1971
  for (const e of allEngrams) {
1367
1972
  if (resultIds.has(e.id)) {
1368
1973
  e.activation.retrieval_strength = reactivate(e.activation.retrieval_strength);
1369
- e.activation.last_accessed = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
1974
+ e.activation.last_accessed = today;
1370
1975
  e.activation.frequency += 1;
1371
1976
  modified = true;
1372
1977
  }
1373
1978
  }
1979
+ if (results.length >= 2 && this.config.injection?.co_access !== false) {
1980
+ const topHalf = results.slice(0, Math.max(2, Math.ceil(results.length / 2)));
1981
+ const topIds = topHalf.map((e) => e.id);
1982
+ for (const sourceId of topIds) {
1983
+ const source = allEngrams.find((e) => e.id === sourceId);
1984
+ if (!source) continue;
1985
+ for (const targetId of topIds) {
1986
+ if (targetId === sourceId) continue;
1987
+ const existing = source.associations.find(
1988
+ (a) => a.type === "co_accessed" && a.target === targetId
1989
+ );
1990
+ if (existing) {
1991
+ existing.strength = Math.min(0.95, existing.strength + 0.05);
1992
+ existing.updated_at = today;
1993
+ modified = true;
1994
+ } else {
1995
+ const coAccessCount = source.associations.filter((a) => a.type === "co_accessed").length;
1996
+ if (coAccessCount < 5) {
1997
+ source.associations.push({
1998
+ target_type: "engram",
1999
+ target: targetId,
2000
+ type: "co_accessed",
2001
+ strength: 0.3,
2002
+ updated_at: today
2003
+ });
2004
+ modified = true;
2005
+ }
2006
+ }
2007
+ }
2008
+ }
2009
+ }
1374
2010
  if (modified) saveEngrams(this.paths.engrams, allEngrams);
1375
2011
  }
1376
2012
  /** Scored injection within token budget (BM25 only). Returns formatted strings. */
@@ -1416,11 +2052,13 @@ var Plur = class {
1416
2052
  return wires.map((e) => `[${e.id}] ${e.statement}`).join("\n");
1417
2053
  };
1418
2054
  const directivesStr = formatEngrams(result.directives);
2055
+ const constraintsStr = formatEngrams(result.constraints);
1419
2056
  const considerStr = formatEngrams(result.consider);
1420
- const count = result.directives.length + result.consider.length;
2057
+ const count = result.directives.length + result.constraints.length + result.consider.length;
1421
2058
  const tokensUsed = result.tokens_used.directives + result.tokens_used.consider;
1422
2059
  return {
1423
2060
  directives: directivesStr,
2061
+ constraints: constraintsStr,
1424
2062
  consider: considerStr,
1425
2063
  count,
1426
2064
  tokens_used: tokensUsed
@@ -1442,6 +2080,32 @@ var Plur = class {
1442
2080
  }
1443
2081
  saveEngrams(this.paths.engrams, engrams);
1444
2082
  }
2083
+ /** Save extracted meta-engrams to the engram store. Skips IDs that already exist. */
2084
+ saveMetaEngrams(metas) {
2085
+ const engrams = loadEngrams(this.paths.engrams);
2086
+ const existingIds = new Set(engrams.map((e) => e.id));
2087
+ let saved = 0;
2088
+ let skipped = 0;
2089
+ for (const meta of metas) {
2090
+ if (existingIds.has(meta.id)) {
2091
+ skipped++;
2092
+ } else {
2093
+ engrams.push(meta);
2094
+ saved++;
2095
+ }
2096
+ }
2097
+ if (saved > 0) saveEngrams(this.paths.engrams, engrams);
2098
+ return { saved, skipped };
2099
+ }
2100
+ /** Update an existing engram in the store by ID. Returns true if found and updated. */
2101
+ updateEngram(updated) {
2102
+ const engrams = loadEngrams(this.paths.engrams);
2103
+ const idx = engrams.findIndex((e) => e.id === updated.id);
2104
+ if (idx === -1) return false;
2105
+ engrams[idx] = updated;
2106
+ saveEngrams(this.paths.engrams, engrams);
2107
+ return true;
2108
+ }
1445
2109
  /** Set engram status to 'retired'. */
1446
2110
  forget(id, reason) {
1447
2111
  const engrams = loadEngrams(this.paths.engrams);
@@ -1472,6 +2136,7 @@ var Plur = class {
1472
2136
  const captured = match.slice(1).filter(Boolean).join(" ").trim();
1473
2137
  if (!captured || captured.length < 5) continue;
1474
2138
  if (seen.has(captured.toLowerCase())) continue;
2139
+ if (!this.config.allow_secrets && detectSecrets(captured).length > 0) continue;
1475
2140
  seen.add(captured.toLowerCase());
1476
2141
  candidates.push({
1477
2142
  statement: captured,
@@ -1527,10 +2192,34 @@ var Plur = class {
1527
2192
  }
1528
2193
  };
1529
2194
  export {
2195
+ DomainCoverageSchema,
2196
+ EvidenceEntrySchema,
2197
+ FalsificationSchema,
2198
+ HierarchyPositionSchema,
2199
+ MetaConfidenceSchema,
2200
+ MetaFieldSchema,
2201
+ PLATITUDE_PATTERNS,
1530
2202
  Plur,
2203
+ SessionBreadcrumbs,
2204
+ StructuralTemplateSchema,
2205
+ alignCluster,
2206
+ analyzeStructure,
1531
2207
  checkForUpdate,
2208
+ classifyPolarity,
1532
2209
  clearVersionCache,
2210
+ clusterByStructure,
2211
+ computeConfidence,
2212
+ computeMetaConfidence,
2213
+ confidenceBand,
1533
2214
  detectPlurStorage,
2215
+ detectSecrets,
1534
2216
  engramSearchText,
1535
- getCachedUpdateCheck
2217
+ extractMetaEngrams,
2218
+ formulateMetaEngram,
2219
+ generateGuardrails,
2220
+ getCachedUpdateCheck,
2221
+ isPlatitude,
2222
+ organizeHierarchy,
2223
+ tokenSimilarity,
2224
+ validateMetaEngram
1536
2225
  };