@nxuss/lemma 1.38.0 → 1.40.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.
Files changed (431) hide show
  1. package/README.md +3 -4
  2. package/bin/brain-ingest.js +68 -31
  3. package/bin/init.js +25 -28
  4. package/dashboard/dist/assets/index-DNTQXLER.css +1 -0
  5. package/dashboard/dist/assets/index-DzL_Zu3m.js +452 -0
  6. package/dashboard/dist/index.html +2 -2
  7. package/dist/cjs/cli/gitHooks.d.ts +9 -2
  8. package/dist/cjs/cli/gitHooks.d.ts.map +1 -1
  9. package/dist/cjs/cli/gitHooks.js +31 -4
  10. package/dist/cjs/cli/gitHooks.js.map +1 -1
  11. package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
  12. package/dist/cjs/cli/lemma-proxy.js +21 -1
  13. package/dist/cjs/cli/lemma-proxy.js.map +1 -1
  14. package/dist/cjs/infra/analyzers/index.d.ts +0 -2
  15. package/dist/cjs/infra/analyzers/index.d.ts.map +1 -1
  16. package/dist/cjs/infra/analyzers/index.js +1 -6
  17. package/dist/cjs/infra/analyzers/index.js.map +1 -1
  18. package/dist/cjs/infra/cli.d.ts +4 -0
  19. package/dist/cjs/infra/cli.d.ts.map +1 -1
  20. package/dist/cjs/infra/cli.js +6 -199
  21. package/dist/cjs/infra/cli.js.map +1 -1
  22. package/dist/cjs/infra/index.d.ts +1 -3
  23. package/dist/cjs/infra/index.d.ts.map +1 -1
  24. package/dist/cjs/infra/index.js +1 -16
  25. package/dist/cjs/infra/index.js.map +1 -1
  26. package/dist/cjs/infra/mcp-tools.d.ts.map +1 -1
  27. package/dist/cjs/infra/mcp-tools.js +8 -453
  28. package/dist/cjs/infra/mcp-tools.js.map +1 -1
  29. package/dist/cjs/infra/types.d.ts +0 -101
  30. package/dist/cjs/infra/types.d.ts.map +1 -1
  31. package/dist/cjs/infra/types.js +2 -1
  32. package/dist/cjs/infra/types.js.map +1 -1
  33. package/dist/cjs/mcp/cognitiveMap.d.ts.map +1 -1
  34. package/dist/cjs/mcp/cognitiveMap.js +6 -2
  35. package/dist/cjs/mcp/cognitiveMap.js.map +1 -1
  36. package/dist/cjs/mcp/index.js +2 -0
  37. package/dist/cjs/mcp/index.js.map +1 -1
  38. package/dist/cjs/mcp/prompts.d.ts +1 -1
  39. package/dist/cjs/mcp/prompts.d.ts.map +1 -1
  40. package/dist/cjs/mcp/prompts.js +8 -23
  41. package/dist/cjs/mcp/prompts.js.map +1 -1
  42. package/dist/cjs/mcp/tool-profiles.d.ts +8 -3
  43. package/dist/cjs/mcp/tool-profiles.d.ts.map +1 -1
  44. package/dist/cjs/mcp/tool-profiles.js +25 -54
  45. package/dist/cjs/mcp/tool-profiles.js.map +1 -1
  46. package/dist/cjs/mcp/tools/devtools.d.ts.map +1 -1
  47. package/dist/cjs/mcp/tools/devtools.js +11 -1
  48. package/dist/cjs/mcp/tools/devtools.js.map +1 -1
  49. package/dist/cjs/mcp/tools/memory.d.ts +8 -0
  50. package/dist/cjs/mcp/tools/memory.d.ts.map +1 -1
  51. package/dist/cjs/mcp/tools/memory.js +209 -137
  52. package/dist/cjs/mcp/tools/memory.js.map +1 -1
  53. package/dist/cjs/mcp/tools/refactor.d.ts.map +1 -1
  54. package/dist/cjs/mcp/tools/refactor.js +129 -32
  55. package/dist/cjs/mcp/tools/refactor.js.map +1 -1
  56. package/dist/cjs/mcp/tools/workspace.d.ts.map +1 -1
  57. package/dist/cjs/mcp/tools/workspace.js +108 -8
  58. package/dist/cjs/mcp/tools/workspace.js.map +1 -1
  59. package/dist/cjs/mcp/tools.d.ts.map +1 -1
  60. package/dist/cjs/mcp/tools.js +11 -6
  61. package/dist/cjs/mcp/tools.js.map +1 -1
  62. package/dist/cjs/mcp/workspaceShared.d.ts.map +1 -1
  63. package/dist/cjs/mcp/workspaceShared.js +8 -4
  64. package/dist/cjs/mcp/workspaceShared.js.map +1 -1
  65. package/dist/cjs/proxy/ProjectRegistry.d.ts +20 -0
  66. package/dist/cjs/proxy/ProjectRegistry.d.ts.map +1 -1
  67. package/dist/cjs/proxy/ProjectRegistry.js +46 -4
  68. package/dist/cjs/proxy/ProjectRegistry.js.map +1 -1
  69. package/dist/cjs/proxy/ProjectStore.d.ts.map +1 -1
  70. package/dist/cjs/proxy/ProjectStore.js +9 -6
  71. package/dist/cjs/proxy/ProjectStore.js.map +1 -1
  72. package/dist/cjs/subconscious/HostRecall.d.ts +26 -2
  73. package/dist/cjs/subconscious/HostRecall.d.ts.map +1 -1
  74. package/dist/cjs/subconscious/HostRecall.js +115 -40
  75. package/dist/cjs/subconscious/HostRecall.js.map +1 -1
  76. package/dist/cjs/subconscious/NarrowEvidence.d.ts +53 -0
  77. package/dist/cjs/subconscious/NarrowEvidence.d.ts.map +1 -0
  78. package/dist/cjs/subconscious/NarrowEvidence.js +237 -0
  79. package/dist/cjs/subconscious/NarrowEvidence.js.map +1 -0
  80. package/dist/cjs/subconscious/TheBrainV2.d.ts +48 -0
  81. package/dist/cjs/subconscious/TheBrainV2.d.ts.map +1 -1
  82. package/dist/cjs/subconscious/TheBrainV2.js +227 -26
  83. package/dist/cjs/subconscious/TheBrainV2.js.map +1 -1
  84. package/dist/cjs/subconscious/freshness/LocalFsResolver.d.ts.map +1 -1
  85. package/dist/cjs/subconscious/freshness/LocalFsResolver.js +32 -0
  86. package/dist/cjs/subconscious/freshness/LocalFsResolver.js.map +1 -1
  87. package/dist/cjs/subconscious/recallDigest.d.ts +8 -0
  88. package/dist/cjs/subconscious/recallDigest.d.ts.map +1 -1
  89. package/dist/cjs/subconscious/recallDigest.js +13 -1
  90. package/dist/cjs/subconscious/recallDigest.js.map +1 -1
  91. package/dist/cjs/utils/AffectedTests.d.ts +1 -5
  92. package/dist/cjs/utils/AffectedTests.d.ts.map +1 -1
  93. package/dist/cjs/utils/AffectedTests.js +5 -37
  94. package/dist/cjs/utils/AffectedTests.js.map +1 -1
  95. package/dist/cjs/utils/AtomicFile.d.ts +14 -0
  96. package/dist/cjs/utils/AtomicFile.d.ts.map +1 -0
  97. package/dist/cjs/utils/AtomicFile.js +44 -0
  98. package/dist/cjs/utils/AtomicFile.js.map +1 -0
  99. package/dist/cjs/utils/AutoContextBundle.js +1 -1
  100. package/dist/cjs/utils/AutoContextBundle.js.map +1 -1
  101. package/dist/cjs/utils/BulkFileDigest.js +1 -1
  102. package/dist/cjs/utils/BulkFileDigest.js.map +1 -1
  103. package/dist/cjs/utils/ContextSqueezer.d.ts +36 -4
  104. package/dist/cjs/utils/ContextSqueezer.d.ts.map +1 -1
  105. package/dist/cjs/utils/ContextSqueezer.js +69 -21
  106. package/dist/cjs/utils/ContextSqueezer.js.map +1 -1
  107. package/dist/cjs/utils/FileLock.d.ts +2 -0
  108. package/dist/cjs/utils/FileLock.d.ts.map +1 -0
  109. package/dist/cjs/utils/FileLock.js +32 -0
  110. package/dist/cjs/utils/FileLock.js.map +1 -0
  111. package/dist/cjs/utils/FileOutline.d.ts +1 -1
  112. package/dist/cjs/utils/FileOutline.d.ts.map +1 -1
  113. package/dist/cjs/utils/FileOutline.js +5 -1
  114. package/dist/cjs/utils/FileOutline.js.map +1 -1
  115. package/dist/cjs/utils/FixCapture.d.ts.map +1 -1
  116. package/dist/cjs/utils/FixCapture.js +4 -3
  117. package/dist/cjs/utils/FixCapture.js.map +1 -1
  118. package/dist/cjs/utils/GitChanges.d.ts +11 -0
  119. package/dist/cjs/utils/GitChanges.d.ts.map +1 -0
  120. package/dist/cjs/utils/GitChanges.js +44 -0
  121. package/dist/cjs/utils/GitChanges.js.map +1 -0
  122. package/dist/cjs/utils/JsonKeys.d.ts +17 -0
  123. package/dist/cjs/utils/JsonKeys.d.ts.map +1 -0
  124. package/dist/cjs/utils/JsonKeys.js +75 -0
  125. package/dist/cjs/utils/JsonKeys.js.map +1 -0
  126. package/dist/cjs/utils/LocalExclude.d.ts +3 -0
  127. package/dist/cjs/utils/LocalExclude.d.ts.map +1 -0
  128. package/dist/cjs/utils/LocalExclude.js +68 -0
  129. package/dist/cjs/utils/LocalExclude.js.map +1 -0
  130. package/dist/cjs/utils/OtherLanguageSymbols.d.ts +31 -0
  131. package/dist/cjs/utils/OtherLanguageSymbols.d.ts.map +1 -0
  132. package/dist/cjs/utils/OtherLanguageSymbols.js +276 -0
  133. package/dist/cjs/utils/OtherLanguageSymbols.js.map +1 -0
  134. package/dist/cjs/utils/OutputDelta.d.ts +14 -2
  135. package/dist/cjs/utils/OutputDelta.d.ts.map +1 -1
  136. package/dist/cjs/utils/OutputDelta.js +22 -15
  137. package/dist/cjs/utils/OutputDelta.js.map +1 -1
  138. package/dist/cjs/utils/RoiLedger.d.ts.map +1 -1
  139. package/dist/cjs/utils/RoiLedger.js +7 -3
  140. package/dist/cjs/utils/RoiLedger.js.map +1 -1
  141. package/dist/cjs/utils/SavingsLedger.d.ts +27 -0
  142. package/dist/cjs/utils/SavingsLedger.d.ts.map +1 -1
  143. package/dist/cjs/utils/SavingsLedger.js +56 -2
  144. package/dist/cjs/utils/SavingsLedger.js.map +1 -1
  145. package/dist/cjs/utils/SharedLedgerStore.d.ts.map +1 -1
  146. package/dist/cjs/utils/SharedLedgerStore.js +2 -1
  147. package/dist/cjs/utils/SharedLedgerStore.js.map +1 -1
  148. package/dist/cjs/utils/StoreDraft.d.ts +12 -0
  149. package/dist/cjs/utils/StoreDraft.d.ts.map +1 -1
  150. package/dist/cjs/utils/StoreDraft.js +53 -1
  151. package/dist/cjs/utils/StoreDraft.js.map +1 -1
  152. package/dist/cjs/utils/SurgicalASTInsert.d.ts.map +1 -1
  153. package/dist/cjs/utils/SurgicalASTInsert.js +2 -1
  154. package/dist/cjs/utils/SurgicalASTInsert.js.map +1 -1
  155. package/dist/cjs/utils/SymbolSurgicalContext.d.ts +2 -0
  156. package/dist/cjs/utils/SymbolSurgicalContext.d.ts.map +1 -1
  157. package/dist/cjs/utils/SymbolSurgicalContext.js +30 -62
  158. package/dist/cjs/utils/SymbolSurgicalContext.js.map +1 -1
  159. package/dist/cjs/utils/Utf8Guard.d.ts +23 -0
  160. package/dist/cjs/utils/Utf8Guard.d.ts.map +1 -0
  161. package/dist/cjs/utils/Utf8Guard.js +81 -0
  162. package/dist/cjs/utils/Utf8Guard.js.map +1 -0
  163. package/dist/cjs/utils/WorkspaceSearch.d.ts.map +1 -1
  164. package/dist/cjs/utils/WorkspaceSearch.js +26 -8
  165. package/dist/cjs/utils/WorkspaceSearch.js.map +1 -1
  166. package/dist/cjs/utils/reportSavings.d.ts +17 -4
  167. package/dist/cjs/utils/reportSavings.d.ts.map +1 -1
  168. package/dist/cjs/utils/reportSavings.js +67 -22
  169. package/dist/cjs/utils/reportSavings.js.map +1 -1
  170. package/dist/cjs/utils/tsLoader.d.ts +5 -0
  171. package/dist/cjs/utils/tsLoader.d.ts.map +1 -0
  172. package/dist/cjs/utils/tsLoader.js +15 -0
  173. package/dist/cjs/utils/tsLoader.js.map +1 -0
  174. package/dist/esm/cli/gitHooks.d.ts +9 -2
  175. package/dist/esm/cli/gitHooks.d.ts.map +1 -1
  176. package/dist/esm/cli/gitHooks.js +31 -4
  177. package/dist/esm/cli/gitHooks.js.map +1 -1
  178. package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
  179. package/dist/esm/cli/lemma-proxy.js +21 -1
  180. package/dist/esm/cli/lemma-proxy.js.map +1 -1
  181. package/dist/esm/infra/analyzers/index.d.ts +0 -2
  182. package/dist/esm/infra/analyzers/index.d.ts.map +1 -1
  183. package/dist/esm/infra/analyzers/index.js +0 -2
  184. package/dist/esm/infra/analyzers/index.js.map +1 -1
  185. package/dist/esm/infra/cli.d.ts +4 -0
  186. package/dist/esm/infra/cli.d.ts.map +1 -1
  187. package/dist/esm/infra/cli.js +6 -199
  188. package/dist/esm/infra/cli.js.map +1 -1
  189. package/dist/esm/infra/index.d.ts +1 -3
  190. package/dist/esm/infra/index.d.ts.map +1 -1
  191. package/dist/esm/infra/index.js +1 -3
  192. package/dist/esm/infra/index.js.map +1 -1
  193. package/dist/esm/infra/mcp-tools.d.ts.map +1 -1
  194. package/dist/esm/infra/mcp-tools.js +9 -454
  195. package/dist/esm/infra/mcp-tools.js.map +1 -1
  196. package/dist/esm/infra/types.d.ts +0 -101
  197. package/dist/esm/infra/types.d.ts.map +1 -1
  198. package/dist/esm/infra/types.js +2 -1
  199. package/dist/esm/infra/types.js.map +1 -1
  200. package/dist/esm/mcp/cognitiveMap.d.ts.map +1 -1
  201. package/dist/esm/mcp/cognitiveMap.js +6 -2
  202. package/dist/esm/mcp/cognitiveMap.js.map +1 -1
  203. package/dist/esm/mcp/index.js +2 -0
  204. package/dist/esm/mcp/index.js.map +1 -1
  205. package/dist/esm/mcp/prompts.d.ts +1 -1
  206. package/dist/esm/mcp/prompts.d.ts.map +1 -1
  207. package/dist/esm/mcp/prompts.js +8 -23
  208. package/dist/esm/mcp/prompts.js.map +1 -1
  209. package/dist/esm/mcp/tool-profiles.d.ts +8 -3
  210. package/dist/esm/mcp/tool-profiles.d.ts.map +1 -1
  211. package/dist/esm/mcp/tool-profiles.js +25 -54
  212. package/dist/esm/mcp/tool-profiles.js.map +1 -1
  213. package/dist/esm/mcp/tools/devtools.d.ts.map +1 -1
  214. package/dist/esm/mcp/tools/devtools.js +11 -1
  215. package/dist/esm/mcp/tools/devtools.js.map +1 -1
  216. package/dist/esm/mcp/tools/memory.d.ts +8 -0
  217. package/dist/esm/mcp/tools/memory.d.ts.map +1 -1
  218. package/dist/esm/mcp/tools/memory.js +211 -140
  219. package/dist/esm/mcp/tools/memory.js.map +1 -1
  220. package/dist/esm/mcp/tools/refactor.d.ts.map +1 -1
  221. package/dist/esm/mcp/tools/refactor.js +129 -32
  222. package/dist/esm/mcp/tools/refactor.js.map +1 -1
  223. package/dist/esm/mcp/tools/workspace.d.ts.map +1 -1
  224. package/dist/esm/mcp/tools/workspace.js +108 -8
  225. package/dist/esm/mcp/tools/workspace.js.map +1 -1
  226. package/dist/esm/mcp/tools.d.ts.map +1 -1
  227. package/dist/esm/mcp/tools.js +12 -7
  228. package/dist/esm/mcp/tools.js.map +1 -1
  229. package/dist/esm/mcp/workspaceShared.d.ts.map +1 -1
  230. package/dist/esm/mcp/workspaceShared.js +9 -5
  231. package/dist/esm/mcp/workspaceShared.js.map +1 -1
  232. package/dist/esm/proxy/ProjectRegistry.d.ts +20 -0
  233. package/dist/esm/proxy/ProjectRegistry.d.ts.map +1 -1
  234. package/dist/esm/proxy/ProjectRegistry.js +45 -3
  235. package/dist/esm/proxy/ProjectRegistry.js.map +1 -1
  236. package/dist/esm/proxy/ProjectStore.d.ts.map +1 -1
  237. package/dist/esm/proxy/ProjectStore.js +9 -6
  238. package/dist/esm/proxy/ProjectStore.js.map +1 -1
  239. package/dist/esm/subconscious/HostRecall.d.ts +26 -2
  240. package/dist/esm/subconscious/HostRecall.d.ts.map +1 -1
  241. package/dist/esm/subconscious/HostRecall.js +113 -41
  242. package/dist/esm/subconscious/HostRecall.js.map +1 -1
  243. package/dist/esm/subconscious/NarrowEvidence.d.ts +53 -0
  244. package/dist/esm/subconscious/NarrowEvidence.d.ts.map +1 -0
  245. package/dist/esm/subconscious/NarrowEvidence.js +228 -0
  246. package/dist/esm/subconscious/NarrowEvidence.js.map +1 -0
  247. package/dist/esm/subconscious/TheBrainV2.d.ts +48 -0
  248. package/dist/esm/subconscious/TheBrainV2.d.ts.map +1 -1
  249. package/dist/esm/subconscious/TheBrainV2.js +226 -25
  250. package/dist/esm/subconscious/TheBrainV2.js.map +1 -1
  251. package/dist/esm/subconscious/freshness/LocalFsResolver.d.ts.map +1 -1
  252. package/dist/esm/subconscious/freshness/LocalFsResolver.js +32 -0
  253. package/dist/esm/subconscious/freshness/LocalFsResolver.js.map +1 -1
  254. package/dist/esm/subconscious/recallDigest.d.ts +8 -0
  255. package/dist/esm/subconscious/recallDigest.d.ts.map +1 -1
  256. package/dist/esm/subconscious/recallDigest.js +12 -1
  257. package/dist/esm/subconscious/recallDigest.js.map +1 -1
  258. package/dist/esm/utils/AffectedTests.d.ts +1 -5
  259. package/dist/esm/utils/AffectedTests.d.ts.map +1 -1
  260. package/dist/esm/utils/AffectedTests.js +2 -35
  261. package/dist/esm/utils/AffectedTests.js.map +1 -1
  262. package/dist/esm/utils/AtomicFile.d.ts +14 -0
  263. package/dist/esm/utils/AtomicFile.d.ts.map +1 -0
  264. package/dist/esm/utils/AtomicFile.js +37 -0
  265. package/dist/esm/utils/AtomicFile.js.map +1 -0
  266. package/dist/esm/utils/AutoContextBundle.js +1 -1
  267. package/dist/esm/utils/AutoContextBundle.js.map +1 -1
  268. package/dist/esm/utils/BulkFileDigest.js +1 -1
  269. package/dist/esm/utils/BulkFileDigest.js.map +1 -1
  270. package/dist/esm/utils/ContextSqueezer.d.ts +36 -4
  271. package/dist/esm/utils/ContextSqueezer.d.ts.map +1 -1
  272. package/dist/esm/utils/ContextSqueezer.js +67 -21
  273. package/dist/esm/utils/ContextSqueezer.js.map +1 -1
  274. package/dist/esm/utils/FileLock.d.ts +2 -0
  275. package/dist/esm/utils/FileLock.d.ts.map +1 -0
  276. package/dist/esm/utils/FileLock.js +29 -0
  277. package/dist/esm/utils/FileLock.js.map +1 -0
  278. package/dist/esm/utils/FileOutline.d.ts +1 -1
  279. package/dist/esm/utils/FileOutline.d.ts.map +1 -1
  280. package/dist/esm/utils/FileOutline.js +5 -1
  281. package/dist/esm/utils/FileOutline.js.map +1 -1
  282. package/dist/esm/utils/FixCapture.d.ts.map +1 -1
  283. package/dist/esm/utils/FixCapture.js +3 -2
  284. package/dist/esm/utils/FixCapture.js.map +1 -1
  285. package/dist/esm/utils/GitChanges.d.ts +11 -0
  286. package/dist/esm/utils/GitChanges.d.ts.map +1 -0
  287. package/dist/esm/utils/GitChanges.js +41 -0
  288. package/dist/esm/utils/GitChanges.js.map +1 -0
  289. package/dist/esm/utils/JsonKeys.d.ts +17 -0
  290. package/dist/esm/utils/JsonKeys.d.ts.map +1 -0
  291. package/dist/esm/utils/JsonKeys.js +71 -0
  292. package/dist/esm/utils/JsonKeys.js.map +1 -0
  293. package/dist/esm/utils/LocalExclude.d.ts +3 -0
  294. package/dist/esm/utils/LocalExclude.d.ts.map +1 -0
  295. package/dist/esm/utils/LocalExclude.js +62 -0
  296. package/dist/esm/utils/LocalExclude.js.map +1 -0
  297. package/dist/esm/utils/OtherLanguageSymbols.d.ts +31 -0
  298. package/dist/esm/utils/OtherLanguageSymbols.d.ts.map +1 -0
  299. package/dist/esm/utils/OtherLanguageSymbols.js +268 -0
  300. package/dist/esm/utils/OtherLanguageSymbols.js.map +1 -0
  301. package/dist/esm/utils/OutputDelta.d.ts +14 -2
  302. package/dist/esm/utils/OutputDelta.d.ts.map +1 -1
  303. package/dist/esm/utils/OutputDelta.js +22 -15
  304. package/dist/esm/utils/OutputDelta.js.map +1 -1
  305. package/dist/esm/utils/RoiLedger.d.ts.map +1 -1
  306. package/dist/esm/utils/RoiLedger.js +7 -3
  307. package/dist/esm/utils/RoiLedger.js.map +1 -1
  308. package/dist/esm/utils/SavingsLedger.d.ts +27 -0
  309. package/dist/esm/utils/SavingsLedger.d.ts.map +1 -1
  310. package/dist/esm/utils/SavingsLedger.js +56 -2
  311. package/dist/esm/utils/SavingsLedger.js.map +1 -1
  312. package/dist/esm/utils/SharedLedgerStore.d.ts.map +1 -1
  313. package/dist/esm/utils/SharedLedgerStore.js +2 -1
  314. package/dist/esm/utils/SharedLedgerStore.js.map +1 -1
  315. package/dist/esm/utils/StoreDraft.d.ts +12 -0
  316. package/dist/esm/utils/StoreDraft.d.ts.map +1 -1
  317. package/dist/esm/utils/StoreDraft.js +52 -1
  318. package/dist/esm/utils/StoreDraft.js.map +1 -1
  319. package/dist/esm/utils/SurgicalASTInsert.d.ts.map +1 -1
  320. package/dist/esm/utils/SurgicalASTInsert.js +2 -1
  321. package/dist/esm/utils/SurgicalASTInsert.js.map +1 -1
  322. package/dist/esm/utils/SymbolSurgicalContext.d.ts +2 -0
  323. package/dist/esm/utils/SymbolSurgicalContext.d.ts.map +1 -1
  324. package/dist/esm/utils/SymbolSurgicalContext.js +2 -2
  325. package/dist/esm/utils/SymbolSurgicalContext.js.map +1 -1
  326. package/dist/esm/utils/Utf8Guard.d.ts +23 -0
  327. package/dist/esm/utils/Utf8Guard.d.ts.map +1 -0
  328. package/dist/esm/utils/Utf8Guard.js +74 -0
  329. package/dist/esm/utils/Utf8Guard.js.map +1 -0
  330. package/dist/esm/utils/WorkspaceSearch.d.ts.map +1 -1
  331. package/dist/esm/utils/WorkspaceSearch.js +26 -8
  332. package/dist/esm/utils/WorkspaceSearch.js.map +1 -1
  333. package/dist/esm/utils/reportSavings.d.ts +17 -4
  334. package/dist/esm/utils/reportSavings.d.ts.map +1 -1
  335. package/dist/esm/utils/reportSavings.js +65 -22
  336. package/dist/esm/utils/reportSavings.js.map +1 -1
  337. package/dist/esm/utils/tsLoader.d.ts +5 -0
  338. package/dist/esm/utils/tsLoader.d.ts.map +1 -0
  339. package/dist/esm/utils/tsLoader.js +13 -0
  340. package/dist/esm/utils/tsLoader.js.map +1 -0
  341. package/package.json +3 -2
  342. package/dashboard/dist/assets/index-CLXWgzTm.css +0 -1
  343. package/dashboard/dist/assets/index-CoMIMxyC.js +0 -451
  344. package/dist/cjs/infra/analyzers/DriftDetector.d.ts +0 -4
  345. package/dist/cjs/infra/analyzers/DriftDetector.d.ts.map +0 -1
  346. package/dist/cjs/infra/analyzers/DriftDetector.js +0 -88
  347. package/dist/cjs/infra/analyzers/DriftDetector.js.map +0 -1
  348. package/dist/cjs/infra/analyzers/InfraAnalyzer.d.ts +0 -3
  349. package/dist/cjs/infra/analyzers/InfraAnalyzer.d.ts.map +0 -1
  350. package/dist/cjs/infra/analyzers/InfraAnalyzer.js +0 -73
  351. package/dist/cjs/infra/analyzers/InfraAnalyzer.js.map +0 -1
  352. package/dist/cjs/infra/config.d.ts +0 -17
  353. package/dist/cjs/infra/config.d.ts.map +0 -1
  354. package/dist/cjs/infra/config.js +0 -111
  355. package/dist/cjs/infra/config.js.map +0 -1
  356. package/dist/cjs/infra/errorCause.d.ts +0 -36
  357. package/dist/cjs/infra/errorCause.d.ts.map +0 -1
  358. package/dist/cjs/infra/errorCause.js +0 -143
  359. package/dist/cjs/infra/errorCause.js.map +0 -1
  360. package/dist/cjs/infra/providers/InfraProvider.d.ts +0 -9
  361. package/dist/cjs/infra/providers/InfraProvider.d.ts.map +0 -1
  362. package/dist/cjs/infra/providers/InfraProvider.js +0 -3
  363. package/dist/cjs/infra/providers/InfraProvider.js.map +0 -1
  364. package/dist/cjs/infra/providers/JenkinsProvider.d.ts +0 -16
  365. package/dist/cjs/infra/providers/JenkinsProvider.d.ts.map +0 -1
  366. package/dist/cjs/infra/providers/JenkinsProvider.js +0 -193
  367. package/dist/cjs/infra/providers/JenkinsProvider.js.map +0 -1
  368. package/dist/cjs/infra/providers/OKDProvider.d.ts +0 -24
  369. package/dist/cjs/infra/providers/OKDProvider.d.ts.map +0 -1
  370. package/dist/cjs/infra/providers/OKDProvider.js +0 -296
  371. package/dist/cjs/infra/providers/OKDProvider.js.map +0 -1
  372. package/dist/cjs/infra/providers/TerraformProvider.d.ts +0 -17
  373. package/dist/cjs/infra/providers/TerraformProvider.d.ts.map +0 -1
  374. package/dist/cjs/infra/providers/TerraformProvider.js +0 -111
  375. package/dist/cjs/infra/providers/TerraformProvider.js.map +0 -1
  376. package/dist/cjs/infra/providers/index.d.ts +0 -9
  377. package/dist/cjs/infra/providers/index.d.ts.map +0 -1
  378. package/dist/cjs/infra/providers/index.js +0 -34
  379. package/dist/cjs/infra/providers/index.js.map +0 -1
  380. package/dist/cjs/infra/templates/jenkins/index.d.ts +0 -15
  381. package/dist/cjs/infra/templates/jenkins/index.d.ts.map +0 -1
  382. package/dist/cjs/infra/templates/jenkins/index.js +0 -128
  383. package/dist/cjs/infra/templates/jenkins/index.js.map +0 -1
  384. package/dist/cjs/infra/templates/okd/index.d.ts +0 -31
  385. package/dist/cjs/infra/templates/okd/index.d.ts.map +0 -1
  386. package/dist/cjs/infra/templates/okd/index.js +0 -149
  387. package/dist/cjs/infra/templates/okd/index.js.map +0 -1
  388. package/dist/esm/infra/analyzers/DriftDetector.d.ts +0 -4
  389. package/dist/esm/infra/analyzers/DriftDetector.d.ts.map +0 -1
  390. package/dist/esm/infra/analyzers/DriftDetector.js +0 -84
  391. package/dist/esm/infra/analyzers/DriftDetector.js.map +0 -1
  392. package/dist/esm/infra/analyzers/InfraAnalyzer.d.ts +0 -3
  393. package/dist/esm/infra/analyzers/InfraAnalyzer.d.ts.map +0 -1
  394. package/dist/esm/infra/analyzers/InfraAnalyzer.js +0 -70
  395. package/dist/esm/infra/analyzers/InfraAnalyzer.js.map +0 -1
  396. package/dist/esm/infra/config.d.ts +0 -17
  397. package/dist/esm/infra/config.d.ts.map +0 -1
  398. package/dist/esm/infra/config.js +0 -101
  399. package/dist/esm/infra/config.js.map +0 -1
  400. package/dist/esm/infra/errorCause.d.ts +0 -36
  401. package/dist/esm/infra/errorCause.d.ts.map +0 -1
  402. package/dist/esm/infra/errorCause.js +0 -138
  403. package/dist/esm/infra/errorCause.js.map +0 -1
  404. package/dist/esm/infra/providers/InfraProvider.d.ts +0 -9
  405. package/dist/esm/infra/providers/InfraProvider.d.ts.map +0 -1
  406. package/dist/esm/infra/providers/InfraProvider.js +0 -2
  407. package/dist/esm/infra/providers/InfraProvider.js.map +0 -1
  408. package/dist/esm/infra/providers/JenkinsProvider.d.ts +0 -16
  409. package/dist/esm/infra/providers/JenkinsProvider.d.ts.map +0 -1
  410. package/dist/esm/infra/providers/JenkinsProvider.js +0 -186
  411. package/dist/esm/infra/providers/JenkinsProvider.js.map +0 -1
  412. package/dist/esm/infra/providers/OKDProvider.d.ts +0 -24
  413. package/dist/esm/infra/providers/OKDProvider.d.ts.map +0 -1
  414. package/dist/esm/infra/providers/OKDProvider.js +0 -292
  415. package/dist/esm/infra/providers/OKDProvider.js.map +0 -1
  416. package/dist/esm/infra/providers/TerraformProvider.d.ts +0 -17
  417. package/dist/esm/infra/providers/TerraformProvider.d.ts.map +0 -1
  418. package/dist/esm/infra/providers/TerraformProvider.js +0 -107
  419. package/dist/esm/infra/providers/TerraformProvider.js.map +0 -1
  420. package/dist/esm/infra/providers/index.d.ts +0 -9
  421. package/dist/esm/infra/providers/index.d.ts.map +0 -1
  422. package/dist/esm/infra/providers/index.js +0 -27
  423. package/dist/esm/infra/providers/index.js.map +0 -1
  424. package/dist/esm/infra/templates/jenkins/index.d.ts +0 -15
  425. package/dist/esm/infra/templates/jenkins/index.d.ts.map +0 -1
  426. package/dist/esm/infra/templates/jenkins/index.js +0 -124
  427. package/dist/esm/infra/templates/jenkins/index.js.map +0 -1
  428. package/dist/esm/infra/templates/okd/index.d.ts +0 -31
  429. package/dist/esm/infra/templates/okd/index.d.ts.map +0 -1
  430. package/dist/esm/infra/templates/okd/index.js +0 -142
  431. package/dist/esm/infra/templates/okd/index.js.map +0 -1
