brains-mcp 1.61.2

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 (350) hide show
  1. package/README.md +95 -0
  2. package/dist/access/projectShares.d.ts +48 -0
  3. package/dist/access/projectShares.d.ts.map +1 -0
  4. package/dist/access/projectShares.js +203 -0
  5. package/dist/access/projectShares.js.map +1 -0
  6. package/dist/access/sharedInstructionsNote.d.ts +37 -0
  7. package/dist/access/sharedInstructionsNote.d.ts.map +1 -0
  8. package/dist/access/sharedInstructionsNote.js +76 -0
  9. package/dist/access/sharedInstructionsNote.js.map +1 -0
  10. package/dist/admin/seedUsers.d.ts +23 -0
  11. package/dist/admin/seedUsers.d.ts.map +1 -0
  12. package/dist/admin/seedUsers.js +168 -0
  13. package/dist/admin/seedUsers.js.map +1 -0
  14. package/dist/api/openapi.d.ts +2 -0
  15. package/dist/api/openapi.d.ts.map +1 -0
  16. package/dist/api/openapi.js +942 -0
  17. package/dist/api/openapi.js.map +1 -0
  18. package/dist/auth/clientStore.d.ts +43 -0
  19. package/dist/auth/clientStore.d.ts.map +1 -0
  20. package/dist/auth/clientStore.js +168 -0
  21. package/dist/auth/clientStore.js.map +1 -0
  22. package/dist/auth/deleteAccount.d.ts +34 -0
  23. package/dist/auth/deleteAccount.d.ts.map +1 -0
  24. package/dist/auth/deleteAccount.js +203 -0
  25. package/dist/auth/deleteAccount.js.map +1 -0
  26. package/dist/auth/oauth.d.ts +118 -0
  27. package/dist/auth/oauth.d.ts.map +1 -0
  28. package/dist/auth/oauth.js +491 -0
  29. package/dist/auth/oauth.js.map +1 -0
  30. package/dist/auth/patStore.d.ts +87 -0
  31. package/dist/auth/patStore.d.ts.map +1 -0
  32. package/dist/auth/patStore.js +308 -0
  33. package/dist/auth/patStore.js.map +1 -0
  34. package/dist/auth/supabase.d.ts +15 -0
  35. package/dist/auth/supabase.d.ts.map +1 -0
  36. package/dist/auth/supabase.js +66 -0
  37. package/dist/auth/supabase.js.map +1 -0
  38. package/dist/auth/tokenStore.d.ts +73 -0
  39. package/dist/auth/tokenStore.d.ts.map +1 -0
  40. package/dist/auth/tokenStore.js +261 -0
  41. package/dist/auth/tokenStore.js.map +1 -0
  42. package/dist/backup/drive.d.ts +24 -0
  43. package/dist/backup/drive.d.ts.map +1 -0
  44. package/dist/backup/drive.js +70 -0
  45. package/dist/backup/drive.js.map +1 -0
  46. package/dist/billing/tierStore.d.ts +59 -0
  47. package/dist/billing/tierStore.d.ts.map +1 -0
  48. package/dist/billing/tierStore.js +152 -0
  49. package/dist/billing/tierStore.js.map +1 -0
  50. package/dist/digest/activityDigest.d.ts +32 -0
  51. package/dist/digest/activityDigest.d.ts.map +1 -0
  52. package/dist/digest/activityDigest.js +299 -0
  53. package/dist/digest/activityDigest.js.map +1 -0
  54. package/dist/digest/digestCron.d.ts +40 -0
  55. package/dist/digest/digestCron.d.ts.map +1 -0
  56. package/dist/digest/digestCron.js +146 -0
  57. package/dist/digest/digestCron.js.map +1 -0
  58. package/dist/digest/digestPreferences.d.ts +25 -0
  59. package/dist/digest/digestPreferences.d.ts.map +1 -0
  60. package/dist/digest/digestPreferences.js +79 -0
  61. package/dist/digest/digestPreferences.js.map +1 -0
  62. package/dist/digest/emailSender.d.ts +20 -0
  63. package/dist/digest/emailSender.d.ts.map +1 -0
  64. package/dist/digest/emailSender.js +35 -0
  65. package/dist/digest/emailSender.js.map +1 -0
  66. package/dist/drive/client.d.ts +43 -0
  67. package/dist/drive/client.d.ts.map +1 -0
  68. package/dist/drive/client.js +282 -0
  69. package/dist/drive/client.js.map +1 -0
  70. package/dist/drive/errors.d.ts +27 -0
  71. package/dist/drive/errors.d.ts.map +1 -0
  72. package/dist/drive/errors.js +51 -0
  73. package/dist/drive/errors.js.map +1 -0
  74. package/dist/drive/fileCache.d.ts +22 -0
  75. package/dist/drive/fileCache.d.ts.map +1 -0
  76. package/dist/drive/fileCache.js +57 -0
  77. package/dist/drive/fileCache.js.map +1 -0
  78. package/dist/governance/accessControl.d.ts +87 -0
  79. package/dist/governance/accessControl.d.ts.map +1 -0
  80. package/dist/governance/accessControl.js +179 -0
  81. package/dist/governance/accessControl.js.map +1 -0
  82. package/dist/html/components.d.ts +8 -0
  83. package/dist/html/components.d.ts.map +1 -0
  84. package/dist/html/components.js +19 -0
  85. package/dist/html/components.js.map +1 -0
  86. package/dist/html/layout.d.ts +7 -0
  87. package/dist/html/layout.d.ts.map +1 -0
  88. package/dist/html/layout.js +24 -0
  89. package/dist/html/layout.js.map +1 -0
  90. package/dist/html/metricsUi.d.ts +8 -0
  91. package/dist/html/metricsUi.d.ts.map +1 -0
  92. package/dist/html/metricsUi.js +271 -0
  93. package/dist/html/metricsUi.js.map +1 -0
  94. package/dist/httpServer.d.ts +19 -0
  95. package/dist/httpServer.d.ts.map +1 -0
  96. package/dist/httpServer.js +3913 -0
  97. package/dist/httpServer.js.map +1 -0
  98. package/dist/index.d.ts +3 -0
  99. package/dist/index.d.ts.map +1 -0
  100. package/dist/index.js +40 -0
  101. package/dist/index.js.map +1 -0
  102. package/dist/jobs/asyncJobRegistry.d.ts +30 -0
  103. package/dist/jobs/asyncJobRegistry.d.ts.map +1 -0
  104. package/dist/jobs/asyncJobRegistry.js +70 -0
  105. package/dist/jobs/asyncJobRegistry.js.map +1 -0
  106. package/dist/observability/metricsQuery.d.ts +41 -0
  107. package/dist/observability/metricsQuery.d.ts.map +1 -0
  108. package/dist/observability/metricsQuery.js +106 -0
  109. package/dist/observability/metricsQuery.js.map +1 -0
  110. package/dist/observability/relevanceSignal.d.ts +26 -0
  111. package/dist/observability/relevanceSignal.d.ts.map +1 -0
  112. package/dist/observability/relevanceSignal.js +95 -0
  113. package/dist/observability/relevanceSignal.js.map +1 -0
  114. package/dist/observability/requestEvents.d.ts +31 -0
  115. package/dist/observability/requestEvents.d.ts.map +1 -0
  116. package/dist/observability/requestEvents.js +54 -0
  117. package/dist/observability/requestEvents.js.map +1 -0
  118. package/dist/observability/slowQueryAlert.d.ts +25 -0
  119. package/dist/observability/slowQueryAlert.d.ts.map +1 -0
  120. package/dist/observability/slowQueryAlert.js +67 -0
  121. package/dist/observability/slowQueryAlert.js.map +1 -0
  122. package/dist/observability/zeroResultTriage.d.ts +22 -0
  123. package/dist/observability/zeroResultTriage.d.ts.map +1 -0
  124. package/dist/observability/zeroResultTriage.js +116 -0
  125. package/dist/observability/zeroResultTriage.js.map +1 -0
  126. package/dist/search/embeddings.d.ts +31 -0
  127. package/dist/search/embeddings.d.ts.map +1 -0
  128. package/dist/search/embeddings.js +91 -0
  129. package/dist/search/embeddings.js.map +1 -0
  130. package/dist/search/fileWatcher.d.ts +28 -0
  131. package/dist/search/fileWatcher.d.ts.map +1 -0
  132. package/dist/search/fileWatcher.js +103 -0
  133. package/dist/search/fileWatcher.js.map +1 -0
  134. package/dist/search/hotQueryCache.d.ts +31 -0
  135. package/dist/search/hotQueryCache.d.ts.map +1 -0
  136. package/dist/search/hotQueryCache.js +103 -0
  137. package/dist/search/hotQueryCache.js.map +1 -0
  138. package/dist/search/postgresIndex.d.ts +439 -0
  139. package/dist/search/postgresIndex.d.ts.map +1 -0
  140. package/dist/search/postgresIndex.js +1610 -0
  141. package/dist/search/postgresIndex.js.map +1 -0
  142. package/dist/search/sqliteIndex.d.ts +66 -0
  143. package/dist/search/sqliteIndex.d.ts.map +1 -0
  144. package/dist/search/sqliteIndex.js +342 -0
  145. package/dist/search/sqliteIndex.js.map +1 -0
  146. package/dist/server.d.ts +43 -0
  147. package/dist/server.d.ts.map +1 -0
  148. package/dist/server.js +532 -0
  149. package/dist/server.js.map +1 -0
  150. package/dist/session/bundle.d.ts +53 -0
  151. package/dist/session/bundle.d.ts.map +1 -0
  152. package/dist/session/bundle.js +97 -0
  153. package/dist/session/bundle.js.map +1 -0
  154. package/dist/storage/client.d.ts +157 -0
  155. package/dist/storage/client.d.ts.map +1 -0
  156. package/dist/storage/client.js +825 -0
  157. package/dist/storage/client.js.map +1 -0
  158. package/dist/tools/addWebhookPattern.d.ts +15 -0
  159. package/dist/tools/addWebhookPattern.d.ts.map +1 -0
  160. package/dist/tools/addWebhookPattern.js +15 -0
  161. package/dist/tools/addWebhookPattern.js.map +1 -0
  162. package/dist/tools/appendLog.d.ts +18 -0
  163. package/dist/tools/appendLog.d.ts.map +1 -0
  164. package/dist/tools/appendLog.js +18 -0
  165. package/dist/tools/appendLog.js.map +1 -0
  166. package/dist/tools/auditIndex.d.ts +15 -0
  167. package/dist/tools/auditIndex.d.ts.map +1 -0
  168. package/dist/tools/auditIndex.js +165 -0
  169. package/dist/tools/auditIndex.js.map +1 -0
  170. package/dist/tools/batchDeletePages.d.ts +18 -0
  171. package/dist/tools/batchDeletePages.d.ts.map +1 -0
  172. package/dist/tools/batchDeletePages.js +143 -0
  173. package/dist/tools/batchDeletePages.js.map +1 -0
  174. package/dist/tools/coerce.d.ts +3 -0
  175. package/dist/tools/coerce.d.ts.map +1 -0
  176. package/dist/tools/coerce.js +12 -0
  177. package/dist/tools/coerce.js.map +1 -0
  178. package/dist/tools/createPage.d.ts +24 -0
  179. package/dist/tools/createPage.d.ts.map +1 -0
  180. package/dist/tools/createPage.js +99 -0
  181. package/dist/tools/createPage.js.map +1 -0
  182. package/dist/tools/createPages.d.ts +51 -0
  183. package/dist/tools/createPages.d.ts.map +1 -0
  184. package/dist/tools/createPages.js +91 -0
  185. package/dist/tools/createPages.js.map +1 -0
  186. package/dist/tools/deletePage.d.ts +19 -0
  187. package/dist/tools/deletePage.d.ts.map +1 -0
  188. package/dist/tools/deletePage.js +127 -0
  189. package/dist/tools/deletePage.js.map +1 -0
  190. package/dist/tools/exportWiki.d.ts +48 -0
  191. package/dist/tools/exportWiki.d.ts.map +1 -0
  192. package/dist/tools/exportWiki.js +233 -0
  193. package/dist/tools/exportWiki.js.map +1 -0
  194. package/dist/tools/extractLinks.d.ts +14 -0
  195. package/dist/tools/extractLinks.d.ts.map +1 -0
  196. package/dist/tools/extractLinks.js +25 -0
  197. package/dist/tools/extractLinks.js.map +1 -0
  198. package/dist/tools/generateClaudeInstructions.d.ts +27 -0
  199. package/dist/tools/generateClaudeInstructions.d.ts.map +1 -0
  200. package/dist/tools/generateClaudeInstructions.js +263 -0
  201. package/dist/tools/generateClaudeInstructions.js.map +1 -0
  202. package/dist/tools/generateGptInstructions.d.ts +27 -0
  203. package/dist/tools/generateGptInstructions.d.ts.map +1 -0
  204. package/dist/tools/generateGptInstructions.js +208 -0
  205. package/dist/tools/generateGptInstructions.js.map +1 -0
  206. package/dist/tools/getBacklinks.d.ts +12 -0
  207. package/dist/tools/getBacklinks.d.ts.map +1 -0
  208. package/dist/tools/getBacklinks.js +13 -0
  209. package/dist/tools/getBacklinks.js.map +1 -0
  210. package/dist/tools/getRelated.d.ts +12 -0
  211. package/dist/tools/getRelated.d.ts.map +1 -0
  212. package/dist/tools/getRelated.js +13 -0
  213. package/dist/tools/getRelated.js.map +1 -0
  214. package/dist/tools/healthCheck.d.ts +5 -0
  215. package/dist/tools/healthCheck.d.ts.map +1 -0
  216. package/dist/tools/healthCheck.js +167 -0
  217. package/dist/tools/healthCheck.js.map +1 -0
  218. package/dist/tools/importBrainSource.d.ts +36 -0
  219. package/dist/tools/importBrainSource.d.ts.map +1 -0
  220. package/dist/tools/importBrainSource.js +314 -0
  221. package/dist/tools/importBrainSource.js.map +1 -0
  222. package/dist/tools/importWikiZip.d.ts +60 -0
  223. package/dist/tools/importWikiZip.d.ts.map +1 -0
  224. package/dist/tools/importWikiZip.js +379 -0
  225. package/dist/tools/importWikiZip.js.map +1 -0
  226. package/dist/tools/initProject.d.ts +34 -0
  227. package/dist/tools/initProject.d.ts.map +1 -0
  228. package/dist/tools/initProject.js +443 -0
  229. package/dist/tools/initProject.js.map +1 -0
  230. package/dist/tools/instructionContext.d.ts +60 -0
  231. package/dist/tools/instructionContext.d.ts.map +1 -0
  232. package/dist/tools/instructionContext.js +210 -0
  233. package/dist/tools/instructionContext.js.map +1 -0
  234. package/dist/tools/listArchivedPages.d.ts +17 -0
  235. package/dist/tools/listArchivedPages.d.ts.map +1 -0
  236. package/dist/tools/listArchivedPages.js +51 -0
  237. package/dist/tools/listArchivedPages.js.map +1 -0
  238. package/dist/tools/listPages.d.ts +28 -0
  239. package/dist/tools/listPages.d.ts.map +1 -0
  240. package/dist/tools/listPages.js +166 -0
  241. package/dist/tools/listPages.js.map +1 -0
  242. package/dist/tools/listWebhooks.d.ts +7 -0
  243. package/dist/tools/listWebhooks.d.ts.map +1 -0
  244. package/dist/tools/listWebhooks.js +10 -0
  245. package/dist/tools/listWebhooks.js.map +1 -0
  246. package/dist/tools/movePage.d.ts +18 -0
  247. package/dist/tools/movePage.d.ts.map +1 -0
  248. package/dist/tools/movePage.js +182 -0
  249. package/dist/tools/movePage.js.map +1 -0
  250. package/dist/tools/pageHistory.d.ts +36 -0
  251. package/dist/tools/pageHistory.d.ts.map +1 -0
  252. package/dist/tools/pageHistory.js +60 -0
  253. package/dist/tools/pageHistory.js.map +1 -0
  254. package/dist/tools/patchPage.d.ts +141 -0
  255. package/dist/tools/patchPage.d.ts.map +1 -0
  256. package/dist/tools/patchPage.js +287 -0
  257. package/dist/tools/patchPage.js.map +1 -0
  258. package/dist/tools/pullSessionBundle.d.ts +34 -0
  259. package/dist/tools/pullSessionBundle.d.ts.map +1 -0
  260. package/dist/tools/pullSessionBundle.js +432 -0
  261. package/dist/tools/pullSessionBundle.js.map +1 -0
  262. package/dist/tools/purgeWiki.d.ts +23 -0
  263. package/dist/tools/purgeWiki.d.ts.map +1 -0
  264. package/dist/tools/purgeWiki.js +113 -0
  265. package/dist/tools/purgeWiki.js.map +1 -0
  266. package/dist/tools/pushSessionBundle.d.ts +139 -0
  267. package/dist/tools/pushSessionBundle.d.ts.map +1 -0
  268. package/dist/tools/pushSessionBundle.js +282 -0
  269. package/dist/tools/pushSessionBundle.js.map +1 -0
  270. package/dist/tools/readGovernanceAudit.d.ts +17 -0
  271. package/dist/tools/readGovernanceAudit.d.ts.map +1 -0
  272. package/dist/tools/readGovernanceAudit.js +21 -0
  273. package/dist/tools/readGovernanceAudit.js.map +1 -0
  274. package/dist/tools/readPage.d.ts +13 -0
  275. package/dist/tools/readPage.d.ts.map +1 -0
  276. package/dist/tools/readPage.js +46 -0
  277. package/dist/tools/readPage.js.map +1 -0
  278. package/dist/tools/removeWebhook.d.ts +14 -0
  279. package/dist/tools/removeWebhook.d.ts.map +1 -0
  280. package/dist/tools/removeWebhook.js +12 -0
  281. package/dist/tools/removeWebhook.js.map +1 -0
  282. package/dist/tools/resolveProject.d.ts +58 -0
  283. package/dist/tools/resolveProject.d.ts.map +1 -0
  284. package/dist/tools/resolveProject.js +175 -0
  285. package/dist/tools/resolveProject.js.map +1 -0
  286. package/dist/tools/restorePage.d.ts +47 -0
  287. package/dist/tools/restorePage.d.ts.map +1 -0
  288. package/dist/tools/restorePage.js +111 -0
  289. package/dist/tools/restorePage.js.map +1 -0
  290. package/dist/tools/searchPages.d.ts +28 -0
  291. package/dist/tools/searchPages.d.ts.map +1 -0
  292. package/dist/tools/searchPages.js +372 -0
  293. package/dist/tools/searchPages.js.map +1 -0
  294. package/dist/tools/setWebhook.d.ts +30 -0
  295. package/dist/tools/setWebhook.d.ts.map +1 -0
  296. package/dist/tools/setWebhook.js +30 -0
  297. package/dist/tools/setWebhook.js.map +1 -0
  298. package/dist/tools/shareProject.d.ts +25 -0
  299. package/dist/tools/shareProject.d.ts.map +1 -0
  300. package/dist/tools/shareProject.js +56 -0
  301. package/dist/tools/shareProject.js.map +1 -0
  302. package/dist/tools/suggestLinks.d.ts +29 -0
  303. package/dist/tools/suggestLinks.d.ts.map +1 -0
  304. package/dist/tools/suggestLinks.js +214 -0
  305. package/dist/tools/suggestLinks.js.map +1 -0
  306. package/dist/tools/updatePage.d.ts +27 -0
  307. package/dist/tools/updatePage.d.ts.map +1 -0
  308. package/dist/tools/updatePage.js +118 -0
  309. package/dist/tools/updatePage.js.map +1 -0
  310. package/dist/webhooks/dispatch.d.ts +49 -0
  311. package/dist/webhooks/dispatch.d.ts.map +1 -0
  312. package/dist/webhooks/dispatch.js +159 -0
  313. package/dist/webhooks/dispatch.js.map +1 -0
  314. package/dist/webhooks/webhookRules.d.ts +34 -0
  315. package/dist/webhooks/webhookRules.d.ts.map +1 -0
  316. package/dist/webhooks/webhookRules.js +129 -0
  317. package/dist/webhooks/webhookRules.js.map +1 -0
  318. package/dist/wiki/frontmatter.d.ts +45 -0
  319. package/dist/wiki/frontmatter.d.ts.map +1 -0
  320. package/dist/wiki/frontmatter.js +68 -0
  321. package/dist/wiki/frontmatter.js.map +1 -0
  322. package/dist/wiki/index.d.ts +22 -0
  323. package/dist/wiki/index.d.ts.map +1 -0
  324. package/dist/wiki/index.js +203 -0
  325. package/dist/wiki/index.js.map +1 -0
  326. package/dist/wiki/ingestPolicy.d.ts +18 -0
  327. package/dist/wiki/ingestPolicy.d.ts.map +1 -0
  328. package/dist/wiki/ingestPolicy.js +64 -0
  329. package/dist/wiki/ingestPolicy.js.map +1 -0
  330. package/dist/wiki/layoutLint.d.ts +51 -0
  331. package/dist/wiki/layoutLint.d.ts.map +1 -0
  332. package/dist/wiki/layoutLint.js +146 -0
  333. package/dist/wiki/layoutLint.js.map +1 -0
  334. package/dist/wiki/links.d.ts +6 -0
  335. package/dist/wiki/links.d.ts.map +1 -0
  336. package/dist/wiki/links.js +45 -0
  337. package/dist/wiki/links.js.map +1 -0
  338. package/dist/wiki/log.d.ts +58 -0
  339. package/dist/wiki/log.d.ts.map +1 -0
  340. package/dist/wiki/log.js +126 -0
  341. package/dist/wiki/log.js.map +1 -0
  342. package/dist/wiki/path.d.ts +8 -0
  343. package/dist/wiki/path.d.ts.map +1 -0
  344. package/dist/wiki/path.js +25 -0
  345. package/dist/wiki/path.js.map +1 -0
  346. package/dist/wiki/storageLimits.d.ts +163 -0
  347. package/dist/wiki/storageLimits.d.ts.map +1 -0
  348. package/dist/wiki/storageLimits.js +281 -0
  349. package/dist/wiki/storageLimits.js.map +1 -0
  350. package/package.json +81 -0
