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
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* webhookRules.ts
|
|
3
|
+
*
|
|
4
|
+
* Postgres CRUD for user-configured outbound webhook rules.
|
|
5
|
+
* Table schema: scripts/webhooks-migration.sql
|
|
6
|
+
*/
|
|
7
|
+
function rowToRule(row) {
|
|
8
|
+
return {
|
|
9
|
+
id: row.id,
|
|
10
|
+
userId: row.user_id,
|
|
11
|
+
name: row.name,
|
|
12
|
+
url: row.url,
|
|
13
|
+
secret: row.secret,
|
|
14
|
+
events: row.events ?? [],
|
|
15
|
+
patterns: row.patterns ?? [],
|
|
16
|
+
enabled: row.enabled,
|
|
17
|
+
createdAt: row.created_at,
|
|
18
|
+
updatedAt: row.updated_at,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function getHeaders(serviceRoleKey) {
|
|
22
|
+
return {
|
|
23
|
+
"content-type": "application/json",
|
|
24
|
+
"apikey": serviceRoleKey,
|
|
25
|
+
"authorization": "Bearer " + serviceRoleKey,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function getBaseUrl() {
|
|
29
|
+
const supabaseUrl = (process.env.SUPABASE_URL ?? "").trim().replace(/\/$/, "");
|
|
30
|
+
return supabaseUrl + "/rest/v1/webhook_rules";
|
|
31
|
+
}
|
|
32
|
+
function isConfigured() {
|
|
33
|
+
const supabaseUrl = (process.env.SUPABASE_URL ?? "").trim();
|
|
34
|
+
const serviceRoleKey = (process.env.SUPABASE_SERVICE_ROLE_KEY ?? "").trim();
|
|
35
|
+
return supabaseUrl.length > 0 && serviceRoleKey.length > 0;
|
|
36
|
+
}
|
|
37
|
+
export async function listWebhookRules(userId) {
|
|
38
|
+
if (!isConfigured())
|
|
39
|
+
return [];
|
|
40
|
+
const serviceRoleKey = (process.env.SUPABASE_SERVICE_ROLE_KEY ?? "").trim();
|
|
41
|
+
const url = getBaseUrl() + "?user_id=eq." + encodeURIComponent(userId) + "&order=created_at.asc";
|
|
42
|
+
const res = await fetch(url, {
|
|
43
|
+
headers: { ...getHeaders(serviceRoleKey), "Accept": "application/json" },
|
|
44
|
+
signal: AbortSignal.timeout(8000),
|
|
45
|
+
});
|
|
46
|
+
if (!res.ok) {
|
|
47
|
+
const text = await res.text().catch(() => "");
|
|
48
|
+
throw new Error("Failed to list webhook rules: " + res.status + " " + text);
|
|
49
|
+
}
|
|
50
|
+
const rows = await res.json();
|
|
51
|
+
return rows.map(rowToRule);
|
|
52
|
+
}
|
|
53
|
+
export async function getWebhookRule(id, userId) {
|
|
54
|
+
if (!isConfigured())
|
|
55
|
+
return null;
|
|
56
|
+
const serviceRoleKey = (process.env.SUPABASE_SERVICE_ROLE_KEY ?? "").trim();
|
|
57
|
+
const url = getBaseUrl() + "?id=eq." + encodeURIComponent(id) + "&user_id=eq." + encodeURIComponent(userId);
|
|
58
|
+
const res = await fetch(url, {
|
|
59
|
+
headers: { ...getHeaders(serviceRoleKey), "Accept": "application/json" },
|
|
60
|
+
signal: AbortSignal.timeout(8000),
|
|
61
|
+
});
|
|
62
|
+
if (!res.ok)
|
|
63
|
+
return null;
|
|
64
|
+
const rows = await res.json();
|
|
65
|
+
return rows.length > 0 ? rowToRule(rows[0]) : null;
|
|
66
|
+
}
|
|
67
|
+
export async function upsertWebhookRule(userId, rule) {
|
|
68
|
+
if (!isConfigured())
|
|
69
|
+
throw new Error("Postgres not configured — cannot store webhook rules");
|
|
70
|
+
const serviceRoleKey = (process.env.SUPABASE_SERVICE_ROLE_KEY ?? "").trim();
|
|
71
|
+
const body = {
|
|
72
|
+
user_id: userId,
|
|
73
|
+
name: rule.name,
|
|
74
|
+
url: rule.url,
|
|
75
|
+
secret: rule.secret ?? "",
|
|
76
|
+
events: rule.events ?? ["create", "update"],
|
|
77
|
+
patterns: rule.patterns ?? [],
|
|
78
|
+
enabled: rule.enabled ?? true,
|
|
79
|
+
};
|
|
80
|
+
if (rule.id)
|
|
81
|
+
body["id"] = rule.id;
|
|
82
|
+
const res = await fetch(getBaseUrl(), {
|
|
83
|
+
method: "POST",
|
|
84
|
+
headers: {
|
|
85
|
+
...getHeaders(serviceRoleKey),
|
|
86
|
+
"Prefer": "return=representation,resolution=merge-duplicates",
|
|
87
|
+
},
|
|
88
|
+
body: JSON.stringify(body),
|
|
89
|
+
signal: AbortSignal.timeout(8000),
|
|
90
|
+
});
|
|
91
|
+
if (!res.ok) {
|
|
92
|
+
const text = await res.text().catch(() => "");
|
|
93
|
+
throw new Error("Failed to upsert webhook rule: " + res.status + " " + text);
|
|
94
|
+
}
|
|
95
|
+
const rows = await res.json();
|
|
96
|
+
if (!rows[0])
|
|
97
|
+
throw new Error("Upsert returned no rows");
|
|
98
|
+
return rowToRule(rows[0]);
|
|
99
|
+
}
|
|
100
|
+
export async function deleteWebhookRule(id, userId) {
|
|
101
|
+
if (!isConfigured())
|
|
102
|
+
return false;
|
|
103
|
+
const serviceRoleKey = (process.env.SUPABASE_SERVICE_ROLE_KEY ?? "").trim();
|
|
104
|
+
const url = getBaseUrl() + "?id=eq." + encodeURIComponent(id) + "&user_id=eq." + encodeURIComponent(userId);
|
|
105
|
+
const res = await fetch(url, {
|
|
106
|
+
method: "DELETE",
|
|
107
|
+
headers: { ...getHeaders(serviceRoleKey), "Prefer": "return=minimal" },
|
|
108
|
+
signal: AbortSignal.timeout(8000),
|
|
109
|
+
});
|
|
110
|
+
return res.ok;
|
|
111
|
+
}
|
|
112
|
+
export async function addPatternToRule(id, userId, pattern) {
|
|
113
|
+
const rule = await getWebhookRule(id, userId);
|
|
114
|
+
if (!rule)
|
|
115
|
+
return null;
|
|
116
|
+
if (rule.patterns.includes(pattern))
|
|
117
|
+
return rule; // idempotent
|
|
118
|
+
const updated = await upsertWebhookRule(userId, {
|
|
119
|
+
...rule,
|
|
120
|
+
patterns: [...rule.patterns, pattern],
|
|
121
|
+
});
|
|
122
|
+
return updated;
|
|
123
|
+
}
|
|
124
|
+
/** Returns enabled rules for a user that have at least one pattern configured. */
|
|
125
|
+
export async function getEnabledWebhookRulesForUser(userId) {
|
|
126
|
+
const all = await listWebhookRules(userId);
|
|
127
|
+
return all.filter((r) => r.enabled && r.patterns.length > 0);
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=webhookRules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhookRules.js","sourceRoot":"","sources":["../../src/webhooks/webhookRules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { WikiValidationWarning } from "../drive/errors.js";
|
|
2
|
+
export interface WikiFrontmatter {
|
|
3
|
+
title: string;
|
|
4
|
+
updated: string;
|
|
5
|
+
/** ISO 8601 datetime when the page was first created (e.g. 2026-05-11T14:32:00Z). */
|
|
6
|
+
created?: string;
|
|
7
|
+
tags?: string[];
|
|
8
|
+
/**
|
|
9
|
+
* Alternate names for the project this page is the readme of — the nicknames
|
|
10
|
+
* a user actually says. Read by resolve_project; ignored elsewhere.
|
|
11
|
+
*
|
|
12
|
+
* Deliberately separate from `tags`. Tags express membership as often as
|
|
13
|
+
* naming (`oio` on a vehicle's readme means "belongs to OIO"), so inferring
|
|
14
|
+
* aliases from them produced false matches no filter could reliably remove
|
|
15
|
+
* (GH #446). Absent means no aliases — there is no tag fallback.
|
|
16
|
+
*/
|
|
17
|
+
aliases?: string[];
|
|
18
|
+
status?: "active" | "archived" | "draft";
|
|
19
|
+
summary?: string;
|
|
20
|
+
/** Access level gate (1–5). Pages are only visible to users at this level or above. */
|
|
21
|
+
access_level?: number;
|
|
22
|
+
/** Audience classification: internal | client-safe | public. */
|
|
23
|
+
audience?: string;
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
}
|
|
26
|
+
export interface ParsedPage {
|
|
27
|
+
frontmatter: WikiFrontmatter;
|
|
28
|
+
content: string;
|
|
29
|
+
warnings: WikiValidationWarning[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parse markdown content and soft-validate frontmatter.
|
|
33
|
+
* Returns warnings for missing/invalid fields but never throws.
|
|
34
|
+
*/
|
|
35
|
+
export declare function parsePage(raw: string): ParsedPage;
|
|
36
|
+
/**
|
|
37
|
+
* Serialize frontmatter + body back to a markdown string.
|
|
38
|
+
* Stamps the current date into the 'updated' field.
|
|
39
|
+
*/
|
|
40
|
+
export declare function serializePage(fm: WikiFrontmatter, body: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* Build a fresh page string from title + body, inserting required frontmatter.
|
|
43
|
+
*/
|
|
44
|
+
export declare function buildNewPage(title: string, body: string, tags?: string[]): string;
|
|
45
|
+
//# sourceMappingURL=frontmatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../src/wiki/frontmatter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,eAAe,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,qBAAqB,EAAE,CAAC;CACnC;AAoBD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAqCjD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMvE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAQjF"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import matter from "gray-matter";
|
|
2
|
+
import { WikiValidationWarning } from "../drive/errors.js";
|
|
3
|
+
const REQUIRED_FIELDS = ["title", "updated"];
|
|
4
|
+
/**
|
|
5
|
+
* gray-matter (via js-yaml) parses unquoted YAML dates like `updated: 2026-07-27`
|
|
6
|
+
* into JS Date objects rather than strings. Left alone, `String(date)` produces
|
|
7
|
+
* `"Mon Jul 27 2026 00:00:00 GMT..."`, which fails downstream YYYY-MM-DD checks
|
|
8
|
+
* even though the source frontmatter was written correctly (GH #464).
|
|
9
|
+
*/
|
|
10
|
+
function normalizeDateFields(fm) {
|
|
11
|
+
for (const key of Object.keys(fm)) {
|
|
12
|
+
const value = fm[key];
|
|
13
|
+
if (value instanceof Date) {
|
|
14
|
+
const iso = value.toISOString();
|
|
15
|
+
fm[key] = iso.endsWith("T00:00:00.000Z") ? iso.slice(0, 10) : iso;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parse markdown content and soft-validate frontmatter.
|
|
21
|
+
* Returns warnings for missing/invalid fields but never throws.
|
|
22
|
+
*/
|
|
23
|
+
export function parsePage(raw) {
|
|
24
|
+
const parsed = matter(raw);
|
|
25
|
+
const fm = (parsed.data ?? {});
|
|
26
|
+
normalizeDateFields(fm);
|
|
27
|
+
const warnings = [];
|
|
28
|
+
for (const field of REQUIRED_FIELDS) {
|
|
29
|
+
if (!fm[field]) {
|
|
30
|
+
warnings.push(new WikiValidationWarning(field, `Required field '${field}' is missing`));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (fm.updated && !/^\d{4}-\d{2}-\d{2}/.test(String(fm.updated))) {
|
|
34
|
+
warnings.push(new WikiValidationWarning("updated", `'updated' should be in YYYY-MM-DD format, got: ${fm.updated}`));
|
|
35
|
+
}
|
|
36
|
+
if (fm.status && !["active", "archived", "draft"].includes(String(fm.status))) {
|
|
37
|
+
warnings.push(new WikiValidationWarning("status", `'status' should be active | archived | draft, got: ${fm.status}`));
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
frontmatter: fm,
|
|
41
|
+
content: parsed.content,
|
|
42
|
+
warnings,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Serialize frontmatter + body back to a markdown string.
|
|
47
|
+
* Stamps the current date into the 'updated' field.
|
|
48
|
+
*/
|
|
49
|
+
export function serializePage(fm, body) {
|
|
50
|
+
const frontmatterWithDate = {
|
|
51
|
+
...fm,
|
|
52
|
+
updated: new Date().toISOString().slice(0, 10),
|
|
53
|
+
};
|
|
54
|
+
return matter.stringify(body, frontmatterWithDate);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Build a fresh page string from title + body, inserting required frontmatter.
|
|
58
|
+
*/
|
|
59
|
+
export function buildNewPage(title, body, tags) {
|
|
60
|
+
const fm = {
|
|
61
|
+
title,
|
|
62
|
+
updated: new Date().toISOString().slice(0, 10),
|
|
63
|
+
status: "active",
|
|
64
|
+
...(tags && tags.length > 0 ? { tags } : {}),
|
|
65
|
+
};
|
|
66
|
+
return matter.stringify(`\n${body}`, fm);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/wiki/frontmatter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { StorageClient } from "../storage/client.js";
|
|
2
|
+
export interface IndexEntry {
|
|
3
|
+
name: string;
|
|
4
|
+
title: string;
|
|
5
|
+
summary: string;
|
|
6
|
+
updated: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Append or update an entry in index.md.
|
|
10
|
+
* Reads current index, upserts the row for `name`, then writes back.
|
|
11
|
+
* Safe to call fire-and-forget; retries once on write conflict.
|
|
12
|
+
*
|
|
13
|
+
* No-op when the Postgres index is configured — see indexFileIsAuthoritative().
|
|
14
|
+
*/
|
|
15
|
+
export declare function upsertIndexEntry(drive: StorageClient, entry: IndexEntry): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Remove an entry from index.md by filename.
|
|
18
|
+
*
|
|
19
|
+
* No-op when the Postgres index is configured — see indexFileIsAuthoritative().
|
|
20
|
+
*/
|
|
21
|
+
export declare function removeIndexEntry(drive: StorageClient, name: string): Promise<void>;
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/wiki/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAK1D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AA4BD;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,IAAI,CAAC,CAMf;AAyDD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAMf"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import crypto from "crypto";
|
|
2
|
+
import { DriveConflictError } from "../drive/errors.js";
|
|
3
|
+
import { getPostgresSearchIndex } from "../search/postgresIndex.js";
|
|
4
|
+
const INDEX_FILE = "index.md";
|
|
5
|
+
const TABLE_HEADER = "| ID | Page | Summary | Updated |";
|
|
6
|
+
const TABLE_SEPARATOR = "|---|---|---|---|";
|
|
7
|
+
const LEGACY_TABLE_HEADER = "| Page | Summary | Updated |";
|
|
8
|
+
const LEGACY_TABLE_SEPARATOR = "|---|---|---|";
|
|
9
|
+
const DATA_INDEX_NAME = "data/";
|
|
10
|
+
/**
|
|
11
|
+
* True when index.md is still the catalog of record.
|
|
12
|
+
*
|
|
13
|
+
* Once the Postgres index is configured it is authoritative for every listing
|
|
14
|
+
* path — list_pages and search_pages query it directly and exclude index.md at
|
|
15
|
+
* the query level, the tool descriptions tell agents not to read index.md for
|
|
16
|
+
* routing, and seed/instructions/brains-protocol.md repeats that instruction.
|
|
17
|
+
* Maintaining the file anyway cost a full read-modify-write of it on every
|
|
18
|
+
* create/update/patch/move/restore/delete — ~400 KB of Storage transfer per
|
|
19
|
+
* page write on a large wiki, plus a conflict-retry path that concurrent
|
|
20
|
+
* writes made more likely (GH #410).
|
|
21
|
+
*
|
|
22
|
+
* The file is still bootstrapped and still exists — httpServer's scoped-client
|
|
23
|
+
* wipe check probes it — it just stops being rewritten.
|
|
24
|
+
*/
|
|
25
|
+
function indexFileIsAuthoritative() {
|
|
26
|
+
return !getPostgresSearchIndex().isConfigured();
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Append or update an entry in index.md.
|
|
30
|
+
* Reads current index, upserts the row for `name`, then writes back.
|
|
31
|
+
* Safe to call fire-and-forget; retries once on write conflict.
|
|
32
|
+
*
|
|
33
|
+
* No-op when the Postgres index is configured — see indexFileIsAuthoritative().
|
|
34
|
+
*/
|
|
35
|
+
export async function upsertIndexEntry(drive, entry) {
|
|
36
|
+
if (!indexFileIsAuthoritative())
|
|
37
|
+
return;
|
|
38
|
+
await upsertIndexEntryOnce(drive, entry).catch(async (err) => {
|
|
39
|
+
if (!(err instanceof DriveConflictError))
|
|
40
|
+
throw err;
|
|
41
|
+
await upsertIndexEntryOnce(drive, entry);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async function upsertIndexEntryOnce(drive, entry) {
|
|
45
|
+
const file = await drive.readFile(INDEX_FILE);
|
|
46
|
+
const lines = file.content.split("\n");
|
|
47
|
+
// Find the table start
|
|
48
|
+
let headerIdx = lines.findIndex((l) => l.startsWith(TABLE_HEADER));
|
|
49
|
+
const legacyHeaderIdx = lines.findIndex((l) => l.startsWith(LEGACY_TABLE_HEADER));
|
|
50
|
+
if (headerIdx === -1 && legacyHeaderIdx !== -1) {
|
|
51
|
+
// Migrate legacy 3-column table to 4-column ID table in-place.
|
|
52
|
+
lines[legacyHeaderIdx] = TABLE_HEADER;
|
|
53
|
+
if (lines[legacyHeaderIdx + 1]?.startsWith(LEGACY_TABLE_SEPARATOR)) {
|
|
54
|
+
lines[legacyHeaderIdx + 1] = TABLE_SEPARATOR;
|
|
55
|
+
}
|
|
56
|
+
migrateLegacyRows(lines, legacyHeaderIdx + 2);
|
|
57
|
+
headerIdx = legacyHeaderIdx;
|
|
58
|
+
}
|
|
59
|
+
if (headerIdx === -1) {
|
|
60
|
+
// Append table if it doesn't exist
|
|
61
|
+
const rows = [buildRow(entry)];
|
|
62
|
+
if (isDataPageName(entry.name)) {
|
|
63
|
+
const dataEntry = await buildDataAggregateEntry(drive);
|
|
64
|
+
rows.splice(0, rows.length, buildRow(dataEntry));
|
|
65
|
+
}
|
|
66
|
+
const updated = file.content.trim() +
|
|
67
|
+
`\n\n${TABLE_HEADER}\n${TABLE_SEPARATOR}\n${rows.join("\n")}\n`;
|
|
68
|
+
await drive.updateFile(file.fileId, updated, file.revision);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const tableStart = headerIdx + 2; // skip separator row
|
|
72
|
+
pruneDataFileRows(lines, tableStart);
|
|
73
|
+
if (isDataPageName(entry.name)) {
|
|
74
|
+
const dataEntry = await buildDataAggregateEntry(drive);
|
|
75
|
+
upsertRow(lines, tableStart, buildRow(dataEntry), dataEntry.name);
|
|
76
|
+
await drive.updateFile(file.fileId, lines.join("\n"), file.revision);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const row = buildRow(entry);
|
|
80
|
+
upsertRow(lines, tableStart, row, entry.name);
|
|
81
|
+
const dataEntry = await buildDataAggregateEntry(drive);
|
|
82
|
+
upsertRow(lines, tableStart, buildRow(dataEntry), dataEntry.name);
|
|
83
|
+
await drive.updateFile(file.fileId, lines.join("\n"), file.revision);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Remove an entry from index.md by filename.
|
|
87
|
+
*
|
|
88
|
+
* No-op when the Postgres index is configured — see indexFileIsAuthoritative().
|
|
89
|
+
*/
|
|
90
|
+
export async function removeIndexEntry(drive, name) {
|
|
91
|
+
if (!indexFileIsAuthoritative())
|
|
92
|
+
return;
|
|
93
|
+
await removeIndexEntryOnce(drive, name).catch(async (err) => {
|
|
94
|
+
if (!(err instanceof DriveConflictError))
|
|
95
|
+
throw err;
|
|
96
|
+
await removeIndexEntryOnce(drive, name);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
async function removeIndexEntryOnce(drive, name) {
|
|
100
|
+
const file = await drive.readFile(INDEX_FILE);
|
|
101
|
+
const lines = file.content.split("\n").filter((l) => !l.includes(`[${name}]`));
|
|
102
|
+
const headerIdx = lines.findIndex((l) => l.startsWith(TABLE_HEADER));
|
|
103
|
+
if (headerIdx !== -1) {
|
|
104
|
+
const tableStart = headerIdx + 2;
|
|
105
|
+
pruneDataFileRows(lines, tableStart);
|
|
106
|
+
const dataEntry = await buildDataAggregateEntry(drive);
|
|
107
|
+
upsertRow(lines, tableStart, buildRow(dataEntry), dataEntry.name);
|
|
108
|
+
}
|
|
109
|
+
await drive.updateFile(file.fileId, lines.join("\n"), file.revision);
|
|
110
|
+
}
|
|
111
|
+
function upsertRow(lines, tableStart, row, name) {
|
|
112
|
+
const existingIdx = lines.findIndex((l, i) => i >= tableStart && l.includes(`[${name}]`));
|
|
113
|
+
if (existingIdx !== -1) {
|
|
114
|
+
lines[existingIdx] = row;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
lines.splice(tableStart, 0, row);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function buildRow(entry) {
|
|
121
|
+
const id = indexIdFromName(entry.name);
|
|
122
|
+
const link = `[${entry.name}](${entry.name})`;
|
|
123
|
+
const summary = entry.summary.replace(/\|/g, "\\|");
|
|
124
|
+
return `| ${id} | ${link} | ${summary} | ${entry.updated} |`;
|
|
125
|
+
}
|
|
126
|
+
function dataAggregateEntry(fileCount, latestDate) {
|
|
127
|
+
return {
|
|
128
|
+
name: DATA_INDEX_NAME,
|
|
129
|
+
title: "Data Folder",
|
|
130
|
+
summary: `Data repository (${fileCount} files). Individual data pages are omitted from index; browse data/ for details.`,
|
|
131
|
+
updated: latestDate,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Build the `data/` rollup row for index.md.
|
|
136
|
+
*
|
|
137
|
+
* Only reached when index.md is still the catalog of record, i.e. Postgres is
|
|
138
|
+
* not configured — which in practice means a local or Drive backend, where
|
|
139
|
+
* listFiles() is a cheap filesystem walk rather than one HTTP request per
|
|
140
|
+
* folder. (Supabase storage always implies a configured Postgres index, so the
|
|
141
|
+
* expensive combination cannot occur.)
|
|
142
|
+
*/
|
|
143
|
+
async function buildDataAggregateEntry(drive) {
|
|
144
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
145
|
+
const files = await drive.listFiles();
|
|
146
|
+
const dataFiles = files.filter((f) => isDataPageName(f.name));
|
|
147
|
+
const latestDate = dataFiles
|
|
148
|
+
.map((f) => f.modifiedTime.slice(0, 10))
|
|
149
|
+
.sort((a, b) => b.localeCompare(a))[0] ?? today;
|
|
150
|
+
return dataAggregateEntry(dataFiles.length, latestDate);
|
|
151
|
+
}
|
|
152
|
+
function pruneDataFileRows(lines, tableStart) {
|
|
153
|
+
for (let i = lines.length - 1; i >= tableStart; i -= 1) {
|
|
154
|
+
const line = lines[i]?.trim() ?? "";
|
|
155
|
+
if (!line.startsWith("|"))
|
|
156
|
+
continue;
|
|
157
|
+
if (line.startsWith("|---"))
|
|
158
|
+
continue;
|
|
159
|
+
const name = extractLinkedName(line);
|
|
160
|
+
if (!name)
|
|
161
|
+
continue;
|
|
162
|
+
if (name === DATA_INDEX_NAME || isDataPageName(name)) {
|
|
163
|
+
lines.splice(i, 1);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function extractLinkedName(row) {
|
|
168
|
+
const match = row.match(/\[([^\]]+)\]\([^)]+\)/);
|
|
169
|
+
return match?.[1] ?? null;
|
|
170
|
+
}
|
|
171
|
+
function isDataPageName(name) {
|
|
172
|
+
return name.startsWith("data/") && name.endsWith(".md");
|
|
173
|
+
}
|
|
174
|
+
function indexIdFromName(name) {
|
|
175
|
+
return crypto.createHash("sha1").update(name, "utf8").digest("hex").slice(0, 8);
|
|
176
|
+
}
|
|
177
|
+
function migrateLegacyRows(lines, startIdx) {
|
|
178
|
+
for (let i = startIdx; i < lines.length; i += 1) {
|
|
179
|
+
const line = lines[i].trim();
|
|
180
|
+
if (!line.startsWith("|"))
|
|
181
|
+
break;
|
|
182
|
+
if (line.startsWith("|---"))
|
|
183
|
+
continue;
|
|
184
|
+
const cells = splitRowCells(line);
|
|
185
|
+
if (cells.length !== 3)
|
|
186
|
+
continue;
|
|
187
|
+
const pageCell = cells[0];
|
|
188
|
+
const nameMatch = pageCell.match(/\[([^\]]+)\]\([^)]+\)/);
|
|
189
|
+
if (!nameMatch)
|
|
190
|
+
continue;
|
|
191
|
+
const name = nameMatch[1];
|
|
192
|
+
const id = indexIdFromName(name);
|
|
193
|
+
lines[i] = `| ${id} | ${cells[0]} | ${cells[1]} | ${cells[2]} |`;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function splitRowCells(row) {
|
|
197
|
+
return row
|
|
198
|
+
.replace(/^\|/, "")
|
|
199
|
+
.replace(/\|$/, "")
|
|
200
|
+
.split("|")
|
|
201
|
+
.map((c) => c.trim());
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/wiki/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface RoutingWarning {
|
|
2
|
+
field: string;
|
|
3
|
+
message: string;
|
|
4
|
+
}
|
|
5
|
+
interface IngestPolicyInput {
|
|
6
|
+
name: string;
|
|
7
|
+
title?: string;
|
|
8
|
+
tags?: string[];
|
|
9
|
+
body: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Heuristic policy to nudge multi-file decomposition for rich ingest pages.
|
|
13
|
+
* Also warns when project-scoped content appears to be missing a project-slug prefix.
|
|
14
|
+
* This does not block writes, but returns explicit warnings for the caller.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getIngestRoutingWarnings(input: IngestPolicyInput): RoutingWarning[];
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=ingestPolicy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingestPolicy.d.ts","sourceRoot":"","sources":["../../src/wiki/ingestPolicy.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,iBAAiB,GAAG,cAAc,EAAE,CAqEnF"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heuristic policy to nudge multi-file decomposition for rich ingest pages.
|
|
3
|
+
* Also warns when project-scoped content appears to be missing a project-slug prefix.
|
|
4
|
+
* This does not block writes, but returns explicit warnings for the caller.
|
|
5
|
+
*/
|
|
6
|
+
export function getIngestRoutingWarnings(input) {
|
|
7
|
+
const warnings = [];
|
|
8
|
+
// ── Ingest breakdown check ────────────────────────────────────────────────
|
|
9
|
+
const isDataPath = input.name.startsWith("data/");
|
|
10
|
+
const tags = (input.tags ?? []).map((t) => t.toLowerCase());
|
|
11
|
+
const looksLikeIngest = tags.includes("ingest") ||
|
|
12
|
+
input.title?.toLowerCase().includes("ingest") === true;
|
|
13
|
+
if (isDataPath && looksLikeIngest) {
|
|
14
|
+
const body = input.body;
|
|
15
|
+
const signals = [
|
|
16
|
+
/^##\s+open\s+loops?/gim,
|
|
17
|
+
/^##\s+.*actions?/gim,
|
|
18
|
+
/^##\s+.*decisions?/gim,
|
|
19
|
+
/^##\s+.*competition/gim,
|
|
20
|
+
/^##\s+.*arc/gim,
|
|
21
|
+
/^##\s+.*technical\s+state/gim,
|
|
22
|
+
];
|
|
23
|
+
const signalCount = signals.reduce((acc, rx) => acc + (rx.test(body) ? 1 : 0), 0);
|
|
24
|
+
if (signalCount >= 2) {
|
|
25
|
+
warnings.push({
|
|
26
|
+
field: "routing",
|
|
27
|
+
message: "INGEST_BREAKDOWN_RECOMMENDED: This data/ ingest appears to contain canonical facts, active actions, and/or decisions. Decompose into multiple pages: canonical/<topic>-profile.md, projects/<topic>-plan.md, decisions/<date>-<topic>-*.md, and keep data/<topic>.md as raw synthesis.",
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// ── Project prefix check ──────────────────────────────────────────────────
|
|
32
|
+
// Warn if a page looks project-specific but is placed at the root of a folder
|
|
33
|
+
// rather than under a project-slug subfolder (e.g. projects/readme.md instead
|
|
34
|
+
// of projects/oio-racing/readme.md).
|
|
35
|
+
// canonical/ is intentionally excluded: it is a user-level folder for durable
|
|
36
|
+
// cross-project facts, so root-level pages (e.g. canonical/sammy.md) are valid
|
|
37
|
+
// and must not trigger a project-slug namespacing warning.
|
|
38
|
+
const projectFolderPrefixes = ["projects/", "data/", "decisions/", "history/"];
|
|
39
|
+
const nameInProjectFolder = projectFolderPrefixes.some((p) => input.name.startsWith(p));
|
|
40
|
+
const isActiveFile = /^projects\/active-[^/]+\.md$/.test(input.name);
|
|
41
|
+
const isBrainLevelFile = input.name.indexOf("/") === -1 ||
|
|
42
|
+
/^(instructions|wiki)\//.test(input.name);
|
|
43
|
+
if (nameInProjectFolder && !isActiveFile && !isBrainLevelFile) {
|
|
44
|
+
// Check if there is at least one slug-level subfolder after the root folder
|
|
45
|
+
// e.g. "projects/oio-racing/readme.md" → segments after root: ["oio-racing", "readme.md"] ✓
|
|
46
|
+
// "projects/readme.md" → segments after root: ["readme.md"] ✗
|
|
47
|
+
const parts = input.name.split("/");
|
|
48
|
+
const hasSlugSubfolder = parts.length >= 3;
|
|
49
|
+
// readme.md files at any folder root are legitimate scaffolding/index pages;
|
|
50
|
+
// suppress the warning for e.g. canonical/readme.md, decisions/readme.md, etc.
|
|
51
|
+
const isFolderReadme = parts.length === 2 && parts[1].toLowerCase() === "readme.md";
|
|
52
|
+
if (!hasSlugSubfolder && !isFolderReadme) {
|
|
53
|
+
warnings.push({
|
|
54
|
+
field: "routing",
|
|
55
|
+
message: "PROJECT_PREFIX_MISSING: This page appears at the root of a project folder. " +
|
|
56
|
+
"If it belongs to a specific project, move it under a project-slug subfolder " +
|
|
57
|
+
"(e.g. projects/<slug>/, canonical/<slug>/, decisions/<slug>/). " +
|
|
58
|
+
"See instructions/brain-routing.md for the full namespacing convention.",
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return warnings;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=ingestPolicy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ingestPolicy.js","sourceRoot":"","sources":["../../src/wiki/ingestPolicy.ts"],"names":[],"mappings":"AAYA;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,KAAwB;IAC/D,MAAM,QAAQ,GAAqB,EAAE,CAAC;IAEtC,6EAA6E;IAC7E,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAClD,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,MAAM,eAAe,GACnB,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACvB,KAAK,CAAC,KAAK,EAAE,WAAW,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC;IAEzD,IAAI,UAAU,IAAI,eAAe,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACxB,MAAM,OAAO,GAAG;YACd,wBAAwB;YACxB,qBAAqB;YACrB,uBAAuB;YACvB,wBAAwB;YACxB,gBAAgB;YAChB,8BAA8B;SAC/B,CAAC;QAEF,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAClF,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;YACrB,QAAQ,CAAC,IAAI,CAAC;gBACZ,KAAK,EAAE,SAAS;gBAChB,OAAO,EACL,wRAAwR;aAC3R,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,6EAA6E;IAC7E,8EAA8E;IAC9E,8EAA8E;IAC9E,qCAAqC;IACrC,8EAA8E;IAC9E,+EAA+E;IAC/E,2DAA2D;IAC3D,MAAM,qBAAqB,GAAG,CAAC,WAAW,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;IAC/E,MAAM,mBAAmB,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IACxF,MAAM,YAAY,GAAG,8BAA8B,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrE,MAAM,gBAAgB,GACpB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC9B,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAE5C,IAAI,mBAAmB,IAAI,CAAC,YAAY,IAAI,CAAC,gBAAgB,EAAE,CAAC;QAC9D,4EAA4E;QAC5E,4FAA4F;QAC5F,8EAA8E;QAC9E,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,gBAAgB,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;QAE3C,6EAA6E;QAC7E,+EAA+E;QAC/E,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,WAAW,CAAC;QAEpF,IAAI,CAAC,gBAAgB,IAAI,CAAC,cAAc,EAAE,CAAC;YACzC,QAAQ,CAAC,IAAI,CAAC;gBACZ,KAAK,EAAE,SAAS;gBAChB,OAAO,EACL,6EAA6E;oBAC7E,8EAA8E;oBAC9E,iEAAiE;oBACjE,wEAAwE;aAC3E,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|