@nxuss/lemma 1.23.0 → 1.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. package/README.md +18 -6
  2. package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
  3. package/dist/cjs/cli/lemma-proxy.js +15 -3
  4. package/dist/cjs/cli/lemma-proxy.js.map +1 -1
  5. package/dist/cjs/infra/errorCause.d.ts +36 -0
  6. package/dist/cjs/infra/errorCause.d.ts.map +1 -0
  7. package/dist/cjs/infra/errorCause.js +143 -0
  8. package/dist/cjs/infra/errorCause.js.map +1 -0
  9. package/dist/cjs/infra/providers/JenkinsProvider.d.ts.map +1 -1
  10. package/dist/cjs/infra/providers/JenkinsProvider.js +5 -0
  11. package/dist/cjs/infra/providers/JenkinsProvider.js.map +1 -1
  12. package/dist/cjs/infra/providers/OKDProvider.d.ts.map +1 -1
  13. package/dist/cjs/infra/providers/OKDProvider.js +5 -1
  14. package/dist/cjs/infra/providers/OKDProvider.js.map +1 -1
  15. package/dist/cjs/infra/providers/TerraformProvider.d.ts.map +1 -1
  16. package/dist/cjs/infra/providers/TerraformProvider.js +3 -1
  17. package/dist/cjs/infra/providers/TerraformProvider.js.map +1 -1
  18. package/dist/cjs/mcp/index.js +21 -0
  19. package/dist/cjs/mcp/index.js.map +1 -1
  20. package/dist/cjs/mcp/tool-profiles.d.ts +6 -4
  21. package/dist/cjs/mcp/tool-profiles.d.ts.map +1 -1
  22. package/dist/cjs/mcp/tool-profiles.js.map +1 -1
  23. package/dist/cjs/mcp/tools/context-tools.d.ts.map +1 -1
  24. package/dist/cjs/mcp/tools/context-tools.js +3 -1
  25. package/dist/cjs/mcp/tools/context-tools.js.map +1 -1
  26. package/dist/cjs/mcp/tools/memory.d.ts.map +1 -1
  27. package/dist/cjs/mcp/tools/memory.js +45 -10
  28. package/dist/cjs/mcp/tools/memory.js.map +1 -1
  29. package/dist/cjs/mcp/tools/misc.d.ts.map +1 -1
  30. package/dist/cjs/mcp/tools/misc.js +21 -9
  31. package/dist/cjs/mcp/tools/misc.js.map +1 -1
  32. package/dist/cjs/mcp/tools/squeeze-cache.d.ts +6 -0
  33. package/dist/cjs/mcp/tools/squeeze-cache.d.ts.map +1 -1
  34. package/dist/cjs/mcp/tools/squeeze-cache.js +57 -17
  35. package/dist/cjs/mcp/tools/squeeze-cache.js.map +1 -1
  36. package/dist/cjs/mcp/tools/workspace.d.ts.map +1 -1
  37. package/dist/cjs/mcp/tools/workspace.js +7 -2
  38. package/dist/cjs/mcp/tools/workspace.js.map +1 -1
  39. package/dist/cjs/mcp/tools.d.ts +9 -0
  40. package/dist/cjs/mcp/tools.d.ts.map +1 -1
  41. package/dist/cjs/mcp/tools.js +72 -12
  42. package/dist/cjs/mcp/tools.js.map +1 -1
  43. package/dist/cjs/mcp/utils.d.ts.map +1 -1
  44. package/dist/cjs/mcp/utils.js +18 -4
  45. package/dist/cjs/mcp/utils.js.map +1 -1
  46. package/dist/cjs/mcp/workspaceShared.d.ts +1 -0
  47. package/dist/cjs/mcp/workspaceShared.d.ts.map +1 -1
  48. package/dist/cjs/mcp/workspaceShared.js +27 -0
  49. package/dist/cjs/mcp/workspaceShared.js.map +1 -1
  50. package/dist/cjs/subconscious/TheBrainV2.d.ts +43 -0
  51. package/dist/cjs/subconscious/TheBrainV2.d.ts.map +1 -1
  52. package/dist/cjs/subconscious/TheBrainV2.js +79 -7
  53. package/dist/cjs/subconscious/TheBrainV2.js.map +1 -1
  54. package/dist/cjs/utils/AnomalyInventory.d.ts +29 -0
  55. package/dist/cjs/utils/AnomalyInventory.d.ts.map +1 -0
  56. package/dist/cjs/utils/AnomalyInventory.js +58 -0
  57. package/dist/cjs/utils/AnomalyInventory.js.map +1 -0
  58. package/dist/cjs/utils/ExecutiveReport.d.ts +10 -0
  59. package/dist/cjs/utils/ExecutiveReport.d.ts.map +1 -1
  60. package/dist/cjs/utils/ExecutiveReport.js +17 -1
  61. package/dist/cjs/utils/ExecutiveReport.js.map +1 -1
  62. package/dist/cjs/utils/SavingsLedger.d.ts +45 -2
  63. package/dist/cjs/utils/SavingsLedger.d.ts.map +1 -1
  64. package/dist/cjs/utils/SavingsLedger.js +89 -5
  65. package/dist/cjs/utils/SavingsLedger.js.map +1 -1
  66. package/dist/cjs/utils/SessionEvidence.d.ts +28 -0
  67. package/dist/cjs/utils/SessionEvidence.d.ts.map +1 -0
  68. package/dist/cjs/utils/SessionEvidence.js +55 -0
  69. package/dist/cjs/utils/SessionEvidence.js.map +1 -0
  70. package/dist/cjs/utils/StateHashCache.d.ts +10 -0
  71. package/dist/cjs/utils/StateHashCache.d.ts.map +1 -1
  72. package/dist/cjs/utils/StateHashCache.js +15 -0
  73. package/dist/cjs/utils/StateHashCache.js.map +1 -1
  74. package/dist/cjs/utils/reportSavings.d.ts +4 -0
  75. package/dist/cjs/utils/reportSavings.d.ts.map +1 -1
  76. package/dist/cjs/utils/reportSavings.js.map +1 -1
  77. package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
  78. package/dist/esm/cli/lemma-proxy.js +15 -3
  79. package/dist/esm/cli/lemma-proxy.js.map +1 -1
  80. package/dist/esm/infra/errorCause.d.ts +36 -0
  81. package/dist/esm/infra/errorCause.d.ts.map +1 -0
  82. package/dist/esm/infra/errorCause.js +138 -0
  83. package/dist/esm/infra/errorCause.js.map +1 -0
  84. package/dist/esm/infra/providers/JenkinsProvider.d.ts.map +1 -1
  85. package/dist/esm/infra/providers/JenkinsProvider.js +5 -0
  86. package/dist/esm/infra/providers/JenkinsProvider.js.map +1 -1
  87. package/dist/esm/infra/providers/OKDProvider.d.ts.map +1 -1
  88. package/dist/esm/infra/providers/OKDProvider.js +5 -1
  89. package/dist/esm/infra/providers/OKDProvider.js.map +1 -1
  90. package/dist/esm/infra/providers/TerraformProvider.d.ts.map +1 -1
  91. package/dist/esm/infra/providers/TerraformProvider.js +3 -1
  92. package/dist/esm/infra/providers/TerraformProvider.js.map +1 -1
  93. package/dist/esm/mcp/index.js +21 -0
  94. package/dist/esm/mcp/index.js.map +1 -1
  95. package/dist/esm/mcp/tool-profiles.d.ts +6 -4
  96. package/dist/esm/mcp/tool-profiles.d.ts.map +1 -1
  97. package/dist/esm/mcp/tool-profiles.js.map +1 -1
  98. package/dist/esm/mcp/tools/context-tools.d.ts.map +1 -1
  99. package/dist/esm/mcp/tools/context-tools.js +3 -1
  100. package/dist/esm/mcp/tools/context-tools.js.map +1 -1
  101. package/dist/esm/mcp/tools/memory.d.ts.map +1 -1
  102. package/dist/esm/mcp/tools/memory.js +45 -10
  103. package/dist/esm/mcp/tools/memory.js.map +1 -1
  104. package/dist/esm/mcp/tools/misc.d.ts.map +1 -1
  105. package/dist/esm/mcp/tools/misc.js +21 -9
  106. package/dist/esm/mcp/tools/misc.js.map +1 -1
  107. package/dist/esm/mcp/tools/squeeze-cache.d.ts +6 -0
  108. package/dist/esm/mcp/tools/squeeze-cache.d.ts.map +1 -1
  109. package/dist/esm/mcp/tools/squeeze-cache.js +56 -17
  110. package/dist/esm/mcp/tools/squeeze-cache.js.map +1 -1
  111. package/dist/esm/mcp/tools/workspace.d.ts.map +1 -1
  112. package/dist/esm/mcp/tools/workspace.js +8 -3
  113. package/dist/esm/mcp/tools/workspace.js.map +1 -1
  114. package/dist/esm/mcp/tools.d.ts +9 -0
  115. package/dist/esm/mcp/tools.d.ts.map +1 -1
  116. package/dist/esm/mcp/tools.js +71 -12
  117. package/dist/esm/mcp/tools.js.map +1 -1
  118. package/dist/esm/mcp/utils.d.ts.map +1 -1
  119. package/dist/esm/mcp/utils.js +18 -4
  120. package/dist/esm/mcp/utils.js.map +1 -1
  121. package/dist/esm/mcp/workspaceShared.d.ts +1 -0
  122. package/dist/esm/mcp/workspaceShared.d.ts.map +1 -1
  123. package/dist/esm/mcp/workspaceShared.js +26 -0
  124. package/dist/esm/mcp/workspaceShared.js.map +1 -1
  125. package/dist/esm/subconscious/TheBrainV2.d.ts +43 -0
  126. package/dist/esm/subconscious/TheBrainV2.d.ts.map +1 -1
  127. package/dist/esm/subconscious/TheBrainV2.js +79 -7
  128. package/dist/esm/subconscious/TheBrainV2.js.map +1 -1
  129. package/dist/esm/utils/AnomalyInventory.d.ts +29 -0
  130. package/dist/esm/utils/AnomalyInventory.d.ts.map +1 -0
  131. package/dist/esm/utils/AnomalyInventory.js +49 -0
  132. package/dist/esm/utils/AnomalyInventory.js.map +1 -0
  133. package/dist/esm/utils/ExecutiveReport.d.ts +10 -0
  134. package/dist/esm/utils/ExecutiveReport.d.ts.map +1 -1
  135. package/dist/esm/utils/ExecutiveReport.js +17 -1
  136. package/dist/esm/utils/ExecutiveReport.js.map +1 -1
  137. package/dist/esm/utils/SavingsLedger.d.ts +45 -2
  138. package/dist/esm/utils/SavingsLedger.d.ts.map +1 -1
  139. package/dist/esm/utils/SavingsLedger.js +89 -5
  140. package/dist/esm/utils/SavingsLedger.js.map +1 -1
  141. package/dist/esm/utils/SessionEvidence.d.ts +28 -0
  142. package/dist/esm/utils/SessionEvidence.d.ts.map +1 -0
  143. package/dist/esm/utils/SessionEvidence.js +49 -0
  144. package/dist/esm/utils/SessionEvidence.js.map +1 -0
  145. package/dist/esm/utils/StateHashCache.d.ts +10 -0
  146. package/dist/esm/utils/StateHashCache.d.ts.map +1 -1
  147. package/dist/esm/utils/StateHashCache.js +14 -0
  148. package/dist/esm/utils/StateHashCache.js.map +1 -1
  149. package/dist/esm/utils/reportSavings.d.ts +4 -0
  150. package/dist/esm/utils/reportSavings.d.ts.map +1 -1
  151. package/dist/esm/utils/reportSavings.js.map +1 -1
  152. package/package.json +1 -1