@@ -0,0 +1,91 @@
1
+ /**
2
+ * embeddings.ts
3
+ *
4
+ * OpenAI text-embedding-3-small client for wiki page vectors.
5
+ * Used at ingest time (upsertPage) and at query time (hybrid search).
6
+ *
7
+ * Cost: $0.020 / 1M tokens (text-embedding-3-small).
8
+ * Falls back silently when OPENAI_API_KEY is unset so the server
9
+ * continues to function with FTS-only search.
10
+ */
11
+ import OpenAI from "openai";
12
+ export const EMBEDDING_MODEL = "text-embedding-3-small";
13
+ export const EMBEDDING_DIMS = 1536;
14
+ let _client = null;
15
+ function getClient() {
16
+ const key = process.env.OPENAI_API_KEY?.trim();
17
+ if (!key)
18
+ return null;
19
+ if (!_client)
20
+ _client = new OpenAI({ apiKey: key });
21
+ return _client;
22
+ }
23
+ export function isEmbeddingEnabled() {
24
+ return Boolean(process.env.OPENAI_API_KEY?.trim()) &&
25
+ process.env.ENABLE_HYBRID_RETRIEVAL === "true";
26
+ }
27
+ /**
28
+ * Generate a single embedding for `text`.
29
+ * Returns null when OPENAI_API_KEY is unset or the API call fails.
30
+ * Text is truncated to ~8000 tokens before sending (model max is 8192).
31
+ */
32
+ export async function generateEmbedding(text) {
33
+ const client = getClient();
34
+ if (!client)
35
+ return null;
36
+ const truncated = text.slice(0, 32_000); // ~8k tokens safety margin
37
+ try {
38
+ const response = await client.embeddings.create({
39
+ model: EMBEDDING_MODEL,
40
+ input: truncated,
41
+ });
42
+ return response.data[0]?.embedding ?? null;
43
+ }
44
+ catch (err) {
45
+ console.error("[embeddings] generateEmbedding failed:", err instanceof Error ? err.message : String(err));
46
+ return null;
47
+ }
48
+ }
49
+ /**
50
+ * Generate embeddings for a batch of texts.
51
+ * OpenAI allows up to 2048 inputs per request; callers should chunk larger batches.
52
+ * Returns an array of the same length; failed entries are null.
53
+ */
54
+ export async function generateEmbeddings(texts) {
55
+ if (texts.length === 0)
56
+ return [];
57
+ const client = getClient();
58
+ if (!client)
59
+ return texts.map(() => null);
60
+ const truncated = texts.map((t) => t.slice(0, 32_000));
61
+ try {
62
+ const response = await client.embeddings.create({
63
+ model: EMBEDDING_MODEL,
64
+ input: truncated,
65
+ });
66
+ const out = texts.map(() => null);
67
+ for (const item of response.data) {
68
+ out[item.index] = item.embedding;
69
+ }
70
+ return out;
71
+ }
72
+ catch (err) {
73
+ console.error("[embeddings] generateEmbeddings batch failed:", err instanceof Error ? err.message : String(err));
74
+ return texts.map(() => null);
75
+ }
76
+ }
77
+ /**
78
+ * Build the text to embed for a page: title + summary + (first 2000 chars of content).
79
+ * Keeping content short reduces token cost while preserving semantic signal.
80
+ */
81
+ export function buildEmbeddingInput(title, summary, content) {
82
+ const parts = [];
83
+ if (title)
84
+ parts.push(title);
85
+ if (summary)
86
+ parts.push(summary);
87
+ if (content)
88
+ parts.push(content.slice(0, 2000));
89
+ return parts.join("\n\n");
90
+ }
91
+ //# sourceMappingURL=embeddings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../../src/search/embeddings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { StorageClient } from "../storage/client.js";
2
+ import type { SqliteSearchIndex } from "./sqliteIndex.js";
3
+ export interface WikiFileWatcher {
4
+ /** Stop watching and release filesystem handles. */
5
+ close(): Promise<void>;
6
+ /** Resolves once chokidar's initial scan completes and events are live. */
7
+ whenReady(): Promise<void>;
8
+ /** Resolves once any pending or in-flight resync has settled (tests). */
9
+ whenIdle(): Promise<void>;
10
+ }
11
+ export interface WikiFileWatcherOptions {
12
+ debounceMs?: number;
13
+ /** Injectable for tests; defaults to console.warn. */
14
+ onError?: (err: unknown) => void;
15
+ }
16
+ /**
17
+ * Watches the local wiki directory for markdown changes made outside the app
18
+ * (e.g. moves/renames in Obsidian) and reconciles the SQLite search index.
19
+ *
20
+ * Without this, an external move only surfaces on the next `search` call (which
21
+ * triggers a throttled `ensureSynced`); the watcher closes that gap so the
22
+ * index follows the filesystem in near real time.
23
+ *
24
+ * Only meaningful for the local storage backend — the Supabase backend has no
25
+ * local source of truth to watch. Caller is responsible for that gate.
26
+ */
27
+ export declare function startWikiFileWatcher(wikiDir: string, drive: StorageClient, index: SqliteSearchIndex, options?: WikiFileWatcherOptions): WikiFileWatcher;
28
+ //# sourceMappingURL=fileWatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileWatcher.d.ts","sourceRoot":"","sources":["../../src/search/fileWatcher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAI1D,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,2EAA2E;IAC3E,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,yEAAyE;IACzE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,IAAI,CAAC;CAClC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,iBAAiB,EACxB,OAAO,GAAE,sBAA2B,GACnC,eAAe,CAuFjB"}
@@ -0,0 +1,103 @@
1
+ import path from "path";
2
+ import chokidar from "chokidar";
3
+ const DEFAULT_DEBOUNCE_MS = 400;
4
+ /**
5
+ * Watches the local wiki directory for markdown changes made outside the app
6
+ * (e.g. moves/renames in Obsidian) and reconciles the SQLite search index.
7
+ *
8
+ * Without this, an external move only surfaces on the next `search` call (which
9
+ * triggers a throttled `ensureSynced`); the watcher closes that gap so the
10
+ * index follows the filesystem in near real time.
11
+ *
12
+ * Only meaningful for the local storage backend — the Supabase backend has no
13
+ * local source of truth to watch. Caller is responsible for that gate.
14
+ */
15
+ export function startWikiFileWatcher(wikiDir, drive, index, options = {}) {
16
+ const debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
17
+ const onError = options.onError ?? ((err) => console.warn("[watch] resync failed:", err));
18
+ const watcher = chokidar.watch(wikiDir, {
19
+ ignoreInitial: true, // startBackgroundSync already covers the initial state
20
+ persistent: true,
21
+ // Skip hidden entries — notably the `.cache/` sqlite db (and its WAL), which
22
+ // the index itself writes; reacting to those would create a feedback loop.
23
+ ignored: (target) => path.basename(target).startsWith("."),
24
+ // Coalesce the burst of events an editor emits while saving a file.
25
+ awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 },
26
+ });
27
+ let debounceTimer = null;
28
+ let resyncInFlight = null;
29
+ let dirtyDuringResync = false;
30
+ let idleResolvers = [];
31
+ let ready = false;
32
+ let readyResolvers = [];
33
+ watcher.once("ready", () => {
34
+ ready = true;
35
+ const resolvers = readyResolvers;
36
+ readyResolvers = [];
37
+ for (const resolve of resolvers)
38
+ resolve();
39
+ });
40
+ const settleIdle = () => {
41
+ if (debounceTimer || resyncInFlight)
42
+ return;
43
+ const resolvers = idleResolvers;
44
+ idleResolvers = [];
45
+ for (const resolve of resolvers)
46
+ resolve();
47
+ };
48
+ const runResync = () => {
49
+ if (resyncInFlight) {
50
+ // A resync is already running; remember that more changed and re-run after.
51
+ dirtyDuringResync = true;
52
+ return;
53
+ }
54
+ const run = index
55
+ .syncNow(drive)
56
+ .catch(onError)
57
+ .finally(() => {
58
+ resyncInFlight = null;
59
+ if (dirtyDuringResync) {
60
+ dirtyDuringResync = false;
61
+ runResync();
62
+ }
63
+ else {
64
+ settleIdle();
65
+ }
66
+ });
67
+ resyncInFlight = run;
68
+ };
69
+ const scheduleResync = (changedPath) => {
70
+ if (!changedPath.endsWith(".md"))
71
+ return;
72
+ if (debounceTimer)
73
+ clearTimeout(debounceTimer);
74
+ debounceTimer = setTimeout(() => {
75
+ debounceTimer = null;
76
+ runResync();
77
+ }, debounceMs);
78
+ };
79
+ watcher
80
+ .on("add", scheduleResync)
81
+ .on("change", scheduleResync)
82
+ .on("unlink", scheduleResync)
83
+ .on("error", onError);
84
+ return {
85
+ async close() {
86
+ if (debounceTimer)
87
+ clearTimeout(debounceTimer);
88
+ debounceTimer = null;
89
+ await watcher.close();
90
+ },
91
+ whenReady() {
92
+ if (ready)
93
+ return Promise.resolve();
94
+ return new Promise((resolve) => readyResolvers.push(resolve));
95
+ },
96
+ whenIdle() {
97
+ if (!debounceTimer && !resyncInFlight)
98
+ return Promise.resolve();
99
+ return new Promise((resolve) => idleResolvers.push(resolve));
100
+ },
101
+ };
102
+ }
103
+ //# sourceMappingURL=fileWatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileWatcher.js","sourceRoot":"","sources":["../../src/search/fileWatcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * hotQueryCache.ts
3
+ *
4
+ * In-memory TTL cache for search results targeting the top-N repeated queries.
5
+ * Phase 4 speed improvement: near-zero cost cache hits for repeated MCP searches.
6
+ *
7
+ * Design:
8
+ * - Keyed by (userId, normalised query) — safe across multi-user Supabase deployments.
9
+ * - Short TTL (default 7 s) keeps results fresh enough for interactive use.
10
+ * - Capped at MAX_ENTRIES; oldest entry evicted when full.
11
+ * - Warm-up queries Supabase request_events for the top-20 terms (last 7 d)
12
+ * and pre-runs those searches so the first real request is already cached.
13
+ */
14
+ export interface HotCacheStats {
15
+ size: number;
16
+ hits: number;
17
+ misses: number;
18
+ hitRate: number;
19
+ }
20
+ export declare function getHotCached(userId: string, query: string): object | null;
21
+ export declare function setHotCached(userId: string, query: string, result: object): void;
22
+ export declare function getHotCacheStats(): HotCacheStats;
23
+ export declare function clearHotCache(): void;
24
+ /**
25
+ * Fetch the top-N query strings from request_events (last 7 days) and return
26
+ * them so the caller can pre-warm the cache by running those searches.
27
+ *
28
+ * Returns an empty array when Supabase is not configured or the query fails.
29
+ */
30
+ export declare function fetchTopQueries(supabaseUrl: string, serviceRoleKey: string, limit?: number): Promise<string[]>;
31
+ //# sourceMappingURL=hotQueryCache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hotQueryCache.d.ts","sourceRoot":"","sources":["../../src/search/hotQueryCache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAyBD,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASzE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAShF;AAED,wBAAgB,gBAAgB,IAAI,aAAa,CAShD;AAED,wBAAgB,aAAa,IAAI,IAAI,CAIpC;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,KAAK,SAAK,GACT,OAAO,CAAC,MAAM,EAAE,CAAC,CA+BnB"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * hotQueryCache.ts
3
+ *
4
+ * In-memory TTL cache for search results targeting the top-N repeated queries.
5
+ * Phase 4 speed improvement: near-zero cost cache hits for repeated MCP searches.
6
+ *
7
+ * Design:
8
+ * - Keyed by (userId, normalised query) — safe across multi-user Supabase deployments.
9
+ * - Short TTL (default 7 s) keeps results fresh enough for interactive use.
10
+ * - Capped at MAX_ENTRIES; oldest entry evicted when full.
11
+ * - Warm-up queries Supabase request_events for the top-20 terms (last 7 d)
12
+ * and pre-runs those searches so the first real request is already cached.
13
+ */
14
+ const HOT_CACHE_TTL_MS = 7_000;
15
+ const HOT_CACHE_MAX_ENTRIES = 50;
16
+ const cache = new Map();
17
+ let totalHits = 0;
18
+ let totalMisses = 0;
19
+ function normKey(userId, query) {
20
+ return `${userId}\0${query.trim().toLowerCase()}`;
21
+ }
22
+ function evictExpired() {
23
+ const now = Date.now();
24
+ for (const [k, v] of cache) {
25
+ if (now > v.expiresAt)
26
+ cache.delete(k);
27
+ }
28
+ }
29
+ export function getHotCached(userId, query) {
30
+ evictExpired();
31
+ const entry = cache.get(normKey(userId, query));
32
+ if (!entry) {
33
+ totalMisses++;
34
+ return null;
35
+ }
36
+ totalHits++;
37
+ return entry.result;
38
+ }
39
+ export function setHotCached(userId, query, result) {
40
+ evictExpired();
41
+ const key = normKey(userId, query);
42
+ if (!cache.has(key) && cache.size >= HOT_CACHE_MAX_ENTRIES) {
43
+ // Evict the oldest (first inserted) entry.
44
+ const oldest = cache.keys().next().value;
45
+ if (oldest !== undefined)
46
+ cache.delete(oldest);
47
+ }
48
+ cache.set(key, { result, expiresAt: Date.now() + HOT_CACHE_TTL_MS });
49
+ }
50
+ export function getHotCacheStats() {
51
+ evictExpired();
52
+ const total = totalHits + totalMisses;
53
+ return {
54
+ size: cache.size,
55
+ hits: totalHits,
56
+ misses: totalMisses,
57
+ hitRate: total === 0 ? 0 : totalHits / total,
58
+ };
59
+ }
60
+ export function clearHotCache() {
61
+ cache.clear();
62
+ totalHits = 0;
63
+ totalMisses = 0;
64
+ }
65
+ /**
66
+ * Fetch the top-N query strings from request_events (last 7 days) and return
67
+ * them so the caller can pre-warm the cache by running those searches.
68
+ *
69
+ * Returns an empty array when Supabase is not configured or the query fails.
70
+ */
71
+ export async function fetchTopQueries(supabaseUrl, serviceRoleKey, limit = 20) {
72
+ const url = `${supabaseUrl}/rest/v1/request_events` +
73
+ `?select=query_text` +
74
+ `&path=eq./api/v1/search` +
75
+ `&query_text=not.is.null` +
76
+ `&ts=gte.${new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString()}` +
77
+ `&limit=500`;
78
+ try {
79
+ const res = await fetch(url, {
80
+ headers: {
81
+ apikey: serviceRoleKey,
82
+ authorization: `Bearer ${serviceRoleKey}`,
83
+ },
84
+ });
85
+ if (!res.ok)
86
+ return [];
87
+ const rows = (await res.json());
88
+ const freq = new Map();
89
+ for (const row of rows) {
90
+ const q = row.query_text.trim().toLowerCase();
91
+ if (q)
92
+ freq.set(q, (freq.get(q) ?? 0) + 1);
93
+ }
94
+ return [...freq.entries()]
95
+ .sort((a, b) => b[1] - a[1])
96
+ .slice(0, limit)
97
+ .map(([q]) => q);
98
+ }
99
+ catch {
100
+ return [];
101
+ }
102
+ }
103
+ //# sourceMappingURL=hotQueryCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hotQueryCache.js","sourceRoot":"","sources":["../../src/search/hotQueryCache.ts"],"names":[],"mappings":"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"}