@j0hanz/filesystem-mcp 2.3.0 → 2.4.1
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 +1 -8
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +14 -41
- package/dist/cli-help.js.map +1 -1
- package/dist/cli.d.ts +0 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +14 -41
- package/dist/cli.js.map +1 -1
- package/dist/core/concurrency.d.ts +5 -17
- package/dist/core/concurrency.d.ts.map +1 -1
- package/dist/core/concurrency.js +11 -34
- package/dist/core/concurrency.js.map +1 -1
- package/dist/core/cursor.d.ts +1 -12
- package/dist/core/cursor.d.ts.map +1 -1
- package/dist/core/cursor.js +2 -12
- package/dist/core/cursor.js.map +1 -1
- package/dist/core/errors.d.ts +0 -2
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +6 -17
- package/dist/core/errors.js.map +1 -1
- package/dist/core/file-uri.d.ts +2 -2
- package/dist/core/file-uri.js +3 -3
- package/dist/core/file-uri.js.map +1 -1
- package/dist/core/fmt.d.ts +0 -10
- package/dist/core/fmt.d.ts.map +1 -1
- package/dist/core/fmt.js +1 -18
- package/dist/core/fmt.js.map +1 -1
- package/dist/core/fs.d.ts +3 -3
- package/dist/core/fs.d.ts.map +1 -1
- package/dist/core/fs.js +9 -10
- package/dist/core/fs.js.map +1 -1
- package/dist/core/glob.d.ts +1 -2
- package/dist/core/glob.d.ts.map +1 -1
- package/dist/core/glob.js +9 -20
- package/dist/core/glob.js.map +1 -1
- package/dist/core/input-required.d.ts +15 -16
- package/dist/core/input-required.d.ts.map +1 -1
- package/dist/core/input-required.js +34 -34
- package/dist/core/input-required.js.map +1 -1
- package/dist/core/observability.js +2 -2
- package/dist/core/observability.js.map +1 -1
- package/dist/core/path-completer.d.ts +6 -9
- package/dist/core/path-completer.d.ts.map +1 -1
- package/dist/core/path-completer.js +28 -55
- package/dist/core/path-completer.js.map +1 -1
- package/dist/core/path-discovery.d.ts.map +1 -1
- package/dist/core/path-discovery.js +3 -4
- package/dist/core/path-discovery.js.map +1 -1
- package/dist/core/path-utils.d.ts +28 -0
- package/dist/core/path-utils.d.ts.map +1 -1
- package/dist/core/path-utils.js +57 -2
- package/dist/core/path-utils.js.map +1 -1
- package/dist/core/path.d.ts +3 -8
- package/dist/core/path.d.ts.map +1 -1
- package/dist/core/path.js +8 -9
- package/dist/core/path.js.map +1 -1
- package/dist/core/read.d.ts +3 -22
- package/dist/core/read.d.ts.map +1 -1
- package/dist/core/read.js +46 -96
- package/dist/core/read.js.map +1 -1
- package/dist/core/schema.d.ts +8 -9
- package/dist/core/schema.d.ts.map +1 -1
- package/dist/core/schema.js +11 -14
- package/dist/core/schema.js.map +1 -1
- package/dist/core/search.d.ts +1 -1
- package/dist/core/search.d.ts.map +1 -1
- package/dist/core/search.js +3 -4
- package/dist/core/search.js.map +1 -1
- package/dist/core/sensitive.d.ts.map +1 -1
- package/dist/core/sensitive.js +4 -5
- package/dist/core/sensitive.js.map +1 -1
- package/dist/core/store.d.ts +41 -16
- package/dist/core/store.d.ts.map +1 -1
- package/dist/core/store.js +147 -82
- package/dist/core/store.js.map +1 -1
- package/dist/core/util.d.ts +3 -2
- package/dist/core/util.d.ts.map +1 -1
- package/dist/core/util.js +5 -6
- package/dist/core/util.js.map +1 -1
- package/dist/core/watcher-registry.d.ts +1 -1
- package/dist/core/watcher-registry.js +4 -4
- package/dist/core/watcher-registry.js.map +1 -1
- package/dist/index.js +5 -6
- package/dist/index.js.map +1 -1
- package/dist/instructions.js +2 -2
- package/dist/instructions.js.map +1 -1
- package/dist/prompts.js +1 -1
- package/dist/prompts.js.map +1 -1
- package/dist/resources.d.ts +11 -19
- package/dist/resources.d.ts.map +1 -1
- package/dist/resources.js +39 -59
- package/dist/resources.js.map +1 -1
- package/dist/server.d.ts +4 -5
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +8 -9
- package/dist/server.js.map +1 -1
- package/dist/tools/batch.d.ts +2 -2
- package/dist/tools/batch.js +3 -3
- package/dist/tools/batch.js.map +1 -1
- package/dist/tools/create.d.ts +1 -1
- package/dist/tools/create.js +17 -15
- package/dist/tools/create.js.map +1 -1
- package/dist/tools/define.d.ts +10 -9
- package/dist/tools/define.d.ts.map +1 -1
- package/dist/tools/define.js +26 -92
- package/dist/tools/define.js.map +1 -1
- package/dist/tools/delete.d.ts +1 -1
- package/dist/tools/delete.js +16 -13
- package/dist/tools/delete.js.map +1 -1
- package/dist/tools/diff.d.ts +1 -1
- package/dist/tools/diff.d.ts.map +1 -1
- package/dist/tools/diff.js +7 -37
- package/dist/tools/diff.js.map +1 -1
- package/dist/tools/edit.d.ts +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +27 -26
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/find-files.d.ts +1 -1
- package/dist/tools/find-files.d.ts.map +1 -1
- package/dist/tools/find-files.js +18 -37
- package/dist/tools/find-files.js.map +1 -1
- package/dist/tools/index.d.ts +9 -10
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +13 -13
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/list-roots.d.ts +1 -1
- package/dist/tools/list-roots.js +3 -3
- package/dist/tools/list-roots.js.map +1 -1
- package/dist/tools/list.d.ts +1 -1
- package/dist/tools/list.d.ts.map +1 -1
- package/dist/tools/list.js +23 -29
- package/dist/tools/list.js.map +1 -1
- package/dist/tools/move.d.ts +1 -1
- package/dist/tools/move.js +18 -13
- package/dist/tools/move.js.map +1 -1
- package/dist/tools/patch.d.ts +1 -1
- package/dist/tools/patch.js +4 -4
- package/dist/tools/patch.js.map +1 -1
- package/dist/tools/progress.d.ts +17 -28
- package/dist/tools/progress.d.ts.map +1 -1
- package/dist/tools/progress.js +42 -94
- package/dist/tools/progress.js.map +1 -1
- package/dist/tools/read.d.ts +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js +10 -12
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/replace-text.d.ts +1 -1
- package/dist/tools/replace-text.d.ts.map +1 -1
- package/dist/tools/replace-text.js +32 -49
- package/dist/tools/replace-text.js.map +1 -1
- package/dist/tools/search-text.d.ts +1 -1
- package/dist/tools/search-text.d.ts.map +1 -1
- package/dist/tools/search-text.js +19 -45
- package/dist/tools/search-text.js.map +1 -1
- package/dist/tools/stat.d.ts +1 -1
- package/dist/tools/stat.d.ts.map +1 -1
- package/dist/tools/stat.js +9 -29
- package/dist/tools/stat.js.map +1 -1
- package/dist/transport/http-policy.js +4 -4
- package/dist/transport/http-policy.js.map +1 -1
- package/dist/transport/http.d.ts +2 -2
- package/dist/transport/http.d.ts.map +1 -1
- package/dist/transport/http.js +16 -17
- package/dist/transport/http.js.map +1 -1
- package/dist/transport/shared.d.ts +2 -2
- package/dist/transport/shared.js +2 -2
- package/dist/transport/shared.js.map +1 -1
- package/dist/transport/stdio.d.ts +3 -3
- package/dist/transport/stdio.js +6 -6
- package/dist/transport/stdio.js.map +1 -1
- package/dist/transport.d.ts +2 -2
- package/dist/transport.js +2 -2
- package/dist/transport.js.map +1 -1
- package/package.json +3 -7
- package/dist/core/page-store.d.ts +0 -42
- package/dist/core/page-store.d.ts.map +0 -1
- package/dist/core/page-store.js +0 -75
- package/dist/core/page-store.js.map +0 -1
- package/dist/core/primitives.d.ts +0 -34
- package/dist/core/primitives.d.ts.map +0 -1
- package/dist/core/primitives.js +0 -63
- package/dist/core/primitives.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/transport/stdio.ts"],"names":[],"mappings":"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","sourcesContent":["// stdio hosting: the pinned-instance factory, legacy roots seeding, and the\n// gated transport that attaches listen-filter watchers before the SDK sees the\n// message.\nimport type { McpServerFactory } from '@modelcontextprotocol/server';\nimport { ProtocolErrorCode } from '@modelcontextprotocol/server';\nimport {\n serveStdio,\n type StdioServerHandle,\n StdioServerTransport,\n} from '@modelcontextprotocol/server/stdio';\n\nimport { fileURLToPath } from 'node:url';\n\nimport { formatUnknownErrorMessage } from '../core/errors.js';\nimport { Logger } from '../core/observability.js';\nimport type { ServerOptions } from '../core/path.js';\nimport { PathGuard } from '../core/path.js';\nimport { createWatcherRegistry } from '../core/watcher-registry.js';\nimport type { FilesystemServerContext } from '../server.js';\nimport { createServer } from '../server.js';\nimport type { RuntimeConfig } from './shared.js';\nimport {\n isStructurallyValidListen,\n jsonRpcError,\n jsonRpcRequestId,\n listenSubscriptionUris,\n prepareListenWatchers,\n} from './shared.js';\n\ninterface StdioListenState {\n acquiredUris: string[];\n cancelled: boolean;\n delivered: boolean;\n}\n\n// Read through a function, not `state.cancelled` directly: a cancellation lands\n// between the checks, and control-flow narrowing from the first one would\n// otherwise make the second read a compile-time constant.\nfunction isListenCancelled(state: StdioListenState): boolean {\n return state.cancelled;\n}\n\nfunction cancelledRequestId(message: unknown): string | number | null {\n if (typeof message !== 'object' || message === null) return null;\n const notification = message as {\n method?: unknown;\n params?: { requestId?: unknown };\n };\n if (notification.method !== 'notifications/cancelled') return null;\n const requestId = notification.params?.requestId;\n return typeof requestId === 'string' || typeof requestId === 'number' ? requestId : null;\n}\n\n/**\n * Seed the guard's allowed roots from the client's declared workspace roots.\n * Legacy-era only: push-style `roots/list` is deprecated (SEP-2577) and throws\n * on a 2026-07-28 connection, where clients pass paths as tool arguments and\n * the access-grant round-trip covers out-of-root paths instead. Every root\n * still passes `applyGrant`'s boundary and unsafe-path guards, so a client\n * cannot root-declare its way into $HOME or past FS_ROOT_BOUNDARY — a refused\n * root is skipped and its paths fail closed at validateAccess like any other.\n * sunset(SEP-2577): removal trigger in docs/adr/002-legacy-protocol-paths-sunset.md.\n */\nexport async function seedRootsFromClient(ctx: FilesystemServerContext): Promise<number> {\n let roots: readonly { uri: string }[];\n try {\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- legacy-era-only; the modern era never reaches the hooks that call this.\n ({ roots } = await ctx.mcp.server.listRoots());\n } catch (err: unknown) {\n // Client without the roots capability (strict-capabilities throw), or the\n // request failed — either way there is nothing to seed.\n Logger.debug('[Stdio] roots/list unavailable', { error: formatUnknownErrorMessage(err) });\n return 0;\n }\n let granted = 0;\n for (const root of roots) {\n let dir: string;\n try {\n dir = fileURLToPath(root.uri);\n } catch {\n continue; // not a file:// root\n }\n try {\n if (await ctx.pathGuard.applyGrant(dir)) granted += 1;\n else Logger.debug('[Stdio] client root refused by grant policy', { dir });\n } catch (err: unknown) {\n Logger.debug('[Stdio] client root grant failed', {\n dir,\n error: formatUnknownErrorMessage(err),\n });\n }\n }\n // No list-changed notification follows a grant. Allowed roots were once listed\n // as concrete resources, and are not any more: the file template's `list()`\n // returns nothing and the other two lists never read the roots at all (see\n // resources.ts). Notifying bought the client a re-fetch of an unchanged list.\n if (granted > 0) {\n Logger.info(`[Stdio] allowed ${granted} client-declared workspace root(s)`);\n }\n return granted;\n}\n\n/**\n * Serve filesystem-mcp over stdio using modern protocol revision 2026-07-28.\n *\n * The SDK's `StdioListenRouter` acknowledges `subscriptions/listen` and routes\n * the pinned instance's outbound change notifications onto the matching\n * streams, but it exposes no listen-filter hook, so nothing attaches the\n * filesystem watcher that would produce those notifications. `serveStdio`'s\n * `transport` option is the seam: it installs its own `onmessage` synchronously\n * and only then starts the wire, so wrapping that callback afterwards gives the\n * same view of the inbound `resourceSubscriptions` filter the HTTP leg reads off\n * `req.body`. The watcher's notify sink calls `sendResourceUpdated` on the\n * pinned instance, which the router then delivers to the listening stream.\n *\n * Watcher leases are tracked by listen request ID and released on cancellation,\n * rejection, graceful completion, or connection close.\n */\nexport function startServer(options: ServerOptions, config: RuntimeConfig = {}): StdioServerHandle {\n let closed = false;\n let activeCtx: FilesystemServerContext | undefined;\n const pathGuard = new PathGuard(options);\n let pathGuardReady: Promise<void> | undefined;\n const ensurePathGuard = (): Promise<void> => {\n pathGuardReady ??= pathGuard.recomputeAllowedDirectories();\n return pathGuardReady;\n };\n // Shared with the resource contract so a `resources/subscribe` and a\n // `subscriptions/listen` naming the same URI reuse one watcher.\n const registry = createWatcherRegistry();\n const factory: McpServerFactory = async ({ era }) => {\n await ensurePathGuard();\n const c = await createServer(options, {\n watcherRegistry: registry,\n pathGuard,\n era,\n ...(config.apiKey !== undefined ? { apiKey: config.apiKey } : {}),\n });\n if (closed) {\n // The connection went away while this instance was being built.\n // `cleanupConnection` already ran and its `closed` guard makes every later\n // call a no-op, so publishing `c` would strand it: nothing would dispose\n // it. Return it unactivated — the wire is gone, so nothing serves it.\n c.disposeRuntimeState();\n return c.mcp;\n }\n activeCtx = c;\n if (era === 'legacy') {\n // Fires when the client's `notifications/initialized` lands. Safe to own:\n // the SDK's only touchpoint is its own initialized handler reading it.\n c.mcp.server.oninitialized = () => {\n void seedRootsFromClient(c);\n };\n // Re-list and grant anything new. Grants are session-additive (R8): a\n // root the client withdrew is not revoked mid-session.\n c.mcp.server.setNotificationHandler('notifications/roots/list_changed', () => {\n void seedRootsFromClient(c);\n });\n }\n return c.mcp;\n };\n\n // One sink for the whole connection. `addCallback` de-duplicates by function\n // identity, so re-using this closure makes a repeat `subscriptions/listen` on\n // an already-watched URI a no-op; a fresh closure per listen would instead\n // stack a callback every time, double-notifying and growing an\n // `activeCallbacks` set that MAX_WATCHERS does not bound (it caps watchers,\n // not callbacks). Reads `activeCtx` when it fires rather than capturing it, so\n // it never pins a disposed instance.\n const sink = (uri: string): void => {\n // A failed notify means the connection went away; nothing to recover.\n void activeCtx?.mcp.server.sendResourceUpdated({ uri }).catch((err: unknown) => {\n Logger.debug('[Stdio] resource update not delivered', {\n uri,\n error: formatUnknownErrorMessage(err),\n });\n });\n };\n\n const wire = new StdioServerTransport();\n const listens = new Map<string | number, StdioListenState>();\n\n // Deleting the entry is what makes this idempotent: a second call for the\n // same id finds nothing to release.\n const releaseListen = (id: string | number): void => {\n const state = listens.get(id);\n if (!state) return;\n listens.delete(id);\n for (const uri of state.acquiredUris) registry.release(uri);\n };\n\n const cleanupConnection = (): void => {\n if (closed) return;\n closed = true;\n for (const state of listens.values()) state.cancelled = true;\n listens.clear();\n registry.destroy();\n const ctx = activeCtx;\n activeCtx = undefined;\n // Both steps below are guarded separately, and for the same reason: this\n // also runs from `wire.onclose`, where a throw is an uncaught exception on\n // the stdin close event rather than a rejected close(). One shared catch\n // would let a failed disposal skip the unref and strand the process.\n try {\n ctx?.disposeRuntimeState();\n } catch {\n /* idempotent — disposeRuntimeState guards cleanedUp */\n }\n try {\n // The SDK's transport close pauses stdin only when no other 'data'\n // listener is left, so a fatal read error (a ReadBuffer overflow) tears\n // the connection down but leaves the handle referenced and this process\n // alive with nothing left to serve. Unref rather than pause: a listener\n // the SDK still owns keeps receiving data, the loop just stops being held\n // open for it.\n process.stdin.unref();\n } catch {\n /* a file-backed stdin is an `fs.ReadStream`, which has no `unref` */\n }\n };\n\n const send = wire.send.bind(wire);\n wire.send = async (message) => {\n if ('id' in message && ('result' in message || 'error' in message)) {\n const id = message.id;\n if (id !== undefined) releaseListen(id);\n }\n await send(message);\n };\n\n const handle = serveStdio(factory, {\n legacy: 'serve',\n transport: wire,\n onerror: (error: unknown) => {\n Logger.error('[Stdio] serve error:', formatUnknownErrorMessage(error));\n },\n });\n const onclose = wire.onclose;\n wire.onclose = () => {\n try {\n cleanupConnection();\n } finally {\n onclose?.();\n }\n };\n\n // Wrap the callback `serveStdio` just installed. Listen requests are admitted\n // in order so two requests naming the same URI cannot race the registry's\n // ref-count. Cancellation is serialized with pending admission by request ID:\n // a pending request is suppressed and releases after preparation, while an\n // active request releases before the SDK closes its stream.\n //\n // serveStdio installs its onmessage synchronously and only then starts the\n // wire; this wrapper is only correct because of that ordering. Assert it\n // rather than degrade to a silent no-op if a future SDK release changes it.\n const deliver = wire.onmessage;\n if (!deliver) {\n throw new Error(\n 'serveStdio did not install a synchronous onmessage handler; the subscriptions/listen watcher gate cannot attach. This is an SDK contract change, not a configuration error.',\n );\n }\n let gated = Promise.resolve();\n wire.onmessage = (message) => {\n const cancelId = cancelledRequestId(message);\n if (cancelId !== null) {\n const state = listens.get(cancelId);\n if (!state) {\n deliver(message);\n return;\n }\n state.cancelled = true;\n if (state.delivered) {\n releaseListen(cancelId);\n deliver(message);\n }\n return;\n }\n\n const subscriptionUris = listenSubscriptionUris(message);\n if (subscriptionUris.length === 0) {\n deliver(message);\n return;\n }\n const id = jsonRpcRequestId(message);\n if (id === null || listens.has(id)) {\n deliver(message);\n return;\n }\n const state: StdioListenState = {\n acquiredUris: [],\n cancelled: false,\n delivered: false,\n };\n listens.set(id, state);\n gated = gated\n .then(async () => {\n if (!isStructurallyValidListen(message)) {\n listens.delete(id);\n deliver(message);\n return;\n }\n if (isListenCancelled(state)) {\n listens.delete(id);\n return;\n }\n await ensurePathGuard();\n const prepared = await prepareListenWatchers(message, pathGuard, registry, sink);\n if (!prepared.ok) {\n listens.delete(id);\n await wire.send(jsonRpcError(ProtocolErrorCode.InvalidParams, prepared.message, id));\n return;\n }\n state.acquiredUris = prepared.acquiredUris;\n if (isListenCancelled(state)) {\n releaseListen(id);\n return;\n }\n state.delivered = true;\n deliver(message);\n })\n .catch(async (error: unknown) => {\n releaseListen(id);\n const failure =\n error instanceof Error ? error : new Error(formatUnknownErrorMessage(error));\n wire.onerror?.(failure);\n // The gate swallowed the message, so nothing downstream will answer it.\n // Without this the client waits out its whole request timeout.\n await wire\n .send(jsonRpcError(ProtocolErrorCode.InternalError, failure.message, id))\n .catch(() => {\n /* the wire is gone; onerror above already reported it */\n });\n });\n };\n\n return {\n close: async () => {\n try {\n cleanupConnection();\n } finally {\n await handle.close();\n }\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../src/transport/stdio.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,OAAO,EACL,UAAU,EAEV,oBAAoB,GACrB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAEpE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EACL,yBAAyB,EACzB,YAAY,EACZ,gBAAgB,EAChB,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAQrB,gFAAgF;AAChF,0EAA0E;AAC1E,0DAA0D;AAC1D,SAAS,iBAAiB,CAAC,KAAuB;IAChD,OAAO,KAAK,CAAC,SAAS,CAAC;AACzB,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAgB;IAC1C,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACjE,MAAM,YAAY,GAAG,OAGpB,CAAC;IACF,IAAI,YAAY,CAAC,MAAM,KAAK,yBAAyB;QAAE,OAAO,IAAI,CAAC;IACnE,MAAM,SAAS,GAAG,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC;IACjD,OAAO,OAAO,SAAS,KAAK,QAAQ,IAAI,OAAO,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3F,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,GAA4B;IACpE,IAAI,KAAiC,CAAC;IACtC,IAAI,CAAC;QACH,uIAAuI;QACvI,CAAC,EAAE,KAAK,EAAE,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,0EAA0E;QAC1E,wDAAwD;QACxD,MAAM,CAAC,KAAK,CAAC,gCAAgC,EAAE,EAAE,KAAK,EAAE,yBAAyB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC1F,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACH,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,SAAS,CAAC,qBAAqB;QACjC,CAAC;QACD,IAAI,CAAC;YACH,IAAI,MAAM,GAAG,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC,CAAC;;gBACjD,MAAM,CAAC,KAAK,CAAC,6CAA6C,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QAC5E,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,CAAC,KAAK,CAAC,kCAAkC,EAAE;gBAC/C,GAAG;gBACH,KAAK,EAAE,yBAAyB,CAAC,GAAG,CAAC;aACtC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,+EAA+E;IAC/E,4EAA4E;IAC5E,2EAA2E;IAC3E,8EAA8E;IAC9E,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;QAChB,MAAM,CAAC,IAAI,CAAC,mBAAmB,OAAO,oCAAoC,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,WAAW,CAAC,OAAsB,EAAE,SAAwB,EAAE;IAC5E,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,SAA8C,CAAC;IACnD,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC;IACzC,IAAI,cAAyC,CAAC;IAC9C,MAAM,eAAe,GAAG,GAAkB,EAAE;QAC1C,cAAc,KAAK,SAAS,CAAC,2BAA2B,EAAE,CAAC;QAC3D,OAAO,cAAc,CAAC;IACxB,CAAC,CAAC;IACF,qEAAqE;IACrE,gEAAgE;IAChE,MAAM,QAAQ,GAAG,qBAAqB,EAAE,CAAC;IACzC,MAAM,OAAO,GAAqB,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE;QAClD,MAAM,eAAe,EAAE,CAAC;QACxB,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,OAAO,EAAE;YACpC,eAAe,EAAE,QAAQ;YACzB,SAAS;YACT,GAAG;YACH,GAAG,CAAC,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAClE,CAAC,CAAC;QACH,IAAI,MAAM,EAAE,CAAC;YACX,gEAAgE;YAChE,2EAA2E;YAC3E,yEAAyE;YACzE,sEAAsE;YACtE,CAAC,CAAC,mBAAmB,EAAE,CAAC;YACxB,OAAO,CAAC,CAAC,GAAG,CAAC;QACf,CAAC;QACD,SAAS,GAAG,CAAC,CAAC;QACd,IAAI,GAAG,KAAK,QAAQ,EAAE,CAAC;YACrB,0EAA0E;YAC1E,uEAAuE;YACvE,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,GAAG,GAAG,EAAE;gBAChC,KAAK,mBAAmB,CAAC,CAAC,CAAC,CAAC;YAC9B,CAAC,CAAC;YACF,sEAAsE;YACtE,uDAAuD;YACvD,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,sBAAsB,CAAC,kCAAkC,EAAE,GAAG,EAAE;gBAC3E,KAAK,mBAAmB,CAAC,CAAC,CAAC,CAAC;YAC9B,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,CAAC,CAAC,GAAG,CAAC;IACf,CAAC,CAAC;IAEF,6EAA6E;IAC7E,8EAA8E;IAC9E,2EAA2E;IAC3E,+DAA+D;IAC/D,4EAA4E;IAC5E,+EAA+E;IAC/E,qCAAqC;IACrC,MAAM,IAAI,GAAG,CAAC,GAAW,EAAQ,EAAE;QACjC,sEAAsE;QACtE,KAAK,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YAC7E,MAAM,CAAC,KAAK,CAAC,uCAAuC,EAAE;gBACpD,GAAG;gBACH,KAAK,EAAE,yBAAyB,CAAC,GAAG,CAAC;aACtC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,IAAI,oBAAoB,EAAE,CAAC;IACxC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAqC,CAAC;IAE7D,0EAA0E;IAC1E,oCAAoC;IACpC,MAAM,aAAa,GAAG,CAAC,EAAmB,EAAQ,EAAE;QAClD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK;YAAE,OAAO;QACnB,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACnB,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,YAAY;YAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9D,CAAC,CAAC;IAEF,MAAM,iBAAiB,GAAG,GAAS,EAAE;QACnC,IAAI,MAAM;YAAE,OAAO;QACnB,MAAM,GAAG,IAAI,CAAC;QACd,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE;YAAE,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;QAC7D,OAAO,CAAC,KAAK,EAAE,CAAC;QAChB,QAAQ,CAAC,OAAO,EAAE,CAAC;QACnB,MAAM,GAAG,GAAG,SAAS,CAAC;QACtB,SAAS,GAAG,SAAS,CAAC;QACtB,yEAAyE;QACzE,2EAA2E;QAC3E,yEAAyE;QACzE,qEAAqE;QACrE,IAAI,CAAC;YACH,GAAG,EAAE,mBAAmB,EAAE,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,uDAAuD;QACzD,CAAC;QACD,IAAI,CAAC;YACH,mEAAmE;YACnE,wEAAwE;YACxE,wEAAwE;YACxE,wEAAwE;YACxE,0EAA0E;YAC1E,eAAe;YACf,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;QACvE,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClC,IAAI,CAAC,IAAI,GAAG,KAAK,EAAE,OAAO,EAAE,EAAE;QAC5B,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,QAAQ,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,CAAC,EAAE,CAAC;YACnE,MAAM,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC;YACtB,IAAI,EAAE,KAAK,SAAS;gBAAE,aAAa,CAAC,EAAE,CAAC,CAAC;QAC1C,CAAC;QACD,MAAM,IAAI,CAAC,OAAO,CAAC,CAAC;IACtB,CAAC,CAAC;IAEF,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,EAAE;QACjC,MAAM,EAAE,OAAO;QACf,SAAS,EAAE,IAAI;QACf,OAAO,EAAE,CAAC,KAAc,EAAE,EAAE;YAC1B,MAAM,CAAC,KAAK,CAAC,sBAAsB,EAAE,yBAAyB,CAAC,KAAK,CAAC,CAAC,CAAC;QACzE,CAAC;KACF,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC7B,IAAI,CAAC,OAAO,GAAG,GAAG,EAAE;QAClB,IAAI,CAAC;YACH,iBAAiB,EAAE,CAAC;QACtB,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,EAAE,CAAC;QACd,CAAC;IACH,CAAC,CAAC;IAEF,8EAA8E;IAC9E,0EAA0E;IAC1E,8EAA8E;IAC9E,2EAA2E;IAC3E,4DAA4D;IAC5D,EAAE;IACF,2EAA2E;IAC3E,yEAAyE;IACzE,4EAA4E;IAC5E,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;IAC/B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,6KAA6K,CAC9K,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAC9B,IAAI,CAAC,SAAS,GAAG,CAAC,OAAO,EAAE,EAAE;QAC3B,MAAM,QAAQ,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAC7C,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACpC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,CAAC,OAAO,CAAC,CAAC;gBACjB,OAAO;YACT,CAAC;YACD,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;YACvB,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;gBACpB,aAAa,CAAC,QAAQ,CAAC,CAAC;gBACxB,OAAO,CAAC,OAAO,CAAC,CAAC;YACnB,CAAC;YACD,OAAO;QACT,CAAC;QAED,MAAM,gBAAgB,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC;QACzD,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,OAAO,CAAC,CAAC;YACjB,OAAO;QACT,CAAC;QACD,MAAM,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,EAAE,KAAK,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACnC,OAAO,CAAC,OAAO,CAAC,CAAC;YACjB,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAqB;YAC9B,YAAY,EAAE,EAAE;YAChB,SAAS,EAAE,KAAK;YAChB,SAAS,EAAE,KAAK;SACjB,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;QACvB,KAAK,GAAG,KAAK;aACV,IAAI,CAAC,KAAK,IAAI,EAAE;YACf,IAAI,CAAC,yBAAyB,CAAC,OAAO,CAAC,EAAE,CAAC;gBACxC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACnB,OAAO,CAAC,OAAO,CAAC,CAAC;gBACjB,OAAO;YACT,CAAC;YACD,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC7B,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACnB,OAAO;YACT,CAAC;YACD,MAAM,eAAe,EAAE,CAAC;YACxB,MAAM,QAAQ,GAAG,MAAM,qBAAqB,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;YACjF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACnB,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,aAAa,EAAE,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;gBACrF,OAAO;YACT,CAAC;YACD,KAAK,CAAC,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC;YAC3C,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC7B,aAAa,CAAC,EAAE,CAAC,CAAC;gBAClB,OAAO;YACT,CAAC;YACD,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;YACvB,OAAO,CAAC,OAAO,CAAC,CAAC;QACnB,CAAC,CAAC;aACD,KAAK,CAAC,KAAK,EAAE,KAAc,EAAE,EAAE;YAC9B,aAAa,CAAC,EAAE,CAAC,CAAC;YAClB,MAAM,OAAO,GACX,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC,CAAC;YAC/E,IAAI,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC;YACxB,wEAAwE;YACxE,+DAA+D;YAC/D,MAAM,IAAI;iBACP,IAAI,CAAC,YAAY,CAAC,iBAAiB,CAAC,aAAa,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;iBACxE,KAAK,CAAC,GAAG,EAAE;gBACV,yDAAyD;YAC3D,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;IAEF,OAAO;QACL,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,IAAI,CAAC;gBACH,iBAAiB,EAAE,CAAC;YACtB,CAAC;oBAAS,CAAC;gBACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YACvB,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["// stdio hosting: the pinned-instance factory, legacy roots seeding, and the\n// gated transport that attaches listen-filter watchers before the SDK sees the\n// message.\nimport type { McpServerFactory } from '@modelcontextprotocol/server';\nimport { ProtocolErrorCode } from '@modelcontextprotocol/server';\nimport {\n serveStdio,\n type StdioServerHandle,\n StdioServerTransport,\n} from '@modelcontextprotocol/server/stdio';\n\nimport { fileURLToPath } from 'node:url';\n\nimport { formatUnknownErrorMessage } from '../core/errors.ts';\nimport { Logger } from '../core/observability.ts';\nimport type { ServerOptions } from '../core/path.ts';\nimport { PathGuard } from '../core/path.ts';\nimport { createWatcherRegistry } from '../core/watcher-registry.ts';\nimport type { FilesystemServerContext } from '../server.ts';\nimport { createServer } from '../server.ts';\nimport type { RuntimeConfig } from './shared.ts';\nimport {\n isStructurallyValidListen,\n jsonRpcError,\n jsonRpcRequestId,\n listenSubscriptionUris,\n prepareListenWatchers,\n} from './shared.ts';\n\ninterface StdioListenState {\n acquiredUris: string[];\n cancelled: boolean;\n delivered: boolean;\n}\n\n// Read through a function, not `state.cancelled` directly: a cancellation lands\n// between the checks, and control-flow narrowing from the first one would\n// otherwise make the second read a compile-time constant.\nfunction isListenCancelled(state: StdioListenState): boolean {\n return state.cancelled;\n}\n\nfunction cancelledRequestId(message: unknown): string | number | null {\n if (typeof message !== 'object' || message === null) return null;\n const notification = message as {\n method?: unknown;\n params?: { requestId?: unknown };\n };\n if (notification.method !== 'notifications/cancelled') return null;\n const requestId = notification.params?.requestId;\n return typeof requestId === 'string' || typeof requestId === 'number' ? requestId : null;\n}\n\n/**\n * Seed the guard's allowed roots from the client's declared workspace roots.\n * Legacy-era only: push-style `roots/list` is deprecated (SEP-2577) and throws\n * on a 2026-07-28 connection, where clients pass paths as tool arguments and\n * the access-grant round-trip covers out-of-root paths instead. Every root\n * still passes `applyGrant`'s boundary and unsafe-path guards, so a client\n * cannot root-declare its way into $HOME or past FS_ROOT_BOUNDARY — a refused\n * root is skipped and its paths fail closed at validateAccess like any other.\n * sunset(SEP-2577): removal trigger in docs/adr/002-legacy-protocol-paths-sunset.md.\n */\nexport async function seedRootsFromClient(ctx: FilesystemServerContext): Promise<number> {\n let roots: readonly { uri: string }[];\n try {\n // eslint-disable-next-line @typescript-eslint/no-deprecated -- legacy-era-only; the modern era never reaches the hooks that call this.\n ({ roots } = await ctx.mcp.server.listRoots());\n } catch (err: unknown) {\n // Client without the roots capability (strict-capabilities throw), or the\n // request failed — either way there is nothing to seed.\n Logger.debug('[Stdio] roots/list unavailable', { error: formatUnknownErrorMessage(err) });\n return 0;\n }\n let granted = 0;\n for (const root of roots) {\n let dir: string;\n try {\n dir = fileURLToPath(root.uri);\n } catch {\n continue; // not a file:// root\n }\n try {\n if (await ctx.pathGuard.applyGrant(dir)) granted += 1;\n else Logger.debug('[Stdio] client root refused by grant policy', { dir });\n } catch (err: unknown) {\n Logger.debug('[Stdio] client root grant failed', {\n dir,\n error: formatUnknownErrorMessage(err),\n });\n }\n }\n // No list-changed notification follows a grant. Allowed roots were once listed\n // as concrete resources, and are not any more: the file template's `list()`\n // returns nothing and the other two lists never read the roots at all (see\n // resources.ts). Notifying bought the client a re-fetch of an unchanged list.\n if (granted > 0) {\n Logger.info(`[Stdio] allowed ${granted} client-declared workspace root(s)`);\n }\n return granted;\n}\n\n/**\n * Serve filesystem-mcp over stdio using modern protocol revision 2026-07-28.\n *\n * The SDK's `StdioListenRouter` acknowledges `subscriptions/listen` and routes\n * the pinned instance's outbound change notifications onto the matching\n * streams, but it exposes no listen-filter hook, so nothing attaches the\n * filesystem watcher that would produce those notifications. `serveStdio`'s\n * `transport` option is the seam: it installs its own `onmessage` synchronously\n * and only then starts the wire, so wrapping that callback afterwards gives the\n * same view of the inbound `resourceSubscriptions` filter the HTTP leg reads off\n * `req.body`. The watcher's notify sink calls `sendResourceUpdated` on the\n * pinned instance, which the router then delivers to the listening stream.\n *\n * Watcher leases are tracked by listen request ID and released on cancellation,\n * rejection, graceful completion, or connection close.\n */\nexport function startServer(options: ServerOptions, config: RuntimeConfig = {}): StdioServerHandle {\n let closed = false;\n let activeCtx: FilesystemServerContext | undefined;\n const pathGuard = new PathGuard(options);\n let pathGuardReady: Promise<void> | undefined;\n const ensurePathGuard = (): Promise<void> => {\n pathGuardReady ??= pathGuard.recomputeAllowedDirectories();\n return pathGuardReady;\n };\n // Shared with the resource contract so a `resources/subscribe` and a\n // `subscriptions/listen` naming the same URI reuse one watcher.\n const registry = createWatcherRegistry();\n const factory: McpServerFactory = async ({ era }) => {\n await ensurePathGuard();\n const c = await createServer(options, {\n watcherRegistry: registry,\n pathGuard,\n era,\n ...(config.apiKey !== undefined ? { apiKey: config.apiKey } : {}),\n });\n if (closed) {\n // The connection went away while this instance was being built.\n // `cleanupConnection` already ran and its `closed` guard makes every later\n // call a no-op, so publishing `c` would strand it: nothing would dispose\n // it. Return it unactivated — the wire is gone, so nothing serves it.\n c.disposeRuntimeState();\n return c.mcp;\n }\n activeCtx = c;\n if (era === 'legacy') {\n // Fires when the client's `notifications/initialized` lands. Safe to own:\n // the SDK's only touchpoint is its own initialized handler reading it.\n c.mcp.server.oninitialized = () => {\n void seedRootsFromClient(c);\n };\n // Re-list and grant anything new. Grants are session-additive (R8): a\n // root the client withdrew is not revoked mid-session.\n c.mcp.server.setNotificationHandler('notifications/roots/list_changed', () => {\n void seedRootsFromClient(c);\n });\n }\n return c.mcp;\n };\n\n // One sink for the whole connection. `addCallback` de-duplicates by function\n // identity, so re-using this closure makes a repeat `subscriptions/listen` on\n // an already-watched URI a no-op; a fresh closure per listen would instead\n // stack a callback every time, double-notifying and growing an\n // `activeCallbacks` set that MAX_WATCHERS does not bound (it caps watchers,\n // not callbacks). Reads `activeCtx` when it fires rather than capturing it, so\n // it never pins a disposed instance.\n const sink = (uri: string): void => {\n // A failed notify means the connection went away; nothing to recover.\n void activeCtx?.mcp.server.sendResourceUpdated({ uri }).catch((err: unknown) => {\n Logger.debug('[Stdio] resource update not delivered', {\n uri,\n error: formatUnknownErrorMessage(err),\n });\n });\n };\n\n const wire = new StdioServerTransport();\n const listens = new Map<string | number, StdioListenState>();\n\n // Deleting the entry is what makes this idempotent: a second call for the\n // same id finds nothing to release.\n const releaseListen = (id: string | number): void => {\n const state = listens.get(id);\n if (!state) return;\n listens.delete(id);\n for (const uri of state.acquiredUris) registry.release(uri);\n };\n\n const cleanupConnection = (): void => {\n if (closed) return;\n closed = true;\n for (const state of listens.values()) state.cancelled = true;\n listens.clear();\n registry.destroy();\n const ctx = activeCtx;\n activeCtx = undefined;\n // Both steps below are guarded separately, and for the same reason: this\n // also runs from `wire.onclose`, where a throw is an uncaught exception on\n // the stdin close event rather than a rejected close(). One shared catch\n // would let a failed disposal skip the unref and strand the process.\n try {\n ctx?.disposeRuntimeState();\n } catch {\n /* idempotent — disposeRuntimeState guards cleanedUp */\n }\n try {\n // The SDK's transport close pauses stdin only when no other 'data'\n // listener is left, so a fatal read error (a ReadBuffer overflow) tears\n // the connection down but leaves the handle referenced and this process\n // alive with nothing left to serve. Unref rather than pause: a listener\n // the SDK still owns keeps receiving data, the loop just stops being held\n // open for it.\n process.stdin.unref();\n } catch {\n /* a file-backed stdin is an `fs.ReadStream`, which has no `unref` */\n }\n };\n\n const send = wire.send.bind(wire);\n wire.send = async (message) => {\n if ('id' in message && ('result' in message || 'error' in message)) {\n const id = message.id;\n if (id !== undefined) releaseListen(id);\n }\n await send(message);\n };\n\n const handle = serveStdio(factory, {\n legacy: 'serve',\n transport: wire,\n onerror: (error: unknown) => {\n Logger.error('[Stdio] serve error:', formatUnknownErrorMessage(error));\n },\n });\n const onclose = wire.onclose;\n wire.onclose = () => {\n try {\n cleanupConnection();\n } finally {\n onclose?.();\n }\n };\n\n // Wrap the callback `serveStdio` just installed. Listen requests are admitted\n // in order so two requests naming the same URI cannot race the registry's\n // ref-count. Cancellation is serialized with pending admission by request ID:\n // a pending request is suppressed and releases after preparation, while an\n // active request releases before the SDK closes its stream.\n //\n // serveStdio installs its onmessage synchronously and only then starts the\n // wire; this wrapper is only correct because of that ordering. Assert it\n // rather than degrade to a silent no-op if a future SDK release changes it.\n const deliver = wire.onmessage;\n if (!deliver) {\n throw new Error(\n 'serveStdio did not install a synchronous onmessage handler; the subscriptions/listen watcher gate cannot attach. This is an SDK contract change, not a configuration error.',\n );\n }\n let gated = Promise.resolve();\n wire.onmessage = (message) => {\n const cancelId = cancelledRequestId(message);\n if (cancelId !== null) {\n const state = listens.get(cancelId);\n if (!state) {\n deliver(message);\n return;\n }\n state.cancelled = true;\n if (state.delivered) {\n releaseListen(cancelId);\n deliver(message);\n }\n return;\n }\n\n const subscriptionUris = listenSubscriptionUris(message);\n if (subscriptionUris.length === 0) {\n deliver(message);\n return;\n }\n const id = jsonRpcRequestId(message);\n if (id === null || listens.has(id)) {\n deliver(message);\n return;\n }\n const state: StdioListenState = {\n acquiredUris: [],\n cancelled: false,\n delivered: false,\n };\n listens.set(id, state);\n gated = gated\n .then(async () => {\n if (!isStructurallyValidListen(message)) {\n listens.delete(id);\n deliver(message);\n return;\n }\n if (isListenCancelled(state)) {\n listens.delete(id);\n return;\n }\n await ensurePathGuard();\n const prepared = await prepareListenWatchers(message, pathGuard, registry, sink);\n if (!prepared.ok) {\n listens.delete(id);\n await wire.send(jsonRpcError(ProtocolErrorCode.InvalidParams, prepared.message, id));\n return;\n }\n state.acquiredUris = prepared.acquiredUris;\n if (isListenCancelled(state)) {\n releaseListen(id);\n return;\n }\n state.delivered = true;\n deliver(message);\n })\n .catch(async (error: unknown) => {\n releaseListen(id);\n const failure =\n error instanceof Error ? error : new Error(formatUnknownErrorMessage(error));\n wire.onerror?.(failure);\n // The gate swallowed the message, so nothing downstream will answer it.\n // Without this the client waits out its whole request timeout.\n await wire\n .send(jsonRpcError(ProtocolErrorCode.InternalError, failure.message, id))\n .catch(() => {\n /* the wire is gone; onerror above already reported it */\n });\n });\n };\n\n return {\n close: async () => {\n try {\n cleanupConnection();\n } finally {\n await handle.close();\n }\n },\n };\n}\n"]}
|
package/dist/transport.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { startServer } from './transport/stdio.
|
|
2
|
-
export { startHttpServer } from './transport/http.
|
|
1
|
+
export { startServer } from './transport/stdio.ts';
|
|
2
|
+
export { startHttpServer } from './transport/http.ts';
|
|
3
3
|
//# sourceMappingURL=transport.d.ts.map
|
package/dist/transport.js
CHANGED
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
// export. The hosting itself lives in `transport/stdio.ts` (pinned-instance
|
|
3
3
|
// stdio serving) and `transport/http.ts` (per-request HTTP hosting);
|
|
4
4
|
// `transport/shared.ts` holds the pieces both legs gate on.
|
|
5
|
-
export { startServer } from
|
|
6
|
-
export { startHttpServer } from
|
|
5
|
+
export { startServer } from "./transport/stdio.js";
|
|
6
|
+
export { startHttpServer } from "./transport/http.js";
|
|
7
7
|
//# sourceMappingURL=transport.js.map
|
package/dist/transport.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,4EAA4E;AAC5E,qEAAqE;AACrE,4DAA4D;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC","sourcesContent":["// Facade for the transport layer, preserving the package's `./transport`\n// export. The hosting itself lives in `transport/stdio.ts` (pinned-instance\n// stdio serving) and `transport/http.ts` (per-request HTTP hosting);\n// `transport/shared.ts` holds the pieces both legs gate on.\nexport { startServer } from './transport/stdio.
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../src/transport.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,4EAA4E;AAC5E,qEAAqE;AACrE,4DAA4D;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC","sourcesContent":["// Facade for the transport layer, preserving the package's `./transport`\n// export. The hosting itself lives in `transport/stdio.ts` (pinned-instance\n// stdio serving) and `transport/http.ts` (per-request HTTP hosting);\n// `transport/shared.ts` holds the pieces both legs gate on.\nexport { startServer } from './transport/stdio.ts';\nexport { startHttpServer } from './transport/http.ts';\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@j0hanz/filesystem-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.1",
|
|
4
4
|
"mcpName": "io.github.j0hanz/filesystem-mcp",
|
|
5
5
|
"description": "Secure filesystem MCP server for reading, writing, searching, diffing, and patching files.",
|
|
6
6
|
"author": "j0hanz",
|
|
@@ -32,10 +32,10 @@
|
|
|
32
32
|
"format": "prettier --write .",
|
|
33
33
|
"type-check": "tsc -p tsconfig.json --noEmit",
|
|
34
34
|
"type-check:test": "tsc -p tsconfig.test.json",
|
|
35
|
-
"check:static": "npm run build && npm run type-check && npm run
|
|
35
|
+
"check:static": "npm run build && npm run type-check:test && npm run lint && prettier --check . && knip",
|
|
36
36
|
"fix": "npm run format && npm run lint:fix && npm run check",
|
|
37
37
|
"check": "npm run check:static && npm run test",
|
|
38
|
-
"test": "node --test
|
|
38
|
+
"test": "node --test"
|
|
39
39
|
},
|
|
40
40
|
"keywords": [
|
|
41
41
|
"mcp",
|
|
@@ -77,14 +77,10 @@
|
|
|
77
77
|
"eslint-config-prettier": "^10.1.8",
|
|
78
78
|
"knip": "^6",
|
|
79
79
|
"prettier": "^3.9.6",
|
|
80
|
-
"tsx": "^4.23.13",
|
|
81
80
|
"typescript": "^6",
|
|
82
81
|
"typescript-eslint": "^8.70.0"
|
|
83
82
|
},
|
|
84
83
|
"engines": {
|
|
85
84
|
"node": ">=24"
|
|
86
|
-
},
|
|
87
|
-
"allowScripts": {
|
|
88
|
-
"esbuild@0.28.2": true
|
|
89
85
|
}
|
|
90
86
|
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { FsError } from './errors.js';
|
|
2
|
-
export interface PageSnapshot<T = unknown, M = unknown> {
|
|
3
|
-
readonly items: readonly T[];
|
|
4
|
-
readonly metadata: M;
|
|
5
|
-
}
|
|
6
|
-
export interface PageSnapshotStoreOptions {
|
|
7
|
-
readonly maxSnapshots?: number;
|
|
8
|
-
readonly ttlMs?: number;
|
|
9
|
-
readonly now?: () => number;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* The one cursor rejection: a cursor whose snapshot expired, was evicted, was
|
|
13
|
-
* already consumed past its end, or belongs to a different query. Every case
|
|
14
|
-
* has the same remedy, so they share one message.
|
|
15
|
-
*/
|
|
16
|
-
export declare function invalidCursor(): FsError;
|
|
17
|
-
/**
|
|
18
|
-
* Short-lived snapshots of a completed query's full result set, so later pages
|
|
19
|
-
* slice a stored array instead of re-scanning and re-sorting the filesystem.
|
|
20
|
-
*
|
|
21
|
-
* ponytail: bounded by snapshot count and TTL, not by bytes — 32 x 20,000
|
|
22
|
-
* `list` entries or 32 x 10,000 `search_text` matches, each match retaining up
|
|
23
|
-
* to 20 more line strings at `context: 10`, order of a few hundred MB held for
|
|
24
|
-
* 60s, and the HTTP leg shares one store so any caller can drive it. If that
|
|
25
|
-
* shows up as memory pressure, meter bytes the way `ResourceStore` does.
|
|
26
|
-
*/
|
|
27
|
-
export declare class PageSnapshotStore {
|
|
28
|
-
private readonly byId;
|
|
29
|
-
private readonly maxSnapshots;
|
|
30
|
-
private readonly ttlMs;
|
|
31
|
-
private readonly now;
|
|
32
|
-
constructor(options?: PageSnapshotStoreOptions);
|
|
33
|
-
private pruneExpired;
|
|
34
|
-
create(params: {
|
|
35
|
-
queryKey: string;
|
|
36
|
-
items: readonly unknown[];
|
|
37
|
-
metadata?: unknown;
|
|
38
|
-
}): string;
|
|
39
|
-
read<T, M = undefined>(snapshotId: string, queryKey: string): PageSnapshot<T, M>;
|
|
40
|
-
clear(): void;
|
|
41
|
-
}
|
|
42
|
-
//# sourceMappingURL=page-store.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"page-store.d.ts","sourceRoot":"","sources":["../../src/core/page-store.ts"],"names":[],"mappings":"AAEA,OAAO,EAAa,OAAO,EAAE,MAAM,aAAa,CAAC;AAYjD,MAAM,WAAW,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO;IACpD,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;CACtB;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAKvC;AAED;;;;;;;;;GASG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAyC;IAC9D,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;gBAEvB,OAAO,GAAE,wBAA6B;IAMlD,OAAO,CAAC,YAAY;IAOpB,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,MAAM;IAmB3F,IAAI,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC;IAYhF,KAAK,IAAI,IAAI;CAGd"}
|
package/dist/core/page-store.js
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { ErrorCode, FsError } from './errors.js';
|
|
3
|
-
const DEFAULT_MAX_SNAPSHOTS = 32;
|
|
4
|
-
const DEFAULT_TTL_MS = 60 * 1000;
|
|
5
|
-
/**
|
|
6
|
-
* The one cursor rejection: a cursor whose snapshot expired, was evicted, was
|
|
7
|
-
* already consumed past its end, or belongs to a different query. Every case
|
|
8
|
-
* has the same remedy, so they share one message.
|
|
9
|
-
*/
|
|
10
|
-
export function invalidCursor() {
|
|
11
|
-
return new FsError(ErrorCode.INVALID_INPUT, 'Invalid cursor. Request the first page without a cursor.');
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Short-lived snapshots of a completed query's full result set, so later pages
|
|
15
|
-
* slice a stored array instead of re-scanning and re-sorting the filesystem.
|
|
16
|
-
*
|
|
17
|
-
* ponytail: bounded by snapshot count and TTL, not by bytes — 32 x 20,000
|
|
18
|
-
* `list` entries or 32 x 10,000 `search_text` matches, each match retaining up
|
|
19
|
-
* to 20 more line strings at `context: 10`, order of a few hundred MB held for
|
|
20
|
-
* 60s, and the HTTP leg shares one store so any caller can drive it. If that
|
|
21
|
-
* shows up as memory pressure, meter bytes the way `ResourceStore` does.
|
|
22
|
-
*/
|
|
23
|
-
export class PageSnapshotStore {
|
|
24
|
-
byId = new Map();
|
|
25
|
-
maxSnapshots;
|
|
26
|
-
ttlMs;
|
|
27
|
-
now;
|
|
28
|
-
constructor(options = {}) {
|
|
29
|
-
this.maxSnapshots = options.maxSnapshots ?? DEFAULT_MAX_SNAPSHOTS;
|
|
30
|
-
this.ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
|
|
31
|
-
this.now = options.now ?? Date.now;
|
|
32
|
-
}
|
|
33
|
-
pruneExpired() {
|
|
34
|
-
const now = this.now();
|
|
35
|
-
for (const [snapshotId, entry] of this.byId) {
|
|
36
|
-
if (entry.expiresAt <= now)
|
|
37
|
-
this.byId.delete(snapshotId);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
create(params) {
|
|
41
|
-
this.pruneExpired();
|
|
42
|
-
const snapshotId = randomUUID();
|
|
43
|
-
this.byId.set(snapshotId, {
|
|
44
|
-
queryKey: params.queryKey,
|
|
45
|
-
items: params.items,
|
|
46
|
-
metadata: params.metadata,
|
|
47
|
-
expiresAt: this.now() + this.ttlMs,
|
|
48
|
-
});
|
|
49
|
-
// Oldest first: Map keeps insertion order and `read` re-inserts, so the
|
|
50
|
-
// first key is the least recently used snapshot.
|
|
51
|
-
while (this.byId.size > this.maxSnapshots) {
|
|
52
|
-
const oldest = this.byId.keys().next();
|
|
53
|
-
if (oldest.done)
|
|
54
|
-
break;
|
|
55
|
-
this.byId.delete(oldest.value);
|
|
56
|
-
}
|
|
57
|
-
return snapshotId;
|
|
58
|
-
}
|
|
59
|
-
read(snapshotId, queryKey) {
|
|
60
|
-
this.pruneExpired();
|
|
61
|
-
const entry = this.byId.get(snapshotId);
|
|
62
|
-
if (entry?.queryKey !== queryKey)
|
|
63
|
-
throw invalidCursor();
|
|
64
|
-
this.byId.delete(snapshotId);
|
|
65
|
-
this.byId.set(snapshotId, entry);
|
|
66
|
-
return {
|
|
67
|
-
items: entry.items,
|
|
68
|
-
metadata: entry.metadata,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
clear() {
|
|
72
|
-
this.byId.clear();
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
//# sourceMappingURL=page-store.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"page-store.js","sourceRoot":"","sources":["../../src/core/page-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,qBAAqB,GAAG,EAAE,CAAC;AACjC,MAAM,cAAc,GAAG,EAAE,GAAG,IAAI,CAAC;AAoBjC;;;;GAIG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,OAAO,CAChB,SAAS,CAAC,aAAa,EACvB,0DAA0D,CAC3D,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,OAAO,iBAAiB;IACX,IAAI,GAAG,IAAI,GAAG,EAA8B,CAAC;IAC7C,YAAY,CAAS;IACrB,KAAK,CAAS;IACd,GAAG,CAAe;IAEnC,YAAY,UAAoC,EAAE;QAChD,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,qBAAqB,CAAC;QAClE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,cAAc,CAAC;QAC7C,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACrC,CAAC;IAEO,YAAY;QAClB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,KAAK,CAAC,SAAS,IAAI,GAAG;gBAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,MAAM,CAAC,MAA2E;QAChF,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,MAAM,UAAU,GAAG,UAAU,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE;YACxB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK;SACnC,CAAC,CAAC;QACH,wEAAwE;QACxE,iDAAiD;QACjD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;YACvC,IAAI,MAAM,CAAC,IAAI;gBAAE,MAAM;YACvB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,IAAI,CAAmB,UAAkB,EAAE,QAAgB;QACzD,IAAI,CAAC,YAAY,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACxC,IAAI,KAAK,EAAE,QAAQ,KAAK,QAAQ;YAAE,MAAM,aAAa,EAAE,CAAC;QACxD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC7B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QACjC,OAAO;YACL,KAAK,EAAE,KAAK,CAAC,KAAqB;YAClC,QAAQ,EAAE,KAAK,CAAC,QAAa;SAC9B,CAAC;IACJ,CAAC;IAED,KAAK;QACH,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;CACF","sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { ErrorCode, FsError } from './errors.js';\n\nconst DEFAULT_MAX_SNAPSHOTS = 32;\nconst DEFAULT_TTL_MS = 60 * 1000;\n\ninterface StoredPageSnapshot {\n readonly queryKey: string;\n readonly items: readonly unknown[];\n readonly metadata: unknown;\n readonly expiresAt: number;\n}\n\nexport interface PageSnapshot<T = unknown, M = unknown> {\n readonly items: readonly T[];\n readonly metadata: M;\n}\n\nexport interface PageSnapshotStoreOptions {\n readonly maxSnapshots?: number;\n readonly ttlMs?: number;\n readonly now?: () => number;\n}\n\n/**\n * The one cursor rejection: a cursor whose snapshot expired, was evicted, was\n * already consumed past its end, or belongs to a different query. Every case\n * has the same remedy, so they share one message.\n */\nexport function invalidCursor(): FsError {\n return new FsError(\n ErrorCode.INVALID_INPUT,\n 'Invalid cursor. Request the first page without a cursor.',\n );\n}\n\n/**\n * Short-lived snapshots of a completed query's full result set, so later pages\n * slice a stored array instead of re-scanning and re-sorting the filesystem.\n *\n * ponytail: bounded by snapshot count and TTL, not by bytes — 32 x 20,000\n * `list` entries or 32 x 10,000 `search_text` matches, each match retaining up\n * to 20 more line strings at `context: 10`, order of a few hundred MB held for\n * 60s, and the HTTP leg shares one store so any caller can drive it. If that\n * shows up as memory pressure, meter bytes the way `ResourceStore` does.\n */\nexport class PageSnapshotStore {\n private readonly byId = new Map<string, StoredPageSnapshot>();\n private readonly maxSnapshots: number;\n private readonly ttlMs: number;\n private readonly now: () => number;\n\n constructor(options: PageSnapshotStoreOptions = {}) {\n this.maxSnapshots = options.maxSnapshots ?? DEFAULT_MAX_SNAPSHOTS;\n this.ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;\n this.now = options.now ?? Date.now;\n }\n\n private pruneExpired(): void {\n const now = this.now();\n for (const [snapshotId, entry] of this.byId) {\n if (entry.expiresAt <= now) this.byId.delete(snapshotId);\n }\n }\n\n create(params: { queryKey: string; items: readonly unknown[]; metadata?: unknown }): string {\n this.pruneExpired();\n const snapshotId = randomUUID();\n this.byId.set(snapshotId, {\n queryKey: params.queryKey,\n items: params.items,\n metadata: params.metadata,\n expiresAt: this.now() + this.ttlMs,\n });\n // Oldest first: Map keeps insertion order and `read` re-inserts, so the\n // first key is the least recently used snapshot.\n while (this.byId.size > this.maxSnapshots) {\n const oldest = this.byId.keys().next();\n if (oldest.done) break;\n this.byId.delete(oldest.value);\n }\n return snapshotId;\n }\n\n read<T, M = undefined>(snapshotId: string, queryKey: string): PageSnapshot<T, M> {\n this.pruneExpired();\n const entry = this.byId.get(snapshotId);\n if (entry?.queryKey !== queryKey) throw invalidCursor();\n this.byId.delete(snapshotId);\n this.byId.set(snapshotId, entry);\n return {\n items: entry.items as readonly T[],\n metadata: entry.metadata as M,\n };\n }\n\n clear(): void {\n this.byId.clear();\n }\n}\n"]}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Minimal shared primitives with no intra-package dependencies.
|
|
3
|
-
* Kept separate to avoid import cycles between observability.ts and util.ts.
|
|
4
|
-
*/
|
|
5
|
-
/** The four filesystem entry types; published as the `FileType` schema. */
|
|
6
|
-
export declare const ENTRY_TYPES: readonly ["file", "directory", "symlink", "other"];
|
|
7
|
-
export type EntryType = (typeof ENTRY_TYPES)[number];
|
|
8
|
-
/** The three predicates both `Dirent` and `Stats` expose - all `resolveEntryType` needs. */
|
|
9
|
-
export interface DirentLike {
|
|
10
|
-
isDirectory(): boolean;
|
|
11
|
-
isFile(): boolean;
|
|
12
|
-
isSymbolicLink(): boolean;
|
|
13
|
-
}
|
|
14
|
-
export declare function resolveEntryType(dirent: DirentLike): EntryType;
|
|
15
|
-
/**
|
|
16
|
-
* Warn once per (setting, value) that a configured value was rejected, and say
|
|
17
|
-
* what was used instead. console.error, not Logger: this module stays
|
|
18
|
-
* dependency-free to avoid import cycles, and a startup misconfiguration is
|
|
19
|
-
* worth printing even when the operator asked for errors only.
|
|
20
|
-
*/
|
|
21
|
-
export declare function warnInvalidSetting(name: string, value: string, expected: string, fallback: string | number | boolean): void;
|
|
22
|
-
/**
|
|
23
|
-
* Parse a boolean env flag: `true`/`1` enable, `false`/`0`/empty disable.
|
|
24
|
-
* Any other value warns once per var (when `name` is given) and reads as
|
|
25
|
-
* false, so a typo like `FS_ALLOW_SENSITIVE=yes` is never silent.
|
|
26
|
-
*/
|
|
27
|
-
export declare function parseTrueEnvFlag(value: string | undefined, name?: string): boolean;
|
|
28
|
-
export declare function escapeRegexLiteral(str: string): string;
|
|
29
|
-
export declare function splitDirList(val: string | undefined): string[];
|
|
30
|
-
export declare const IS_WINDOWS: boolean;
|
|
31
|
-
export declare const isSlash: (code: number) => boolean;
|
|
32
|
-
export declare const isAlpha: (code: number) => boolean;
|
|
33
|
-
export declare const toPosixPath: (value: string) => string;
|
|
34
|
-
//# sourceMappingURL=primitives.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/core/primitives.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,2EAA2E;AAC3E,eAAO,MAAM,WAAW,oDAAqD,CAAC;AAC9E,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,4FAA4F;AAC5F,MAAM,WAAW,UAAU;IACzB,WAAW,IAAI,OAAO,CAAC;IACvB,MAAM,IAAI,OAAO,CAAC;IAClB,cAAc,IAAI,OAAO,CAAC;CAC3B;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,CAK9D;AAID;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAClC,IAAI,CAON;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAQlF;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CAM9D;AAID,eAAO,MAAM,UAAU,SAA+B,CAAC;AAEvD,eAAO,MAAM,OAAO,GAAI,MAAM,MAAM,KAAG,OAAqC,CAAC;AAE7E,eAAO,MAAM,OAAO,GAAI,MAAM,MAAM,KAAG,OACoB,CAAC;AAE5D,eAAO,MAAM,WAAW,GAAI,OAAO,MAAM,KAAG,MAAqC,CAAC"}
|
package/dist/core/primitives.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { delimiter } from 'node:path';
|
|
2
|
-
/**
|
|
3
|
-
* Minimal shared primitives with no intra-package dependencies.
|
|
4
|
-
* Kept separate to avoid import cycles between observability.ts and util.ts.
|
|
5
|
-
*/
|
|
6
|
-
/** The four filesystem entry types; published as the `FileType` schema. */
|
|
7
|
-
export const ENTRY_TYPES = ['file', 'directory', 'symlink', 'other'];
|
|
8
|
-
export function resolveEntryType(dirent) {
|
|
9
|
-
if (dirent.isDirectory())
|
|
10
|
-
return 'directory';
|
|
11
|
-
if (dirent.isFile())
|
|
12
|
-
return 'file';
|
|
13
|
-
if (dirent.isSymbolicLink())
|
|
14
|
-
return 'symlink';
|
|
15
|
-
return 'other';
|
|
16
|
-
}
|
|
17
|
-
const warnedSettings = new Set();
|
|
18
|
-
/**
|
|
19
|
-
* Warn once per (setting, value) that a configured value was rejected, and say
|
|
20
|
-
* what was used instead. console.error, not Logger: this module stays
|
|
21
|
-
* dependency-free to avoid import cycles, and a startup misconfiguration is
|
|
22
|
-
* worth printing even when the operator asked for errors only.
|
|
23
|
-
*/
|
|
24
|
-
export function warnInvalidSetting(name, value, expected, fallback) {
|
|
25
|
-
const key = `${name}:${value}`;
|
|
26
|
-
if (warnedSettings.has(key))
|
|
27
|
-
return;
|
|
28
|
-
warnedSettings.add(key);
|
|
29
|
-
console.error(`[warning] Invalid ${name} value: ${value} (must be ${expected}). Using default: ${String(fallback)}`);
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Parse a boolean env flag: `true`/`1` enable, `false`/`0`/empty disable.
|
|
33
|
-
* Any other value warns once per var (when `name` is given) and reads as
|
|
34
|
-
* false, so a typo like `FS_ALLOW_SENSITIVE=yes` is never silent.
|
|
35
|
-
*/
|
|
36
|
-
export function parseTrueEnvFlag(value, name) {
|
|
37
|
-
if (value === undefined)
|
|
38
|
-
return false;
|
|
39
|
-
const trimmed = value.trim().toLowerCase();
|
|
40
|
-
if (trimmed === 'true' || trimmed === '1')
|
|
41
|
-
return true;
|
|
42
|
-
if (name && trimmed !== '' && trimmed !== 'false' && trimmed !== '0') {
|
|
43
|
-
warnInvalidSetting(name, value, '"true" or "1"', false);
|
|
44
|
-
}
|
|
45
|
-
return false;
|
|
46
|
-
}
|
|
47
|
-
export function escapeRegexLiteral(str) {
|
|
48
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
49
|
-
}
|
|
50
|
-
export function splitDirList(val) {
|
|
51
|
-
if (!val)
|
|
52
|
-
return [];
|
|
53
|
-
return val
|
|
54
|
-
.split(delimiter)
|
|
55
|
-
.map((p) => p.trim())
|
|
56
|
-
.filter((p) => p.length > 0);
|
|
57
|
-
}
|
|
58
|
-
// ─── Path primitives (moved from path.ts to break the path↔sensitive cycle) ──
|
|
59
|
-
export const IS_WINDOWS = process.platform === 'win32';
|
|
60
|
-
export const isSlash = (code) => code === 47 || code === 92;
|
|
61
|
-
export const isAlpha = (code) => (code >= 65 && code <= 90) || (code >= 97 && code <= 122);
|
|
62
|
-
export const toPosixPath = (value) => value.replaceAll('\\', '/');
|
|
63
|
-
//# sourceMappingURL=primitives.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"primitives.js","sourceRoot":"","sources":["../../src/core/primitives.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC;;;GAGG;AAEH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,CAAU,CAAC;AAU9E,MAAM,UAAU,gBAAgB,CAAC,MAAkB;IACjD,IAAI,MAAM,CAAC,WAAW,EAAE;QAAE,OAAO,WAAW,CAAC;IAC7C,IAAI,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,MAAM,CAAC;IACnC,IAAI,MAAM,CAAC,cAAc,EAAE;QAAE,OAAO,SAAS,CAAC;IAC9C,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,cAAc,GAAG,IAAI,GAAG,EAAU,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAY,EACZ,KAAa,EACb,QAAgB,EAChB,QAAmC;IAEnC,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC;IAC/B,IAAI,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO;IACpC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACxB,OAAO,CAAC,KAAK,CACX,qBAAqB,IAAI,WAAW,KAAK,aAAa,QAAQ,qBAAqB,MAAM,CAAC,QAAQ,CAAC,EAAE,CACtG,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAyB,EAAE,IAAa;IACvE,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IACtC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IACvD,IAAI,IAAI,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,GAAG,EAAE,CAAC;QACrE,kBAAkB,CAAC,IAAI,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,OAAO,GAAG,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAuB;IAClD,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,OAAO,GAAG;SACP,KAAK,CAAC,SAAS,CAAC;SAChB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACjC,CAAC;AAED,gFAAgF;AAEhF,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC;AAEvD,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,EAAE,CAAC;AAE7E,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,IAAY,EAAW,EAAE,CAC/C,CAAC,IAAI,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,IAAI,IAAI,IAAI,GAAG,CAAC,CAAC;AAE5D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC","sourcesContent":["import { delimiter } from 'node:path';\n\n/**\n * Minimal shared primitives with no intra-package dependencies.\n * Kept separate to avoid import cycles between observability.ts and util.ts.\n */\n\n/** The four filesystem entry types; published as the `FileType` schema. */\nexport const ENTRY_TYPES = ['file', 'directory', 'symlink', 'other'] as const;\nexport type EntryType = (typeof ENTRY_TYPES)[number];\n\n/** The three predicates both `Dirent` and `Stats` expose - all `resolveEntryType` needs. */\nexport interface DirentLike {\n isDirectory(): boolean;\n isFile(): boolean;\n isSymbolicLink(): boolean;\n}\n\nexport function resolveEntryType(dirent: DirentLike): EntryType {\n if (dirent.isDirectory()) return 'directory';\n if (dirent.isFile()) return 'file';\n if (dirent.isSymbolicLink()) return 'symlink';\n return 'other';\n}\n\nconst warnedSettings = new Set<string>();\n\n/**\n * Warn once per (setting, value) that a configured value was rejected, and say\n * what was used instead. console.error, not Logger: this module stays\n * dependency-free to avoid import cycles, and a startup misconfiguration is\n * worth printing even when the operator asked for errors only.\n */\nexport function warnInvalidSetting(\n name: string,\n value: string,\n expected: string,\n fallback: string | number | boolean,\n): void {\n const key = `${name}:${value}`;\n if (warnedSettings.has(key)) return;\n warnedSettings.add(key);\n console.error(\n `[warning] Invalid ${name} value: ${value} (must be ${expected}). Using default: ${String(fallback)}`,\n );\n}\n\n/**\n * Parse a boolean env flag: `true`/`1` enable, `false`/`0`/empty disable.\n * Any other value warns once per var (when `name` is given) and reads as\n * false, so a typo like `FS_ALLOW_SENSITIVE=yes` is never silent.\n */\nexport function parseTrueEnvFlag(value: string | undefined, name?: string): boolean {\n if (value === undefined) return false;\n const trimmed = value.trim().toLowerCase();\n if (trimmed === 'true' || trimmed === '1') return true;\n if (name && trimmed !== '' && trimmed !== 'false' && trimmed !== '0') {\n warnInvalidSetting(name, value, '\"true\" or \"1\"', false);\n }\n return false;\n}\n\nexport function escapeRegexLiteral(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function splitDirList(val: string | undefined): string[] {\n if (!val) return [];\n return val\n .split(delimiter)\n .map((p) => p.trim())\n .filter((p) => p.length > 0);\n}\n\n// ─── Path primitives (moved from path.ts to break the path↔sensitive cycle) ──\n\nexport const IS_WINDOWS = process.platform === 'win32';\n\nexport const isSlash = (code: number): boolean => code === 47 || code === 92;\n\nexport const isAlpha = (code: number): boolean =>\n (code >= 65 && code <= 90) || (code >= 97 && code <= 122);\n\nexport const toPosixPath = (value: string): string => value.replaceAll('\\\\', '/');\n"]}
|