@@ -331,6 +331,12 @@ function parseEntriesWithStats(raw) {
331
331
  // don't. Rebuilding from termFreq covers both without a migration step.
332
332
  if (!Array.isArray(entry.terms))
333
333
  entry.terms = Object.keys(entry.termFreq || {});
334
+ // Entries written before clear-path persistence keep only hashes: backfill the
335
+ // labels from the hash keys so old memories become navigable on first read.
336
+ // Next save() persists the backfill — no separate migration step, no rewrite.
337
+ syncClearEvidencePaths(entry);
338
+ for (const claim of entry.claims || [])
339
+ syncClearEvidencePaths(claim);
334
340
  out.set(entry.id, entry);
335
341
  }
336
342
  catch {
@@ -1114,16 +1120,38 @@ function trackedClaimArtifactCount(claim) {
1114
1120
  return Object.keys(claim.fileHashes || {}).length + Object.keys(claim.symbolHashes || {}).length;
1115
1121
  }
1116
1122
  /** Builds the persisted `Claim[]` for an entry from the caller-supplied claim inputs. */
1123
+ /**
1124
+ * Re-derive the clear-path labels from the hash keys they describe. One-way only:
1125
+ * hashes are the source of truth, these fields are the navigable label. Called on
1126
+ * every path that (re)writes evidence — store(), reanchorEvidence(), and the load
1127
+ * backfill — so the three can never disagree about which file a memory means.
1128
+ */
1129
+ function syncClearEvidencePaths(target) {
1130
+ const files = target.fileHashes ? Object.keys(target.fileHashes).sort() : [];
1131
+ if (files.length > 0)
1132
+ target.filePaths = files;
1133
+ else
1134
+ delete target.filePaths;
1135
+ const syms = target.symbolHashes ? Object.keys(target.symbolHashes).sort() : [];
1136
+ if (syms.length > 0)
1137
+ target.symbols = syms;
1138
+ else
1139
+ delete target.symbols;
1140
+ }
1117
1141
  function buildClaims(inputs) {
1118
1142
  return inputs
1119
1143
  .filter((c) => c?.text)
1120
- .map((c) => ({
1121
- id: crypto_1.default.createHash('sha1').update(c.text.trim().toLowerCase()).digest('hex').substring(0, 10),
1122
- text: c.text.trim(),
1123
- fileHashes: c.filePaths && c.filePaths.length > 0 ? hashFilesForFreshness(c.filePaths) : undefined,
1124
- symbolHashes: c.symbols && c.symbols.length > 0 ? hashSymbolsForFreshness(c.symbols) : undefined,
1125
- symbolNormalizedHashes: c.symbols && c.symbols.length > 0 ? hashSymbolsNormalizedForFreshness(c.symbols) : undefined,
1126
- }));
1144
+ .map((c) => {
1145
+ const claim = {
1146
+ id: crypto_1.default.createHash('sha1').update(c.text.trim().toLowerCase()).digest('hex').substring(0, 10),
1147
+ text: c.text.trim(),
1148
+ fileHashes: c.filePaths && c.filePaths.length > 0 ? hashFilesForFreshness(c.filePaths) : undefined,
1149
+ symbolHashes: c.symbols && c.symbols.length > 0 ? hashSymbolsForFreshness(c.symbols) : undefined,
1150
+ symbolNormalizedHashes: c.symbols && c.symbols.length > 0 ? hashSymbolsNormalizedForFreshness(c.symbols) : undefined,
1151
+ };
1152
+ syncClearEvidencePaths(claim);
1153
+ return claim;
1154
+ });
1127
1155
  }
1128
1156
  /**
1129
1157
  * Same hash-compare as checkEntryFreshness, scoped to one claim's own evidence — a claim
@@ -1352,6 +1380,22 @@ class TheBrainV2 {
1352
1380
  this.save();
1353
1381
  }, 500);
1354
1382
  }
1383
+ /**
1384
+ * Synchronously persist pending writes, if any. The debounced scheduleSave() above
1385
+ * is correct for a long-lived server but loses data when the process is about to
1386
+ * die: one-shot clients (lemma-call, the Muse skill path) kill the MCP server right
1387
+ * after the tool response, so without this every one-shot store/update/forget is
1388
+ * silently dropped. Installed as a SIGTERM/SIGINT handler by the MCP bootstrap —
1389
+ * never called on the hot path, where the debounce still applies.
1390
+ */
1391
+ flushSync() {
1392
+ if (this.flushTimer) {
1393
+ clearTimeout(this.flushTimer);
1394
+ this.flushTimer = null;
1395
+ }
1396
+ if (this.dirty)
1397
+ this.save();
1398
+ }
1355
1399
  save() {
1356
1400
  const fd = acquireLock();
1357
1401
  let wroteClean = false;
@@ -1575,6 +1619,9 @@ class TheBrainV2 {
1575
1619
  ...(git.commit ? { gitCommit: git.commit } : {}),
1576
1620
  ...(git.branch ? { gitBranch: git.branch } : {}),
1577
1621
  };
1622
+ // Persist the tracked paths in clear next to the hashes (AN-03) — the labels
1623
+ // display and navigation read from here; freshness keeps reading the hashes.
1624
+ syncClearEvidencePaths(entry);
1578
1625
  this.entries.set(id, entry);
1579
1626
  // Update inverted index
1580
1627
  for (const term of entry.terms) {
@@ -1687,6 +1734,11 @@ class TheBrainV2 {
1687
1734
  const entry = this.entries.get(id);
1688
1735
  if (!entry)
1689
1736
  continue;
1737
+ // A superseded entry is a known-wrong conclusion with a named successor (AN-22) — it
1738
+ // must never rank as if still live, unlike a downvote which only demotes. get_memory
1739
+ // still resolves it directly and points at the successor; search() just never offers it.
1740
+ if (entry.supersededBy)
1741
+ continue;
1690
1742
  const bm25 = bm25Score(queryTerms, entry.termFreq, entry.terms.length, this.avgDocLength || 10, idf);
1691
1743
  const docTermSet = new Set(entry.terms);
1692
1744
  const jaccard = jaccardSimilarity(queryTermSet, docTermSet);
@@ -2470,6 +2522,11 @@ class TheBrainV2 {
2470
2522
  }
2471
2523
  }
2472
2524
  }
2525
+ // Hashes were just rewritten — re-derive the clear labels so they track the same
2526
+ // files (covers both the re-point and the re-anchor branches above, and update()).
2527
+ syncClearEvidencePaths(entry);
2528
+ for (const claim of entry.claims || [])
2529
+ syncClearEvidencePaths(claim);
2473
2530
  return retracked;
2474
2531
  }
2475
2532
  refresh(id, opts = {}) {
@@ -2521,6 +2578,16 @@ class TheBrainV2 {
2521
2578
  const entry = this.entries.get(id);
2522
2579
  if (!entry)
2523
2580
  return { ok: false, message: `No entry with id "${id}" in the Brain.` };
2581
+ if (patch.supersededBy !== undefined) {
2582
+ const successorId = patch.supersededBy.trim();
2583
+ if (successorId && successorId === id) {
2584
+ return { ok: false, message: `"${id}" cannot supersede itself.` };
2585
+ }
2586
+ if (successorId && !this.entries.has(successorId)) {
2587
+ return { ok: false, message: `supersededBy target "${successorId}" is not an entry in the Brain — check the id with get_memory first.` };
2588
+ }
2589
+ entry.supersededBy = successorId || undefined;
2590
+ }
2524
2591
  // Same one-way redaction as store(): a corrected response pasted with a fresh secret
2525
2592
  // must not be the one write path that persists credentials.
2526
2593
  let updateRedactions = 0;
@@ -3066,6 +3133,7 @@ class TheBrainV2 {
3066
3133
  let downvoted = 0;
3067
3134
  let unscoped = 0;
3068
3135
  let untracked = 0;
3136
+ let withClearPaths = 0;
3069
3137
  let oldest = '';
3070
3138
  let totalTokensSaved = 0;
3071
3139
  const savers = [];
@@ -3082,6 +3150,9 @@ class TheBrainV2 {
3082
3150
  projects.add(entry.projectId);
3083
3151
  if (trackedArtifactCount(entry) === 0)
3084
3152
  untracked++;
3153
+ else if (entry.filePaths !== undefined || entry.symbols !== undefined ||
3154
+ (entry.claims || []).some((c) => c.filePaths !== undefined || c.symbols !== undefined))
3155
+ withClearPaths++;
3085
3156
  if (entry.tokensSaved) {
3086
3157
  totalTokensSaved += entry.tokensSaved;
3087
3158
  savers.push({ id: entry.id, query: entry.query.slice(0, 80), tokensSaved: entry.tokensSaved, hits: entry.hits });
@@ -3102,6 +3173,7 @@ class TheBrainV2 {
3102
3173
  base.projects = projects.size;
3103
3174
  base.unscopedEntries = unscoped;
3104
3175
  base.untrackedEntries = untracked;
3176
+ base.withClearPaths = withClearPaths;
3105
3177
  base.tombstones = this.tombstones.size;
3106
3178
  if (oldest)
3107
3179
  base.oldestEntry = oldest;