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.
- package/README.md +95 -0
- package/dist/access/projectShares.d.ts +48 -0
- package/dist/access/projectShares.d.ts.map +1 -0
- package/dist/access/projectShares.js +203 -0
- package/dist/access/projectShares.js.map +1 -0
- package/dist/access/sharedInstructionsNote.d.ts +37 -0
- package/dist/access/sharedInstructionsNote.d.ts.map +1 -0
- package/dist/access/sharedInstructionsNote.js +76 -0
- package/dist/access/sharedInstructionsNote.js.map +1 -0
- package/dist/admin/seedUsers.d.ts +23 -0
- package/dist/admin/seedUsers.d.ts.map +1 -0
- package/dist/admin/seedUsers.js +168 -0
- package/dist/admin/seedUsers.js.map +1 -0
- package/dist/api/openapi.d.ts +2 -0
- package/dist/api/openapi.d.ts.map +1 -0
- package/dist/api/openapi.js +942 -0
- package/dist/api/openapi.js.map +1 -0
- package/dist/auth/clientStore.d.ts +43 -0
- package/dist/auth/clientStore.d.ts.map +1 -0
- package/dist/auth/clientStore.js +168 -0
- package/dist/auth/clientStore.js.map +1 -0
- package/dist/auth/deleteAccount.d.ts +34 -0
- package/dist/auth/deleteAccount.d.ts.map +1 -0
- package/dist/auth/deleteAccount.js +203 -0
- package/dist/auth/deleteAccount.js.map +1 -0
- package/dist/auth/oauth.d.ts +118 -0
- package/dist/auth/oauth.d.ts.map +1 -0
- package/dist/auth/oauth.js +491 -0
- package/dist/auth/oauth.js.map +1 -0
- package/dist/auth/patStore.d.ts +87 -0
- package/dist/auth/patStore.d.ts.map +1 -0
- package/dist/auth/patStore.js +308 -0
- package/dist/auth/patStore.js.map +1 -0
- package/dist/auth/supabase.d.ts +15 -0
- package/dist/auth/supabase.d.ts.map +1 -0
- package/dist/auth/supabase.js +66 -0
- package/dist/auth/supabase.js.map +1 -0
- package/dist/auth/tokenStore.d.ts +73 -0
- package/dist/auth/tokenStore.d.ts.map +1 -0
- package/dist/auth/tokenStore.js +261 -0
- package/dist/auth/tokenStore.js.map +1 -0
- package/dist/backup/drive.d.ts +24 -0
- package/dist/backup/drive.d.ts.map +1 -0
- package/dist/backup/drive.js +70 -0
- package/dist/backup/drive.js.map +1 -0
- package/dist/billing/tierStore.d.ts +59 -0
- package/dist/billing/tierStore.d.ts.map +1 -0
- package/dist/billing/tierStore.js +152 -0
- package/dist/billing/tierStore.js.map +1 -0
- package/dist/digest/activityDigest.d.ts +32 -0
- package/dist/digest/activityDigest.d.ts.map +1 -0
- package/dist/digest/activityDigest.js +299 -0
- package/dist/digest/activityDigest.js.map +1 -0
- package/dist/digest/digestCron.d.ts +40 -0
- package/dist/digest/digestCron.d.ts.map +1 -0
- package/dist/digest/digestCron.js +146 -0
- package/dist/digest/digestCron.js.map +1 -0
- package/dist/digest/digestPreferences.d.ts +25 -0
- package/dist/digest/digestPreferences.d.ts.map +1 -0
- package/dist/digest/digestPreferences.js +79 -0
- package/dist/digest/digestPreferences.js.map +1 -0
- package/dist/digest/emailSender.d.ts +20 -0
- package/dist/digest/emailSender.d.ts.map +1 -0
- package/dist/digest/emailSender.js +35 -0
- package/dist/digest/emailSender.js.map +1 -0
- package/dist/drive/client.d.ts +43 -0
- package/dist/drive/client.d.ts.map +1 -0
- package/dist/drive/client.js +282 -0
- package/dist/drive/client.js.map +1 -0
- package/dist/drive/errors.d.ts +27 -0
- package/dist/drive/errors.d.ts.map +1 -0
- package/dist/drive/errors.js +51 -0
- package/dist/drive/errors.js.map +1 -0
- package/dist/drive/fileCache.d.ts +22 -0
- package/dist/drive/fileCache.d.ts.map +1 -0
- package/dist/drive/fileCache.js +57 -0
- package/dist/drive/fileCache.js.map +1 -0
- package/dist/governance/accessControl.d.ts +87 -0
- package/dist/governance/accessControl.d.ts.map +1 -0
- package/dist/governance/accessControl.js +179 -0
- package/dist/governance/accessControl.js.map +1 -0
- package/dist/html/components.d.ts +8 -0
- package/dist/html/components.d.ts.map +1 -0
- package/dist/html/components.js +19 -0
- package/dist/html/components.js.map +1 -0
- package/dist/html/layout.d.ts +7 -0
- package/dist/html/layout.d.ts.map +1 -0
- package/dist/html/layout.js +24 -0
- package/dist/html/layout.js.map +1 -0
- package/dist/html/metricsUi.d.ts +8 -0
- package/dist/html/metricsUi.d.ts.map +1 -0
- package/dist/html/metricsUi.js +271 -0
- package/dist/html/metricsUi.js.map +1 -0
- package/dist/httpServer.d.ts +19 -0
- package/dist/httpServer.d.ts.map +1 -0
- package/dist/httpServer.js +3913 -0
- package/dist/httpServer.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -0
- package/dist/index.js.map +1 -0
- package/dist/jobs/asyncJobRegistry.d.ts +30 -0
- package/dist/jobs/asyncJobRegistry.d.ts.map +1 -0
- package/dist/jobs/asyncJobRegistry.js +70 -0
- package/dist/jobs/asyncJobRegistry.js.map +1 -0
- package/dist/observability/metricsQuery.d.ts +41 -0
- package/dist/observability/metricsQuery.d.ts.map +1 -0
- package/dist/observability/metricsQuery.js +106 -0
- package/dist/observability/metricsQuery.js.map +1 -0
- package/dist/observability/relevanceSignal.d.ts +26 -0
- package/dist/observability/relevanceSignal.d.ts.map +1 -0
- package/dist/observability/relevanceSignal.js +95 -0
- package/dist/observability/relevanceSignal.js.map +1 -0
- package/dist/observability/requestEvents.d.ts +31 -0
- package/dist/observability/requestEvents.d.ts.map +1 -0
- package/dist/observability/requestEvents.js +54 -0
- package/dist/observability/requestEvents.js.map +1 -0
- package/dist/observability/slowQueryAlert.d.ts +25 -0
- package/dist/observability/slowQueryAlert.d.ts.map +1 -0
- package/dist/observability/slowQueryAlert.js +67 -0
- package/dist/observability/slowQueryAlert.js.map +1 -0
- package/dist/observability/zeroResultTriage.d.ts +22 -0
- package/dist/observability/zeroResultTriage.d.ts.map +1 -0
- package/dist/observability/zeroResultTriage.js +116 -0
- package/dist/observability/zeroResultTriage.js.map +1 -0
- package/dist/search/embeddings.d.ts +31 -0
- package/dist/search/embeddings.d.ts.map +1 -0
- package/dist/search/embeddings.js +91 -0
- package/dist/search/embeddings.js.map +1 -0
- package/dist/search/fileWatcher.d.ts +28 -0
- package/dist/search/fileWatcher.d.ts.map +1 -0
- package/dist/search/fileWatcher.js +103 -0
- package/dist/search/fileWatcher.js.map +1 -0
- package/dist/search/hotQueryCache.d.ts +31 -0
- package/dist/search/hotQueryCache.d.ts.map +1 -0
- package/dist/search/hotQueryCache.js +103 -0
- package/dist/search/hotQueryCache.js.map +1 -0
- package/dist/search/postgresIndex.d.ts +439 -0
- package/dist/search/postgresIndex.d.ts.map +1 -0
- package/dist/search/postgresIndex.js +1610 -0
- package/dist/search/postgresIndex.js.map +1 -0
- package/dist/search/sqliteIndex.d.ts +66 -0
- package/dist/search/sqliteIndex.d.ts.map +1 -0
- package/dist/search/sqliteIndex.js +342 -0
- package/dist/search/sqliteIndex.js.map +1 -0
- package/dist/server.d.ts +43 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +532 -0
- package/dist/server.js.map +1 -0
- package/dist/session/bundle.d.ts +53 -0
- package/dist/session/bundle.d.ts.map +1 -0
- package/dist/session/bundle.js +97 -0
- package/dist/session/bundle.js.map +1 -0
- package/dist/storage/client.d.ts +157 -0
- package/dist/storage/client.d.ts.map +1 -0
- package/dist/storage/client.js +825 -0
- package/dist/storage/client.js.map +1 -0
- package/dist/tools/addWebhookPattern.d.ts +15 -0
- package/dist/tools/addWebhookPattern.d.ts.map +1 -0
- package/dist/tools/addWebhookPattern.js +15 -0
- package/dist/tools/addWebhookPattern.js.map +1 -0
- package/dist/tools/appendLog.d.ts +18 -0
- package/dist/tools/appendLog.d.ts.map +1 -0
- package/dist/tools/appendLog.js +18 -0
- package/dist/tools/appendLog.js.map +1 -0
- package/dist/tools/auditIndex.d.ts +15 -0
- package/dist/tools/auditIndex.d.ts.map +1 -0
- package/dist/tools/auditIndex.js +165 -0
- package/dist/tools/auditIndex.js.map +1 -0
- package/dist/tools/batchDeletePages.d.ts +18 -0
- package/dist/tools/batchDeletePages.d.ts.map +1 -0
- package/dist/tools/batchDeletePages.js +143 -0
- package/dist/tools/batchDeletePages.js.map +1 -0
- package/dist/tools/coerce.d.ts +3 -0
- package/dist/tools/coerce.d.ts.map +1 -0
- package/dist/tools/coerce.js +12 -0
- package/dist/tools/coerce.js.map +1 -0
- package/dist/tools/createPage.d.ts +24 -0
- package/dist/tools/createPage.d.ts.map +1 -0
- package/dist/tools/createPage.js +99 -0
- package/dist/tools/createPage.js.map +1 -0
- package/dist/tools/createPages.d.ts +51 -0
- package/dist/tools/createPages.d.ts.map +1 -0
- package/dist/tools/createPages.js +91 -0
- package/dist/tools/createPages.js.map +1 -0
- package/dist/tools/deletePage.d.ts +19 -0
- package/dist/tools/deletePage.d.ts.map +1 -0
- package/dist/tools/deletePage.js +127 -0
- package/dist/tools/deletePage.js.map +1 -0
- package/dist/tools/exportWiki.d.ts +48 -0
- package/dist/tools/exportWiki.d.ts.map +1 -0
- package/dist/tools/exportWiki.js +233 -0
- package/dist/tools/exportWiki.js.map +1 -0
- package/dist/tools/extractLinks.d.ts +14 -0
- package/dist/tools/extractLinks.d.ts.map +1 -0
- package/dist/tools/extractLinks.js +25 -0
- package/dist/tools/extractLinks.js.map +1 -0
- package/dist/tools/generateClaudeInstructions.d.ts +27 -0
- package/dist/tools/generateClaudeInstructions.d.ts.map +1 -0
- package/dist/tools/generateClaudeInstructions.js +263 -0
- package/dist/tools/generateClaudeInstructions.js.map +1 -0
- package/dist/tools/generateGptInstructions.d.ts +27 -0
- package/dist/tools/generateGptInstructions.d.ts.map +1 -0
- package/dist/tools/generateGptInstructions.js +208 -0
- package/dist/tools/generateGptInstructions.js.map +1 -0
- package/dist/tools/getBacklinks.d.ts +12 -0
- package/dist/tools/getBacklinks.d.ts.map +1 -0
- package/dist/tools/getBacklinks.js +13 -0
- package/dist/tools/getBacklinks.js.map +1 -0
- package/dist/tools/getRelated.d.ts +12 -0
- package/dist/tools/getRelated.d.ts.map +1 -0
- package/dist/tools/getRelated.js +13 -0
- package/dist/tools/getRelated.js.map +1 -0
- package/dist/tools/healthCheck.d.ts +5 -0
- package/dist/tools/healthCheck.d.ts.map +1 -0
- package/dist/tools/healthCheck.js +167 -0
- package/dist/tools/healthCheck.js.map +1 -0
- package/dist/tools/importBrainSource.d.ts +36 -0
- package/dist/tools/importBrainSource.d.ts.map +1 -0
- package/dist/tools/importBrainSource.js +314 -0
- package/dist/tools/importBrainSource.js.map +1 -0
- package/dist/tools/importWikiZip.d.ts +60 -0
- package/dist/tools/importWikiZip.d.ts.map +1 -0
- package/dist/tools/importWikiZip.js +379 -0
- package/dist/tools/importWikiZip.js.map +1 -0
- package/dist/tools/initProject.d.ts +34 -0
- package/dist/tools/initProject.d.ts.map +1 -0
- package/dist/tools/initProject.js +443 -0
- package/dist/tools/initProject.js.map +1 -0
- package/dist/tools/instructionContext.d.ts +60 -0
- package/dist/tools/instructionContext.d.ts.map +1 -0
- package/dist/tools/instructionContext.js +210 -0
- package/dist/tools/instructionContext.js.map +1 -0
- package/dist/tools/listArchivedPages.d.ts +17 -0
- package/dist/tools/listArchivedPages.d.ts.map +1 -0
- package/dist/tools/listArchivedPages.js +51 -0
- package/dist/tools/listArchivedPages.js.map +1 -0
- package/dist/tools/listPages.d.ts +28 -0
- package/dist/tools/listPages.d.ts.map +1 -0
- package/dist/tools/listPages.js +166 -0
- package/dist/tools/listPages.js.map +1 -0
- package/dist/tools/listWebhooks.d.ts +7 -0
- package/dist/tools/listWebhooks.d.ts.map +1 -0
- package/dist/tools/listWebhooks.js +10 -0
- package/dist/tools/listWebhooks.js.map +1 -0
- package/dist/tools/movePage.d.ts +18 -0
- package/dist/tools/movePage.d.ts.map +1 -0
- package/dist/tools/movePage.js +182 -0
- package/dist/tools/movePage.js.map +1 -0
- package/dist/tools/pageHistory.d.ts +36 -0
- package/dist/tools/pageHistory.d.ts.map +1 -0
- package/dist/tools/pageHistory.js +60 -0
- package/dist/tools/pageHistory.js.map +1 -0
- package/dist/tools/patchPage.d.ts +141 -0
- package/dist/tools/patchPage.d.ts.map +1 -0
- package/dist/tools/patchPage.js +287 -0
- package/dist/tools/patchPage.js.map +1 -0
- package/dist/tools/pullSessionBundle.d.ts +34 -0
- package/dist/tools/pullSessionBundle.d.ts.map +1 -0
- package/dist/tools/pullSessionBundle.js +432 -0
- package/dist/tools/pullSessionBundle.js.map +1 -0
- package/dist/tools/purgeWiki.d.ts +23 -0
- package/dist/tools/purgeWiki.d.ts.map +1 -0
- package/dist/tools/purgeWiki.js +113 -0
- package/dist/tools/purgeWiki.js.map +1 -0
- package/dist/tools/pushSessionBundle.d.ts +139 -0
- package/dist/tools/pushSessionBundle.d.ts.map +1 -0
- package/dist/tools/pushSessionBundle.js +282 -0
- package/dist/tools/pushSessionBundle.js.map +1 -0
- package/dist/tools/readGovernanceAudit.d.ts +17 -0
- package/dist/tools/readGovernanceAudit.d.ts.map +1 -0
- package/dist/tools/readGovernanceAudit.js +21 -0
- package/dist/tools/readGovernanceAudit.js.map +1 -0
- package/dist/tools/readPage.d.ts +13 -0
- package/dist/tools/readPage.d.ts.map +1 -0
- package/dist/tools/readPage.js +46 -0
- package/dist/tools/readPage.js.map +1 -0
- package/dist/tools/removeWebhook.d.ts +14 -0
- package/dist/tools/removeWebhook.d.ts.map +1 -0
- package/dist/tools/removeWebhook.js +12 -0
- package/dist/tools/removeWebhook.js.map +1 -0
- package/dist/tools/resolveProject.d.ts +58 -0
- package/dist/tools/resolveProject.d.ts.map +1 -0
- package/dist/tools/resolveProject.js +175 -0
- package/dist/tools/resolveProject.js.map +1 -0
- package/dist/tools/restorePage.d.ts +47 -0
- package/dist/tools/restorePage.d.ts.map +1 -0
- package/dist/tools/restorePage.js +111 -0
- package/dist/tools/restorePage.js.map +1 -0
- package/dist/tools/searchPages.d.ts +28 -0
- package/dist/tools/searchPages.d.ts.map +1 -0
- package/dist/tools/searchPages.js +372 -0
- package/dist/tools/searchPages.js.map +1 -0
- package/dist/tools/setWebhook.d.ts +30 -0
- package/dist/tools/setWebhook.d.ts.map +1 -0
- package/dist/tools/setWebhook.js +30 -0
- package/dist/tools/setWebhook.js.map +1 -0
- package/dist/tools/shareProject.d.ts +25 -0
- package/dist/tools/shareProject.d.ts.map +1 -0
- package/dist/tools/shareProject.js +56 -0
- package/dist/tools/shareProject.js.map +1 -0
- package/dist/tools/suggestLinks.d.ts +29 -0
- package/dist/tools/suggestLinks.d.ts.map +1 -0
- package/dist/tools/suggestLinks.js +214 -0
- package/dist/tools/suggestLinks.js.map +1 -0
- package/dist/tools/updatePage.d.ts +27 -0
- package/dist/tools/updatePage.d.ts.map +1 -0
- package/dist/tools/updatePage.js +118 -0
- package/dist/tools/updatePage.js.map +1 -0
- package/dist/webhooks/dispatch.d.ts +49 -0
- package/dist/webhooks/dispatch.d.ts.map +1 -0
- package/dist/webhooks/dispatch.js +159 -0
- package/dist/webhooks/dispatch.js.map +1 -0
- package/dist/webhooks/webhookRules.d.ts +34 -0
- package/dist/webhooks/webhookRules.d.ts.map +1 -0
- package/dist/webhooks/webhookRules.js +129 -0
- package/dist/webhooks/webhookRules.js.map +1 -0
- package/dist/wiki/frontmatter.d.ts +45 -0
- package/dist/wiki/frontmatter.d.ts.map +1 -0
- package/dist/wiki/frontmatter.js +68 -0
- package/dist/wiki/frontmatter.js.map +1 -0
- package/dist/wiki/index.d.ts +22 -0
- package/dist/wiki/index.d.ts.map +1 -0
- package/dist/wiki/index.js +203 -0
- package/dist/wiki/index.js.map +1 -0
- package/dist/wiki/ingestPolicy.d.ts +18 -0
- package/dist/wiki/ingestPolicy.d.ts.map +1 -0
- package/dist/wiki/ingestPolicy.js +64 -0
- package/dist/wiki/ingestPolicy.js.map +1 -0
- package/dist/wiki/layoutLint.d.ts +51 -0
- package/dist/wiki/layoutLint.d.ts.map +1 -0
- package/dist/wiki/layoutLint.js +146 -0
- package/dist/wiki/layoutLint.js.map +1 -0
- package/dist/wiki/links.d.ts +6 -0
- package/dist/wiki/links.d.ts.map +1 -0
- package/dist/wiki/links.js +45 -0
- package/dist/wiki/links.js.map +1 -0
- package/dist/wiki/log.d.ts +58 -0
- package/dist/wiki/log.d.ts.map +1 -0
- package/dist/wiki/log.js +126 -0
- package/dist/wiki/log.js.map +1 -0
- package/dist/wiki/path.d.ts +8 -0
- package/dist/wiki/path.d.ts.map +1 -0
- package/dist/wiki/path.js +25 -0
- package/dist/wiki/path.js.map +1 -0
- package/dist/wiki/storageLimits.d.ts +163 -0
- package/dist/wiki/storageLimits.d.ts.map +1 -0
- package/dist/wiki/storageLimits.js +281 -0
- package/dist/wiki/storageLimits.js.map +1 -0
- 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"}
|