@@ -14,7 +14,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  return (mod && mod.__esModule) ? mod : { "default": mod };
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.TheBrainV2 = exports.MAX_DERIVED_DEPTH = exports.BloomFilter = void 0;
17
+ exports.TheBrainV2 = exports.MAX_DERIVED_DEPTH = exports.BloomFilter = exports.TOKENIZER_VERSION = void 0;
18
18
  exports.resetBrainKeyCache = resetBrainKeyCache;
19
19
  exports.listSnapshotNames = listSnapshotNames;
20
20
  exports.mergeEntryMaps = mergeEntryMaps;
@@ -658,6 +658,14 @@ function tokenize(text) {
658
658
  'cada', 'otra', 'otro', 'otras', 'otros', 'entre', 'sobre', 'sin', 'ya', 'tan', 'mas',
659
659
  'lo', 'le', 'les', 'nos', 'os', 'ni', 'sino', 'porque', 'cuando', 'donde', 'quien',
660
660
  'cual', 'cuales', 'sea', 'ha', 'han', 'hemos', 'habia', 'habían', 'esta', 'están',
661
+ // Conversational filler. Prompts are written to a person ("can you please help me…",
662
+ // "necesito que realmente…"), and these words outweighed the topic when measuring how much
663
+ // of a prompt a memory covers. They name no subject a memory could be about.
664
+ 'please', 'help', 'know', 'want', 'like', 'just', 'really', 'actually', 'maybe', 'also', 'let',
665
+ 'me', 'my', 'we', 'our', 'us', 'you', 'your', 'i', 'im', 'get', 'got', 'make', 'sure', 'thing', 'things',
666
+ 'por', 'favor', 'necesito', 'quiero', 'puedes', 'podemos', 'podrias', 'haz', 'hacer', 'dime', 'ayuda',
667
+ 'ayudame', 'realmente', 'actualmente', 'tambien', 'solo', 'algo', 'cosa', 'cosas', 'nos', 'tu', 'yo',
668
+ 'me', 'mi', 'mis', 'te', 'ver', 'bien',
661
669
  ]);
