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,432 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import matter from "gray-matter";
|
|
3
|
+
import { resolveIndexOwnerSubject } from "../storage/client.js";
|
|
4
|
+
import { serializeBundle, buildBundleHeader } from "../session/bundle.js";
|
|
5
|
+
import { getPostgresSearchIndex } from "../search/postgresIndex.js";
|
|
6
|
+
import { listActiveGrantsForGrantee } from "../access/projectShares.js";
|
|
7
|
+
import { DEFAULT_ACCESS_CONTEXT, isHiveModeEnabled, parseAccessLevel, parseAudience, pagePassesFilter, writeGovernanceAuditEntry, } from "../governance/accessControl.js";
|
|
8
|
+
const MIN_BYTES = 1024;
|
|
9
|
+
const MAX_BYTES = 200_000;
|
|
10
|
+
const DEFAULT_MAX_BYTES = 150_000;
|
|
11
|
+
const DEFAULT_MAX_PAGES = 10;
|
|
12
|
+
const FTS_MAX_RESULTS = 500;
|
|
13
|
+
const SYSTEM_FILES = new Set(["index.md", "log.md"]);
|
|
14
|
+
export const pullSessionBundleInputSchema = z.object({
|
|
15
|
+
folder: z
|
|
16
|
+
.string()
|
|
17
|
+
.optional()
|
|
18
|
+
.describe("Optional path prefix filter (e.g. 'projects/brainsapp')."),
|
|
19
|
+
tags: z
|
|
20
|
+
.array(z.string())
|
|
21
|
+
.optional()
|
|
22
|
+
.describe("Optional tag filter — any-match OR semantics. Pages matching any of the given tags are included."),
|
|
23
|
+
query: z
|
|
24
|
+
.string()
|
|
25
|
+
.optional()
|
|
26
|
+
.describe("Optional full-text query for relevance-ranked selection when Postgres search is enabled."),
|
|
27
|
+
includeSystem: z
|
|
28
|
+
.boolean()
|
|
29
|
+
.default(false)
|
|
30
|
+
.describe("If true, includes system files index.md and log.md."),
|
|
31
|
+
cursor: z
|
|
32
|
+
.string()
|
|
33
|
+
.optional()
|
|
34
|
+
.describe("Opaque continuation token from a prior call's nextCursor. Omit for the first page."),
|
|
35
|
+
maxBytes: z
|
|
36
|
+
.number()
|
|
37
|
+
.default(DEFAULT_MAX_BYTES)
|
|
38
|
+
.describe(`Soft cap on bundle text size in bytes (clamp ${MIN_BYTES}–${MAX_BYTES}). Default: ${DEFAULT_MAX_BYTES}.`),
|
|
39
|
+
maxPages: z
|
|
40
|
+
.number()
|
|
41
|
+
.default(DEFAULT_MAX_PAGES)
|
|
42
|
+
.describe(`Hard cap on pages per slice. Default: ${DEFAULT_MAX_PAGES}.`),
|
|
43
|
+
session_audience: z
|
|
44
|
+
.enum(["internal", "client-safe", "public"])
|
|
45
|
+
.optional()
|
|
46
|
+
.describe("Optional audience constraint for this session. When set, only pages whose audience matches are included. " +
|
|
47
|
+
"'client-safe' → client-safe + public pages. 'public' → public pages only. " +
|
|
48
|
+
"Only effective when BRAINS_HIVE_MODE=true."),
|
|
49
|
+
});
|
|
50
|
+
function encodeCursor(lastName) {
|
|
51
|
+
return Buffer.from(JSON.stringify({ lastName }), "utf8").toString("base64");
|
|
52
|
+
}
|
|
53
|
+
function decodeCursor(cursor) {
|
|
54
|
+
try {
|
|
55
|
+
const parsed = JSON.parse(Buffer.from(cursor, "base64").toString("utf8"));
|
|
56
|
+
if (typeof parsed === "object" &&
|
|
57
|
+
parsed !== null &&
|
|
58
|
+
"lastName" in parsed &&
|
|
59
|
+
typeof parsed.lastName === "string") {
|
|
60
|
+
return parsed;
|
|
61
|
+
}
|
|
62
|
+
throw new Error("missing lastName");
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
throw new Error("Invalid cursor: malformed or corrupt");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function pageMatchesFilter(name, content, normalizedFolder, tags) {
|
|
69
|
+
const hasFilter = normalizedFolder !== undefined || (tags !== undefined && tags.length > 0);
|
|
70
|
+
if (!hasFilter)
|
|
71
|
+
return true;
|
|
72
|
+
const matchesFolder = normalizedFolder ? name.startsWith(normalizedFolder) : false;
|
|
73
|
+
if (tags && tags.length > 0) {
|
|
74
|
+
try {
|
|
75
|
+
const parsed = matter(content);
|
|
76
|
+
const pageTags = parsed.data?.tags ?? [];
|
|
77
|
+
if (tags.some((t) => pageTags.includes(t)))
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// fall through to folder match
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return matchesFolder;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Active project-share grants (BRA-368) for `userId`, narrowed to those
|
|
88
|
+
* relevant to `folder` (if set) so a folder-scoped bundle pull doesn't drag
|
|
89
|
+
* in unrelated shared projects. Without this, a grantee's bundle only ever
|
|
90
|
+
* contains their own pages — the owner's shared content is invisible
|
|
91
|
+
* (BRA-383, mirrors the list_pages/search_pages fix in BRA-379/#380).
|
|
92
|
+
*/
|
|
93
|
+
async function grantScopesFor(userId, folder) {
|
|
94
|
+
if (!userId)
|
|
95
|
+
return [];
|
|
96
|
+
// Strip any trailing slash before comparing — callers may pass either
|
|
97
|
+
// form, but a raw trailing slash would double up in the startsWith
|
|
98
|
+
// checks below (e.g. "projects/" -> "projects//") and silently drop
|
|
99
|
+
// otherwise-matching grants.
|
|
100
|
+
const normalizedFolder = folder ? folder.replace(/\/$/, "") : undefined;
|
|
101
|
+
const grants = await listActiveGrantsForGrantee(userId).catch(() => []);
|
|
102
|
+
return grants
|
|
103
|
+
.filter((g) => !normalizedFolder ||
|
|
104
|
+
g.project_path === normalizedFolder ||
|
|
105
|
+
g.project_path.startsWith(`${normalizedFolder}/`) ||
|
|
106
|
+
normalizedFolder.startsWith(`${g.project_path}/`))
|
|
107
|
+
.map((g) => ({ userId: g.owner_subject, folder: g.project_path }));
|
|
108
|
+
}
|
|
109
|
+
function usePostgresIndex() {
|
|
110
|
+
const searchBackend = (process.env.SEARCH_BACKEND ?? "").toLowerCase();
|
|
111
|
+
const storageBackend = (process.env.STORAGE_BACKEND ?? "local").toLowerCase();
|
|
112
|
+
return (storageBackend === "supabase" &&
|
|
113
|
+
searchBackend !== "sqlite" &&
|
|
114
|
+
searchBackend !== "scan");
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* The files at a project root that every instruction file tells an agent to read
|
|
118
|
+
* first. They are hoisted ahead of the rest of the candidate list so a capped
|
|
119
|
+
* slice cannot drop them.
|
|
120
|
+
*
|
|
121
|
+
* They were being dropped, and the ordering made it systematic rather than
|
|
122
|
+
* unlucky. `listPages` returns `modified.desc.nullslast,name.asc`, so candidate
|
|
123
|
+
* order is newest-touched-first — which means any bulk operation buries the
|
|
124
|
+
* pages that matter most. Measured on `projects/oio` (GH #462): a migration
|
|
125
|
+
* touched 22 pages over seven minutes, and the next `folder=projects/oio` pull
|
|
126
|
+
* returned 20 pages, all of them from that migration window. `status.md` and
|
|
127
|
+
* `readme.md`, untouched two hours earlier, sorted to positions ~27 and ~28 and
|
|
128
|
+
* fell outside the byte cap. The better-maintained the project, the more
|
|
129
|
+
* reliably its entry points get pushed out of its own bundle.
|
|
130
|
+
*/
|
|
131
|
+
const CONVENTIONAL_ROOT_FILES = ["readme.md", "status.md", "open-loops.md", "index.md"];
|
|
132
|
+
function conventionalRootPaths(folder) {
|
|
133
|
+
if (!folder)
|
|
134
|
+
return [];
|
|
135
|
+
const prefix = folder.replace(/\/$/, "") + "/";
|
|
136
|
+
return CONVENTIONAL_ROOT_FILES.map((name) => prefix + name);
|
|
137
|
+
}
|
|
138
|
+
function hoistConventionalRootFiles(candidates, folder) {
|
|
139
|
+
const priority = conventionalRootPaths(folder);
|
|
140
|
+
if (priority.length === 0)
|
|
141
|
+
return candidates;
|
|
142
|
+
const rank = new Map(priority.map((name, i) => [name, i]));
|
|
143
|
+
const hoisted = [];
|
|
144
|
+
const rest = [];
|
|
145
|
+
for (const name of candidates) {
|
|
146
|
+
if (rank.has(name))
|
|
147
|
+
hoisted.push(name);
|
|
148
|
+
else
|
|
149
|
+
rest.push(name);
|
|
150
|
+
}
|
|
151
|
+
if (hoisted.length === 0)
|
|
152
|
+
return candidates;
|
|
153
|
+
hoisted.sort((a, b) => rank.get(a) - rank.get(b));
|
|
154
|
+
return [...hoisted, ...rest];
|
|
155
|
+
}
|
|
156
|
+
async function getCandidateNames(drive, folder, tags, query, includeSystem, userId, accessCtx) {
|
|
157
|
+
const normalizedFolder = folder ? folder.replace(/\/$/, "") + "/" : undefined;
|
|
158
|
+
if (usePostgresIndex()) {
|
|
159
|
+
const index = getPostgresSearchIndex();
|
|
160
|
+
const accessLevel = isHiveModeEnabled() ? accessCtx.userAccessLevel : undefined;
|
|
161
|
+
// Folder must be pushed into the query, not applied to the result.
|
|
162
|
+
// Without it these calls fetch every page the user has and filter in JS —
|
|
163
|
+
// but PostgREST caps rows, so the cap truncates before the filter runs and
|
|
164
|
+
// the folder pull silently undercounts. Measured on a 2,750-page wiki:
|
|
165
|
+
// folder=projects/job-search returned 164 of a true 213, losing the 49
|
|
166
|
+
// oldest by modified date, which is the order the cap slices on (GH #432).
|
|
167
|
+
// listPages/search take the prefix without a trailing slash.
|
|
168
|
+
const folderPrefix = folder ? folder.replace(/\/$/, "") : undefined;
|
|
169
|
+
// Cross-account sharing (BRA-383): without this, a grantee's bundle only
|
|
170
|
+
// ever contains pages they authored themselves — the owner's shared
|
|
171
|
+
// content never comes back, same root cause as BRA-379/#380.
|
|
172
|
+
const grantScopes = await grantScopesFor(userId, folder);
|
|
173
|
+
let names;
|
|
174
|
+
const trimmedQuery = query?.trim();
|
|
175
|
+
if (trimmedQuery) {
|
|
176
|
+
let rankedLists;
|
|
177
|
+
if (tags && tags.length > 0) {
|
|
178
|
+
rankedLists = await Promise.all(tags.map((tag) => index.search({ query: trimmedQuery, tag, folder: folderPrefix, maxResults: FTS_MAX_RESULTS, userId, accessLevel, grantScopes })
|
|
179
|
+
.then((result) => result.results.map((r) => r.name))));
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
const searchResult = await index.search({
|
|
183
|
+
query: trimmedQuery,
|
|
184
|
+
folder: folderPrefix,
|
|
185
|
+
maxResults: FTS_MAX_RESULTS,
|
|
186
|
+
userId,
|
|
187
|
+
accessLevel,
|
|
188
|
+
grantScopes,
|
|
189
|
+
});
|
|
190
|
+
rankedLists = [searchResult.results.map((r) => r.name)];
|
|
191
|
+
}
|
|
192
|
+
const seen = new Set();
|
|
193
|
+
names = [];
|
|
194
|
+
for (const list of rankedLists) {
|
|
195
|
+
for (const name of list) {
|
|
196
|
+
if (!seen.has(name)) {
|
|
197
|
+
seen.add(name);
|
|
198
|
+
names.push(name);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
else if (tags && tags.length > 0) {
|
|
204
|
+
const sets = await Promise.all(tags.map((tag) => index.listPages({ tag, folder: folderPrefix, userId, accessLevel, grantScopes }).then((rows) => rows.map((r) => r.name))));
|
|
205
|
+
const union = new Set();
|
|
206
|
+
for (const set of sets)
|
|
207
|
+
for (const name of set)
|
|
208
|
+
union.add(name);
|
|
209
|
+
names = Array.from(union);
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
const rows = await index.listPages({ folder: folderPrefix, userId, accessLevel, grantScopes });
|
|
213
|
+
names = rows.map((r) => r.name);
|
|
214
|
+
}
|
|
215
|
+
// Belt-and-braces: the prefix is already applied server-side above, so this
|
|
216
|
+
// only catches anything a scope merge might reintroduce.
|
|
217
|
+
if (normalizedFolder) {
|
|
218
|
+
names = names.filter((name) => name.startsWith(normalizedFolder));
|
|
219
|
+
}
|
|
220
|
+
// Exclude system files unless includeSystem is set
|
|
221
|
+
if (!includeSystem) {
|
|
222
|
+
names = names.filter((name) => !SYSTEM_FILES.has(name));
|
|
223
|
+
}
|
|
224
|
+
// Exclude version-history snapshots regardless of includeSystem
|
|
225
|
+
names = names.filter((name) => !name.startsWith("page-versions/"));
|
|
226
|
+
return names;
|
|
227
|
+
}
|
|
228
|
+
// Fallback: drive.listFiles() + frontmatter scan for tags
|
|
229
|
+
const allFiles = await drive.listFiles();
|
|
230
|
+
const candidates = [];
|
|
231
|
+
const hasFilter = normalizedFolder !== undefined || (tags !== undefined && tags.length > 0);
|
|
232
|
+
const hiveActive = isHiveModeEnabled();
|
|
233
|
+
/**
|
|
234
|
+
* Check governance access for a file whose content has already been read.
|
|
235
|
+
* Returns false and emits an audit entry when the page should be excluded.
|
|
236
|
+
*/
|
|
237
|
+
function passesGovernanceFilter(name, content) {
|
|
238
|
+
if (!hiveActive)
|
|
239
|
+
return true;
|
|
240
|
+
const parsed = matter(content);
|
|
241
|
+
const pageLevel = parseAccessLevel(parsed.data.access_level);
|
|
242
|
+
const pageAudience = parseAudience(parsed.data.audience);
|
|
243
|
+
if (!pagePassesFilter(pageLevel, pageAudience, accessCtx.userAccessLevel, accessCtx.sessionAudience)) {
|
|
244
|
+
writeGovernanceAuditEntry(userId, name, pageLevel, accessCtx.userAccessLevel, accessCtx.sessionAudience, pageLevel > accessCtx.userAccessLevel ? "access_level_exceeded" : "audience_mismatch");
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
for (const entry of allFiles) {
|
|
250
|
+
if (!entry.name.endsWith(".md"))
|
|
251
|
+
continue;
|
|
252
|
+
if (!includeSystem && SYSTEM_FILES.has(entry.name))
|
|
253
|
+
continue;
|
|
254
|
+
if (entry.name.startsWith("page-versions/"))
|
|
255
|
+
continue;
|
|
256
|
+
if (!hasFilter && !hiveActive) {
|
|
257
|
+
candidates.push(entry.name);
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
// We need to read file content for tag matching or access filtering
|
|
261
|
+
if (tags && tags.length > 0) {
|
|
262
|
+
const file = await drive.readFile(entry.name);
|
|
263
|
+
if (!passesGovernanceFilter(entry.name, file.content))
|
|
264
|
+
continue;
|
|
265
|
+
if (pageMatchesFilter(entry.name, file.content, normalizedFolder, tags)) {
|
|
266
|
+
candidates.push(entry.name);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
else if (normalizedFolder && entry.name.startsWith(normalizedFolder)) {
|
|
270
|
+
if (hiveActive) {
|
|
271
|
+
const file = await drive.readFile(entry.name);
|
|
272
|
+
if (!passesGovernanceFilter(entry.name, file.content))
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
candidates.push(entry.name);
|
|
276
|
+
}
|
|
277
|
+
else if (!hasFilter) {
|
|
278
|
+
if (hiveActive) {
|
|
279
|
+
const file = await drive.readFile(entry.name);
|
|
280
|
+
if (!passesGovernanceFilter(entry.name, file.content))
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
candidates.push(entry.name);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return candidates.sort();
|
|
287
|
+
}
|
|
288
|
+
export async function pullSessionBundle(drive, input, userId = "", accessCtx = DEFAULT_ACCESS_CONTEXT) {
|
|
289
|
+
const maxBytes = Math.min(Math.max(input.maxBytes, MIN_BYTES), MAX_BYTES);
|
|
290
|
+
const maxPages = Math.max(1, input.maxPages);
|
|
291
|
+
// Decode cursor if present
|
|
292
|
+
let lastNameFromCursor;
|
|
293
|
+
if (input.cursor) {
|
|
294
|
+
try {
|
|
295
|
+
const decoded = decodeCursor(input.cursor);
|
|
296
|
+
lastNameFromCursor = decoded.lastName;
|
|
297
|
+
}
|
|
298
|
+
catch (err) {
|
|
299
|
+
return { ok: false, error: err instanceof Error ? err.message : "Invalid cursor" };
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
// Merge session_audience from input into the access context
|
|
303
|
+
const effectiveAccessCtx = {
|
|
304
|
+
...accessCtx,
|
|
305
|
+
sessionAudience: input.session_audience ?? accessCtx.sessionAudience,
|
|
306
|
+
};
|
|
307
|
+
// Get candidate names
|
|
308
|
+
const rawCandidates = await getCandidateNames(drive, input.folder, input.tags, input.query, input.includeSystem, userId, effectiveAccessCtx);
|
|
309
|
+
// Hoist the project's entry points, but only on a plain folder pull. With a
|
|
310
|
+
// query the caller asked for specific content and the list is relevance-ranked;
|
|
311
|
+
// promoting four fixed files ahead of the hits would answer a different
|
|
312
|
+
// question than the one asked.
|
|
313
|
+
const allCandidates = input.query?.trim()
|
|
314
|
+
? rawCandidates
|
|
315
|
+
: hoistConventionalRootFiles(rawCandidates, input.folder);
|
|
316
|
+
const totalMatchingPages = allCandidates.length;
|
|
317
|
+
// Naming the filter and the match count lets an agent judge whether the bundle
|
|
318
|
+
// plausibly covers what it needs. Without it, an under-matching filter yields a
|
|
319
|
+
// bundle that looks authoritative — see buildBundleHeader's note. Computed
|
|
320
|
+
// before the selection loop because header size counts against maxBytes.
|
|
321
|
+
const filterParts = [];
|
|
322
|
+
if (input.folder)
|
|
323
|
+
filterParts.push(`folder=${input.folder}`);
|
|
324
|
+
if (input.tags && input.tags.length > 0)
|
|
325
|
+
filterParts.push(`tags=[${input.tags.join(", ")}]`);
|
|
326
|
+
if (input.query?.trim())
|
|
327
|
+
filterParts.push(`query="${input.query.trim()}"`);
|
|
328
|
+
const filterDescription = filterParts.length > 0 ? filterParts.join(" ") : "no filter (whole wiki)";
|
|
329
|
+
const candidatePositions = new Map(allCandidates.map((name, index) => [name, index]));
|
|
330
|
+
// Which entry points actually exist for this folder. Hoisting means they are
|
|
331
|
+
// normally all included, so this is a backstop for the cases hoisting does not
|
|
332
|
+
// cover: a query pull, a tags-only pull with no folder, a cap too small to fit
|
|
333
|
+
// even these, or a later slice reached by cursor.
|
|
334
|
+
const conventionalPresent = conventionalRootPaths(input.folder).filter((name) => candidatePositions.has(name));
|
|
335
|
+
// Skip past cursor based on candidate order
|
|
336
|
+
const remaining = (() => {
|
|
337
|
+
if (!lastNameFromCursor)
|
|
338
|
+
return allCandidates;
|
|
339
|
+
const cursorIndex = candidatePositions.get(lastNameFromCursor) ?? -1;
|
|
340
|
+
return cursorIndex >= 0 ? allCandidates.slice(cursorIndex + 1) : allCandidates;
|
|
341
|
+
})();
|
|
342
|
+
// Build bundle slice
|
|
343
|
+
const includedPages = [];
|
|
344
|
+
const bundlePages = [];
|
|
345
|
+
const errors = [];
|
|
346
|
+
let bundleBytes = 0;
|
|
347
|
+
let lastProcessed;
|
|
348
|
+
for (const name of remaining) {
|
|
349
|
+
if (includedPages.length >= maxPages)
|
|
350
|
+
break;
|
|
351
|
+
let file;
|
|
352
|
+
try {
|
|
353
|
+
// Hot path: read from DB row when Postgres is the primary (avoids Storage read on stale mirror).
|
|
354
|
+
// Cross-account sharing (BRA-383): the row (if any) is indexed under the
|
|
355
|
+
// true storage owner, not the raw actor — resolve that first so shared
|
|
356
|
+
// content actually hits the hot path instead of falling back silently.
|
|
357
|
+
const dbRow = usePostgresIndex()
|
|
358
|
+
? await getPostgresSearchIndex().fetchPageRow(name, resolveIndexOwnerSubject(drive, name, userId)).catch(() => null)
|
|
359
|
+
: null;
|
|
360
|
+
file = dbRow ?? await drive.readFile(name);
|
|
361
|
+
}
|
|
362
|
+
catch (err) {
|
|
363
|
+
errors.push({ name, reason: err instanceof Error ? err.message : String(err) });
|
|
364
|
+
lastProcessed = name;
|
|
365
|
+
continue;
|
|
366
|
+
}
|
|
367
|
+
const delimiter = `===PAGE: ${name}===\n`;
|
|
368
|
+
const pageContrib = (bundlePages.length === 0 ? delimiter : "\n" + delimiter) + file.content;
|
|
369
|
+
const pageBytes = Buffer.byteLength(pageContrib, "utf8");
|
|
370
|
+
// The working-set header ships inside `bundle`, so its bytes count against
|
|
371
|
+
// maxBytes too — it grows by a line per page, so ignoring it would overshoot
|
|
372
|
+
// by more the larger the bundle. Measured against the truncated variant,
|
|
373
|
+
// which is the longer of the two: adding a page can be what causes the next
|
|
374
|
+
// one to be dropped, and the resulting truncation notice must already fit.
|
|
375
|
+
const prospectiveHeaderBytes = Buffer.byteLength(buildBundleHeader([...bundlePages, { name }], {
|
|
376
|
+
truncated: true,
|
|
377
|
+
filter: filterDescription,
|
|
378
|
+
totalMatching: totalMatchingPages,
|
|
379
|
+
// Worst case — assume every entry point ends up omitted, so the estimate
|
|
380
|
+
// is never smaller than the header this bundle actually ships with.
|
|
381
|
+
omittedConventional: conventionalPresent,
|
|
382
|
+
}), "utf8");
|
|
383
|
+
if (prospectiveHeaderBytes + bundleBytes + pageBytes > maxBytes && includedPages.length > 0) {
|
|
384
|
+
// Would exceed soft cap — stop here (but only if we already have at least one page)
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
387
|
+
bundlePages.push({ name, content: file.content });
|
|
388
|
+
includedPages.push({
|
|
389
|
+
name,
|
|
390
|
+
bytes: Buffer.byteLength(file.content, "utf8"),
|
|
391
|
+
modifiedTime: file.modifiedTime,
|
|
392
|
+
revision: file.revision,
|
|
393
|
+
});
|
|
394
|
+
bundleBytes += pageBytes;
|
|
395
|
+
lastProcessed = name;
|
|
396
|
+
}
|
|
397
|
+
// Compute nextCursor: advance past all attempted pages (including those that errored),
|
|
398
|
+
// so subsequent slices don't get stuck on an unreadable page.
|
|
399
|
+
const lastProcessedIndex = lastProcessed === undefined
|
|
400
|
+
? -1
|
|
401
|
+
: (candidatePositions.get(lastProcessed) ?? -1);
|
|
402
|
+
const hasMore = lastProcessedIndex >= 0 && lastProcessedIndex < allCandidates.length - 1;
|
|
403
|
+
const nextCursor = hasMore ? encodeCursor(lastProcessed) : undefined;
|
|
404
|
+
// Header is composed after hasMore so a truncated bundle can say so — an agent
|
|
405
|
+
// that cannot tell whether a page was included will re-read defensively, which
|
|
406
|
+
// is exactly the behaviour this is meant to remove (GH #426).
|
|
407
|
+
// Naming the filter and the match count lets an agent judge whether the
|
|
408
|
+
// bundle plausibly covers what it needs. Without it, an under-matching filter
|
|
409
|
+
// produces a bundle that looks authoritative — see the header's own note.
|
|
410
|
+
// A count of "20 of 132" does not tell an agent that the 112 it did not get
|
|
411
|
+
// include the two pages its instructions call read-first. Name them.
|
|
412
|
+
const includedNames = new Set(includedPages.map((p) => p.name));
|
|
413
|
+
const omittedConventional = conventionalPresent.filter((name) => !includedNames.has(name));
|
|
414
|
+
const bundle = buildBundleHeader(bundlePages, {
|
|
415
|
+
truncated: hasMore,
|
|
416
|
+
filter: filterDescription,
|
|
417
|
+
totalMatching: totalMatchingPages,
|
|
418
|
+
omittedConventional,
|
|
419
|
+
}) + serializeBundle(bundlePages);
|
|
420
|
+
return {
|
|
421
|
+
ok: true,
|
|
422
|
+
bundle,
|
|
423
|
+
pages: includedPages,
|
|
424
|
+
pageCount: includedPages.length,
|
|
425
|
+
totalMatchingPages,
|
|
426
|
+
bytes: Buffer.byteLength(bundle, "utf8"),
|
|
427
|
+
generatedAt: new Date().toISOString(),
|
|
428
|
+
...(errors.length > 0 ? { errors } : {}),
|
|
429
|
+
...(nextCursor !== undefined ? { nextCursor } : {}),
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
//# sourceMappingURL=pullSessionBundle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pullSessionBundle.js","sourceRoot":"","sources":["../../src/tools/pullSessionBundle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { StorageClient } from "../storage/client.js";
|
|
3
|
+
export declare const purgeWikiInputSchema: z.ZodObject<{
|
|
4
|
+
confirm: z.ZodDefault<z.ZodBoolean>;
|
|
5
|
+
exportBeforeDelete: z.ZodDefault<z.ZodBoolean>;
|
|
6
|
+
exportOutputPath: z.ZodOptional<z.ZodString>;
|
|
7
|
+
includeSystem: z.ZodDefault<z.ZodBoolean>;
|
|
8
|
+
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
includeSystem: boolean;
|
|
10
|
+
confirm: boolean;
|
|
11
|
+
exportBeforeDelete: boolean;
|
|
12
|
+
exportOutputPath?: string | undefined;
|
|
13
|
+
}, {
|
|
14
|
+
includeSystem?: boolean | undefined;
|
|
15
|
+
confirm?: boolean | undefined;
|
|
16
|
+
exportBeforeDelete?: boolean | undefined;
|
|
17
|
+
exportOutputPath?: string | undefined;
|
|
18
|
+
}>;
|
|
19
|
+
export type PurgeWikiInput = z.infer<typeof purgeWikiInputSchema>;
|
|
20
|
+
export declare function purgeWiki(drive: StorageClient, input: PurgeWikiInput, userId?: string, opts?: {
|
|
21
|
+
onProgress?: (processed: number, total: number) => void;
|
|
22
|
+
}): Promise<object>;
|
|
23
|
+
//# sourceMappingURL=purgeWiki.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"purgeWiki.d.ts","sourceRoot":"","sources":["../../src/tools/purgeWiki.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAK1D,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;EA6B/B,CAAC;AAEH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAIlE,wBAAsB,SAAS,CAC9B,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,cAAc,EACrB,MAAM,SAAK,EACX,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CAAO,GACpE,OAAO,CAAC,MAAM,CAAC,CAkGjB"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { exportWiki } from "./exportWiki.js";
|
|
3
|
+
import { appendLogEntry } from "../wiki/log.js";
|
|
4
|
+
import { getPostgresSearchIndex } from "../search/postgresIndex.js";
|
|
5
|
+
export const purgeWikiInputSchema = z.object({
|
|
6
|
+
confirm: z
|
|
7
|
+
.boolean()
|
|
8
|
+
.default(false)
|
|
9
|
+
.describe("Must be set to true to proceed with deletion. " +
|
|
10
|
+
"If false, returns a warning with the list of files that would be deleted."),
|
|
11
|
+
exportBeforeDelete: z
|
|
12
|
+
.boolean()
|
|
13
|
+
.default(false)
|
|
14
|
+
.describe("If true, runs export_wiki to create a ZIP archive before deleting. " +
|
|
15
|
+
"Requires exportOutputPath to be set."),
|
|
16
|
+
exportOutputPath: z
|
|
17
|
+
.string()
|
|
18
|
+
.optional()
|
|
19
|
+
.describe("Path where the ZIP archive will be written when exportBeforeDelete is true " +
|
|
20
|
+
"(e.g. '/tmp/wiki-backup.zip'). Required when exportBeforeDelete is true."),
|
|
21
|
+
includeSystem: z
|
|
22
|
+
.boolean()
|
|
23
|
+
.default(false)
|
|
24
|
+
.describe("If true, also deletes system files index.md and log.md. " +
|
|
25
|
+
"Default is false to protect system files."),
|
|
26
|
+
});
|
|
27
|
+
const SYSTEM_FILES = new Set(["index.md", "log.md"]);
|
|
28
|
+
export async function purgeWiki(drive, input, userId = "", opts = {}) {
|
|
29
|
+
const files = await drive.listFiles();
|
|
30
|
+
const toDelete = files.filter((f) => input.includeSystem || !SYSTEM_FILES.has(f.name));
|
|
31
|
+
if (!input.confirm) {
|
|
32
|
+
return {
|
|
33
|
+
success: false,
|
|
34
|
+
confirmed: false,
|
|
35
|
+
warning: "This operation will permanently delete all wiki pages. " +
|
|
36
|
+
"Set confirm=true to proceed. " +
|
|
37
|
+
"Set exportBeforeDelete=true with exportOutputPath to create a backup first.",
|
|
38
|
+
fileCount: toDelete.length,
|
|
39
|
+
files: toDelete.map((f) => f.name),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (input.exportBeforeDelete) {
|
|
43
|
+
if (!input.exportOutputPath) {
|
|
44
|
+
return {
|
|
45
|
+
success: false,
|
|
46
|
+
error: "exportOutputPath is required when exportBeforeDelete is true. " +
|
|
47
|
+
"Provide a path such as '/tmp/wiki-backup.zip'.",
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
await exportWiki(drive, {
|
|
51
|
+
outputPath: input.exportOutputPath,
|
|
52
|
+
includeSystem: true,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const deleted = [];
|
|
56
|
+
const failures = [];
|
|
57
|
+
// Flush Postgres index deletes every FLUSH_CHUNK files so that if the process is
|
|
58
|
+
// interrupted mid-loop, at most FLUSH_CHUNK ghost rows are left rather than all of them.
|
|
59
|
+
const FLUSH_CHUNK = 50;
|
|
60
|
+
const pgIndex = getPostgresSearchIndex();
|
|
61
|
+
const pgConfigured = pgIndex.isConfigured();
|
|
62
|
+
const pendingIndexDeletes = [];
|
|
63
|
+
async function flushIndexDeletes() {
|
|
64
|
+
if (!pgConfigured || pendingIndexDeletes.length === 0)
|
|
65
|
+
return;
|
|
66
|
+
const names = pendingIndexDeletes.splice(0);
|
|
67
|
+
await pgIndex.deletePages(names, userId).catch((err) => {
|
|
68
|
+
console.error("[purge] Postgres index cleanup failed:", err instanceof Error ? err.message : err);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
let progressProcessed = 0;
|
|
72
|
+
for (const file of toDelete) {
|
|
73
|
+
try {
|
|
74
|
+
await drive.deleteFile(file.name);
|
|
75
|
+
deleted.push(file.name);
|
|
76
|
+
pendingIndexDeletes.push(file.name);
|
|
77
|
+
if (pendingIndexDeletes.length >= FLUSH_CHUNK) {
|
|
78
|
+
await flushIndexDeletes();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
failures.push({
|
|
83
|
+
name: file.name,
|
|
84
|
+
error: err instanceof Error ? err.message : String(err),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
opts.onProgress?.(++progressProcessed, toDelete.length);
|
|
88
|
+
}
|
|
89
|
+
// Flush any remaining index deletes.
|
|
90
|
+
await flushIndexDeletes();
|
|
91
|
+
const exportInfo = input.exportBeforeDelete && input.exportOutputPath
|
|
92
|
+
? { exportedTo: input.exportOutputPath }
|
|
93
|
+
: undefined;
|
|
94
|
+
if (failures.length === 0) {
|
|
95
|
+
await appendLogEntry(drive, {
|
|
96
|
+
type: "update",
|
|
97
|
+
title: "Purge wiki",
|
|
98
|
+
detail: `deleted=${deleted.length}${exportInfo ? `, exportedTo=${exportInfo.exportedTo}` : ""}`,
|
|
99
|
+
}, userId).catch(() => {
|
|
100
|
+
/* non-fatal -- log.md may have been deleted if includeSystem was true */
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
success: failures.length === 0,
|
|
105
|
+
confirmed: true,
|
|
106
|
+
deletedCount: deleted.length,
|
|
107
|
+
failedCount: failures.length,
|
|
108
|
+
deleted,
|
|
109
|
+
failures,
|
|
110
|
+
...(exportInfo ?? {}),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=purgeWiki.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"purgeWiki.js","sourceRoot":"","sources":["../../src/tools/purgeWiki.ts"],"names":[],"mappings":"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"}
|