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
package/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # Brains
2
+
3
+ A personal second-brain HTTP API and MCP (Model Context Protocol) server backed by Supabase Storage with Postgres full-text search. Designed for ChatGPT Actions, Claude integrations, and any MCP-compatible agent.
4
+
5
+ ---
6
+
7
+ ## Quickstart: init a project
8
+
9
+ Run this once per project from any MCP-connected agent:
10
+
11
+ ```
12
+ init_project({
13
+ projectSlug: "my-project",
14
+ projectName: "My Project",
15
+ platform: "claude",
16
+ execute: true
17
+ })
18
+ ```
19
+
20
+ This single call idempotently:
21
+
22
+ 1. Creates `projects/my-project/readme.md` (project registry page).
23
+ 2. Generates and saves `projects/my-project/instructions/claude.md` (platform-specific instruction file).
24
+ 3. Seeds the three foundation pages (`instructions/agent-instruction-schema-v1.md`, `instructions/agent-instruction-template-v1.md`, `instructions/brain-routing.md`) if they are missing.
25
+ 4. Creates stub cross-project tracking pages at the brain root (`active-open-loops.md`, `active-unanswered-questions.md`, `active-next-actions.md`, `decisions/core-decisions-log.md`) if they are missing. Wikis that already carry the pre-#455 copies at `projects/active-*.md` keep using those — no duplicate is created.
26
+
27
+ The response includes two artifacts:
28
+ - `instructionMarkdown` — the full wiki instruction file saved to `projects/my-project/instructions/claude.md`. This is the canonical reference document an agent reads at session start.
29
+ - `systemPromptMarkdown` — a short pointer block to paste into your Claude Project system prompt (or `CLAUDE.md`). It contains the identity, brain-first rule, activation gate, and a single boot sequence that ends with "read `projects/my-project/instructions/claude.md` and follow it."
30
+
31
+ Paste `systemPromptMarkdown` into your system prompt. The instruction file handles all domain context and write-back rules — keep the system prompt short.
32
+
33
+ ### Preview before applying
34
+
35
+ ```
36
+ init_project({
37
+ projectSlug: "my-project",
38
+ projectName: "My Project",
39
+ execute: false
40
+ })
41
+ ```
42
+
43
+ Returns the full operation plan with no writes.
44
+
45
+ ---
46
+
47
+ > **Why not `pull_wiki`?** It returns a base64-encoded ZIP inline in the tool response, which overflows MCP tool-result token caps at modest scale (~30 pages). `pull_session_bundle` returns plain text sized to fit in a single response and paginates via `nextCursor`. `pull_wiki` remains available for filesystem-equipped clients (e.g. Claude Desktop with filesystem access) and full-archive backup workflows.
48
+
49
+ ---
50
+
51
+ ## Architecture
52
+
53
+ - **HTTP server** (`src/httpServer.ts`) — REST API with OAuth 2.0, designed for ChatGPT Actions and Claude integrations.
54
+ - **MCP server** (`src/server.ts`) — MCP tool registry over stdio or HTTP transport.
55
+ - **Storage** (`src/storage/client.ts`) — Local filesystem or Supabase Storage backend.
56
+ - **Search** (`src/search/postgresIndex.ts`) — Postgres full-text search index (Supabase) or local scan fallback.
57
+
58
+ See [API-FIRST-ARCHITECTURE.md](./API-FIRST-ARCHITECTURE.md), [STORAGE.md](./STORAGE.md), and [WIKI-SCHEMA.md](./WIKI-SCHEMA.md) for deeper documentation.
59
+
60
+ ---
61
+
62
+ ## Observability
63
+
64
+ Every HTTP response carries an `X-Response-Time` header (e.g. `X-Response-Time: 43ms`) indicating server-side processing time. Every request also emits a single log line to stdout:
65
+
66
+ **Plain format (default):**
67
+ ```
68
+ [req] GET /api/v1/search 200 43ms backend=sqlite-fts queryMs=12
69
+ [req] POST /api/v1/pages 200 11ms
70
+ [req] GET /api/v1/search 200 8ms zero-results=true
71
+ ```
72
+
73
+ **Structured JSON (`LOG_FORMAT=json`):**
74
+ ```json
75
+ {"ts":"2026-04-17T10:00:00.000Z","method":"GET","path":"/api/v1/search","status":200,"durationMs":43,"backend":"sqlite-fts","queryMs":12}
76
+ ```
77
+
78
+ Set `LOG_FORMAT=json` to enable structured logging for log-shipping (e.g. Datadog, Logtail). Search requests additionally log `backend` and `queryMs` when available, and `zero-results=true` when a search returns no results.
79
+
80
+ ---
81
+
82
+
83
+ ```bash
84
+ npm install
85
+ npm run build
86
+ npm start
87
+ ```
88
+
89
+ Set `BRAINS_TRANSPORT=stdio` to run as an MCP stdio server.
90
+
91
+ ## Testing
92
+
93
+ ```bash
94
+ npm test
95
+ ```
@@ -0,0 +1,48 @@
1
+ /**
2
+ * projectShares.ts
3
+ *
4
+ * CRUD for the `project_shares` Postgres table via Supabase PostgREST.
5
+ * Backs the internal-only `share_project` MCP tool (BRA-368): lets an owner
6
+ * account grant a named grantee account read+write access to one project
7
+ * (folder prefix) of the owner's own wiki storage namespace.
8
+ *
9
+ * Table: scripts/project-shares.sql
10
+ */
11
+ export interface ProjectShareGrant {
12
+ owner_subject: string;
13
+ project_path: string;
14
+ }
15
+ /**
16
+ * Normalizes a project identity into a folder-prefix path, e.g. 'projects/5280'.
17
+ * Matches the segment rules storage/client.ts enforces for wiki paths.
18
+ */
19
+ export declare function normalizeProjectPath(input: string): string;
20
+ /**
21
+ * Resolves a grantee identifier (email or existing subject/UUID) to a Supabase
22
+ * user id. Per BRA-368 v0 decision: the grantee must already have a Brains
23
+ * account — no pending/email-based invite support yet. Returns null if no
24
+ * matching user exists.
25
+ */
26
+ export declare function resolveGranteeSubject(input: string): Promise<string | null>;
27
+ export declare function upsertProjectShare(params: {
28
+ owner_subject: string;
29
+ project_path: string;
30
+ grantee_subject: string;
31
+ enabled: boolean;
32
+ }): Promise<void>;
33
+ /** Drop cached grants for one grantee, or all of them when called bare. */
34
+ export declare function invalidateGrantCache(granteeSubject?: string): void;
35
+ export declare function listActiveGrantsForGrantee(granteeSubject: string): Promise<ProjectShareGrant[]>;
36
+ /**
37
+ * Returns the subjects of everyone who currently holds an active (non-revoked)
38
+ * grant on the given owner+project_path. Used to re-render the "Shared
39
+ * Workspace" note in project instructions whenever a grant is created or
40
+ * revoked (BRA-388).
41
+ */
42
+ export declare function listActiveGranteesForProject(ownerSubject: string, projectPath: string): Promise<string[]>;
43
+ /**
44
+ * Best-effort reverse lookup of a Supabase user's email from their subject/UUID.
45
+ * Returns null if unavailable — callers should fall back to the raw subject.
46
+ */
47
+ export declare function resolveSubjectEmail(subject: string): Promise<string | null>;
48
+ //# sourceMappingURL=projectShares.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectShares.d.ts","sourceRoot":"","sources":["../../src/access/projectShares.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB;AAkBD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAa1D;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA8BjF;AAED,wBAAsB,kBAAkB,CAAC,MAAM,EAAE;IAC/C,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;CAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BhB;AAwBD,2EAA2E;AAC3E,wBAAgB,oBAAoB,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAGlE;AAED,wBAAsB,0BAA0B,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAwBrG;AAED;;;;;GAKG;AACH,wBAAsB,4BAA4B,CAChD,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,EAAE,CAAC,CAanB;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CASjF"}
@@ -0,0 +1,203 @@
1
+ /**
2
+ * projectShares.ts
3
+ *
4
+ * CRUD for the `project_shares` Postgres table via Supabase PostgREST.
5
+ * Backs the internal-only `share_project` MCP tool (BRA-368): lets an owner
6
+ * account grant a named grantee account read+write access to one project
7
+ * (folder prefix) of the owner's own wiki storage namespace.
8
+ *
9
+ * Table: scripts/project-shares.sql
10
+ */
11
+ function config() {
12
+ const supabaseUrl = (process.env.SUPABASE_URL ?? "").trim().replace(/\/$/, "");
13
+ const serviceRoleKey = (process.env.SUPABASE_SERVICE_ROLE_KEY ?? "").trim();
14
+ if (!supabaseUrl || !serviceRoleKey)
15
+ return null;
16
+ return { supabaseUrl, serviceRoleKey };
17
+ }
18
+ function headers(serviceRoleKey, extra) {
19
+ return {
20
+ "content-type": "application/json",
21
+ apikey: serviceRoleKey,
22
+ authorization: `Bearer ${serviceRoleKey}`,
23
+ ...extra,
24
+ };
25
+ }
26
+ /**
27
+ * Normalizes a project identity into a folder-prefix path, e.g. 'projects/5280'.
28
+ * Matches the segment rules storage/client.ts enforces for wiki paths.
29
+ */
30
+ export function normalizeProjectPath(input) {
31
+ const trimmed = input.trim().replace(/^\/+|\/+$/g, "");
32
+ if (!trimmed)
33
+ throw new Error("project_path is required");
34
+ const segments = trimmed.split("/");
35
+ if (segments[0] !== "projects" || segments.length < 2) {
36
+ throw new Error("project_path must be a folder prefix under 'projects/', e.g. 'projects/5280'");
37
+ }
38
+ for (const segment of segments) {
39
+ if (!/^[a-z0-9-]+$/.test(segment)) {
40
+ throw new Error(`Unsafe project_path segment: '${segment}'`);
41
+ }
42
+ }
43
+ return segments.join("/");
44
+ }
45
+ /**
46
+ * Resolves a grantee identifier (email or existing subject/UUID) to a Supabase
47
+ * user id. Per BRA-368 v0 decision: the grantee must already have a Brains
48
+ * account — no pending/email-based invite support yet. Returns null if no
49
+ * matching user exists.
50
+ */
51
+ export async function resolveGranteeSubject(input) {
52
+ const cfg = config();
53
+ if (!cfg)
54
+ throw new Error("share_project requires Supabase auth to be configured");
55
+ const { supabaseUrl, serviceRoleKey } = cfg;
56
+ const trimmed = input.trim();
57
+ if (!trimmed)
58
+ return null;
59
+ if (trimmed.includes("@")) {
60
+ const email = trimmed.toLowerCase();
61
+ let page = 1;
62
+ // Small user bases in practice; cap pagination as a sane upper bound.
63
+ while (page <= 20) {
64
+ const url = `${supabaseUrl}/auth/v1/admin/users?page=${page}&per_page=1000`;
65
+ const res = await fetch(url, { headers: headers(serviceRoleKey) });
66
+ if (!res.ok)
67
+ return null;
68
+ const body = (await res.json().catch(() => null));
69
+ const batch = body?.users ?? [];
70
+ const match = batch.find((u) => (u.email ?? "").toLowerCase() === email);
71
+ if (match)
72
+ return match.id;
73
+ if (batch.length < 1000)
74
+ break;
75
+ page++;
76
+ }
77
+ return null;
78
+ }
79
+ const url = `${supabaseUrl}/auth/v1/admin/users/${encodeURIComponent(trimmed)}`;
80
+ const res = await fetch(url, { headers: headers(serviceRoleKey) });
81
+ if (!res.ok)
82
+ return null;
83
+ const user = (await res.json().catch(() => null));
84
+ return user?.id ?? null;
85
+ }
86
+ export async function upsertProjectShare(params) {
87
+ const cfg = config();
88
+ if (!cfg)
89
+ throw new Error("share_project requires Supabase to be configured");
90
+ const { supabaseUrl, serviceRoleKey } = cfg;
91
+ const now = new Date().toISOString();
92
+ const url = `${supabaseUrl}/rest/v1/project_shares` +
93
+ `?on_conflict=owner_subject,project_path,grantee_subject`;
94
+ const res = await fetch(url, {
95
+ method: "POST",
96
+ headers: headers(serviceRoleKey, { prefer: "resolution=merge-duplicates,return=minimal" }),
97
+ body: JSON.stringify({
98
+ id: `${params.owner_subject}:${params.project_path}:${params.grantee_subject}`,
99
+ owner_subject: params.owner_subject,
100
+ project_path: params.project_path,
101
+ grantee_subject: params.grantee_subject,
102
+ permissions: "read_write",
103
+ revoked_at: params.enabled ? null : now,
104
+ updated_at: now,
105
+ }),
106
+ });
107
+ if (!res.ok) {
108
+ const body = await res.text().catch(() => "");
109
+ throw new Error(`upsertProjectShare failed (${res.status}): ${body}`);
110
+ }
111
+ // Both granting and revoking flow through here (via `enabled`), so dropping
112
+ // the grantee's cache entry keeps revocation effective on the next request
113
+ // rather than up to a TTL later — the property BRA-377 exists to guarantee.
114
+ invalidateGrantCache(params.grantee_subject);
115
+ }
116
+ /**
117
+ * Short-lived cache for grant lookups.
118
+ *
119
+ * The drive is re-resolved on every request and every MCP tool call so a
120
+ * revoked grant stops working immediately (BRA-377). That correctness property
121
+ * is worth keeping, but it made this an uncached Supabase round trip on every
122
+ * authenticated request — measured at roughly a third of the ~570ms floor for
123
+ * even the cheapest authenticated endpoint (GH #412).
124
+ *
125
+ * Correctness is preserved by invalidating on mutation rather than relying on
126
+ * expiry: upsertProjectShare() drops the grantee's entry, so a grant or
127
+ * revocation still takes effect on the very next request. The TTL is only a
128
+ * backstop for rows changed out of band (direct SQL, another instance).
129
+ */
130
+ const GRANT_CACHE_TTL_MS = 30_000;
131
+ const grantCache = new Map();
132
+ function grantCacheTtlMs() {
133
+ const raw = parseInt(process.env.BRAINS_GRANT_CACHE_TTL_MS ?? "", 10);
134
+ return Number.isFinite(raw) && raw >= 0 ? raw : GRANT_CACHE_TTL_MS;
135
+ }
136
+ /** Drop cached grants for one grantee, or all of them when called bare. */
137
+ export function invalidateGrantCache(granteeSubject) {
138
+ if (granteeSubject)
139
+ grantCache.delete(granteeSubject);
140
+ else
141
+ grantCache.clear();
142
+ }
143
+ export async function listActiveGrantsForGrantee(granteeSubject) {
144
+ const cfg = config();
145
+ if (!cfg)
146
+ return [];
147
+ const ttl = grantCacheTtlMs();
148
+ const cached = grantCache.get(granteeSubject);
149
+ if (cached && ttl > 0 && Date.now() - cached.at < ttl)
150
+ return cached.grants;
151
+ const { supabaseUrl, serviceRoleKey } = cfg;
152
+ const url = `${supabaseUrl}/rest/v1/project_shares` +
153
+ `?grantee_subject=eq.${encodeURIComponent(granteeSubject)}&revoked_at=is.null` +
154
+ `&select=owner_subject,project_path`;
155
+ const res = await fetch(url, { headers: headers(serviceRoleKey) });
156
+ // Do not cache failures. On this deployment the table may be missing
157
+ // entirely (GH #409), and caching a 404's empty result would turn a
158
+ // transient/schema fault into a sticky "user has no grants".
159
+ if (!res.ok)
160
+ return [];
161
+ const rows = (await res.json().catch(() => []));
162
+ const grants = Array.isArray(rows) ? rows : [];
163
+ grantCache.set(granteeSubject, { grants, at: Date.now() });
164
+ return grants;
165
+ }
166
+ /**
167
+ * Returns the subjects of everyone who currently holds an active (non-revoked)
168
+ * grant on the given owner+project_path. Used to re-render the "Shared
169
+ * Workspace" note in project instructions whenever a grant is created or
170
+ * revoked (BRA-388).
171
+ */
172
+ export async function listActiveGranteesForProject(ownerSubject, projectPath) {
173
+ const cfg = config();
174
+ if (!cfg)
175
+ return [];
176
+ const { supabaseUrl, serviceRoleKey } = cfg;
177
+ const url = `${supabaseUrl}/rest/v1/project_shares` +
178
+ `?owner_subject=eq.${encodeURIComponent(ownerSubject)}` +
179
+ `&project_path=eq.${encodeURIComponent(projectPath)}&revoked_at=is.null` +
180
+ `&select=grantee_subject`;
181
+ const res = await fetch(url, { headers: headers(serviceRoleKey) });
182
+ if (!res.ok)
183
+ return [];
184
+ const rows = (await res.json().catch(() => []));
185
+ return Array.isArray(rows) ? rows.map((r) => r.grantee_subject) : [];
186
+ }
187
+ /**
188
+ * Best-effort reverse lookup of a Supabase user's email from their subject/UUID.
189
+ * Returns null if unavailable — callers should fall back to the raw subject.
190
+ */
191
+ export async function resolveSubjectEmail(subject) {
192
+ const cfg = config();
193
+ if (!cfg)
194
+ return null;
195
+ const { supabaseUrl, serviceRoleKey } = cfg;
196
+ const url = `${supabaseUrl}/auth/v1/admin/users/${encodeURIComponent(subject)}`;
197
+ const res = await fetch(url, { headers: headers(serviceRoleKey) });
198
+ if (!res.ok)
199
+ return null;
200
+ const user = (await res.json().catch(() => null));
201
+ return user?.email ?? null;
202
+ }
203
+ //# sourceMappingURL=projectShares.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projectShares.js","sourceRoot":"","sources":["../../src/access/projectShares.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * sharedInstructionsNote.ts (BRA-388)
3
+ *
4
+ * When a project transitions from solo to shared (a `share_project` grant is
5
+ * created or revoked), the project's generated instructions were almost
6
+ * certainly written assuming a single owner-operator. This module keeps a
7
+ * "Shared Workspace" note in sync inside `projects/<slug>/instructions/*.md`
8
+ * so the instructions name the current collaborator(s), establish
9
+ * shared-workspace filing rules, and warn against sole-ownership assumptions
10
+ * written elsewhere in the document.
11
+ *
12
+ * The note is idempotent: it lives between START/END markers so re-syncing
13
+ * (on every grant/revoke) replaces it in place rather than duplicating it.
14
+ * When no active collaborators remain, the note is removed entirely.
15
+ */
16
+ import type { StorageClient } from "../storage/client.js";
17
+ /**
18
+ * Returns updated markdown with the Shared Workspace note applied: replaced
19
+ * in place if present, appended if not, or removed entirely if there are no
20
+ * active collaborators.
21
+ */
22
+ export declare function applySharedWorkspaceSection(content: string, projectSlug: string, collaborators: string[]): string;
23
+ export interface SyncSharedInstructionsResult {
24
+ collaborators: string[];
25
+ updated: string[];
26
+ skipped: string[];
27
+ }
28
+ /**
29
+ * Re-renders the Shared Workspace note in every existing
30
+ * `projects/<slug>/instructions/<platform>.md` file for a project, based on
31
+ * the project's current set of active grantees. Safe to call on both grant
32
+ * creation and revocation. Non-fatal by design — callers should treat
33
+ * failures here as best-effort and not block the underlying share/unshare
34
+ * operation.
35
+ */
36
+ export declare function syncSharedInstructionsNote(drive: StorageClient, ownerSubject: string, projectPath: string): Promise<SyncSharedInstructionsResult>;
37
+ //# sourceMappingURL=sharedInstructionsNote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sharedInstructionsNote.d.ts","sourceRoot":"","sources":["../../src/access/sharedInstructionsNote.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA4C1D;;;;GAIG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EAAE,GACtB,MAAM,CAOR;AAED,MAAM,WAAW,4BAA4B;IAC3C,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,aAAa,EACpB,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,4BAA4B,CAAC,CA6BvC"}
@@ -0,0 +1,76 @@
1
+ import { DriveNotFoundError } from "../drive/errors.js";
2
+ import { listActiveGranteesForProject, resolveSubjectEmail, } from "./projectShares.js";
3
+ const SECTION_START = "<!-- SHARED-WORKSPACE:START -->";
4
+ const SECTION_END = "<!-- SHARED-WORKSPACE:END -->";
5
+ const SECTION_PATTERN = new RegExp(`\\n*${SECTION_START}[\\s\\S]*?${SECTION_END}\\n*`, "g");
6
+ const INSTRUCTION_PLATFORMS = ["claude", "gpt"];
7
+ function projectSlugFromPath(projectPath) {
8
+ return projectPath.replace(/^projects\//, "");
9
+ }
10
+ function buildSection(projectSlug, collaborators) {
11
+ const collaboratorList = collaborators.length
12
+ ? collaborators.map((c) => `- ${c}`).join("\n")
13
+ : "- (no active collaborators)";
14
+ return [
15
+ SECTION_START,
16
+ "## Shared Workspace",
17
+ "",
18
+ `This project (\`projects/${projectSlug}/\`) is shared. Active collaborators with read/write access to everything under this folder:`,
19
+ "",
20
+ collaboratorList,
21
+ "",
22
+ `- Everything for this project must live under \`projects/${projectSlug}/\` — do not create or expect project content elsewhere in the wiki.`,
23
+ "- Any collaborator (or their own agent/assistant, which may be a different platform than yours) can read and edit any page under this folder. Do not assume you are the only reader or writer.",
24
+ "- Assumptions written elsewhere in this document that predate sharing (sole ownership, private working notes, etc.) may no longer hold — verify before relying on them.",
25
+ "",
26
+ SECTION_END,
27
+ ].join("\n");
28
+ }
29
+ function stripSection(content) {
30
+ return content.replace(SECTION_PATTERN, "\n");
31
+ }
32
+ /**
33
+ * Returns updated markdown with the Shared Workspace note applied: replaced
34
+ * in place if present, appended if not, or removed entirely if there are no
35
+ * active collaborators.
36
+ */
37
+ export function applySharedWorkspaceSection(content, projectSlug, collaborators) {
38
+ const stripped = stripSection(content).replace(/\s+$/, "");
39
+ if (collaborators.length === 0) {
40
+ return `${stripped}\n`;
41
+ }
42
+ const section = buildSection(projectSlug, collaborators);
43
+ return `${stripped}\n\n${section}\n`;
44
+ }
45
+ /**
46
+ * Re-renders the Shared Workspace note in every existing
47
+ * `projects/<slug>/instructions/<platform>.md` file for a project, based on
48
+ * the project's current set of active grantees. Safe to call on both grant
49
+ * creation and revocation. Non-fatal by design — callers should treat
50
+ * failures here as best-effort and not block the underlying share/unshare
51
+ * operation.
52
+ */
53
+ export async function syncSharedInstructionsNote(drive, ownerSubject, projectPath) {
54
+ const projectSlug = projectSlugFromPath(projectPath);
55
+ const granteeSubjects = await listActiveGranteesForProject(ownerSubject, projectPath);
56
+ const collaborators = await Promise.all(granteeSubjects.map(async (subject) => (await resolveSubjectEmail(subject)) ?? subject));
57
+ const updated = [];
58
+ const skipped = [];
59
+ for (const platform of INSTRUCTION_PLATFORMS) {
60
+ const filePath = `${projectPath}/instructions/${platform}.md`;
61
+ const existing = await drive.readFile(filePath).catch((err) => err instanceof DriveNotFoundError ? null : Promise.reject(err));
62
+ if (!existing) {
63
+ skipped.push(filePath);
64
+ continue;
65
+ }
66
+ const nextContent = applySharedWorkspaceSection(existing.content, projectSlug, collaborators);
67
+ if (nextContent === existing.content) {
68
+ skipped.push(filePath);
69
+ continue;
70
+ }
71
+ await drive.updateFile(existing.fileId, nextContent, existing.revision);
72
+ updated.push(filePath);
73
+ }
74
+ return { collaborators, updated, skipped };
75
+ }
76
+ //# sourceMappingURL=sharedInstructionsNote.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sharedInstructionsNote.js","sourceRoot":"","sources":["../../src/access/sharedInstructionsNote.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { type StorageClient } from "../storage/client.js";
2
+ export type SeedTier = "free_beta" | "launch_user" | "solo" | "pro" | "team";
3
+ export interface SeedUsersInput {
4
+ count: number;
5
+ tier: SeedTier;
6
+ prefix: string;
7
+ }
8
+ export interface SeedUsersResult {
9
+ subjects: string[];
10
+ }
11
+ export interface PurgeSeedUsersResult {
12
+ deleted: {
13
+ tokens: number;
14
+ clients: number;
15
+ accessLevels: number;
16
+ };
17
+ }
18
+ export declare const SEED_DOMAIN = "brains.test";
19
+ export declare function isSeedEnabled(): boolean;
20
+ export declare function isGodModeSubject(subject: string): boolean;
21
+ export declare function seedUsers(rootDrive: StorageClient, input: SeedUsersInput): Promise<SeedUsersResult>;
22
+ export declare function purgeSeedUsers(prefix: string): Promise<PurgeSeedUsersResult>;
23
+ //# sourceMappingURL=seedUsers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seedUsers.d.ts","sourceRoot":"","sources":["../../src/admin/seedUsers.ts"],"names":[],"mappings":"AACA,OAAO,EAA6B,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrF,MAAM,MAAM,QAAQ,GAAG,WAAW,GAAG,aAAa,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAE7E,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAWD,eAAO,MAAM,WAAW,gBAAgB,CAAC;AAEzC,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAIzD;AAgID,wBAAsB,SAAS,CAC7B,SAAS,EAAE,aAAa,EACxB,KAAK,EAAE,cAAc,GACpB,OAAO,CAAC,eAAe,CAAC,CA2C1B;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAkBlF"}