662
670
  const terms = normalized
663
671
  .split(/\s+/)
@@ -679,7 +687,25 @@ function tokenize(text) {
679
687
  const synonymTags = terms
680
688
  .map(t => SYNONYM_CLUSTERS.get(t))
681
689
  .filter((c) => c !== undefined);
682
- return [...new Set([...terms, ...bigrams, ...stems, ...synonymTags])];
690
+ // 8. English/Spanish cognates share a root once their suffix is dropped: "description" and
691
+ // "descripcion", "configuration"/"configuracion", "velocity"/"velocidad", "automatic"/
692
+ // "automatico". Same additive rule as stems and synonyms.
693
+ const cognateTags = terms.map(cognate).filter((c) => c !== undefined);
694
+ return [...new Set([...terms, ...bigrams, ...stems, ...synonymTags, ...cognateTags])];
695
+ }
696
+ /**
697
+ * Bump whenever tokenize() changes what it emits. Terms are computed once, at store time, and
698
+ * persisted, so a tokenizer improvement (stems, diacritics, synonym groups) used to reach new
699
+ * memories only — every memory already in the Brain kept the vocabulary it was stored with.
700
+ * rebuildIndex() re-tokenizes any entry indexed under another version.
701
+ */
702
+ exports.TOKENIZER_VERSION = 6;
703
+ /** (Re)computes an entry's index terms with the current tokenizer. */
704
+ function indexTerms(entry) {
705
+ const terms = tokenize(`${entry.query} ${entry.response || ''}`);
706
+ entry.terms = [...new Set(terms)];
707
+ entry.termFreq = termFrequencies(terms);
708
+ entry.tokv = exports.TOKENIZER_VERSION;
683
709
  }
684
710
  // Groups of interchangeable dev-vocabulary terms (bilingual). Each member maps to a shared
685
711
  // `syn_<canonical>` token so any two synonyms in the same group become a shared index bucket
@@ -689,14 +715,43 @@ function tokenize(text) {
689
715
  const SYNONYM_GROUPS = [
690
716
  ['jwt', 'token', 'session', 'auth', 'login', 'autenticacion', 'sesion', 'autenticar'],
691
717
  ['timeout', 'expiration', 'expiry', 'vencimiento', 'caducidad', 'expirar', 'vencer'],
692
- ['bug', 'error', 'fallo', 'falla', 'issue', 'defect', 'defecto'],
718
+ ['bug', 'error', 'fallo', 'falla', 'issue', 'defect', 'defecto', 'fail', 'fails', 'failing', 'failed', 'fallar', 'fallaba'],
693
719
  ['fix', 'patch', 'solucion', 'solucionar', 'arreglar', 'corregir', 'hotfix'],
694
720
  ['delete', 'remove', 'eliminar', 'borrar', 'quitar'],
695
721
  ['config', 'configuration', 'configuracion', 'settings', 'ajustes'],
696
722
  ['deploy', 'deployment', 'despliegue', 'desplegar', 'release'],
697
- ['crash', 'exception', 'excepcion', 'throw', 'falla'],
723
+ ['crash', 'exception', 'excepcion', 'throw'],
698
724
  ['slow', 'lento', 'lentitud', 'latency', 'latencia', 'performance', 'rendimiento'],
699
725
  ['test', 'tests', 'testing', 'prueba', 'pruebas', 'spec'],
726
+ // Everyday words a bilingual corpus splits across languages: a Spanish memory and an English
727
+ // question about the same thing otherwise share no term at all.
728
+ ['change', 'changes', 'changed', 'cambio', 'cambios', 'cambiar', 'cambia', 'cambiado'],
729
+ ['active', 'activo', 'activos', 'activa', 'activas', 'enabled', 'habilitado'],
730
+ ['file', 'files', 'archivo', 'archivos', 'fichero'],
731
+ ['search', 'searches', 'buscar', 'busqueda', 'busca', 'find'],
732
+ ['memory', 'memories', 'memoria', 'memorias'],
733
+ ['write', 'writes', 'escribir', 'escribe', 'escritura'],
734
+ ['read', 'reads', 'leer', 'lee', 'lectura', 'lecturas'],
735
+ ['build', 'compile', 'compilar', 'compila', 'compilacion'],
736
+ ['publish', 'published', 'publicar', 'publicado', 'publicada', 'publicacion'],
737
+ ['comment', 'comments', 'comentario', 'comentarios'],
738
+ ['string', 'strings', 'cadena', 'cadenas'],
739
+ ['server', 'servidor'],
740
+ ['tool', 'tools', 'herramienta', 'herramientas'],
741
+ ['project', 'projects', 'proyecto', 'proyectos'],
742
+ ['broken', 'breaks', 'roto', 'rota', 'rompe', 'romper', 'rompia'],
743
+ ['missing', 'falta', 'faltante', 'faltaba'],
744
+ ['ignore', 'ignored', 'ignores', 'ignora', 'ignorar', 'ignorado', 'ignoraba'],
745
+ ['update', 'updated', 'actualizar', 'actualiza', 'actualizacion'],
746
+ ['stale', 'outdated', 'desactualizado', 'desactualizada', 'obsoleto', 'obsoleta'],
747
+ ['restart', 'reconnect', 'reiniciar', 'reconectar'],
748
+ ['wrong', 'incorrect', 'incorrecto', 'incorrecta', 'erroneo'],
749
+ // Money vocabulary: "¿por qué el saldo sale negativo?" shared only "negativo" with the memory
750
+ // that answers it ("why the ledger was negative") — and that with every "falso negativo".
751
+ ['ledger', 'saldo', 'balance', 'bitacora'],
752
+ ['negative', 'negativo', 'negativa', 'negativos', 'negativas'],
753
+ ['cost', 'costs', 'costo', 'costos', 'gasto', 'gastos', 'spent', 'spend', 'charge', 'charged', 'cobro', 'cobrar', 'cobrado', 'cobraba'],
754
+ ['savings', 'saving', 'saved', 'ahorro', 'ahorros', 'ahorrar', 'ahorra'],
700
755
  ];
701
756
  const SYNONYM_CLUSTERS = new Map();
702
757
  for (const group of SYNONYM_GROUPS) {
@@ -704,6 +759,24 @@ for (const group of SYNONYM_GROUPS) {
704
759
  for (const member of group)
705
760
  SYNONYM_CLUSTERS.set(member, canonical);
706
761
  }
762
+ const COGNATE_RULES = [
763
+ [/(?:tions?|ciones|cion)$/, 'tion'],
764
+ [/(?:ities|ity|idades|idad)$/, 'ity'],
765
+ [/(?:ically|icamente)$/, 'ic'],
766
+ [/(?:ics?|icos?|icas?)$/, 'ic'],
767
+ ];
768
+ /** `cog_<root><suffix>` for a word with an English/Spanish cognate suffix, else undefined. */
769
+ function cognate(term) {
770
+ if (term.length < 6 || term.includes('_'))
771
+ return undefined;
772
+ for (const [re, kind] of COGNATE_RULES) {
773
+ if (re.test(term)) {
774
+ const root = term.replace(re, '');
775
+ return root.length >= 3 ? `cog_${root}_${kind}` : undefined;
776
+ }
777
+ }
778
+ return undefined;
779
+ }
707
780
  // Suffix-stripping rules, longest/most-specific match first. Additive expansion only —
708
781
  // this is not a correctness-critical stemmer, so mild over-stemming (merging two distinct
709
782
  // words into one stem) is an acceptable recall/precision trade: it can only ever add a
@@ -873,6 +946,31 @@ function hashSymbolsForFreshness(refs) {
873
946
  }
874
947
  return hashes;
875
948
  }
949
+ /**
950
+ * Splits symbol refs into the ones the resolver can actually locate and the ones it cannot
951
+ * (a typo, a rename, a file that is not code). An unlocatable symbol hashes MISSING when it is
952
+ * stored and MISSING again when it is verified, so MISSING === MISSING and the memory could
953
+ * never go stale — the worst way for freshness to fail, because the reply still says
954
+ * "tracking N symbols". Callers track the whole file for those instead and say so.
955
+ */
956
+ function partitionSymbolRefs(refs) {
957
+ const resolved = [];
958
+ const unresolved = [];
959
+ for (const ref of refs) {
960
+ const hash = defaultLocalResolver.hashSymbol(path_1.default.resolve(ref.filePath), ref.symbolName);
961
+ (hash && hash.raw !== 'MISSING' ? resolved : unresolved).push(ref);
962
+ }
963
+ return { resolved, unresolved };
964
+ }
965
+ /** `files` minus those that contain one of the tracked `symbols`; `dropped` lists what was removed. */
966
+ function dropFilesCoveredBySymbols(files, symbols) {
967
+ const covered = new Set(symbols.map((r) => path_1.default.resolve(r.filePath)));
968
+ const kept = [];
969
+ const dropped = [];
970
+ for (const f of files ?? [])
971
+ (covered.has(path_1.default.resolve(f)) ? dropped : kept).push(f);
972
+ return { files: kept, dropped };
973
+ }
876
974
  /**
877
975
  * Fase D companion to hashSymbolsForFreshness: same symbols, hashed after
878
976
  * normalizeForFreshness strips comments/whitespace. Always computed alongside the raw hash
@@ -1265,6 +1363,13 @@ class TheBrainV2 {
1265
1363
  this.diskStamp = null;
1266
1364
  /** id -> ISO deletion time, for ids that must not come back through a merge. */
1267
1365
  this.tombstones = new Map();
1366
+ /**
1367
+ * Ids a restore brought back that the on-disk meta.json still lists as deleted. save() absorbs
1368
+ * the peers' tombstones first, which re-added the one restore had just removed and dropped the
1369
+ * entry again: "Restored memory…" was followed by the memory vanishing at the next save. Skipped
1370
+ * by the absorb until a save has written meta.json without them.
1371
+ */
1372
+ this.revived = new Set();
1268
1373
  /**
1269
1374
  * Last integrity incident on the corpus files (corrupt main file, undecryptable
1270
1375
  * envelope, skipped sync). Set by load()/save()/syncIfChanged(), never cleared
@@ -1317,7 +1422,9 @@ class TheBrainV2 {
1317
1422
  // index.json. It is a pure derivation of the entries, so reconstructing it is the
1318
1423
  // only way it can never disagree with them — and a stale or half-written index.json
1319
1424
  // used to be able to hide entries from search entirely while they sat on disk intact.
1320
- this.rebuildIndex();
1425
+ // Entries indexed by an older tokenizer were re-tokenized: write that back once.
1426
+ if (this.rebuildIndex() > 0)
1427
+ this.scheduleSave();
1321
1428
  this.recalcAvgDocLength();
1322
1429
  }
1323
1430
  catch (err) {
@@ -1343,7 +1450,12 @@ class TheBrainV2 {
1343
1450
  // A merge can replace an id's entry with a peer's newer version whose query differs, so
1344
1451
  // the memo is rebuilt alongside the index rather than trusted across one.
1345
1452
  this.queryTermCache.clear();
1453
+ let retokenized = 0;
1346
1454
  for (const entry of this.entries.values()) {
1455
+ if (entry.tokv !== exports.TOKENIZER_VERSION) {
1456
+ indexTerms(entry);
1457
+ retokenized++;
1458
+ }
1347
1459
  for (const term of entry.terms) {
1348
1460
  let ids = this.invertedIndex.get(term);
1349
1461
  if (!ids) {
@@ -1353,6 +1465,7 @@ class TheBrainV2 {
1353
1465
  ids.add(entry.id);
1354
1466
  }
1355
1467
  }
1468
+ return retokenized;
1356
1469
  }
1357
1470
  /**
1358
1471
  * Pull in anything another process wrote since we last touched the corpus.
@@ -1511,6 +1624,7 @@ class TheBrainV2 {
1511
1624
  }));
1512
1625
  this.diskStamp = stampOf(ENTRIES_FILE);
1513
1626
  this.dirty = false;
1627
+ this.revived.clear(); // meta.json no longer lists them
1514
1628
  }
1515
1629
  catch { /* fail silently */ }
1516
1630
  finally {
@@ -1529,6 +1643,8 @@ class TheBrainV2 {
1529
1643
  */
1530
1644
  absorbPeerTombstones() {
1531
1645
  for (const [id, at] of readTombstonesFile()) {
1646
+ if (this.revived.has(id))
1647
+ continue;
1532
1648
  if (!this.tombstones.has(id))
1533
1649
  this.tombstones.set(id, at);
1534
1650
  const entry = this.entries.get(id);
@@ -1607,6 +1723,24 @@ class TheBrainV2 {
1607
1723
  };
1608
1724
  }
1609
1725
  }
1726
+ let unresolvedSymbols;
1727
+ let narrowedFiles;
1728
+ if (symbolRefs && symbolRefs.length > 0 && !options.evidence?.symbols) {
1729
+ const split = partitionSymbolRefs(symbolRefs);
1730
+ if (split.unresolved.length > 0) {
1731
+ unresolvedSymbols = split.unresolved;
1732
+ symbolRefs = split.resolved;
1733
+ filePaths = [...new Set([...(filePaths ?? []), ...split.unresolved.map((r) => r.filePath)])];
1734
+ }
1735
+ // A file whose symbols are tracked is not also tracked whole: the symbol is the narrower
1736
+ // claim, and the whole file would stale the memory on every unrelated edit to it (callers
1737
+ // routinely pass both: the file the symbol lives in, and the symbol).
1738
+ const narrowed = dropFilesCoveredBySymbols(filePaths, split.resolved);
1739
+ if (narrowed.dropped.length > 0) {
1740
+ filePaths = narrowed.files;
1741
+ narrowedFiles = narrowed.dropped;
1742
+ }
1743
+ }
1610
1744
  // Conflict check: another entry about the exact same symbol, with the opposite
1611
1745
  // outcome, is worth flagging before this one is even written — two memories about one
1612
1746
  // function disagreeing on whether an approach works is a trap for whoever searches next.
@@ -1651,6 +1785,7 @@ class TheBrainV2 {
1651
1785
  response: response.trim(),
1652
1786
  terms: [...new Set(terms)],
1653
1787
  termFreq,
1788
+ tokv: exports.TOKENIZER_VERSION,
1654
1789
  provider,
1655
1790
  timestamp: options.timestamp || new Date().toISOString(),
1656
1791
  hits: 0,
@@ -1687,7 +1822,7 @@ class TheBrainV2 {
1687
1822
  this.recalcAvgDocLength();
1688
1823
  this.evictIfOverCapacity();
1689
1824
  this.scheduleSave();
1690
- return { stored: true, reason: 'Stored successfully', id, conflicts, textConflicts, redactions };
1825
+ return { stored: true, reason: 'Stored successfully', id, conflicts, textConflicts, redactions, ...(unresolvedSymbols ? { unresolvedSymbols } : {}), ...(narrowedFiles ? { narrowedFiles } : {}) };
1691
1826
  }
1692
1827
  /**
1693
1828
  * Evict the lowest-value entries once the Brain is over capacity. Value = hits (proven
@@ -1762,17 +1897,15 @@ class TheBrainV2 {
1762
1897
  }
1763
1898
  // 2b. Scope to the calling project. Entries with no projectId predate scoping and stay
1764
1899
  // visible everywhere — dropping a user's existing memories to enforce a new field would
1765
- // look exactly like the Brain losing data. If scoping leaves nothing, fall back to the
1766
- // unscoped candidates rather than reporting a miss the Brain could have answered.
1767
- if (options.projectId) {
1768
- const scoped = new Set([...candidateIds].filter((id) => {
1900
+ // look exactly like the Brain losing data — but they are labelled 'unscoped' in the result.
1901
+ // Another project's memories are never returned unless the caller asks for allProjects:
1902
+ // this used to fall back to every project's candidates whenever the caller's own had none,
1903
+ // so a project with an empty Brain was answered from someone else's.
1904
+ if (options.projectId && !options.allProjects) {
1905
+ for (const id of [...candidateIds]) {
1769
1906
  const owner = this.entries.get(id)?.projectId;
1770
- return owner === undefined || owner === options.projectId;
1771
- }));
1772
- if (scoped.size > 0 || options.strictProject) {
1773
- candidateIds.clear();
1774
- for (const id of scoped)
1775
- candidateIds.add(id);
1907
+ if (owner !== undefined && owner !== options.projectId)
1908
+ candidateIds.delete(id);
1776
1909
  }
1777
1910
  }
1778
1911
  if (candidateIds.size === 0) {
@@ -1918,6 +2051,11 @@ class TheBrainV2 {
1918
2051
  ...(r.entry.outcome ? { outcome: r.entry.outcome } : {}),
1919
2052
  ...(claims && claims.length > 0 ? { claims } : {}),
1920
2053
  ...(r.entry.domain ? { domain: r.entry.domain } : {}),
2054
+ ...(r.entry.projectId === undefined
2055
+ ? { scope: 'unscoped' }
2056
+ : options.projectId && r.entry.projectId !== options.projectId
2057
+ ? { scope: 'other-project', ownerProject: r.entry.projectId }
2058
+ : {}),
1921
2059
  ...(cosmeticChanges && cosmeticChanges.length > 0 ? { cosmeticChanges } : {}),
1922
2060
  };
1923
2061
  });
@@ -2007,6 +2145,36 @@ class TheBrainV2 {
2007
2145
  }
2008
2146
  return results;
2009
2147
  }
2148
+ /**
2149
+ * Give memories stored before projects existed to the project their evidence lives in.
2150
+ *
2151
+ * An unscoped memory is visible to every project, so one project's notes surface in another's
2152
+ * searches. When all the code it tracks sits inside `root`, there is no doubt whose it is, and
2153
+ * it is stamped with `projectId`. A memory that tracks nothing, or tracks files outside `root`,
2154
+ * is left alone: nothing proves who it belongs to, and guessing would hide it from the project
2155
+ * that does own it. Returns how many were adopted.
2156
+ */
2157
+ adoptUnscopedByEvidence(projectId, root) {
2158
+ const base = root.endsWith(path_1.default.sep) ? root : root + path_1.default.sep;
2159
+ let adopted = 0;
2160
+ for (const entry of this.entries.values()) {
2161
+ if (entry.projectId !== undefined)
2162
+ continue;
2163
+ const tracked = [
2164
+ ...Object.keys(entry.fileHashes || {}),
2165
+ ...Object.keys(entry.symbolHashes || {}).map((k) => k.substring(0, k.lastIndexOf('::'))),
2166
+ ];
2167
+ if (tracked.length === 0)
2168
+ continue;
2169
+ if (!tracked.every((abs) => path_1.default.resolve(abs).startsWith(base)))
2170
+ continue;
2171
+ entry.projectId = projectId;
2172
+ adopted++;
2173
+ }
2174
+ if (adopted > 0)
2175
+ this.scheduleSave();
2176
+ return adopted;
2177
+ }
2010
2178
  embeddingSidecar() {
2011
2179
  if (!this.sidecar)
2012
2180
  this.sidecar = new BrainEmbeddings_1.EmbeddingSidecar(EMBEDDINGS_FILE);
@@ -2120,6 +2288,21 @@ class TheBrainV2 {
2120
2288
  * whether a reuse happened. Unknown ids fail silently (a peer may have forgotten the
2121
2289
  * entry since the search ranked it); savings attribution must never break a search.
2122
2290
  */
2291
+ /** Inverse document frequency of one index term over the whole corpus (BM25's formula). */
2292
+ termIdf(term) {
2293
+ this.syncIfChanged();
2294
+ const N = this.entries.size;
2295
+ const df = this.invertedIndex.get(term)?.size ?? 0;
2296
+ return Math.log((N - df + 0.5) / (df + 0.5) + 1);
2297
+ }
2298
+ /** One reuse of a memory the agent chose and read (see search_memory's shortlist). */
2299
+ recordReuse(id) {
2300
+ const entry = this.entries.get(id);
2301
+ if (!entry)
2302
+ return;
2303
+ entry.hits++;
2304
+ this.scheduleSave();
2305
+ }
2123
2306
  creditSavings(id, tokens) {
2124
2307
  if (!Number.isFinite(tokens) || tokens <= 0)
2125
2308
  return;
@@ -2252,6 +2435,7 @@ class TheBrainV2 {
2252
2435
  const terms = tokenize(keeper.query + ' ' + keeper.response);
2253
2436
  keeper.terms = [...new Set(terms)];
2254
2437
  keeper.termFreq = termFrequencies(terms);
2438
+ keeper.tokv = exports.TOKENIZER_VERSION;
2255
2439
  keeper.charCount = keeper.query.length + keeper.response.length;
2256
2440
  this.entries.set(keepId, keeper);
2257
2441
  for (const term of keeper.terms) {
@@ -2363,8 +2547,10 @@ class TheBrainV2 {
2363
2547
  this.bloom.add(entry.query.trim().toLowerCase().substring(0, 200));
2364
2548
  }
2365
2549
  // A restored id was deliberately brought back — its old tombstone must not suppress it.
2366
- for (const id of this.entries.keys())
2367
- this.tombstones.delete(id);
2550
+ for (const id of this.entries.keys()) {
2551
+ if (this.tombstones.delete(id))
2552
+ this.revived.add(id);
2553
+ }
2368
2554
  this.scheduleSave();
2369
2555
  return { ok: true, restored: entries.size, message: `Restored ${entries.size} memories from snapshot "${name}". The pre-restore state was snapshotted, so this is undoable too.` };
2370
2556
  }
@@ -2447,6 +2633,7 @@ class TheBrainV2 {
2447
2633
  }
2448
2634
  this.bloom.add(revived.query.trim().toLowerCase().substring(0, 200));
2449
2635
  this.tombstones.delete(id);
2636
+ this.revived.add(id);
2450
2637
  this.recalcAvgDocLength();
2451
2638
  this.scheduleSave();
2452
2639
  return { ok: true, message: `Restored memory "${id}" from the trash (${revived.hits || 0} prior reuse(s) kept). Its freshness will be re-judged on the next search.` };
@@ -2541,12 +2728,16 @@ class TheBrainV2 {
2541
2728
  if (hasNewTracking) {
2542
2729
  // Re-point: the new tracking replaces the old wholesale rather than merging, because
2543
2730
  // a moved symbol's old path must stop counting against the entry forever.
2544
- entry.fileHashes = opts.filePaths?.length ? hashFilesForFreshness(opts.filePaths) : undefined;
2545
- entry.symbolHashes = opts.symbols?.length ? hashSymbolsForFreshness(opts.symbols) : undefined;
2546
- entry.symbolNormalizedHashes = opts.symbols?.length ? hashSymbolsNormalizedForFreshness(opts.symbols) : undefined;
2547
- for (const p of opts.filePaths || [])
2731
+ // A symbol the resolver cannot locate would be "fresh" forever (MISSING === MISSING), so
2732
+ // its file is tracked whole instead, and the label says file, not symbol.
2733
+ const split = partitionSymbolRefs(opts.symbols ?? []);
2734
+ const files = dropFilesCoveredBySymbols([...new Set([...(opts.filePaths ?? []), ...split.unresolved.map((r) => r.filePath)])], split.resolved).files;
2735
+ entry.fileHashes = files.length ? hashFilesForFreshness(files) : undefined;
2736
+ entry.symbolHashes = split.resolved.length ? hashSymbolsForFreshness(split.resolved) : undefined;
2737
+ entry.symbolNormalizedHashes = split.resolved.length ? hashSymbolsNormalizedForFreshness(split.resolved) : undefined;
2738
+ for (const p of files)
2548
2739
  retracked.push(rel(path_1.default.resolve(p)));
2549
- for (const s of opts.symbols || [])
2740
+ for (const s of split.resolved)
2550
2741
  retracked.push(`${rel(path_1.default.resolve(s.filePath))}::${s.symbolName}`);
2551
2742
  }
2552
2743
  else {
@@ -2564,10 +2755,19 @@ class TheBrainV2 {
2564
2755
  const sep = key.lastIndexOf('::');
2565
2756
  return { filePath: key.substring(0, sep), symbolName: key.substring(sep + 2) };
2566
2757
  });
2567
- entry.symbolHashes = hashSymbolsForFreshness(refs);
2568
- entry.symbolNormalizedHashes = hashSymbolsNormalizedForFreshness(refs);
2758
+ // A symbol that no longer resolves keeps the hash it was stored with: re-hashing it would
2759
+ // write MISSING, which is what it will read as forever, and bless a deleted symbol.
2760
+ const gone = new Set(partitionSymbolRefs(refs).unresolved.map((r) => `${path_1.default.resolve(r.filePath)}::${r.symbolName}`));
2761
+ const rehashed = hashSymbolsForFreshness(refs);
2762
+ const rehashedNorm = hashSymbolsNormalizedForFreshness(refs);
2763
+ for (const key of gone) {
2764
+ rehashed[key] = entry.symbolHashes[key] ?? rehashed[key];
2765
+ rehashedNorm[key] = entry.symbolNormalizedHashes?.[key] ?? rehashedNorm[key];
2766
+ }
2767
+ entry.symbolHashes = rehashed;
2768
+ entry.symbolNormalizedHashes = rehashedNorm;
2569
2769
  for (const r of refs)
2570
- retracked.push(`${rel(r.filePath)}::${r.symbolName}`);
2770
+ retracked.push(`${rel(r.filePath)}::${r.symbolName}${gone.has(`${path_1.default.resolve(r.filePath)}::${r.symbolName}`) ? ' (no longer found — stays stale)' : ''}`);
2571
2771
  }
2572
2772
  if (entry.claims) {
2573
2773
  for (const claim of entry.claims) {
@@ -2695,6 +2895,7 @@ class TheBrainV2 {
2695
2895
  const terms = tokenize(entry.query + ' ' + entry.response);
2696
2896
  entry.terms = [...new Set(terms)];
2697
2897
  entry.termFreq = termFrequencies(terms);
2898
+ entry.tokv = exports.TOKENIZER_VERSION;
2698
2899
  entry.charCount = entry.query.length + entry.response.length;
2699
2900
  // Claims supplied in this patch were just hashed by buildClaims; the helper re-anchors the
2700
2901
  // ones carried over, so either way the entry's evidence describes the code as it is now.