seekstone 0.17.2 → 0.19.0

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/semantic/model-manifest.ts","../src/semantic/config.ts","../src/semantic/fetch-model.ts","../src/index.ts","../src/audit.ts","../src/log.ts","../src/cli-args.ts","../src/tools/append_note.ts","../../core/src/frontmatter.ts","../src/atomic-write.ts","../src/content-hash.ts","../src/journal.ts","../src/policy.ts","../src/vault-path.ts","../../core/src/extract.ts","../src/tools/context_pack.ts","../src/index/excerpt.ts","../src/index/resolve.ts","../src/tools/search.ts","../src/semantic/excerpt.ts","../src/semantic/route.ts","../src/tools/create_note.ts","../src/index/doc.ts","../src/tools/delete_note.ts","../src/index/backlinks.ts","../src/tools/get_backlinks.ts","../src/tools/get_links.ts","../src/tools/list_notes.ts","../src/tools/list_tags.ts","../src/tools/list_writes.ts","../src/tools/move_note.ts","../src/tools/rewrite_links.ts","../src/tools/outline_note.ts","../../core/src/outline.ts","../src/tools/patch_frontmatter.ts","../src/tools/patch_note.ts","../src/tools/periodic_note.ts","../src/tools/query_notes.ts","../src/tools/read_note.ts","../src/tools/rename_heading.ts","../src/tools/replace_in_note.ts","../src/tools/undo_write.ts","../src/dispatch.ts","../src/index/build.ts","../../core/src/walk.ts","../src/init.ts","../src/process-guards.ts","../../core/src/embed/chunk.ts","../../core/src/embed/maxsim.ts","../../core/src/embed/model2vec.ts","../../core/src/embed/safetensors.ts","../../core/src/embed/tokenizer.ts","../../core/src/embed/pooling.ts","../../core/src/embed/types.ts","../src/semantic/cache.ts","../src/semantic/state.ts","../src/semantic/rerank.ts","../src/semantic/store.ts","../src/tool-list.ts","../src/watcher.ts"],"sourcesContent":["/**\n * Pinned download manifests for the supported embedding models. Used ONLY by\n * the `seekstone fetch-model` subcommand — an explicit, out-of-band CLI\n * action. The MCP server itself never touches the network (no-network.test.ts).\n *\n * Hashes mirror packages/harness/fixtures/models/manifest.json (the harness\n * evals run against the same files).\n */\n\nexport interface ModelFile {\n name: string;\n url: string;\n sha256: string;\n bytes: number;\n}\n\nexport interface ModelManifest {\n id: string;\n license: string;\n /** Embedding width — the cache is keyed on it so models never mix. */\n dim: number;\n files: ModelFile[];\n}\n\nfunction hfFiles(\n repo: string,\n hashes: { safetensors: [string, number]; tokenizer: [string, number]; config: [string, number] },\n): ModelFile[] {\n const base = `https://huggingface.co/minishlab/${repo}/resolve/main`;\n return [\n {\n name: 'model.safetensors',\n url: `${base}/model.safetensors`,\n sha256: hashes.safetensors[0],\n bytes: hashes.safetensors[1],\n },\n {\n name: 'tokenizer.json',\n url: `${base}/tokenizer.json`,\n sha256: hashes.tokenizer[0],\n bytes: hashes.tokenizer[1],\n },\n {\n name: 'config.json',\n url: `${base}/config.json`,\n sha256: hashes.config[0],\n bytes: hashes.config[1],\n },\n ];\n}\n\n/** The shipped default: ~30 MB, 256-dim, warm p95 ≈ 14 ms @ 10k notes. */\nexport const DEFAULT_MODEL: ModelManifest = {\n id: 'potion-base-8M',\n license: 'MIT (https://huggingface.co/minishlab/potion-base-8M)',\n dim: 256,\n files: hfFiles('potion-base-8M', {\n safetensors: ['f65d0f325faadc1e121c319e2faa41170d3fa07d8c89abd48ca5358d9a223de2', 30236760],\n tokenizer: ['e67e803f624fb4d67dea1c730d06e1067e1b14d830e2c2202569e3ef0f70bb50', 683666],\n config: ['2a6ac0e9aaa356a68a5688070db78fc3a464fefe85d2f06a1905ce3718687553', 202],\n }),\n};\n\n/**\n * Opt-in bigger model (SHA-310): ~129 MB, 512-dim, +13 pts hit@5 on the\n * semantic golden subset at roughly 2× the query latency. Same Model2Vec\n * inference path — the loader derives vocab size from tokenizer.json.\n */\nexport const RETRIEVAL_32M_MODEL: ModelManifest = {\n id: 'potion-retrieval-32M',\n license: 'MIT (https://huggingface.co/minishlab/potion-retrieval-32M)',\n dim: 512,\n files: hfFiles('potion-retrieval-32M', {\n safetensors: ['07609e5bd33aad37900b3fd62f4ec96f6daec88ca4d46b9d8b928bfababf6ea0', 129210456],\n tokenizer: ['7d75cbc54318138807c401b0f0c9721117c628b39de8e8e0edb6cb17e0ee7d18', 1493150],\n config: ['63c00d90824c832c04ec1d02b6a983fb90489bf049f29fbff15ba481b8a432ee', 202],\n }),\n};\n\n/** Every model `fetch-model --model <id>` / `SEEKSTONE_SEMANTIC_MODEL` accepts. */\nexport const MODELS: readonly ModelManifest[] = [DEFAULT_MODEL, RETRIEVAL_32M_MODEL];\n\nexport const MODEL_IDS: readonly string[] = MODELS.map((m) => m.id);\n\nexport function findModel(id: string): ModelManifest | undefined {\n return MODELS.find((m) => m.id === id);\n}\n","import { join } from 'node:path';\nimport { DEFAULT_MODEL, findModel, MODEL_IDS, type ModelManifest } from './model-manifest.js';\n\n/**\n * Semantic-search configuration, resolved from env at boot.\n *\n * - `SEEKSTONE_SEMANTIC=1` enables the feature (off by default).\n * - `SEEKSTONE_SEMANTIC_MODEL` picks which fetched model to load\n * (`potion-base-8M` default, or the opt-in `potion-retrieval-32M`).\n * - `SEEKSTONE_MODEL_PATH` overrides where the Model2Vec model dir lives;\n * default is `<cache>/models/<model id>`, where `seekstone fetch-model`\n * puts it.\n * - `SEEKSTONE_CACHE_DIR` overrides the cache root (default `~/.cache/seekstone`),\n * which holds both downloaded models and per-vault embedding caches.\n *\n * The server itself NEVER downloads anything — the model is fetched\n * out-of-band by the `fetch-model` subcommand, preserving the zero-network\n * guarantee (no-network.test.ts).\n */\n\nexport const DEFAULT_MODEL_ID = DEFAULT_MODEL.id;\n\nexport interface SemanticConfig {\n /** Manifest id of the selected model (drives the default dir + error hints). */\n modelId: string;\n modelDir: string;\n cacheDir: string;\n}\n\nexport function defaultCacheDir(env: NodeJS.ProcessEnv, homedir: string): string {\n return env.SEEKSTONE_CACHE_DIR || join(homedir, '.cache', 'seekstone');\n}\n\n/**\n * Validate `SEEKSTONE_SEMANTIC_MODEL` (or the given override) against the\n * pinned manifests. Throws a config error naming the accepted values so a\n * typo fails loudly at boot / fetch time instead of silently loading 8M.\n */\nexport function resolveModel(raw: string | undefined): ModelManifest {\n const id = raw?.trim();\n if (!id) return DEFAULT_MODEL;\n const manifest = findModel(id);\n if (!manifest) {\n throw new Error(\n `SEEKSTONE_SEMANTIC_MODEL: unknown model \"${id}\" — expected one of ${MODEL_IDS.join(', ')}`,\n );\n }\n return manifest;\n}\n\nexport function resolveModelId(raw: string | undefined): string {\n return resolveModel(raw).id;\n}\n\n/** The `fetch-model` command that installs the given model. */\nexport function fetchCommandFor(modelId: string): string {\n return modelId === DEFAULT_MODEL_ID\n ? 'npx -y seekstone fetch-model'\n : `npx -y seekstone fetch-model --model ${modelId}`;\n}\n\nexport function resolveSemanticConfig(\n env: NodeJS.ProcessEnv,\n homedir: string,\n): SemanticConfig | undefined {\n if (env.SEEKSTONE_SEMANTIC !== '1') return undefined;\n const modelId = resolveModelId(env.SEEKSTONE_SEMANTIC_MODEL);\n const cacheDir = defaultCacheDir(env, homedir);\n const modelDir = env.SEEKSTONE_MODEL_PATH || join(cacheDir, 'models', modelId);\n return { modelId, modelDir, cacheDir };\n}\n","import { createHash } from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { DEFAULT_MODEL_ID, defaultCacheDir, resolveModel } from './config.js';\nimport { MODEL_IDS, type ModelManifest } from './model-manifest.js';\n\n/**\n * `seekstone fetch-model` — the explicit, out-of-band download of the\n * embedding model that semantic search needs. This is a CLI subcommand that\n * exits before any MCP serving starts; the running server never fetches\n * (no-network.test.ts is the guarantee). Files are verified against pinned\n * SHA-256 hashes; already-present matching files are skipped.\n */\n\nexport interface FetchModelResult {\n output: string[];\n exitCode: number;\n}\n\nexport interface FetchModelDeps {\n env: NodeJS.ProcessEnv;\n homedir: string;\n /** Arguments after the `fetch-model` subcommand (`--model <id>`). */\n argv?: readonly string[];\n /** Test seam: bypass model selection entirely. */\n manifest?: ModelManifest;\n fetchFn?: typeof fetch;\n}\n\n/**\n * Pick the manifest: `--model <id>` wins, then `SEEKSTONE_SEMANTIC_MODEL`, then\n * the default — so `fetch-model` with no flags installs whatever the server\n * would try to load.\n */\nexport function selectManifest(argv: readonly string[], env: NodeJS.ProcessEnv): ModelManifest {\n let requested: string | undefined;\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (arg === '--model') {\n requested = argv[i + 1];\n if (!requested || requested.startsWith('--')) {\n throw new Error(`--model needs a value: one of ${MODEL_IDS.join(', ')}`);\n }\n i++;\n } else if (arg?.startsWith('--model=')) {\n requested = arg.slice('--model='.length);\n } else {\n throw new Error(`fetch-model: unknown argument \"${arg}\" (usage: fetch-model [--model <id>])`);\n }\n }\n return resolveModel(requested ?? env.SEEKSTONE_SEMANTIC_MODEL);\n}\n\nexport async function runFetchModel(deps: FetchModelDeps): Promise<FetchModelResult> {\n const output: string[] = [];\n let manifest: ModelManifest;\n try {\n manifest = deps.manifest ?? selectManifest(deps.argv ?? [], deps.env);\n } catch (err) {\n output.push(`✗ ${err instanceof Error ? err.message : String(err)}`);\n return { output, exitCode: 1 };\n }\n const fetchFn = deps.fetchFn ?? fetch;\n const destDir =\n deps.env.SEEKSTONE_MODEL_PATH ||\n join(defaultCacheDir(deps.env, deps.homedir), 'models', manifest.id);\n output.push(`fetch-model: ${manifest.id} → ${destDir}`);\n try {\n await mkdir(destDir, { recursive: true });\n let fetched = 0;\n let skipped = 0;\n for (const file of manifest.files) {\n const dest = join(destDir, file.name);\n if (existsSync(dest) && sha256(await readFile(dest)) === file.sha256) {\n skipped++;\n continue;\n }\n output.push(`fetching ${file.name} (${file.bytes} bytes)…`);\n const res = await fetchFn(file.url);\n if (!res.ok) throw new Error(`fetch ${file.url} failed: ${res.status}`);\n const buf = Buffer.from(await res.arrayBuffer());\n const got = sha256(buf);\n if (got !== file.sha256) {\n throw new Error(`checksum mismatch for ${file.name}: expected ${file.sha256}, got ${got}`);\n }\n await writeFile(dest, buf);\n fetched++;\n }\n output.push(`✓ ${manifest.id}: ${fetched} fetched, ${skipped} already present (verified).`);\n output.push(\n manifest.id === DEFAULT_MODEL_ID\n ? 'Enable semantic search with SEEKSTONE_SEMANTIC=1 in your MCP server config, then restart the session.'\n : `Enable it with SEEKSTONE_SEMANTIC=1 and SEEKSTONE_SEMANTIC_MODEL=${manifest.id} in your MCP server config, then restart the session.`,\n );\n return { output, exitCode: 0 };\n } catch (err) {\n output.push(`✗ ${err instanceof Error ? err.message : String(err)}`);\n return { output, exitCode: 1 };\n }\n}\n\nfunction sha256(buf: Buffer): string {\n return createHash('sha256').update(buf).digest('hex');\n}\n","#!/usr/bin/env node\nimport { homedir } from 'node:os';\nimport { resolve } from 'node:path';\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n type CallToolResult,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { AuditLog, resolveAuditConfig } from './audit.js';\nimport { helpText, initHelpText, parseCliIntent } from './cli-args.js';\nimport type { ServerContext } from './context.js';\nimport { dispatch } from './dispatch.js';\nimport { buildIndex } from './index/build.js';\nimport { parseInitArgs, runInit } from './init.js';\nimport { Journal, resolveJournalConfig } from './journal.js';\nimport { createLogger } from './log.js';\nimport { parseWritePolicy } from './policy.js';\nimport { installProcessGuards } from './process-guards.js';\nimport { resolveSemanticConfig } from './semantic/config.js';\nimport { Semantic } from './semantic/state.js';\nimport { visibleTools } from './tool-list.js';\nimport { startWatcher } from './watcher.js';\n\n// Inlined at build time by tsup (see tsup.config.ts); falls back in tsx dev.\ndeclare const __SEEKSTONE_VERSION__: string;\nconst VERSION = typeof __SEEKSTONE_VERSION__ === 'string' ? __SEEKSTONE_VERSION__ : '0.0.0-dev';\n\n// CLI subcommands / flags exit before any server setup, printing to stdout\n// (these are explicit invocations, not the MCP stdio session).\nconst intent = parseCliIntent(process.argv.slice(2));\nif (intent === 'version') {\n process.stdout.write(`${VERSION}\\n`);\n process.exit(0);\n}\nif (intent === 'help') {\n process.stdout.write(`${helpText(VERSION)}\\n`);\n process.exit(0);\n}\nif (intent === 'init-help') {\n process.stdout.write(`${initHelpText(VERSION)}\\n`);\n process.exit(0);\n}\nif (intent === 'init') {\n const result = await runInit(parseInitArgs(process.argv.slice(3)), {\n env: process.env,\n platform: process.platform,\n timestamp: new Date().toISOString().replace(/[:.]/g, '-'),\n cwd: process.cwd(),\n });\n process.stdout.write(`${result.output.join('\\n')}\\n`);\n process.exit(result.exitCode);\n}\nif (intent === 'fetch-model') {\n const { runFetchModel } = await import('./semantic/fetch-model.js');\n const { homedir } = await import('node:os');\n const result = await runFetchModel({\n env: process.env,\n homedir: homedir(),\n argv: process.argv.slice(3),\n });\n process.stdout.write(`${result.output.join('\\n')}\\n`);\n process.exit(result.exitCode);\n}\n\nconst log = createLogger();\n\n// Long-lived stdio session: keep the server alive (and its in-memory index)\n// on a stray unhandled rejection rather than crashing the user's session.\ninstallProcessGuards(log);\n\nconst rawVaultRoot = process.env.SEEKSTONE_VAULT;\nif (!rawVaultRoot) {\n log.error('SEEKSTONE_VAULT env var is required');\n process.exit(1);\n}\n// Normalize once so the containment guard (vault-path.ts) compares against a\n// canonical absolute path — a relative or trailing-slash SEEKSTONE_VAULT must\n// not weaken the prefix boundary.\nconst vaultRoot = resolve(rawVaultRoot);\n\nconst policy = parseWritePolicy(process.env);\nif (policy.readOnly) log.info('read-only mode', { env: 'SEEKSTONE_READ_ONLY' });\nif (policy.writeGlobs) log.info('write paths scoped', { globs: policy.writeGlobs });\n\nlog.info('building index', { vault: vaultRoot });\nconst { index, notes, backlinks, buildMs } = await buildIndex(vaultRoot);\nlog.info('index ready', { notes: notes.size, buildMs });\n\nconst ctx: ServerContext = { vaultRoot, index, notes, backlinks, policy };\n\n// Write journal: pre-images under <vault>/.seekstone/history so every write\n// is reversible via undo_write. Read-only mode never writes, so it never\n// journals either — the journal is only opened when writes are possible.\nconst journalCfg = resolveJournalConfig(process.env);\nif (journalCfg && !policy.readOnly) {\n try {\n ctx.journal = await Journal.open(vaultRoot, journalCfg, { log });\n log.info('write journal ready', {\n entries: ctx.journal.list({ limit: 1 }).total,\n maxBytes: journalCfg.maxBytes,\n });\n } catch (err) {\n // A journal that cannot be opened means writes cannot be made reversible;\n // fail loudly rather than silently run without undo.\n log.error(`write journal failed to open: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n} else if (!journalCfg) {\n log.info('write journal disabled', { env: 'SEEKSTONE_HISTORY' });\n}\n\n// Audit log: one JSONL record per write-tool call. Opt-in; an unwritable\n// path fails boot because an unauditable write must never pass silently.\nconst auditCfg = resolveAuditConfig(process.env);\nif (auditCfg) {\n try {\n ctx.audit = AuditLog.open(auditCfg);\n log.info('audit log ready', { file: auditCfg.path, maxBytes: auditCfg.maxBytes });\n } catch (err) {\n log.error(\n `audit log ${auditCfg.path} is not writable: ${err instanceof Error ? err.message : String(err)}`,\n );\n process.exit(1);\n }\n}\n\nconst semanticCfg = resolveSemanticConfig(process.env, homedir());\nif (semanticCfg) {\n try {\n // Model load is fast (~30 MB read); the index build continues in the\n // background — semantic queries report progress until it finishes.\n ctx.semantic = await Semantic.start(ctx, semanticCfg, { log });\n log.info('semantic search enabled', {\n model: ctx.semantic.embedder.id,\n dim: ctx.semantic.embedder.dim,\n notes: notes.size,\n });\n } catch (err) {\n // The user enabled the feature explicitly — a broken setup fails loudly.\n log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\nconst watcher = startWatcher(ctx, log);\n// Exit handlers must stay synchronous — kick off the close; nothing awaits it.\nprocess.on('exit', () => void watcher.stop());\n\nconst server = new Server({ name: 'seekstone', version: VERSION }, { capabilities: { tools: {} } });\n\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: visibleTools(ctx.policy),\n}));\n\nserver.setRequestHandler(CallToolRequestSchema, async (req): Promise<CallToolResult> => {\n const { name, arguments: args } = req.params;\n return dispatch(ctx, name, args, log);\n});\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\nlog.info('ready', { tools: visibleTools(ctx.policy).length, transport: 'stdio' });\n\nprocess.stderr.write(\n `seekstone: add to Claude Desktop:\\n${JSON.stringify(\n {\n mcpServers: {\n seekstone: {\n command: 'npx',\n args: ['-y', 'seekstone'],\n env: { SEEKSTONE_VAULT: vaultRoot },\n },\n },\n },\n null,\n 2,\n )}\\n`,\n);\n","import {\n appendFileSync,\n closeSync,\n fsyncSync,\n openSync,\n renameSync,\n statSync,\n writeSync,\n} from 'node:fs';\nimport { parseSize } from './log.js';\n\n/**\n * Structured audit log — an append-only JSONL trail of every write-tool\n * invocation, successful or refused. Opt-in via SEEKSTONE_AUDIT_FILE.\n *\n * One record per write call:\n *\n * { v: 1, ts, tool, outcome, durationMs, seq?, files: [{ path, hashBefore,\n * hashAfter }], ...opDetail, error? }\n *\n * `outcome` is `ok`, `hash_conflict`, `undo_conflict`, `policy_denied`, or\n * `error`. Hashes are the same sha-256 values `read_note` returns as\n * `contentHash`, so a user can verify a record against their vault. When the\n * write journal is on, `files` and `seq` come from the journal entry the call\n * committed (so the audit row indexes straight into `undo_write`); otherwise\n * only the after-hash from the tool result is known.\n *\n * Privacy: records carry paths, hashes, byte counts, and op metadata — never\n * note content, frontmatter values, or search queries. Safe to attach to a\n * bug report.\n *\n * Durability: each record is appended and fsync'd AFTER the vault write\n * commits (a crash loses at most the in-flight record; earlier records are\n * never touched). Rotation renames `<file>` → `<file>.1` when the next\n * record would exceed SEEKSTONE_AUDIT_MAX_SIZE (default 10 MB). If a record\n * cannot be written, the tool call is reported as failed with a structured\n * `audit_failed` error — an unauditable write does not pass silently, even\n * though the vault write itself has already landed.\n */\n\nexport type AuditOutcome = 'ok' | 'hash_conflict' | 'undo_conflict' | 'policy_denied' | 'error';\n\nexport interface AuditFile {\n path: string;\n /** sha-256 of the bytes before the call; null = did not exist; undefined = unknown (journal off). */\n hashBefore?: string | null;\n /** sha-256 of the bytes after the call; null = does not exist. */\n hashAfter: string | null;\n}\n\nexport interface AuditRecord {\n v: 1;\n ts: string;\n tool: string;\n outcome: AuditOutcome;\n durationMs: number;\n /** Journal seq of the entry this call committed (when the journal is on). */\n seq?: number;\n files?: AuditFile[];\n /** Which policy refused a `policy_denied` call. */\n policy?: 'read_only' | 'write_paths';\n /**\n * Error CODE for non-ok outcomes (`hash_conflict`, `heading_not_found`,\n * `not_found`, `exists`, `invalid_input`, …) — never the message: tool\n * messages can echo headings, patterns, or frontmatter keys, which are\n * content. The full message is in the server log (SEEKSTONE_LOG_FILE).\n */\n error?: string;\n /** Op-specific metadata from the tool result — counts, destinations, flags; never content. */\n [detail: string]: unknown;\n}\n\nconst DEFAULT_MAX_SIZE = 10 * 1e6;\n\nexport interface AuditConfig {\n path: string;\n maxBytes: number;\n}\n\n/** Undefined unless SEEKSTONE_AUDIT_FILE is set. */\nexport function resolveAuditConfig(\n env: Record<string, string | undefined>,\n): AuditConfig | undefined {\n const path = (env.SEEKSTONE_AUDIT_FILE ?? '').trim();\n if (path === '') return undefined;\n return { path, maxBytes: parseSize(env.SEEKSTONE_AUDIT_MAX_SIZE, DEFAULT_MAX_SIZE) };\n}\n\nexport class AuditLog {\n readonly path: string;\n private readonly maxBytes: number;\n private bytes: number;\n\n private constructor(path: string, maxBytes: number, bytes: number) {\n this.path = path;\n this.maxBytes = maxBytes;\n this.bytes = bytes;\n }\n\n /**\n * Open (create if missing) the audit file, verifying it is writable now so\n * an unwritable path fails at boot rather than on the first write.\n */\n static open(config: AuditConfig): AuditLog {\n let bytes = 0;\n try {\n bytes = statSync(config.path).size;\n } catch {\n bytes = 0;\n }\n appendFileSync(config.path, '');\n return new AuditLog(config.path, config.maxBytes, bytes);\n }\n\n /** Append one record durably. Throws if the append or fsync fails. */\n record(rec: AuditRecord): void {\n const line = `${JSON.stringify(rec)}\\n`;\n const len = Buffer.byteLength(line);\n if (this.bytes > 0 && this.bytes + len > this.maxBytes) {\n renameSync(this.path, `${this.path}.1`);\n this.bytes = 0;\n }\n const fd = openSync(this.path, 'a');\n try {\n writeSync(fd, line);\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n this.bytes += len;\n }\n}\n\n/**\n * Classify a thrown tool error into an audit outcome plus a content-free\n * error code. Structured errors are JSON strings with an `error` field\n * (their code is kept verbatim); policy refusals are plain messages from\n * policy.ts; everything else maps to a coarse code — the raw message is\n * deliberately NOT recorded because tool messages can quote note content\n * (available headings, regex patterns, frontmatter keys).\n */\nexport function classifyError(message: string): {\n outcome: AuditOutcome;\n policy?: AuditRecord['policy'];\n error: string;\n} {\n if (message.startsWith('{')) {\n try {\n const parsed = JSON.parse(message) as { error?: unknown };\n if (typeof parsed.error === 'string') {\n if (parsed.error === 'hash_conflict')\n return { outcome: 'hash_conflict', error: parsed.error };\n if (parsed.error === 'undo_conflict')\n return { outcome: 'undo_conflict', error: parsed.error };\n return { outcome: 'error', error: parsed.error };\n }\n } catch {\n /* not JSON after all — fall through */\n }\n }\n if (message.startsWith('Server is read-only')) {\n return { outcome: 'policy_denied', policy: 'read_only', error: 'read_only' };\n }\n if (message.startsWith('Write not permitted')) {\n return { outcome: 'policy_denied', policy: 'write_paths', error: 'write_paths' };\n }\n if (/ENOENT|not found/i.test(message)) return { outcome: 'error', error: 'not_found' };\n if (/already exists/i.test(message)) return { outcome: 'error', error: 'exists' };\n if (/^Invalid regex/.test(message)) return { outcome: 'error', error: 'invalid_regex' };\n if (/^Write-safety violation/.test(message))\n return { outcome: 'error', error: 'write_safety_violation' };\n if (/^\\[\\s*\\{/.test(message) || /invalid_type|Required|Expected|expected/.test(message)) {\n return { outcome: 'error', error: 'invalid_input' };\n }\n return { outcome: 'error', error: 'error' };\n}\n","import { appendFileSync, renameSync, statSync } from 'node:fs';\n\n/**\n * A tiny zero-dependency leveled logger for the MCP server.\n *\n * Two sinks, never stdout (stdout carries the JSON-RPC stdio transport):\n * - stderr: concise human-readable lines, always on (Claude Desktop captures it).\n * - file: JSON-lines, opt-in via SEEKSTONE_LOG_FILE, size-rotated.\n *\n * Privacy: callers pass metadata fields at info/warn/error and only attach note\n * content (bodies, frontmatter values, raw queries) at `debug`. The logger does\n * not inspect or redact fields — that contract lives at the call sites.\n *\n * Note: file writes use appendFileSync. File logging is opt-in and the per-line\n * cost is sub-millisecond, comfortably inside tool latency budgets; the default\n * (stderr-only) path does no disk I/O. An async write queue is a future option.\n */\n\nexport type LogLevel = 'error' | 'warn' | 'info' | 'debug';\n\nconst ORDER: readonly LogLevel[] = ['error', 'warn', 'info', 'debug'] as const;\nconst DEFAULT_MAX_SIZE = 5 * 1024 * 1024;\n\nexport interface Logger {\n readonly level: LogLevel;\n error(msg: string, fields?: Record<string, unknown>): void;\n warn(msg: string, fields?: Record<string, unknown>): void;\n info(msg: string, fields?: Record<string, unknown>): void;\n debug(msg: string, fields?: Record<string, unknown>): void;\n}\n\nexport interface LoggerOptions {\n /** Env to read SEEKSTONE_LOG_* from. Defaults to process.env. */\n env?: Record<string, string | undefined>;\n /** stderr sink — injectable for tests. Defaults to process.stderr. Never stdout. */\n stderr?: (line: string) => void;\n /** Clock — injectable for deterministic tests. */\n now?: () => Date;\n}\n\nfunction parseLevel(raw: string | undefined, onBad: (m: string) => void): LogLevel {\n if (raw === undefined || raw === '') return 'info';\n const v = raw.trim().toLowerCase();\n for (const lvl of ORDER) {\n if (lvl === v) return lvl;\n }\n onBad(`invalid SEEKSTONE_LOG_LEVEL=${JSON.stringify(raw)}; using \"info\"`);\n return 'info';\n}\n\n/** Parse a human size (`10mb`, `512kb`, `1.5gb`, bare bytes); falls back to `fallback`. */\nexport function parseSize(raw: string | undefined, fallback = DEFAULT_MAX_SIZE): number {\n if (raw === undefined) return fallback;\n const m = /^(\\d+(?:\\.\\d+)?)(b|kb|mb|gb)?$/i.exec(raw.trim());\n if (m === null) return fallback;\n const num = Number(m[1]);\n const unit = (m[2] ?? 'b').toLowerCase();\n const mult = unit === 'gb' ? 1e9 : unit === 'mb' ? 1e6 : unit === 'kb' ? 1e3 : 1;\n return Math.max(1, Math.floor(num * mult));\n}\n\nfunction fmtFields(fields: Record<string, unknown>): string {\n const parts: string[] = [];\n for (const [k, v] of Object.entries(fields)) {\n if (v === undefined) continue;\n parts.push(`${k}=${typeof v === 'string' ? v : JSON.stringify(v)}`);\n }\n return parts.length > 0 ? ` ${parts.join(' ')}` : '';\n}\n\nexport function createLogger(opts: LoggerOptions = {}): Logger {\n const env = opts.env ?? process.env;\n // Default sink is stderr — deliberately never process.stdout.\n const stderr = opts.stderr ?? ((line: string): void => void process.stderr.write(line));\n const now = opts.now ?? ((): Date => new Date());\n\n const level = parseLevel(env.SEEKSTONE_LOG_LEVEL, (m) => {\n stderr(`WARN ${now().toISOString()} ${m}\\n`);\n });\n const threshold = ORDER.indexOf(level);\n\n const filePath = env.SEEKSTONE_LOG_FILE;\n const maxSize = parseSize(env.SEEKSTONE_LOG_MAX_SIZE);\n let fileOk = false;\n let bytes = 0;\n if (filePath !== undefined && filePath !== '') {\n try {\n try {\n bytes = statSync(filePath).size;\n } catch {\n bytes = 0;\n }\n appendFileSync(filePath, ''); // verify writable / create\n fileOk = true;\n } catch (err) {\n const m = err instanceof Error ? err.message : String(err);\n stderr(\n `WARN ${now().toISOString()} cannot write log file ${filePath}: ${m}; file logging disabled\\n`,\n );\n }\n }\n\n function writeFile(record: Record<string, unknown>): void {\n if (!fileOk || filePath === undefined) return;\n const line = `${JSON.stringify(record)}\\n`;\n const len = Buffer.byteLength(line);\n try {\n if (bytes > 0 && bytes + len > maxSize) {\n renameSync(filePath, `${filePath}.1`);\n bytes = 0;\n }\n appendFileSync(filePath, line);\n bytes += len;\n } catch {\n fileOk = false; // stop trying; logging must never crash the request path\n }\n }\n\n function emit(lvl: LogLevel, msg: string, fields?: Record<string, unknown>): void {\n if (ORDER.indexOf(lvl) > threshold) return; // below threshold: do no work\n const ts = now().toISOString();\n const f = fields ?? {};\n stderr(`${lvl.toUpperCase().padEnd(5)} ${ts} ${msg}${fmtFields(f)}\\n`);\n writeFile({ t: ts, level: lvl, msg, ...f });\n }\n\n return {\n level,\n error: (m, f) => {\n emit('error', m, f);\n },\n warn: (m, f) => {\n emit('warn', m, f);\n },\n info: (m, f) => {\n emit('info', m, f);\n },\n debug: (m, f) => {\n emit('debug', m, f);\n },\n };\n}\n","/**\n * Tiny argument handling for the `seekstone` bin. Kept pure (no process exit,\n * no IO) so it can be unit-tested. The MCP server itself takes no arguments —\n * these are just the conventional `--version` / `--help` niceties expected of a\n * CLI installed via `npx`.\n */\n\nexport type CliIntent = 'version' | 'help' | 'init' | 'init-help' | 'fetch-model' | 'run';\n\nexport function parseCliIntent(argv: readonly string[]): CliIntent {\n // A subcommand, if present, is the first non-flag token. A help flag after\n // the subcommand asks for the subcommand's help, so it must be recognised\n // here — before the init run path — not swallowed by init's own arg parsing.\n if (argv[0] === 'init') {\n for (const arg of argv.slice(1)) {\n if (arg === '--help' || arg === '-h') return 'init-help';\n }\n return 'init';\n }\n if (argv[0] === 'fetch-model') return 'fetch-model';\n for (const arg of argv) {\n if (arg === '--version' || arg === '-v') return 'version';\n if (arg === '--help' || arg === '-h') return 'help';\n }\n return 'run';\n}\n\n// Shared between the top-level help and `seekstone init --help` so the two\n// can't drift apart.\nconst initOptionLines = ` --vault <path> Vault to use (auto-detected from Obsidian if omitted; fallback: $SEEKSTONE_VAULT)\n --client <name> desktop (default) | code | cursor | vscode\n --write Patch the client config in place (backs it up first)`;\n\nexport function helpText(version: string): string {\n return `seekstone ${version} — an Obsidian MCP server (filesystem-direct, low context-tax)\n\nSeekstone runs as a Model Context Protocol stdio server. It is normally\nlaunched by an MCP client (Claude Desktop, Claude Code, Cursor, …), not run by hand.\n\nUsage:\n seekstone Start the MCP server (reads from stdin/stdout)\n seekstone init Validate a vault and print/patch the client MCP config\n seekstone fetch-model Download the local embedding model for semantic search\n (--model potion-base-8M | potion-retrieval-32M)\n seekstone --version Print the version and exit\n seekstone --help Print this help and exit\n\n\"seekstone init\" options:\n${initOptionLines}\n\nRequired environment:\n SEEKSTONE_VAULT Absolute path to your Obsidian vault\n\nOptional environment:\n SEEKSTONE_LOG_LEVEL error | warn | info (default) | debug\n SEEKSTONE_LOG_FILE Absolute path; append JSON-line logs here\n SEEKSTONE_WATCH_POLL Set to 1 to poll for changes (network drives, WSL)\n SEEKSTONE_WATCH_POLL_INTERVAL Poll interval in ms (default 10000)\n SEEKSTONE_SEMANTIC Set to 1 to enable semantic search (needs fetch-model first)\n SEEKSTONE_SEMANTIC_MODEL potion-base-8M (default) | potion-retrieval-32M (bigger, more accurate)\n SEEKSTONE_MODEL_PATH Override the embedding-model directory\n SEEKSTONE_CACHE_DIR Override the cache root (default ~/.cache/seekstone)\n\nAdd to Claude Code:\n claude mcp add seekstone --env SEEKSTONE_VAULT=/path/to/vault -- npx -y seekstone\n\nDocs: https://github.com/shaqmughal/seekstone`;\n}\n\nexport function initHelpText(version: string): string {\n return `seekstone ${version} — seekstone init\n\nValidate an Obsidian vault and print (or, with --write, patch) the MCP config\nfor the chosen client (Claude Desktop, Claude Code, Cursor, VS Code).\n\nUsage:\n seekstone init [options]\n\nOptions:\n${initOptionLines}\n --help, -h Print this help and exit\n\nExamples:\n seekstone init\n seekstone init --vault \"/Users/you/Obsidian/My Vault\" --client code --write\n\nDocs: https://github.com/shaqmughal/seekstone`;\n}\n","import { readFile } from 'node:fs/promises';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { journalWrite } from '../journal.js';\nimport { assertWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const AppendNoteInput = z.object({\n path: z.string().describe('Vault-relative path to the note.'),\n content: z\n .string()\n .min(1)\n .describe(\n 'Text to append to the note body. Will be separated from existing content by a blank line.',\n ),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n ),\n});\nexport type AppendNoteInput = z.infer<typeof AppendNoteInput>;\n\nexport interface AppendNoteResult {\n path: string;\n bytesWritten: number;\n /** sha-256 (hex) of the new content — usable as prevHash for a chained edit. */\n contentHash: string;\n}\n\n/**\n * Append text to a note body without touching the frontmatter.\n *\n * The write contract:\n * - The frontmatter block (if any) is preserved byte-for-byte.\n * - A blank line is inserted before the appended content if the body\n * does not already end with one (keeps Obsidian's visual spacing).\n * - The file is written atomically (temp file + rename).\n */\nexport async function appendNote(\n ctx: ServerContext,\n input: AppendNoteInput,\n): Promise<AppendNoteResult> {\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n assertWritable(ctx.policy, input.path);\n\n const original = await readFile(absPath, 'utf8');\n if (input.prevHash !== undefined) assertHashMatch(original, input.prevHash, input.path);\n const fm = parseFrontmatter(original);\n\n // Ensure body ends with exactly one trailing newline before appending.\n const body = fm.body.endsWith('\\n') ? fm.body : `${fm.body}\\n`;\n const separator = body.endsWith('\\n\\n') ? '' : '\\n';\n const newBody = `${body}${separator}${input.content}`;\n\n // Reconstruct: original header (FM + delimiters) + new body.\n const header = original.slice(0, fm.bodyStart);\n const newContent = `${header}${newBody}`;\n\n await journalWrite(ctx, 'append_note', input.path, original, newContent);\n await atomicWrite(absPath, newContent);\n\n // Update the in-memory index entry so subsequent searches reflect the change.\n const cached = ctx.notes.get(input.path);\n if (cached) {\n cached.body = newBody;\n cached.raw = newContent;\n }\n\n return {\n path: input.path,\n bytesWritten: Buffer.byteLength(newContent, 'utf8'),\n contentHash: contentHash(newContent),\n };\n}\n","import { parse as parseYaml } from 'yaml';\n\nexport interface FrontmatterResult {\n /** true if the note starts with a YAML block delimited by `---` lines. */\n present: boolean;\n /** Parsed object (null if not present or parse error or block empty). */\n data: Record<string, unknown> | null;\n /** Distinct top-level keys (empty if absent or malformed). */\n keys: string[];\n /** True if a `---` block exists but yaml.parse threw. */\n malformed: boolean;\n /** Byte offset where the body (post-frontmatter) starts. */\n bodyStart: number;\n /** Body text, frontmatter stripped. */\n body: string;\n}\n\n/**\n * Split a note into frontmatter + body without round-tripping through any\n * YAML stringifier. We need to know the *bytes* of the FM block so writers\n * can be byte-faithful — that's the write-safety contract.\n *\n * Obsidian's rule: a YAML block is present iff the file starts with `---`\n * on its own line (no leading whitespace, no BOM stripped silently — though\n * we tolerate a leading BOM since Windows users exist).\n */\nexport function parseFrontmatter(text: string): FrontmatterResult {\n let offset = 0;\n if (text.charCodeAt(0) === 0xfeff) offset = 1; // BOM\n\n // Must start with `---\\n` or `---\\r\\n`\n const head = text.slice(offset, offset + 4);\n if (head !== '---\\n' && text.slice(offset, offset + 5) !== '---\\r\\n') {\n return {\n present: false,\n data: null,\n keys: [],\n malformed: false,\n bodyStart: 0,\n body: text,\n };\n }\n const fmStart = offset + (head === '---\\n' ? 4 : 5);\n\n // Find closing `\\n---\\n` (or CRLF variant) — Obsidian requires `---` on its own line.\n // We search line-by-line from fmStart.\n const closeLF = text.indexOf('\\n---\\n', fmStart - 1);\n const closeCRLF = text.indexOf('\\r\\n---\\r\\n', fmStart - 1);\n let closeIdx = -1;\n let closeLen = 0;\n if (closeLF !== -1 && (closeCRLF === -1 || closeLF < closeCRLF)) {\n closeIdx = closeLF;\n closeLen = 5;\n } else if (closeCRLF !== -1) {\n closeIdx = closeCRLF;\n closeLen = 7;\n }\n if (closeIdx === -1) {\n // Unterminated frontmatter — count as malformed, treat whole file as body.\n return {\n present: true,\n data: null,\n keys: [],\n malformed: true,\n bodyStart: 0,\n body: text,\n };\n }\n\n const yamlText = text.slice(fmStart, closeIdx + 1); // include trailing \\n before ---\n const bodyStart = closeIdx + closeLen;\n const body = text.slice(bodyStart);\n\n let data: Record<string, unknown> | null = null;\n let malformed = false;\n try {\n const parsed = parseYaml(yamlText);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n data = parsed as Record<string, unknown>;\n } else {\n // YAML parsed but isn't a mapping — Obsidian also treats this as malformed-for-our-purposes.\n malformed = parsed !== null && parsed !== undefined;\n }\n } catch {\n malformed = true;\n }\n\n return {\n present: true,\n data,\n keys: data ? Object.keys(data) : [],\n malformed,\n bodyStart,\n body,\n };\n}\n","import { rename, writeFile } from 'node:fs/promises';\n\n/**\n * Crash-safe file write: write to a same-directory temp file, then rename\n * over the destination. A crash mid-write leaves either the old content or\n * the new content on disk — never a torn file. rename-over-existing works on\n * the full CI OS matrix (proven by patch_note's original implementation).\n *\n * Not a lock: two seekstone processes writing the same note share this temp\n * suffix and can race each other — same exposure as any two writers on one\n * file. CAS (content-hash.ts) is the conflict-detection layer above this.\n */\nexport async function atomicWrite(absPath: string, content: string): Promise<void> {\n const tmpPath = `${absPath}.seekstone-tmp`;\n await writeFile(tmpPath, content, 'utf8');\n await rename(tmpPath, absPath);\n}\n","import { createHash } from 'node:crypto';\n\n/**\n * Content hashing for optional compare-and-swap edits.\n *\n * The hash is sha-256 (hex) of the exact raw string a tool read from disk —\n * disk bytes are the version identity. `read_note` and every mutating tool\n * return `contentHash`; edit tools accept `prevHash` and refuse to write when\n * the note changed since it was read. This is conflict DETECTION, not\n * locking: the window between check and rename is the same one the OS gives\n * any two writers. node:crypto is fully offline — the zero-network guarantee\n * is unaffected.\n */\nexport function contentHash(raw: string | Buffer): string {\n return createHash('sha256').update(raw).digest('hex');\n}\n\n/**\n * Throw the structured hash_conflict error when `prevHash` no longer matches\n * the freshly-read content. Call immediately after the disk read, before any\n * edit is computed.\n */\nexport function assertHashMatch(raw: string, prevHash: string, path: string): void {\n const actual = contentHash(raw);\n if (actual !== prevHash) {\n throw new Error(\n JSON.stringify({\n error: 'hash_conflict',\n path,\n expected: prevHash,\n actual,\n hint: 'Note changed on disk since it was read. Re-read it and retry with the new contentHash.',\n }),\n );\n }\n}\n","import { timingSafeEqual } from 'node:crypto';\nimport { mkdir, open, readdir, readFile, rename, rm, stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { contentHash } from './content-hash.js';\nimport type { Logger } from './log.js';\nimport { parseSize } from './log.js';\n\n/**\n * Write journal — the pre-image store behind `list_writes` / `undo_write`.\n *\n * Before any content-modifying write commits, the tool hands the journal the\n * bytes it is about to replace. The journal stores them under\n * `<vault>/.seekstone/history/blobs/<sha256>` (content-addressed: identical\n * states dedupe for free) and appends one JSONL line to\n * `<vault>/.seekstone/history/manifest.jsonl`:\n *\n * { seq, ts, tool, files: [{ path, preHash, postHash }], undoOf? }\n *\n * `preHash: null` = the file did not exist before (a create); `postHash:\n * null` = it does not exist after (a delete or move-away). Only pre-images\n * are stored — the post-state is what is on disk.\n *\n * Durability: blobs and the manifest line are fsync'd before the tool is\n * allowed to touch the vault. A crash after the journal commit but before\n * the vault write leaves an entry whose postHash does not match disk —\n * undo_write reports that as a conflict rather than restoring blindly. A\n * journal failure throws, which aborts the vault write — an unjournalable\n * write does not proceed while the journal is enabled.\n *\n * Retention is size-capped (`SEEKSTONE_HISTORY_MAX_SIZE`, default 50 MB of\n * blobs) and count-capped (`SEEKSTONE_HISTORY_MAX_ENTRIES`, default 1000).\n * Eviction drops the oldest entries' blobs; the entry stays listed with\n * `undoable: false` rather than vanishing silently. `SEEKSTONE_HISTORY=0`\n * disables the journal entirely (ctx.journal is undefined; tools skip it).\n */\n\nexport interface JournalFile {\n /** Vault-relative path. */\n path: string;\n /** sha-256 of the bytes before the write; null when the file did not exist. */\n preHash: string | null;\n /** sha-256 of the bytes after the write; null when the file no longer exists. */\n postHash: string | null;\n}\n\nexport interface JournalEntry {\n /** Monotonic, 1-based, never reused within a vault's journal. */\n seq: number;\n /** ISO-8601 timestamp of the commit. */\n ts: string;\n /** Tool that performed the write (`undo_write` for undos). */\n tool: string;\n files: JournalFile[];\n /** For undo entries: the seq this entry reverted. */\n undoOf?: number;\n}\n\n/** A listed entry: the manifest row plus whether its pre-images are still on disk. */\nexport interface JournalListRow {\n seq: number;\n ts: string;\n tool: string;\n paths: string[];\n undoable: boolean;\n undoOf?: number;\n}\n\nexport interface JournalConfig {\n maxBytes: number;\n maxEntries: number;\n}\n\nconst DEFAULT_MAX_BYTES = 50 * 1e6;\nconst DEFAULT_MAX_ENTRIES = 1000;\n\n/** Vault-relative directory the journal lives in — excluded from indexing like `.trash/`. */\nexport const HISTORY_DIR = '.seekstone/history';\n\n/**\n * Read the journal settings from env. Returns undefined when the journal is\n * disabled (`SEEKSTONE_HISTORY=0|false`).\n */\nexport function resolveJournalConfig(\n env: Record<string, string | undefined>,\n): JournalConfig | undefined {\n const flag = (env.SEEKSTONE_HISTORY ?? '').trim().toLowerCase();\n if (flag === '0' || flag === 'false' || flag === 'off') return undefined;\n const maxEntriesRaw = Number.parseInt(env.SEEKSTONE_HISTORY_MAX_ENTRIES ?? '', 10);\n return {\n maxBytes: parseSize(env.SEEKSTONE_HISTORY_MAX_SIZE, DEFAULT_MAX_BYTES),\n maxEntries:\n Number.isFinite(maxEntriesRaw) && maxEntriesRaw > 0 ? maxEntriesRaw : DEFAULT_MAX_ENTRIES,\n };\n}\n\n/** Write `content` to `dest` durably: temp file, fsync, rename over. */\nasync function writeDurable(dest: string, content: string): Promise<void> {\n const tmp = `${dest}.seekstone-tmp`;\n const fh = await open(tmp, 'w');\n try {\n await fh.writeFile(content, 'utf8');\n await fh.sync();\n } finally {\n await fh.close();\n }\n await rename(tmp, dest);\n}\n\n/** Append one line to `dest` durably (fsync before returning). */\nasync function appendDurable(dest: string, line: string): Promise<void> {\n const fh = await open(dest, 'a');\n try {\n await fh.writeFile(line, 'utf8');\n await fh.sync();\n } finally {\n await fh.close();\n }\n}\n\n/**\n * One tool call's worth of journaling. `add` stores each file's pre-image;\n * `commit` appends the manifest line. Tools call both BEFORE the first vault\n * byte changes. Multi-file tools (move_note, rename_heading) add every\n * touched file under one seq so undo restores all of them or none.\n */\nexport interface JournalTxn {\n add(path: string, pre: string | null, post: string | null): Promise<void>;\n commit(): Promise<JournalEntry>;\n}\n\nexport class Journal {\n readonly config: JournalConfig;\n private readonly dir: string;\n private readonly blobDir: string;\n private readonly manifestPath: string;\n private readonly log?: Logger;\n private entries: JournalEntry[];\n private nextSeq: number;\n /** Blob hash → byte size, for every blob currently on disk. */\n private readonly blobSizes: Map<string, number>;\n private totalBytes: number;\n /** Serialises commits so seq assignment and eviction never interleave. */\n private chain: Promise<unknown> = Promise.resolve();\n\n private constructor(\n vaultRoot: string,\n config: JournalConfig,\n entries: JournalEntry[],\n blobSizes: Map<string, number>,\n log?: Logger,\n ) {\n this.config = config;\n this.dir = join(vaultRoot, HISTORY_DIR);\n this.blobDir = join(this.dir, 'blobs');\n this.manifestPath = join(this.dir, 'manifest.jsonl');\n this.entries = entries;\n this.nextSeq = (entries.at(-1)?.seq ?? 0) + 1;\n this.blobSizes = blobSizes;\n this.totalBytes = 0;\n for (const n of blobSizes.values()) this.totalBytes += n;\n this.log = log;\n }\n\n /** Open (or create) the journal under `vaultRoot`, loading the manifest into memory. */\n static async open(\n vaultRoot: string,\n config: JournalConfig,\n opts: { log?: Logger } = {},\n ): Promise<Journal> {\n const dir = join(vaultRoot, HISTORY_DIR);\n const blobDir = join(dir, 'blobs');\n await mkdir(blobDir, { recursive: true });\n\n const entries: JournalEntry[] = [];\n let manifest = '';\n try {\n manifest = await readFile(join(dir, 'manifest.jsonl'), 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n let lastSeq = 0;\n for (const line of manifest.split('\\n')) {\n if (line.trim() === '') continue;\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n // A torn trailing line from a crash mid-append — the write it\n // described simply is not listed. Never fail boot over it.\n opts.log?.warn('journal: skipping malformed manifest line');\n continue;\n }\n if (!isEntry(parsed) || parsed.seq <= lastSeq) {\n opts.log?.warn('journal: skipping invalid manifest entry');\n continue;\n }\n entries.push(parsed);\n lastSeq = parsed.seq;\n }\n\n const blobSizes = new Map<string, number>();\n for (const name of await readdir(blobDir)) {\n if (!/^[0-9a-f]{64}$/.test(name)) continue;\n try {\n blobSizes.set(name, (await stat(join(blobDir, name))).size);\n } catch {\n /* vanished between readdir and stat — treat as absent */\n }\n }\n return new Journal(vaultRoot, config, entries, blobSizes, opts.log);\n }\n\n begin(tool: string, undoOf?: number): JournalTxn {\n const files: JournalFile[] = [];\n let committed = false;\n return {\n add: async (path, pre, post) => {\n if (committed) throw new Error('journal: add after commit');\n const preHash = pre === null ? null : await this.storeBlob(pre);\n files.push({ path, preHash, postHash: post === null ? null : contentHash(post) });\n },\n commit: async () => {\n if (committed) throw new Error('journal: double commit');\n committed = true;\n return this.enqueue(() => this.commit(tool, files, undoOf));\n },\n };\n }\n\n /** Newest-first rows for `list_writes`. */\n list(opts: { limit?: number; path?: string } = {}): { writes: JournalListRow[]; total: number } {\n const limit = opts.limit ?? 20;\n const filtered =\n opts.path === undefined\n ? this.entries\n : this.entries.filter((e) => e.files.some((f) => f.path === opts.path));\n const writes: JournalListRow[] = [];\n for (let i = filtered.length - 1; i >= 0 && writes.length < limit; i--) {\n const e = filtered[i] as JournalEntry;\n const row: JournalListRow = {\n seq: e.seq,\n ts: e.ts,\n tool: e.tool,\n paths: e.files.map((f) => f.path),\n undoable: this.isUndoable(e),\n };\n if (e.undoOf !== undefined) row.undoOf = e.undoOf;\n writes.push(row);\n }\n return { writes, total: filtered.length };\n }\n\n /** Seq of the newest entry (0 when empty). */\n get lastSeq(): number {\n return this.nextSeq - 1;\n }\n\n /** Entries committed after `seq`, oldest first. */\n since(seq: number): JournalEntry[] {\n return this.entries.filter((e) => e.seq > seq);\n }\n\n get(seq: number): JournalEntry | undefined {\n return this.entries.find((e) => e.seq === seq);\n }\n\n /**\n * The most recent write that is still in effect and restorable — the\n * default target of `undo_write`. Undo entries and writes they reverted are\n * skipped (so repeated default undos walk backwards instead of ping-ponging\n * undo/redo); an undo that was itself undone re-exposes its target. Redo is\n * always explicit: `undo_write({ seq: <the undo's seq> })`.\n */\n latestUndoable(): JournalEntry | undefined {\n const cancelled = new Set<number>();\n for (let i = this.entries.length - 1; i >= 0; i--) {\n const e = this.entries[i] as JournalEntry;\n if (cancelled.has(e.seq)) continue;\n if (e.undoOf !== undefined) {\n cancelled.add(e.undoOf);\n continue;\n }\n if (this.isUndoable(e)) return e;\n }\n return undefined;\n }\n\n isUndoable(entry: JournalEntry): boolean {\n return entry.files.every((f) => f.preHash === null || this.blobSizes.has(f.preHash));\n }\n\n /** Read a stored pre-image by hash. Throws if evicted. */\n async preimage(hash: string): Promise<string> {\n const raw = await readFile(join(this.blobDir, hash), 'utf8');\n // Integrity check on the stored blob (not a secret comparison); the\n // constant-time compare is free and keeps static analysis quiet.\n const actual = Buffer.from(contentHash(raw), 'hex');\n const expected = Buffer.from(hash, 'hex');\n if (actual.length !== expected.length || !timingSafeEqual(actual, expected)) {\n throw new Error(`journal: blob ${hash} is corrupt (hash mismatch)`);\n }\n return raw;\n }\n\n /** Bytes of pre-images currently stored (for diagnostics/tests). */\n get storedBytes(): number {\n return this.totalBytes;\n }\n\n private enqueue<T>(fn: () => Promise<T>): Promise<T> {\n const next = this.chain.then(fn, fn);\n this.chain = next.catch(() => undefined);\n return next;\n }\n\n private async storeBlob(content: string): Promise<string> {\n const hash = contentHash(content);\n if (this.blobSizes.has(hash)) return hash;\n await writeDurable(join(this.blobDir, hash), content);\n const size = Buffer.byteLength(content, 'utf8');\n this.blobSizes.set(hash, size);\n this.totalBytes += size;\n return hash;\n }\n\n private async commit(tool: string, files: JournalFile[], undoOf?: number): Promise<JournalEntry> {\n const entry: JournalEntry = { seq: this.nextSeq, ts: new Date().toISOString(), tool, files };\n if (undoOf !== undefined) entry.undoOf = undoOf;\n await appendDurable(this.manifestPath, `${JSON.stringify(entry)}\\n`);\n this.nextSeq++;\n this.entries.push(entry);\n await this.evict();\n return entry;\n }\n\n /**\n * Enforce the caps. Blobs are reference-counted across entries, so a\n * pre-image shared by an old and a new entry survives the old one's\n * eviction. Over the entry cap, the oldest rows are dropped and the\n * manifest rewritten atomically; over the byte cap, the oldest entries'\n * blobs are removed but the rows stay (listed as undoable: false).\n */\n private async evict(): Promise<void> {\n const refs = new Map<string, number>();\n for (const e of this.entries) {\n for (const f of e.files) {\n if (f.preHash !== null) refs.set(f.preHash, (refs.get(f.preHash) ?? 0) + 1);\n }\n }\n const dropBlobs = async (e: JournalEntry): Promise<void> => {\n for (const f of e.files) {\n if (f.preHash === null) continue;\n const n = (refs.get(f.preHash) ?? 1) - 1;\n refs.set(f.preHash, n);\n if (n > 0 || !this.blobSizes.has(f.preHash)) continue;\n await rm(join(this.blobDir, f.preHash), { force: true });\n this.totalBytes -= this.blobSizes.get(f.preHash) ?? 0;\n this.blobSizes.delete(f.preHash);\n }\n };\n\n let rewrite = false;\n while (this.entries.length > this.config.maxEntries) {\n const oldest = this.entries.shift() as JournalEntry;\n await dropBlobs(oldest);\n rewrite = true;\n }\n // Never evict the entry just committed — a write must be undoable at\n // least until the next one lands, whatever the cap.\n for (let i = 0; this.totalBytes > this.config.maxBytes && i < this.entries.length - 1; i++) {\n await dropBlobs(this.entries[i] as JournalEntry);\n }\n if (rewrite) {\n await writeDurable(\n this.manifestPath,\n this.entries.map((e) => `${JSON.stringify(e)}\\n`).join(''),\n );\n this.log?.debug('journal: manifest compacted', { entries: this.entries.length });\n }\n }\n}\n\nfunction isEntry(v: unknown): v is JournalEntry {\n if (typeof v !== 'object' || v === null) return false;\n const e = v as Record<string, unknown>;\n return (\n typeof e.seq === 'number' &&\n typeof e.ts === 'string' &&\n typeof e.tool === 'string' &&\n Array.isArray(e.files) &&\n e.files.every(\n (f: unknown) =>\n typeof f === 'object' &&\n f !== null &&\n typeof (f as JournalFile).path === 'string' &&\n ((f as JournalFile).preHash === null || typeof (f as JournalFile).preHash === 'string') &&\n ((f as JournalFile).postHash === null || typeof (f as JournalFile).postHash === 'string'),\n )\n );\n}\n\n/**\n * Single-file convenience for the write tools: journal one pre/post pair\n * before the vault write. No-op when the journal is disabled.\n */\nexport async function journalWrite(\n ctx: { journal?: Journal },\n tool: string,\n path: string,\n pre: string | null,\n post: string | null,\n): Promise<void> {\n if (!ctx.journal) return;\n const txn = ctx.journal.begin(tool);\n await txn.add(path, pre, post);\n await txn.commit();\n}\n","import picomatch from 'picomatch';\n\n/**\n * Write policy — read-only mode and write-path scoping, parsed once at boot\n * and enforced at the dispatch layer (tool visibility + rejection) and inside\n * every write handler at the point the final vault-relative path is known\n * (`assertWritable`). Two env vars:\n *\n * SEEKSTONE_READ_ONLY=1 — write tools are unregistered from\n * tools/list AND rejected at dispatch.\n * SEEKSTONE_WRITE_PATHS=<glob,>— comma-separated vault-relative globs;\n * writes are permitted only under matching\n * paths (e.g. \"journal/**,inbox/*.md\").\n *\n * Read-only wins over write paths. Unset write paths = everything writable.\n */\nexport interface WritePolicy {\n readOnly: boolean;\n /** Vault-relative glob allowlist; undefined = all paths writable. */\n writeGlobs?: string[];\n}\n\n/** Default policy for contexts built without env config (tests, benches). */\nexport const PERMISSIVE_POLICY: WritePolicy = { readOnly: false };\n\nexport function parseWritePolicy(env: Record<string, string | undefined>): WritePolicy {\n const ro = (env.SEEKSTONE_READ_ONLY ?? '').toLowerCase();\n const readOnly = ro === '1' || ro === 'true';\n const globs = (env.SEEKSTONE_WRITE_PATHS ?? '')\n .split(',')\n .map((g) => g.trim())\n .filter((g) => g.length > 0);\n return globs.length > 0 ? { readOnly, writeGlobs: globs } : { readOnly };\n}\n\n/** Normalize a vault-relative path for glob matching (Windows separators, ./). */\nfunction normalizeRel(relPath: string): string {\n let p = relPath.replaceAll('\\\\', '/');\n while (p.startsWith('./')) p = p.slice(2);\n return p;\n}\n\nexport function isWritable(policy: WritePolicy, relPath: string): boolean {\n if (policy.readOnly) return false;\n if (!policy.writeGlobs) return true;\n // dot:true so notes under dot-folders still match `**` patterns.\n return picomatch(policy.writeGlobs, { dot: true })(normalizeRel(relPath));\n}\n\n/**\n * Throw with an actionable message when the policy forbids writing `relPath`.\n * Call from write handlers with the final vault-relative path — after any\n * internal path computation (e.g. periodic-note date resolution).\n */\nexport function assertWritable(policy: WritePolicy, relPath: string): void {\n if (policy.readOnly) {\n throw new Error('Server is read-only (SEEKSTONE_READ_ONLY=1); write tools are disabled.');\n }\n if (!isWritable(policy, relPath)) {\n throw new Error(\n `Write not permitted: \"${relPath}\" is outside SEEKSTONE_WRITE_PATHS (${policy.writeGlobs?.join(', ')}).`,\n );\n }\n}\n","import { resolve, sep } from 'node:path';\n\n/**\n * Resolve a vault-relative path to an absolute path, guaranteeing the result\n * stays inside the vault. This is the single containment guard for every tool\n * handler — the previous inline `join(...).startsWith(vaultRoot)` checks had\n * no separator boundary, so with a vault at `/home/u/vault` the input\n * `../vault-backup/x.md` resolved to `/home/u/vault-backup/x.md` and passed.\n *\n * `resolve` (not `join`) also normalizes an absolute `input` instead of\n * concatenating it, so absolute-path inputs are contained too.\n *\n * @throws Error `Path outside vault: <input>` when the resolved path escapes.\n */\nexport function resolveVaultPath(vaultRoot: string, inputPath: string): string {\n const abs = resolve(vaultRoot, inputPath);\n if (abs !== vaultRoot && !abs.startsWith(vaultRoot + sep)) {\n throw new Error(`Path outside vault: ${inputPath}`);\n }\n return abs;\n}\n","/**\n * Link / URL / tag extractors. Most run on note *bodies* (post-frontmatter)\n * so frontmatter values don't double-count as inline content;\n * `extractLinksWithLines` takes the full raw note and handles the\n * frontmatter block YAML-aware.\n *\n * Heuristics here intentionally lean toward \"what Obsidian sees\" rather than\n * full CommonMark parsing — we're profiling shape, not rendering. The regexes\n * are deliberately tolerant of code-fence content; counts are reported with\n * that caveat in the README.\n */\nimport { parseDocument, visit } from 'yaml';\nimport { parseFrontmatter } from './frontmatter.js';\n\nexport interface Wikilink {\n /** Raw target before `#` and `|`. May include path segments. */\n target: string;\n /** Optional heading/block reference (`#heading` or `#^block`). */\n fragment: string | null;\n /** Optional display alias. */\n alias: string | null;\n}\n\n// Quantifiers are bounded at 512 chars — well above any real Obsidian note name\n// or heading (~255 byte OS limit) — to eliminate O(n²) backtracking on\n// pathological inputs where many [[... sequences appear with no closing ]].\nconst WIKILINK_RE = /\\[\\[([^\\]|#\\n]{1,512})(#[^\\]|\\n]{1,512})?(\\|[^\\]\\n]{1,512})?\\]\\]/g;\n\n// Matches both embeds (![[...]]) and plain wikilinks ([[...]]).\nconst LINK_WITH_LINES_RE =\n /(!?\\[\\[)([^\\]|#\\n]{1,512})(#[^\\]|\\n]{1,512})?(\\|[^\\]\\n]{1,512})?(\\]\\])/g;\n\nexport type LinkType = 'wikilink' | 'embed';\n\nexport interface LinkRecord {\n /**\n * Full raw match, e.g. \"[[Note Name|alias]]\" or \"![[embed.png]]\". For links\n * found inside folded frontmatter scalars this is the *parsed* (unfolded)\n * text, which may differ from the source bytes.\n */\n raw: string;\n /** Raw target before `#` and `|`. */\n target: string;\n fragment: string | null;\n alias: string | null;\n linkType: LinkType;\n /**\n * 1-indexed line number in the source file. Links inside multi-line\n * frontmatter scalars are attributed to the line where the scalar begins.\n */\n line: number;\n}\n\n/**\n * Extract all wikilinks and embeds from a raw note (including frontmatter),\n * annotating each with its 1-indexed line number.\n *\n * The frontmatter block is parsed as YAML and its string values walked, so\n * links split across lines by scalar folding (yaml's default 80-col wrap —\n * hand edits, other tools, or pre-0.12.1 seekstone) still extract: folding\n * turns the newline back into a space on parse. Malformed frontmatter falls\n * back to per-line regex over the block, matching the body treatment.\n */\nexport function extractLinksWithLines(raw: string): LinkRecord[] {\n const fm = parseFrontmatter(raw);\n // bodyStart 0 covers both \"no frontmatter\" and \"unterminated frontmatter\"\n // (where the whole file is treated as body).\n if (!fm.present || fm.bodyStart === 0) return linksFromLines(raw, 1);\n\n const fmRegion = raw.slice(0, fm.bodyStart);\n const out = frontmatterLinks(fmRegion, fm.malformed);\n const bodyFirstLine = countNewlines(fmRegion) + 1;\n linksFromLinesInto(out, fm.body, bodyFirstLine);\n return out;\n}\n\nfunction linksFromLines(text: string, firstLine: number): LinkRecord[] {\n const out: LinkRecord[] = [];\n linksFromLinesInto(out, text, firstLine);\n return out;\n}\n\nfunction linksFromLinesInto(out: LinkRecord[], text: string, firstLine: number): void {\n const lines = text.split('\\n');\n for (const [lineIdx, lineText] of lines.entries()) {\n matchLinksInto(out, lineText, firstLine + lineIdx);\n }\n}\n\nfunction matchLinksInto(out: LinkRecord[], text: string, line: number): void {\n for (const m of text.matchAll(LINK_WITH_LINES_RE)) {\n const prefix = m[1] ?? '';\n out.push({\n raw: m[0] ?? '',\n target: (m[2] ?? '').trim(),\n fragment: m[3] ? m[3].slice(1).trim() : null,\n alias: m[4] ? m[4].slice(1).trim() : null,\n linkType: prefix.startsWith('!') ? 'embed' : 'wikilink',\n line,\n });\n }\n}\n\n/**\n * Walk the frontmatter block's string values via the YAML AST. `fmRegion` is\n * the full block including both `---` delimiter lines. Keys are skipped —\n * Obsidian doesn't treat property names as links.\n */\nfunction frontmatterLinks(fmRegion: string, malformed: boolean): LinkRecord[] {\n if (malformed) return linksFromLines(fmRegion, 1);\n\n // Strip the delimiters: yaml content starts after the opening `---` line and\n // ends before the closing `---` line (parseDocument would read a bare `---`\n // as a document marker).\n const yamlStart = fmRegion.indexOf('\\n') + 1;\n const closeLen = fmRegion.endsWith('---\\r\\n') ? 5 : 4;\n const yamlText = fmRegion.slice(yamlStart, fmRegion.length - closeLen);\n\n const doc = parseDocument(yamlText);\n if (doc.errors.length > 0) return linksFromLines(fmRegion, 1);\n\n const out: LinkRecord[] = [];\n visit(doc, {\n Scalar(key, node) {\n if (key === 'key') return;\n if (typeof node.value !== 'string' || node.range == null) return;\n // Opening `---` is line 1, so yamlText's first line is file line 2.\n const line = 2 + countNewlines(yamlText.slice(0, node.range[0]));\n matchLinksInto(out, node.value, line);\n },\n });\n return out;\n}\n\nfunction countNewlines(text: string): number {\n let n = 0;\n for (let i = text.indexOf('\\n'); i !== -1; i = text.indexOf('\\n', i + 1)) n++;\n return n;\n}\nconst URL_RE = /https?:\\/\\/[^\\s<>\"')]+/g;\n// Obsidian inline tag: must start with letter or underscore, then word chars, /, -.\n// Must not be immediately preceded by `]` (avoids matching `]#` from links) or be\n// inside a numeric-only token like `#123` (Obsidian rejects pure-digit tags).\nconst INLINE_TAG_RE = /(?:^|[^\\w\\]/])#([A-Za-z_][\\w/-]*)/g;\n\nexport function extractWikilinks(body: string): Wikilink[] {\n const out: Wikilink[] = [];\n for (const m of body.matchAll(WIKILINK_RE)) {\n out.push({\n target: (m[1] ?? '').trim(),\n fragment: m[2] ? m[2].slice(1).trim() : null,\n alias: m[3] ? m[3].slice(1).trim() : null,\n });\n }\n return out;\n}\n\nexport function extractUrls(body: string): string[] {\n const TRAILING_PUNCT = '.,;:!?)';\n const out: string[] = [];\n for (const m of body.matchAll(URL_RE)) {\n // Strip trailing punctuation with a backward walk — avoids the O(n²)\n // backtracking that /[.,;:!?)]+$/ exhibits on strings with many punct chars.\n const raw = m[0] ?? '';\n let end = raw.length;\n while (end > 0 && TRAILING_PUNCT.includes(raw.charAt(end - 1))) end--;\n out.push(raw.slice(0, end));\n }\n return out;\n}\n\nexport function extractInlineTags(body: string): string[] {\n const out: string[] = [];\n for (const m of body.matchAll(INLINE_TAG_RE)) {\n if (m[1]) out.push(m[1]);\n }\n return out;\n}\n\n/**\n * Pull tags out of a parsed frontmatter object. Obsidian accepts `tags:` or\n * `tag:`, as either a string (space- or comma-separated) or a list.\n */\nexport function frontmatterTags(fm: Record<string, unknown> | null): string[] {\n if (!fm) return [];\n const raw = fm.tags ?? fm.tag;\n if (raw == null) return [];\n if (Array.isArray(raw)) {\n return raw.filter((t): t is string => typeof t === 'string').map((t) => t.replace(/^#/, ''));\n }\n if (typeof raw === 'string') {\n return raw\n .split(/[\\s,]+/)\n .filter(Boolean)\n .map((t) => t.replace(/^#/, ''));\n }\n return [];\n}\n","import { extractLinksWithLines } from '@seekstone/core/extract';\nimport { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { extractExcerpt } from '../index/excerpt.js';\nimport { resolveLink } from '../index/resolve.js';\nimport { basenameNoExt } from './search.js';\n\nexport const ContextPackInput = z.object({\n query: z.string().min(1).describe('Natural-language question or topic to assemble context for.'),\n budgetBytes: z\n .number()\n .int()\n .min(256)\n .max(16384)\n .default(2048)\n .describe('Hard cap on the response JSON size in bytes. The pack never exceeds it.'),\n});\nexport type ContextPackInput = z.infer<typeof ContextPackInput>;\n\nconst MAX_CANDIDATES = 10;\nconst NEIGHBOR_HITS = 3;\nconst MAX_NEIGHBORS = 5;\nconst NEIGHBOR_SUMMARY_LEN = 100;\nconst MIN_EXCERPT_LEN = 60;\nconst FM_MAX_BYTES = 120;\nconst SOURCES_MAX = 8;\n\nexport interface ContextPackExcerpt {\n path: string;\n title?: string;\n score: number;\n excerpt: string;\n tags?: string[];\n /** Scalar frontmatter values, in key order, capped at FM_MAX_BYTES serialized. */\n fm?: Record<string, unknown>;\n}\n\nexport interface ContextPackNeighbor {\n path: string;\n rel: 'backlink' | 'outlink' | 'both';\n /** Line in the neighbor where it links to a hit (backlinks only). */\n line?: number;\n summary: string;\n}\n\nexport interface ContextPackSource {\n path: string;\n line?: number;\n}\n\nexport interface ContextPackResult {\n excerpts: ContextPackExcerpt[];\n neighborhood: ContextPackNeighbor[];\n /** Overflow refs only — matches and neighbors that did not fit the budget. */\n sources: ContextPackSource[];\n totalMatches: number;\n confidence: 'high' | 'low' | 'none';\n truncated?: true;\n}\n\n/** Serialized cost of one array entry, +1 for the separating comma (conservative). */\nfunction entryCost(entry: unknown): number {\n return Buffer.byteLength(JSON.stringify(entry), 'utf8') + 1;\n}\n\n/** Pick scalar frontmatter values in key order until the serialized subset exceeds the cap. */\nfunction pickFm(fm: Record<string, unknown> | null): Record<string, unknown> | undefined {\n if (!fm) return undefined;\n const out: Record<string, unknown> = {};\n let picked = 0;\n for (const key of Object.keys(fm)) {\n const v = fm[key];\n const t = typeof v;\n if (t !== 'string' && t !== 'number' && t !== 'boolean') continue;\n const candidate = { ...out, [key]: v };\n if (Buffer.byteLength(JSON.stringify(candidate), 'utf8') > FM_MAX_BYTES) break;\n out[key] = v;\n picked += 1;\n }\n return picked > 0 ? out : undefined;\n}\n\nfunction clamp(n: number, lo: number, hi: number): number {\n return Math.min(hi, Math.max(lo, n));\n}\n\nexport function contextPack(ctx: ServerContext, input: ContextPackInput): ContextPackResult {\n const results = ctx.index.search(input.query, {\n boost: { title: 3, tags: 2, body: 1 },\n fuzzy: 0.2,\n prefix: true,\n });\n const totalMatches = results.length;\n if (totalMatches === 0) {\n return { excerpts: [], neighborhood: [], sources: [], totalMatches: 0, confidence: 'none' };\n }\n\n const terms = input.query\n .toLowerCase()\n .split(/\\s+/)\n .filter((t) => t.length > 1);\n\n const scoreByPath = new Map<string, number>();\n for (const r of results) scoreByPath.set(r.id, r.score);\n\n // Meter the fixed envelope with worst-case flags so emitting them later can\n // never break the cap. Entries are metered against the same minified\n // serialization dispatch ships, so the budget is exact, not an estimate.\n const budget = input.budgetBytes;\n let used = Buffer.byteLength(\n JSON.stringify({\n excerpts: [],\n neighborhood: [],\n sources: [],\n totalMatches,\n confidence: 'high',\n truncated: true,\n }),\n 'utf8',\n );\n\n // Phase 1 — excerpts: greedy fill in rank order, holding back a soft reserve\n // for the neighborhood. On the first non-fit, shrink the excerpt (half, then\n // the floor); a shrunk entry ends the phase so the pack isn't all fragments.\n const excerptLen = clamp(Math.floor(budget / 10), 80, 400);\n const reserve = Math.min(Math.floor(budget / 4), 600);\n const candidates = results.slice(0, MAX_CANDIDATES);\n const excerpts: ContextPackExcerpt[] = [];\n const overflowHits: ContextPackSource[] = [];\n let droppedForBudget = false;\n\n const buildEntry = (r: (typeof results)[number], len: number): ContextPackExcerpt => {\n const note = ctx.notes.get(r.id);\n const body = note?.body ?? '';\n const noteTags = note?.tags ? note.tags.split(' ').filter(Boolean) : [];\n const entry: ContextPackExcerpt = {\n path: r.id,\n score: Math.round(r.score * 100) / 100,\n excerpt: extractExcerpt(body, terms, len),\n };\n const title = r.title as string;\n if (title && title !== basenameNoExt(r.id)) entry.title = title;\n if (noteTags.length > 0) entry.tags = noteTags;\n const fm = pickFm(note?.fm ?? null);\n if (fm) entry.fm = fm;\n return entry;\n };\n\n const excerptCap = budget - reserve;\n let phaseOpen = true;\n for (const r of candidates) {\n if (!phaseOpen) {\n overflowHits.push({ path: r.id });\n continue;\n }\n let placed = false;\n const shrinkLens = [\n ...new Set([\n excerptLen,\n Math.max(Math.floor(excerptLen / 2), MIN_EXCERPT_LEN),\n MIN_EXCERPT_LEN,\n ]),\n ];\n for (const len of shrinkLens) {\n const entry = buildEntry(r, len);\n const cost = entryCost(entry);\n if (used + cost <= excerptCap) {\n excerpts.push(entry);\n used += cost;\n placed = true;\n // A shrunk excerpt means the budget is nearly spent — stop before\n // packing many useless fragments.\n if (len !== excerptLen) phaseOpen = false;\n break;\n }\n }\n if (!placed) {\n phaseOpen = false;\n droppedForBudget = true;\n overflowHits.push({ path: r.id });\n }\n }\n\n // Phase 2 — neighborhood: backlinks + outlinks of the top included hits.\n // The reserve is released; entries fill whatever budget remains.\n const includedPaths = new Set(excerpts.map((e) => e.path));\n const seeds = excerpts.slice(0, NEIGHBOR_HITS).map((e) => e.path);\n const agg = new Map<\n string,\n { rels: Set<'backlink' | 'outlink'>; seedPaths: Set<string>; line?: number }\n >();\n const connect = (\n neighborPath: string,\n seed: string,\n rel: 'backlink' | 'outlink',\n line?: number,\n ) => {\n if (neighborPath === seed || includedPaths.has(neighborPath)) return; // excerpt wins dedup\n if (!ctx.notes.has(neighborPath)) return;\n let entry = agg.get(neighborPath);\n if (!entry) {\n entry = { rels: new Set(), seedPaths: new Set() };\n agg.set(neighborPath, entry);\n }\n entry.rels.add(rel);\n entry.seedPaths.add(seed);\n if (rel === 'backlink' && entry.line === undefined && line !== undefined) entry.line = line;\n };\n for (const seed of seeds) {\n for (const ref of ctx.backlinks.get(seed) ?? []) {\n connect(ref.path, seed, 'backlink', ref.line);\n }\n const note = ctx.notes.get(seed);\n if (!note) continue;\n for (const link of extractLinksWithLines(note.raw)) {\n const target = resolveLink(link.target, ctx.notes);\n if (target !== undefined) connect(target, seed, 'outlink');\n }\n }\n\n const ranked = [...agg.entries()].sort((a, b) => {\n const conn = b[1].seedPaths.size - a[1].seedPaths.size;\n if (conn !== 0) return conn;\n const score = (scoreByPath.get(b[0]) ?? 0) - (scoreByPath.get(a[0]) ?? 0);\n if (score !== 0) return score;\n return a[0] < b[0] ? -1 : 1;\n });\n\n const neighborhood: ContextPackNeighbor[] = [];\n const overflowNeighbors: ContextPackSource[] = [];\n for (const [path, info] of ranked) {\n if (neighborhood.length >= MAX_NEIGHBORS) {\n overflowNeighbors.push(info.line !== undefined ? { path, line: info.line } : { path });\n continue;\n }\n const note = ctx.notes.get(path);\n const entry: ContextPackNeighbor = {\n path,\n rel: info.rels.size === 2 ? 'both' : info.rels.has('backlink') ? 'backlink' : 'outlink',\n summary: extractExcerpt(note?.body ?? '', terms, NEIGHBOR_SUMMARY_LEN),\n };\n if (info.line !== undefined) entry.line = info.line;\n const cost = entryCost(entry);\n if (used + cost > budget) {\n droppedForBudget = true;\n overflowNeighbors.push(info.line !== undefined ? { path, line: info.line } : { path });\n // First non-fit ends the phase — later entries rank lower anyway.\n for (const [p, i] of ranked.slice(ranked.findIndex(([rp]) => rp === path) + 1)) {\n overflowNeighbors.push(i.line !== undefined ? { path: p, line: i.line } : { path: p });\n }\n break;\n }\n neighborhood.push(entry);\n used += cost;\n }\n\n // Phase 3 — sources: overflow refs (\"read these next\"), deduped, best-first.\n const sources: ContextPackSource[] = [];\n const sourcePaths = new Set<string>();\n for (const ref of [...overflowHits, ...overflowNeighbors]) {\n if (sources.length >= SOURCES_MAX) break;\n if (includedPaths.has(ref.path) || sourcePaths.has(ref.path)) continue;\n const cost = entryCost(ref);\n if (used + cost > budget) break;\n sources.push(ref);\n sourcePaths.add(ref.path);\n used += cost;\n }\n\n const hasTermInExcerpt = excerpts.some((e) =>\n terms.some((t) => e.excerpt.toLowerCase().includes(t)),\n );\n const confidence: ContextPackResult['confidence'] =\n excerpts.length === 0 || (terms.length > 0 && !hasTermInExcerpt) ? 'low' : 'high';\n\n const result: ContextPackResult = { excerpts, neighborhood, sources, totalMatches, confidence };\n if (droppedForBudget) result.truncated = true;\n return result;\n}\n","/**\n * Extract a short excerpt centred on the first occurrence of any query term.\n * Returns at most `maxLen` characters with leading/trailing ellipsis as needed.\n *\n * This is the core context-tax reduction: instead of returning the full note\n * (~7 KB mean, ~70 KB p99), we return ~200 chars of relevant context.\n */\nexport function extractExcerpt(text: string, terms: string[], maxLen = 200): string {\n const lower = text.toLowerCase();\n let bestIdx = -1;\n\n for (const term of terms) {\n const idx = lower.indexOf(term.toLowerCase());\n if (idx !== -1 && (bestIdx === -1 || idx < bestIdx)) {\n bestIdx = idx;\n }\n }\n\n if (bestIdx === -1) {\n // No term found in body (hit may have been in title/tags) — return the start.\n return truncate(text.trimStart(), maxLen);\n }\n\n const half = Math.floor(maxLen / 2);\n const start = Math.max(0, bestIdx - half);\n const end = Math.min(text.length, bestIdx + half + (terms[0]?.length ?? 0));\n const slice = text.slice(start, end).trim();\n\n return `${start > 0 ? '…' : ''}${slice}${end < text.length ? '…' : ''}`;\n}\n\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s;\n return `${s.slice(0, max).trimEnd()}…`;\n}\n","/**\n * Resolve a wikilink target string to a vault-relative note path.\n *\n * Uses Obsidian's loose resolution: exact match → add .md → basename match\n * → path-without-extension match. Returns undefined if no note matches.\n *\n * Ambiguity (two notes sharing a basename, or case-variant paths) resolves to\n * the lexicographically smallest note path — deterministic regardless of how\n * the notes map was populated.\n */\n\nexport interface ResolveMaps {\n /** lowercased basename (no .md) → winning note path */\n byBasename: Map<string, string>;\n /** lowercased path without .md → winning note path */\n byPathNoExt: Map<string, string>;\n}\n\n/**\n * Precompute the loose-resolution lookup maps for a notes map. Build once per\n * batch (index build, watcher event) and pass to resolveLink so each loose\n * resolution is O(1) instead of a scan of every note.\n */\nexport function buildResolveMaps(notes: Map<string, unknown>): ResolveMaps {\n const byBasename = new Map<string, string>();\n const byPathNoExt = new Map<string, string>();\n for (const path of notes.keys()) {\n const pathNoExt = path.replace(/\\.md$/i, '').toLowerCase();\n const base = pathNoExt.split('/').pop() ?? pathNoExt;\n const prevBase = byBasename.get(base);\n if (prevBase === undefined || path < prevBase) byBasename.set(base, path);\n const prevPath = byPathNoExt.get(pathNoExt);\n if (prevPath === undefined || path < prevPath) byPathNoExt.set(pathNoExt, path);\n }\n return { byBasename, byPathNoExt };\n}\n\nexport function resolveLink(\n target: string,\n notes: Map<string, unknown>,\n maps?: ResolveMaps,\n): string | undefined {\n if (notes.has(target)) return target;\n const withMd = `${target}.md`;\n if (notes.has(withMd)) return withMd;\n\n const m = maps ?? buildResolveMaps(notes);\n const targetLower = target.toLowerCase();\n const targetBase = targetLower.split('/').pop() ?? targetLower;\n return m.byBasename.get(targetBase) ?? m.byPathNoExt.get(targetLower);\n}\n","import { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { extractExcerpt } from '../index/excerpt.js';\nimport type { SearchHit } from '../index/types.js';\nimport { chunkExcerpt } from '../semantic/excerpt.js';\nimport { MAX_ROUTE_WORDS, queryWords, routeToLexical } from '../semantic/route.js';\nimport type { Semantic } from '../semantic/state.js';\n\nexport const SearchInput = z.object({\n query: z.string().min(1).describe('Search query. Supports fuzzy matching and prefix search.'),\n // Optional (not .default()) so the inferred type keeps existing direct\n // callers compiling; search() itself defaults it to 'lexical'.\n mode: z\n .enum(['lexical', 'semantic', 'hybrid'])\n .optional()\n .describe(\n 'lexical = keyword search (default). semantic = meaning-based search over local embeddings (requires SEEKSTONE_SEMANTIC=1 and a fetched model). hybrid = exact-title lookups go lexical, everything else semantic.',\n ),\n limit: z\n .number()\n .int()\n .min(1)\n .max(50)\n .default(10)\n .describe('Maximum number of results to return.'),\n folder: z\n .string()\n .optional()\n .describe('Restrict results to notes under this vault-relative folder prefix.'),\n tag: z.string().optional().describe('Restrict results to notes containing this tag.'),\n excerptLength: z\n .number()\n .int()\n .min(20)\n .max(2000)\n .optional()\n .describe(\n 'Max characters of match context per hit (default 120). Lower trims payload; higher gives more context.',\n ),\n});\nexport type SearchInput = z.infer<typeof SearchInput>;\n\n/** Semantic candidates fetched before folder/tag filtering (the schema's limit max). */\nconst SEMANTIC_CANDIDATES = 50;\n\n/** Basename without extension — the title is omitted from a hit when it matches this. */\nexport function basenameNoExt(path: string): string {\n const base = path.slice(path.lastIndexOf('/') + 1);\n const dot = base.lastIndexOf('.');\n return dot > 0 ? base.slice(0, dot) : base;\n}\n\nexport function search(ctx: ServerContext, input: SearchInput): SearchHit[] {\n // Direct in-process callers bypass the zod defaults — normalize here.\n const mode = input.mode ?? 'lexical';\n if (mode === 'lexical') return lexicalSearch(ctx, input);\n\n const semantic = requireSemantic(ctx);\n if (mode === 'semantic') return semanticSearch(ctx, semantic, input);\n\n // hybrid: an exact-title lookup goes lexical; everything else semantic.\n // Long queries can't plausibly be a title, so they skip MiniSearch entirely\n // (fuzzy matching on long queries is the expensive path).\n const words = queryWords(input.query);\n if (words.length > 0 && words.length <= MAX_ROUTE_WORDS) {\n const lexHits = lexicalSearch(ctx, input);\n if (\n routeToLexical(\n input.query,\n lexHits.map((h) => h.path),\n )\n )\n return lexHits;\n }\n return semanticSearch(ctx, semantic, input);\n}\n\nfunction requireSemantic(ctx: ServerContext): Semantic {\n if (!ctx.semantic) {\n throw new Error(\n JSON.stringify({\n error: 'semantic_unavailable',\n hint: 'Semantic search is not enabled. Set SEEKSTONE_SEMANTIC=1 in the server env and run `npx -y seekstone fetch-model` once to download the local embedding model, then restart the session. Meanwhile, mode: \"lexical\" works.',\n }),\n );\n }\n const progress = ctx.semantic.progress;\n if (progress.state === 'building') {\n throw new Error(\n JSON.stringify({\n error: 'semantic_building',\n done: progress.done,\n total: progress.total,\n hint: 'The semantic index is still embedding this vault (first run only — later runs load a cache). Retry shortly, or use mode: \"lexical\".',\n }),\n );\n }\n return ctx.semantic;\n}\n\nfunction searchTerms(query: string): string[] {\n return query\n .toLowerCase()\n .split(/\\s+/)\n .filter((t) => t.length > 1);\n}\n\nfunction lexicalSearch(ctx: ServerContext, input: SearchInput): SearchHit[] {\n const results = ctx.index.search(input.query, {\n boost: { title: 3, tags: 2, body: 1 },\n fuzzy: 0.2,\n prefix: true,\n });\n const terms = searchTerms(input.query);\n\n const hits: SearchHit[] = [];\n for (const r of results) {\n const note = filterNote(ctx, input, r.id);\n if (!note) continue;\n const hit: SearchHit = {\n path: r.id,\n // Round the raw MiniSearch score: 2 decimals preserve relevance gaps without 17-digit float tax.\n score: Math.round(r.score * 100) / 100,\n excerpt: extractExcerpt(note.body, terms, input.excerptLength ?? 120),\n };\n decorate(hit, r.title as string, note.tags);\n hits.push(hit);\n if (hits.length >= input.limit) break;\n }\n return hits;\n}\n\nfunction semanticSearch(ctx: ServerContext, semantic: Semantic, input: SearchInput): SearchHit[] {\n const queryVec = semantic.embedQuery(input.query);\n // Stage 1: pooled cosine top-50; stage 2: MaxSim rerank (SHA-314).\n // 1-hop graph expansion (semantic/expand.ts) is deliberately NOT wired in:\n // the SHA-315 dev-split eval could not measure a gain on the committed\n // fixture (its links are random by design) — see EXPANSION-SHA-315.md.\n const candidates = semantic.rerank(\n input.query,\n semantic.store.topNotes(queryVec, SEMANTIC_CANDIDATES),\n );\n const terms = searchTerms(input.query);\n\n const hits: SearchHit[] = [];\n for (const c of candidates) {\n const note = filterNote(ctx, input, c.path);\n if (!note) continue;\n const hit: SearchHit = {\n path: c.path,\n // Cosine similarity ∈ [-1, 1]: 3 decimals keep the ranking legible.\n score: Math.round(c.score * 1000) / 1000,\n excerpt: chunkExcerpt(note.body, c, terms, input.excerptLength ?? 120),\n };\n decorate(hit, note.title, note.tags);\n hits.push(hit);\n if (hits.length >= input.limit) break;\n }\n return hits;\n}\n\n/** Apply folder/tag filters; returns the note when it passes, else undefined. */\nfunction filterNote(ctx: ServerContext, input: SearchInput, path: string) {\n if (input.folder && !path.startsWith(input.folder)) return undefined;\n const note = ctx.notes.get(path);\n if (!note) return undefined;\n if (input.tag) {\n const noteTags = note.tags.split(' ');\n if (!noteTags.some((t) => t === input.tag || t === input.tag?.replace(/^#/, ''))) {\n return undefined;\n }\n }\n return note;\n}\n\nfunction decorate(hit: SearchHit, title: string, tags: string): void {\n // Omit redundant/empty metadata to keep the payload lean (both are recoverable).\n if (title && title !== basenameNoExt(hit.path)) hit.title = title;\n const noteTags = tags ? tags.split(' ').filter(Boolean) : [];\n if (noteTags.length > 0) hit.tags = noteTags;\n}\n","import { extractExcerpt } from '../index/excerpt.js';\n\n/**\n * Excerpt for a semantic hit: slice the winning chunk's span out of the\n * note's in-memory body (spans were recorded at embed time, so there is no\n * re-chunking on the query path) and excerpt within it. Query terms often\n * don't literally appear in a semantic match, in which case extractExcerpt\n * falls back to the START of the matching chunk — the relevant passage —\n * instead of the head of the note.\n */\nexport function chunkExcerpt(\n body: string,\n span: { start: number; end: number },\n terms: string[],\n maxLen: number,\n): string {\n // Spans are offsets into the CRLF-normalized body (chunkNote normalizes).\n const normalized = body.includes('\\r') ? body.replace(/\\r\\n/g, '\\n') : body;\n // The note may have changed inside the re-embed debounce window — clamp.\n const start = Math.min(span.start, normalized.length);\n const end = Math.min(Math.max(span.end, start), normalized.length);\n const text = start === end ? normalized : normalized.slice(start, end);\n return extractExcerpt(text, terms, maxLen);\n}\n","/**\n * Hybrid-mode query routing, the recipe the SHA-307 golden-set eval chose\n * over RRF and score-weighted fusion: a query goes to lexical search only\n * when it IS a top lexical hit's title — the hit's basename words and the\n * query words are the same set. Exact-name lookups are what MiniSearch's 3×\n * title boost wins; a query that merely *contains* a title (\"green\n * gemstones\" vs a note titled \"Green\") is describing, not naming, and stays\n * semantic. (The same rule lives in the harness's retrieval/fusion.ts, where\n * the eval that picked it runs.)\n */\n\n/** Queries longer than this cannot plausibly be a title — skip lexical entirely. */\nexport const MAX_ROUTE_WORDS = 6;\n\nexport function queryWords(query: string): string[] {\n return query.toLowerCase().split(/\\W+/).filter(Boolean);\n}\n\nexport function routeToLexical(query: string, topPaths: readonly string[], topN = 3): boolean {\n const words = new Set(queryWords(query));\n if (words.size === 0) return false;\n return topPaths.slice(0, topN).some((path) => {\n const base = (path.split('/').pop() ?? '').replace(/\\.md$/, '').toLowerCase();\n const parts = new Set(base.split(/\\W+/).filter(Boolean));\n return parts.size === words.size && [...parts].every((p) => words.has(p));\n });\n}\n","import { access, mkdir, readFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { stringify as stringifyYaml } from 'yaml';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { buildDoc, upsertDoc } from '../index/doc.js';\nimport { journalWrite } from '../journal.js';\nimport { assertWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const CreateNoteInput = z\n .object({\n path: z\n .string()\n .describe(\n 'Vault-relative path for the new note, e.g. \"Daily Notes/2026-06-01.md\". Parent directories are created automatically.',\n ),\n content: z.string().default('').describe('Body content for the note.'),\n frontmatter: z\n .record(z.string(), z.unknown())\n .optional()\n .describe('Frontmatter key-value pairs to write as a YAML block at the top of the note.'),\n overwrite: z\n .boolean()\n .default(false)\n .describe(\n 'Overwrite an existing note. Defaults to false — throws if the note already exists.',\n ),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard for overwrite: true — the contentHash of the note being replaced. Fails with hash_conflict if it changed since it was read.',\n ),\n })\n .refine((v) => v.prevHash === undefined || v.overwrite === true, {\n message:\n 'prevHash only makes sense with overwrite: true (a fresh create has no prior version).',\n });\nexport type CreateNoteInput = z.input<typeof CreateNoteInput>;\n\nexport interface CreateNoteResult {\n path: string;\n bytesWritten: number;\n /** sha-256 (hex) of the written content — usable as prevHash for a chained edit. */\n contentHash: string;\n}\n\nexport async function createNote(\n ctx: ServerContext,\n rawInput: CreateNoteInput,\n): Promise<CreateNoteResult> {\n const input = CreateNoteInput.parse(rawInput);\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n assertWritable(ctx.policy, input.path);\n\n // Pre-image for the journal: the note being overwritten, or null for a\n // fresh create (undo then removes the file).\n let existing: string | null = null;\n if (!input.overwrite) {\n try {\n await access(absPath);\n throw new Error(`Note already exists: ${input.path}. Pass overwrite: true to replace it.`);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n } else {\n try {\n existing = await readFile(absPath, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n if (input.prevHash !== undefined) {\n // CAS on the note being replaced; a missing file is a conflict too\n // (the version the caller read no longer exists).\n throw new Error(\n JSON.stringify({\n error: 'hash_conflict',\n path: input.path,\n expected: input.prevHash,\n actual: null,\n hint: 'The note no longer exists on disk. Re-check before overwriting.',\n }),\n );\n }\n }\n if (existing !== null && input.prevHash !== undefined) {\n assertHashMatch(existing, input.prevHash, input.path);\n }\n }\n\n let raw = '';\n if (input.frontmatter && Object.keys(input.frontmatter).length > 0) {\n raw = `---\\n${stringifyYaml(input.frontmatter, { lineWidth: 0 })}---\\n`;\n }\n raw += input.content ?? '';\n\n await mkdir(dirname(absPath), { recursive: true });\n await journalWrite(ctx, 'create_note', input.path, existing, raw);\n await atomicWrite(absPath, raw);\n\n // Sync in-memory index so the new note is immediately searchable.\n upsertDoc(ctx, buildDoc(input.path, raw));\n\n return {\n path: input.path,\n bytesWritten: Buffer.byteLength(raw, 'utf8'),\n contentHash: contentHash(raw),\n };\n}\n","import { basename, extname } from 'node:path';\nimport { extractInlineTags, frontmatterTags } from '@seekstone/core/extract';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport type { IndexedNote } from './types.js';\n\n/** Build an IndexedNote from a vault-relative path and raw file content. */\nexport function buildDoc(relPath: string, raw: string): IndexedNote {\n const fm = parseFrontmatter(raw);\n const allTags = [...new Set([...extractInlineTags(fm.body), ...frontmatterTags(fm.data)])];\n const title =\n typeof fm.data?.title === 'string' && fm.data.title\n ? fm.data.title\n : basename(relPath, extname(relPath));\n return {\n id: relPath,\n title,\n body: fm.body,\n tags: allTags.join(' '),\n fmKeys: fm.keys.join(' '),\n fm: fm.data,\n raw,\n sizeBytes: Buffer.byteLength(raw, 'utf8'),\n mtimeMs: Date.now(),\n };\n}\n\n/** Upsert a document into the context index. Discards any stale entry first. */\nexport function upsertDoc(\n ctx: {\n index: { discard(id: string): void; add(doc: IndexedNote): void };\n notes: Map<string, IndexedNote>;\n },\n doc: IndexedNote,\n): void {\n if (ctx.notes.has(doc.id)) ctx.index.discard(doc.id);\n ctx.notes.set(doc.id, doc);\n ctx.index.add(doc);\n}\n","import { access, mkdir, readFile, rename, rm } from 'node:fs/promises';\nimport { basename, extname, join } from 'node:path';\nimport { z } from 'zod';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { removeNoteBacklinks } from '../index/backlinks.js';\nimport { journalWrite } from '../journal.js';\nimport { assertWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const DeleteNoteInput = z.object({\n path: z.string().describe('Vault-relative path of the note to delete.'),\n permanent: z\n .boolean()\n .default(false)\n .describe(\n 'Permanently remove the note instead of moving it to the vault .trash/ folder. Defaults to false — deletes are recoverable.',\n ),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since — so you never delete content you have not seen.',\n ),\n});\nexport type DeleteNoteInput = z.input<typeof DeleteNoteInput>;\n\nexport interface DeleteNoteResult {\n path: string;\n /** Vault-relative path the note was moved to, when not permanent. */\n trashedTo?: string;\n permanent: boolean;\n /** sha-256 (hex) of the deleted content — for a recoverable delete this is the hash of the byte-identical file now in .trash/. */\n contentHash: string;\n}\n\n/** Find a free destination name inside .trash/, suffixing before the extension on collision. */\nasync function freeTrashPath(vaultRoot: string, noteBase: string): Promise<string> {\n const ext = extname(noteBase);\n const stem = noteBase.slice(0, noteBase.length - ext.length);\n let candidate = `.trash/${noteBase}`;\n for (;;) {\n try {\n await access(join(vaultRoot, candidate));\n } catch {\n return candidate;\n }\n // Epoch-ms suffix; loop guards the (test-speed) case of two collisions in one ms.\n candidate = `.trash/${stem}.${Date.now()}${ext}`;\n }\n}\n\nexport async function deleteNote(\n ctx: ServerContext,\n rawInput: DeleteNoteInput,\n): Promise<DeleteNoteResult> {\n const input = DeleteNoteInput.parse(rawInput);\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n // Policy applies to the note being deleted; the .trash/ destination is the\n // safety mechanism itself, not a user write.\n assertWritable(ctx.policy, input.path);\n\n // Read before deleting: ENOENT propagates for a missing note (same shape rm\n // gave), the bytes are the CAS identity, and the hash documents exactly\n // what was deleted (byte-identical to the .trash/ copy when recoverable).\n const raw = await readFile(absPath, 'utf8');\n if (input.prevHash !== undefined) assertHashMatch(raw, input.prevHash, input.path);\n\n // Journaled whether or not the delete is permanent: undo_write restores\n // the bytes from the journal, so even permanent: true is reversible.\n await journalWrite(ctx, 'delete_note', input.path, raw, null);\n\n let trashedTo: string | undefined;\n if (input.permanent) {\n await rm(absPath);\n } else {\n await mkdir(join(ctx.vaultRoot, '.trash'), { recursive: true });\n trashedTo = await freeTrashPath(ctx.vaultRoot, basename(input.path));\n // Same-volume rename: atomic, byte-identical, and invisible to the index —\n // the walker and watcher both exclude .trash/.\n await rename(absPath, join(ctx.vaultRoot, trashedTo));\n }\n\n // Clear the note's own outgoing refs while its entry is still readable.\n removeNoteBacklinks(ctx, input.path);\n if (ctx.notes.has(input.path)) {\n ctx.index.discard(input.path);\n ctx.notes.delete(input.path);\n }\n\n const result: DeleteNoteResult = {\n path: input.path,\n permanent: input.permanent,\n contentHash: contentHash(raw),\n };\n if (trashedTo !== undefined) result.trashedTo = trashedTo;\n return result;\n}\n","import { extractLinksWithLines } from '@seekstone/core/extract';\nimport type { BacklinkRef, ServerContext } from '../context.js';\nimport { buildResolveMaps, resolveLink } from './resolve.js';\n\n/**\n * Incremental backlink-index maintenance, shared by the watcher and the\n * link-aware move path. Remove BEFORE mutating the note's entry in ctx.notes\n * (it reads the old raw); add AFTER the entry is current.\n */\n\nexport function removeNoteBacklinks(ctx: ServerContext, relPath: string): void {\n const oldDoc = ctx.notes.get(relPath);\n if (oldDoc === undefined) return;\n const links = extractLinksWithLines(oldDoc.raw);\n if (links.length === 0) return;\n const maps = buildResolveMaps(ctx.notes);\n for (const link of links) {\n const resolved = resolveLink(link.target, ctx.notes, maps);\n if (resolved === undefined) continue;\n const arr = ctx.backlinks.get(resolved);\n if (arr === undefined) continue;\n const filtered = arr.filter((r) => r.path !== relPath);\n ctx.backlinks.set(resolved, filtered);\n }\n}\n\nexport function addNoteBacklinks(ctx: ServerContext, relPath: string, raw: string): void {\n const seen = new Set<string>();\n const links = extractLinksWithLines(raw);\n if (links.length === 0) return;\n const maps = buildResolveMaps(ctx.notes);\n for (const link of links) {\n const resolved = resolveLink(link.target, ctx.notes, maps);\n if (resolved === undefined) continue;\n const dedupeKey = `${relPath}\\0${resolved}`;\n if (seen.has(dedupeKey)) continue;\n seen.add(dedupeKey);\n let arr = ctx.backlinks.get(resolved);\n if (arr === undefined) {\n arr = [];\n ctx.backlinks.set(resolved, arr);\n }\n const ref: BacklinkRef = { path: relPath, line: link.line, linkType: link.linkType };\n arr.push(ref);\n arr.sort((a, b) => a.path.localeCompare(b.path));\n }\n}\n","import { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const GetBacklinksInput = z.object({\n path: z.string().describe('Vault-relative path to the target note.'),\n includeContext: z\n .boolean()\n .optional()\n .describe('Include a short excerpt (~200 chars) from the linking line. Default true.'),\n limit: z\n .number()\n .int()\n .min(1)\n .max(500)\n .optional()\n .describe('Max backlinks to return. Default 50.'),\n});\nexport type GetBacklinksInput = z.infer<typeof GetBacklinksInput>;\n\nexport interface BacklinkEntry {\n path: string;\n line: number;\n excerpt?: string;\n linkType: 'wikilink' | 'embed';\n}\n\nexport interface GetBacklinksResult {\n target: string;\n backlinks: BacklinkEntry[];\n total: number;\n}\n\nconst EXCERPT_MAX = 200;\n\nexport function getBacklinks(ctx: ServerContext, input: GetBacklinksInput): GetBacklinksResult {\n resolveVaultPath(ctx.vaultRoot, input.path); // containment validation only\n\n const includeContext = input.includeContext ?? true;\n const limit = input.limit ?? 50;\n\n const refs = ctx.backlinks.get(input.path) ?? [];\n const total = refs.length;\n const limited = refs.slice(0, limit);\n\n const backlinks: BacklinkEntry[] = [];\n for (const ref of limited) {\n const entry: BacklinkEntry = { path: ref.path, line: ref.line, linkType: ref.linkType };\n if (includeContext) {\n const srcNote = ctx.notes.get(ref.path);\n if (srcNote !== undefined) {\n const rawLines = srcNote.raw.split('\\n');\n const lineText = rawLines[ref.line - 1];\n if (lineText !== undefined) {\n entry.excerpt =\n lineText.length > EXCERPT_MAX ? `${lineText.slice(0, EXCERPT_MAX)}…` : lineText;\n }\n }\n }\n backlinks.push(entry);\n }\n\n return { target: input.path, backlinks, total };\n}\n","import type { LinkType } from '@seekstone/core/extract';\nimport { extractLinksWithLines } from '@seekstone/core/extract';\nimport { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { resolveLink } from '../index/resolve.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const GetLinksInput = z.object({\n path: z.string().describe('Vault-relative path to the note.'),\n});\nexport type GetLinksInput = z.infer<typeof GetLinksInput>;\n\nexport interface GetLinksEntry {\n raw: string;\n /** Resolved vault-relative path. Absent when unresolved. */\n target?: string;\n resolved: boolean;\n linkType: LinkType;\n line: number;\n}\n\nexport interface GetLinksResult {\n path: string;\n links: GetLinksEntry[];\n}\n\nexport function getLinks(ctx: ServerContext, input: GetLinksInput): GetLinksResult {\n resolveVaultPath(ctx.vaultRoot, input.path); // containment validation only\n const note = ctx.notes.get(input.path);\n if (note === undefined) throw new Error(`Note not found: ${input.path}`);\n\n const rawLinks = extractLinksWithLines(note.raw);\n\n // De-duplicate: one entry per (target string) — keep first occurrence by line\n const seen = new Set<string>();\n const links: GetLinksEntry[] = [];\n for (const link of rawLinks) {\n if (seen.has(link.target)) continue;\n seen.add(link.target);\n const resolvedPath = resolveLink(link.target, ctx.notes);\n const entry: GetLinksEntry = {\n raw: link.raw,\n resolved: resolvedPath !== undefined,\n linkType: link.linkType,\n line: link.line,\n };\n if (resolvedPath !== undefined) entry.target = resolvedPath;\n links.push(entry);\n }\n\n links.sort((a, b) => a.line - b.line);\n\n return { path: input.path, links };\n}\n","import { z } from 'zod';\nimport type { ServerContext } from '../context.js';\n\nexport const ListNotesInput = z.object({\n folder: z\n .string()\n .optional()\n .describe(\n 'Vault-relative folder prefix to list. Omit for all notes. Example: \"Daily Notes/2026\".',\n ),\n tag: z.string().optional().describe('Filter by tag. Include or omit the leading #.'),\n limit: z.number().int().min(1).max(500).default(100).describe('Maximum number of results.'),\n});\nexport type ListNotesInput = z.infer<typeof ListNotesInput>;\n\nexport interface NoteEntry {\n path: string;\n title: string;\n tags: string[];\n sizeBytes: number;\n}\n\nexport function listNotes(ctx: ServerContext, input: ListNotesInput): NoteEntry[] {\n const tag = input.tag?.replace(/^#/, '');\n const results: NoteEntry[] = [];\n\n for (const [path, note] of ctx.notes) {\n if (input.folder && !path.startsWith(input.folder)) continue;\n if (tag) {\n const noteTags = note.tags.split(' ').filter(Boolean);\n if (!noteTags.includes(tag)) continue;\n }\n results.push({\n path,\n title: note.title,\n tags: note.tags.split(' ').filter(Boolean),\n sizeBytes: note.sizeBytes,\n });\n if (results.length >= input.limit) break;\n }\n\n return results.sort((a, b) => a.path.localeCompare(b.path));\n}\n","import { z } from 'zod';\nimport type { ServerContext } from '../context.js';\n\nexport const ListTagsInput = z.object({\n pattern: z\n .string()\n .optional()\n .describe('Substring filter on tag name. Example: \"work\" matches \"work\" and \"area/work\".'),\n minCount: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe('Only return tags used in at least this many notes.'),\n sort: z\n .enum(['count', 'name'])\n .default('count')\n .describe('Sort by usage count descending (default) or alphabetically.'),\n});\nexport type ListTagsInput = z.infer<typeof ListTagsInput>;\n\nexport interface TagEntry {\n tag: string;\n count: number;\n parent?: string;\n}\n\nexport interface ListTagsResult {\n tags: TagEntry[];\n total: number;\n}\n\nexport function listTags(ctx: ServerContext, input: ListTagsInput): ListTagsResult {\n const counts = new Map<string, number>();\n\n for (const note of ctx.notes.values()) {\n for (const tag of note.tags.split(' ').filter(Boolean)) {\n counts.set(tag, (counts.get(tag) ?? 0) + 1);\n }\n }\n\n const tags: TagEntry[] = [];\n for (const [tag, count] of counts) {\n if (input.pattern !== undefined && !tag.includes(input.pattern)) continue;\n if (input.minCount !== undefined && count < input.minCount) continue;\n const slashIdx = tag.lastIndexOf('/');\n const entry: TagEntry = { tag, count };\n if (slashIdx !== -1) entry.parent = tag.slice(0, slashIdx);\n tags.push(entry);\n }\n\n if (input.sort === 'name') {\n tags.sort((a, b) => a.tag.localeCompare(b.tag));\n } else {\n tags.sort((a, b) => b.count - a.count || a.tag.localeCompare(b.tag));\n }\n\n return { tags, total: tags.length };\n}\n","import { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport type { JournalListRow } from '../journal.js';\n\nexport const ListWritesInput = z.object({\n limit: z\n .number()\n .int()\n .min(1)\n .max(200)\n .default(20)\n .describe('Max entries to return, newest first (1–200, default 20).'),\n path: z.string().optional().describe('Only entries that touched this vault-relative path.'),\n});\nexport type ListWritesInput = z.input<typeof ListWritesInput>;\n\nexport interface ListWritesResult {\n /** Newest first. Metadata only — no note content. */\n writes: JournalListRow[];\n /** Total matching entries in the journal (before `limit`). */\n total: number;\n /** Present (true) only when the journal is disabled via SEEKSTONE_HISTORY=0. */\n disabled?: true;\n}\n\n/** Recent journal entries — what `undo_write` can revert. */\nexport function listWrites(ctx: ServerContext, rawInput: ListWritesInput): ListWritesResult {\n const input = ListWritesInput.parse(rawInput);\n if (!ctx.journal) return { writes: [], total: 0, disabled: true };\n const opts: { limit: number; path?: string } = { limit: input.limit };\n if (input.path !== undefined) opts.path = input.path;\n return ctx.journal.list(opts);\n}\n","import { mkdir, readFile, rename } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { addNoteBacklinks, removeNoteBacklinks } from '../index/backlinks.js';\nimport { buildDoc, upsertDoc } from '../index/doc.js';\nimport { assertWritable, isWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\nimport { hasMarkdownLinkTo, rewriteNoteLinks } from './rewrite_links.js';\n\nexport const MoveNoteInput = z.object({\n from: z.string().describe('Vault-relative path of the note to move.'),\n to: z.string().describe('Vault-relative destination path.'),\n overwrite: z\n .boolean()\n .default(false)\n .describe('Overwrite the destination if it exists. Defaults to false.'),\n rewriteLinks: z\n .boolean()\n .default(true)\n .describe(\n 'Rewrite wikilinks and markdown links in other notes that point at the moved note, so nothing breaks. Defaults to true; pass false to move the file only.',\n ),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard on the source note: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n ),\n});\nexport type MoveNoteInput = z.input<typeof MoveNoteInput>;\n\nexport interface MoveNoteResult {\n from: string;\n to: string;\n /** Referencing notes whose content was rewritten. */\n notesRewritten: number;\n /** Individual links rewritten across those notes. */\n linksRewritten: number;\n /** Referencing notes left untouched because SEEKSTONE_WRITE_PATHS excludes them. */\n skipped?: string[];\n /** sha-256 (hex) of the note at its new path — a move never changes content, so this is usable as prevHash for a chained edit at `to`. */\n contentHash: string;\n}\n\nexport async function moveNote(\n ctx: ServerContext,\n rawInput: MoveNoteInput,\n): Promise<MoveNoteResult> {\n // Parse here (not only in dispatch) so defaults like rewriteLinks apply to\n // direct callers too — same pattern as periodic_note.\n const input = MoveNoteInput.parse(rawInput);\n const absFrom = resolveVaultPath(ctx.vaultRoot, input.from);\n const absTo = resolveVaultPath(ctx.vaultRoot, input.to);\n assertWritable(ctx.policy, input.from);\n assertWritable(ctx.policy, input.to);\n\n // Read the source bytes up front: they are the CAS identity, the result\n // hash (a rename never changes content), and the truth the index entry at\n // the new path is rebuilt from (more reliable than a possibly-lagging\n // ctx.notes cache).\n let raw: string;\n try {\n raw = await readFile(absFrom, 'utf8');\n } catch {\n throw new Error(`Note not found: ${input.from}`);\n }\n if (input.prevHash !== undefined) assertHashMatch(raw, input.prevHash, input.from);\n\n // Pre-image of the destination (only ever non-null with overwrite: true).\n let existingAtTo: string | null = null;\n try {\n existingAtTo = await readFile(absTo, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n if (existingAtTo !== null && !input.overwrite) {\n throw new Error(`Destination already exists: ${input.to}. Pass overwrite: true to replace it.`);\n }\n\n // Snapshot pre-move state: link resolution before/after the move differs,\n // and the rewriter needs both views to rewrite only what breaks.\n const preNotes = new Map(ctx.notes);\n\n // Candidate referencing notes: wikilink sources from the backlink index,\n // plus a scan for markdown links (which the backlink index doesn't cover).\n // The moved note's own outgoing links are untouched by design — wikilinks\n // are path-independent, and rewriting its relative markdown links is a\n // separate concern from \"don't orphan the note in the graph\".\n const candidates = new Set<string>();\n if (input.rewriteLinks) {\n for (const ref of ctx.backlinks.get(input.from) ?? []) candidates.add(ref.path);\n for (const [path, doc] of preNotes) {\n if (path === input.from || candidates.has(path)) continue;\n if (hasMarkdownLinkTo(doc.raw, path, input.from)) candidates.add(path);\n }\n candidates.delete(input.from);\n }\n\n // Compute every link rewrite against the post-move resolution view BEFORE\n // touching disk, so the whole operation can be journaled under one seq\n // (undo restores all touched files or none) before the first byte changes.\n const postNotes = new Map(preNotes);\n postNotes.delete(input.from);\n postNotes.set(input.to, buildDoc(input.to, raw));\n\n const rewrites: { path: string; pre: string; content: string; count: number }[] = [];\n const skipped: string[] = [];\n for (const path of [...candidates].sort()) {\n const doc = preNotes.get(path);\n if (doc === undefined) continue;\n if (!isWritable(ctx.policy, path)) {\n // Out of write scope: leave the note untouched but report it, so the\n // caller knows which references were NOT updated.\n skipped.push(path);\n continue;\n }\n const { content, count } = rewriteNoteLinks(\n doc.raw,\n path,\n input.from,\n input.to,\n preNotes,\n postNotes,\n );\n rewrites.push({ path, pre: doc.raw, content, count });\n }\n\n if (ctx.journal) {\n const txn = ctx.journal.begin('move_note');\n await txn.add(input.from, raw, null);\n await txn.add(input.to, existingAtTo, raw);\n for (const r of rewrites) if (r.count > 0) await txn.add(r.path, r.pre, r.content);\n await txn.commit();\n }\n\n await mkdir(dirname(absTo), { recursive: true });\n await rename(absFrom, absTo);\n\n // Clear the moved note's own outgoing backlink refs while its old entry is\n // still readable — otherwise they stay registered under the stale source\n // path forever.\n removeNoteBacklinks(ctx, input.from);\n\n if (ctx.notes.has(input.from)) {\n ctx.index.discard(input.from);\n ctx.notes.delete(input.from);\n }\n upsertDoc(ctx, buildDoc(input.to, raw));\n addNoteBacklinks(ctx, input.to, raw);\n\n let notesRewritten = 0;\n let linksRewritten = 0;\n\n for (const { path, content, count } of rewrites) {\n const doc = ctx.notes.get(path);\n if (doc === undefined) continue;\n // Re-register this note's backlinks against post-move resolution even\n // when nothing was rewritten (basename links now resolve to the new\n // path); remove reads the old raw, so call it before updating the entry.\n removeNoteBacklinks(ctx, path);\n if (count > 0) {\n await atomicWrite(join(ctx.vaultRoot, path), content);\n upsertDoc(ctx, buildDoc(path, content));\n notesRewritten++;\n linksRewritten += count;\n addNoteBacklinks(ctx, path, content);\n } else {\n addNoteBacklinks(ctx, path, doc.raw);\n }\n }\n\n // Nothing resolves to the old path anymore — drop the stale key.\n ctx.backlinks.delete(input.from);\n\n const result: MoveNoteResult = {\n from: input.from,\n to: input.to,\n notesRewritten,\n linksRewritten,\n contentHash: contentHash(raw),\n };\n if (skipped.length > 0) result.skipped = skipped;\n return result;\n}\n","import { posix } from 'node:path';\nimport { resolveLink } from '../index/resolve.js';\n\n/**\n * Pure link-rewriting for link-aware moves: given a referencing note's raw\n * content, rewrite every wikilink, embed, and relative/vault-absolute markdown\n * link that pointed at `oldPath` so it points at `newPath`.\n *\n * Principles:\n * - **Rewrite only what breaks.** A link is left byte-identical when it still\n * resolves to the moved note after the move (Obsidian's shortest-unique-\n * basename semantics — e.g. `[[Italy]]` survives a folder move unchanged).\n * - **Preserve everything around the target**: embed `!`, `#fragment`,\n * `|alias`, `%20`-encoding and `<...>` wrapping in markdown links.\n * - **Skip fenced code blocks** (``` / ~~~). Inline backtick spans are NOT\n * skipped — consistent with the repo's deliberately loose link parsing.\n *\n * `preNotes` is the notes map as it was before the move (oldPath present),\n * `postNotes` after (newPath present) — both are needed to decide whether a\n * link used to point at the moved note and whether it still does.\n */\n\n// Mirrors LINK_WITH_LINES_RE in @seekstone/core/extract (same bounded\n// quantifiers), split into groups for reconstruction.\nconst WIKI_RE = /(!?)\\[\\[([^\\]|#\\n]{1,512})(#[^\\]|\\n]{1,512})?(\\|[^\\]\\n]{1,512})?\\]\\]/g;\n\n// Markdown links/embeds: target is everything to the first `)` (titles like\n// `[t](x \"title\")` are out of scope, matching the loose-parsing ethos).\nconst MD_RE = /(!?)\\[([^\\]\\n]*)\\]\\(([^)\\n]+)\\)/g;\n\nconst FENCE_RE = /^\\s*(```|~~~)/;\n\n/**\n * Map `fn` over every line outside fenced code blocks (``` / ~~~), leaving\n * fence delimiters and fenced content byte-identical. Shared by the move and\n * rename-heading rewriters.\n */\nexport function mapUnfencedLines(raw: string, fn: (line: string) => string): string {\n let inFence = false;\n return raw\n .split('\\n')\n .map((line) => {\n if (FENCE_RE.test(line)) {\n inFence = !inFence;\n return line;\n }\n return inFence ? line : fn(line);\n })\n .join('\\n');\n}\n\nexport interface RewriteNoteLinksResult {\n content: string;\n /** Number of individual links rewritten. */\n count: number;\n}\n\n/** Shortest target that still uniquely resolves to newPath: basename if unambiguous, else full path. */\nfunction wikiTargetFor(newPath: string, postNotes: Map<string, unknown>): string {\n const noExt = newPath.replace(/\\.md$/i, '');\n const base = noExt.split('/').pop() ?? noExt;\n // Count basename collisions directly — resolveLink breaks ties toward the\n // lexicographically smallest path, but \"resolves for us\" is not the same as\n // \"unambiguous in Obsidian\".\n const baseLower = base.toLowerCase();\n let matches = 0;\n for (const p of postNotes.keys()) {\n const pBase = (p.replace(/\\.md$/i, '').split('/').pop() ?? '').toLowerCase();\n if (pBase === baseLower && ++matches > 1) return noExt;\n }\n return base;\n}\n\n/** Interpret a markdown-link target as a vault-relative note path (or undefined). */\nfunction mdTargetToVaultPath(rawTarget: string, sourceDir: string): string | undefined {\n let t = rawTarget.trim();\n if (t.startsWith('<') && t.endsWith('>')) t = t.slice(1, -1);\n if (/^[a-z][a-z0-9+.-]*:/i.test(t)) return undefined; // http:, mailto:, obsidian:, …\n if (t.startsWith('#') || t === '') return undefined; // intra-note anchor\n const hashIdx = t.indexOf('#');\n if (hashIdx !== -1) t = t.slice(0, hashIdx);\n try {\n t = decodeURIComponent(t);\n } catch {\n /* malformed escape — use as-is */\n }\n const joined = posix.normalize(posix.join(sourceDir, t));\n if (joined.startsWith('..')) return undefined; // escapes the vault\n return joined;\n}\n\nexport function rewriteNoteLinks(\n raw: string,\n sourcePath: string,\n oldPath: string,\n newPath: string,\n preNotes: Map<string, unknown>,\n postNotes: Map<string, unknown>,\n): RewriteNoteLinksResult {\n const sourceDir = posix.dirname(sourcePath);\n const oldNoExt = oldPath.replace(/\\.md$/i, '');\n let count = 0;\n\n const rewriteWikiLine = (line: string): string =>\n line.replace(WIKI_RE, (full, bang: string, target: string, frag?: string, alias?: string) => {\n const t = target.trim();\n // Still resolves to the moved note → Obsidian keeps working; don't touch.\n if (resolveLink(t, postNotes) === newPath) return full;\n // Only rewrite links that used to point at the moved note.\n if (resolveLink(t, preNotes) !== oldPath) return full;\n count++;\n const next = wikiTargetFor(newPath, postNotes);\n return `${bang}[[${next}${frag ?? ''}${alias ?? ''}]]`;\n });\n\n const rewriteMdLine = (line: string): string =>\n line.replace(MD_RE, (full, bang: string, text: string, rawTarget: string) => {\n // Relative-to-source interpretation first, then vault-absolute.\n const asRelative = mdTargetToVaultPath(rawTarget, sourceDir);\n const asAbsolute = mdTargetToVaultPath(rawTarget, '.');\n let vaultAbsoluteStyle: boolean;\n if (asRelative === oldPath || asRelative === oldNoExt) vaultAbsoluteStyle = false;\n else if (asAbsolute === oldPath || asAbsolute === oldNoExt) vaultAbsoluteStyle = true;\n else return full;\n count++;\n\n const trimmed = rawTarget.trim();\n const wrapped = trimmed.startsWith('<') && trimmed.endsWith('>');\n const inner = wrapped ? trimmed.slice(1, -1) : trimmed;\n const hashIdx = inner.indexOf('#');\n const fragment = hashIdx === -1 ? '' : inner.slice(hashIdx);\n const hadExt = /\\.md(#|$)/i.test(inner);\n\n let next = vaultAbsoluteStyle ? newPath : posix.relative(sourceDir, newPath);\n if (!hadExt) next = next.replace(/\\.md$/i, '');\n // Preserve the original encoding style for spaces; wrap in <> when the\n // new path has spaces and the original used neither style.\n if (inner.includes('%20')) next = next.replaceAll(' ', '%20');\n const needsWrap = wrapped || next.includes(' ');\n const target = needsWrap ? `<${next}${fragment}>` : `${next}${fragment}`;\n return `${bang}[${text}](${target})`;\n });\n\n const content = mapUnfencedLines(raw, (line) => rewriteMdLine(rewriteWikiLine(line)));\n\n return { content, count };\n}\n\n/**\n * Scan a note's raw content for markdown links resolving to `targetPath` —\n * the candidate-discovery pass for referencing notes the backlink index can't\n * see (it only indexes wikilinks).\n */\nexport function hasMarkdownLinkTo(raw: string, sourcePath: string, targetPath: string): boolean {\n if (!raw.includes('](')) return false;\n const sourceDir = posix.dirname(sourcePath);\n const noExt = targetPath.replace(/\\.md$/i, '');\n for (const m of raw.matchAll(MD_RE)) {\n const rawTarget = m[3] ?? '';\n const asRelative = mdTargetToVaultPath(rawTarget, sourceDir);\n const asAbsolute = mdTargetToVaultPath(rawTarget, '.');\n if (\n asRelative === targetPath ||\n asRelative === noExt ||\n asAbsolute === targetPath ||\n asAbsolute === noExt\n ) {\n return true;\n }\n }\n return false;\n}\n","import { readFile } from 'node:fs/promises';\nimport { buildOutline } from '@seekstone/core/outline';\nimport { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const OutlineNoteInput = z.object({\n path: z.string().describe('Vault-relative path to the note.'),\n includeBlocks: z\n .boolean()\n .default(true)\n .describe('Include block-reference anchors (^id). Default true.'),\n includeSizes: z\n .boolean()\n .default(false)\n .describe('Include per-section character length in each heading entry. Default false.'),\n});\nexport type OutlineNoteInput = z.infer<typeof OutlineNoteInput>;\n\nexport async function outlineNote(ctx: ServerContext, input: OutlineNoteInput) {\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n\n const raw = await readFile(absPath, 'utf8');\n return buildOutline(raw, {\n includeBlocks: input.includeBlocks,\n includeSizes: input.includeSizes,\n });\n}\n","import { parseFrontmatter } from './frontmatter.js';\n\nexport interface HeadingEntry {\n text: string;\n level: number;\n /** 1-based line number in the file. */\n line: number;\n /** Character offset of the leading `#` in the raw file string. */\n byteOffset: number;\n /** Characters from this heading to the next (or end of file). Only present when includeSizes is true. */\n byteLength?: number;\n}\n\nexport interface BlockEntry {\n id: string;\n /** 1-based line number in the file. */\n line: number;\n /** Character offset of the `^` in the raw file string. */\n byteOffset: number;\n}\n\nexport interface NoteOutline {\n headings: HeadingEntry[];\n blocks: BlockEntry[];\n /** Top-level frontmatter keys in original order (empty if no frontmatter). */\n frontmatterKeys: string[];\n /** True UTF-8 byte length of the file. */\n totalBytes: number;\n}\n\nexport interface OutlineOptions {\n /** Include block-reference anchors (^id). Default true. */\n includeBlocks?: boolean;\n /** Include per-section character length in each heading entry. Default false. */\n includeSizes?: boolean;\n}\n\nconst HEADING_RE = /^(#{1,6})\\s+(.+)/;\nconst BLOCK_REF_RE = /\\^([a-zA-Z0-9-]+)$/;\n\n/**\n * Parse a note's structure — heading tree, block anchors, frontmatter keys —\n * without touching the prose. Shared by outline_note and patch_note.\n *\n * Offsets are character positions in the raw string (identical to UTF-8 byte\n * offsets for ASCII content, which covers the vast majority of vault notes).\n */\nexport function buildOutline(raw: string, options: OutlineOptions = {}): NoteOutline {\n const { includeBlocks = true, includeSizes = false } = options;\n\n const fm = parseFrontmatter(raw);\n const totalBytes = Buffer.byteLength(raw, 'utf8');\n const headings: HeadingEntry[] = [];\n const blocks: BlockEntry[] = [];\n\n let charOffset = 0;\n\n for (const [i, line] of raw.split('\\n').entries()) {\n const lineCharOffset = charOffset;\n const lineNum = i + 1;\n\n if (charOffset >= fm.bodyStart) {\n const hm = HEADING_RE.exec(line);\n if (hm) {\n headings.push({\n text: (hm[2] ?? '').trim(),\n level: (hm[1] ?? '').length,\n line: lineNum,\n byteOffset: lineCharOffset,\n });\n }\n\n if (includeBlocks) {\n const trimmed = line.trimEnd();\n const bm = BLOCK_REF_RE.exec(trimmed);\n if (bm) {\n const caretPos = trimmed.lastIndexOf('^');\n blocks.push({\n id: bm[1] ?? '',\n line: lineNum,\n byteOffset: lineCharOffset + caretPos,\n });\n }\n }\n }\n\n charOffset += line.length + 1; // +1 for the '\\n' consumed by split\n }\n\n if (includeSizes) {\n for (const [i, heading] of headings.entries()) {\n const next = headings[i + 1];\n heading.byteLength = (next?.byteOffset ?? raw.length) - heading.byteOffset;\n }\n }\n\n return { headings, blocks, frontmatterKeys: fm.keys, totalBytes };\n}\n","import { readFile } from 'node:fs/promises';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport { parseDocument } from 'yaml';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { journalWrite } from '../journal.js';\nimport { assertWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const PatchFrontmatterInput = z.object({\n path: z.string().describe('Vault-relative path to the note.'),\n patch: z\n .record(z.string(), z.unknown())\n .describe(\n 'Key-value pairs to set in the frontmatter. Existing keys not in the patch are unchanged. Pass null as a value to remove a key.',\n ),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n ),\n});\nexport type PatchFrontmatterInput = z.infer<typeof PatchFrontmatterInput>;\n\nexport interface PatchFrontmatterResult {\n path: string;\n keysChanged: string[];\n keysAdded: string[];\n keysRemoved: string[];\n /** sha-256 (hex) of the new content — usable as prevHash for a chained edit. */\n contentHash: string;\n}\n\n/**\n * Edit frontmatter values without reordering existing keys or changing\n * quote style. Uses yaml.parseDocument which preserves the CST, so round-trips\n * are byte-faithful for keys not touched by the patch.\n *\n * Patch semantics:\n * - Key present in patch, value non-null → set/update\n * - Key present in patch, value null → delete\n * - Key absent from patch → untouched\n *\n * If the note has no frontmatter, a new `---` block is created at the top.\n */\nexport async function patchFrontmatter(\n ctx: ServerContext,\n input: PatchFrontmatterInput,\n): Promise<PatchFrontmatterResult> {\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n assertWritable(ctx.policy, input.path);\n\n const original = await readFile(absPath, 'utf8');\n if (input.prevHash !== undefined) assertHashMatch(original, input.prevHash, input.path);\n const fm = parseFrontmatter(original);\n\n const keysChanged: string[] = [];\n const keysAdded: string[] = [];\n const keysRemoved: string[] = [];\n\n let newContent: string;\n\n if (!fm.present) {\n // No existing FM — create a minimal block with just the patch keys.\n const doc = parseDocument('');\n for (const [k, v] of Object.entries(input.patch)) {\n if (v !== null) {\n doc.set(k, v);\n keysAdded.push(k);\n }\n }\n newContent = `---\\n${doc.toString({ lineWidth: 0 })}---\\n${original}`;\n } else {\n // Parse the existing FM block preserving source tokens.\n const opensWithCRLF = original.startsWith('---\\r\\n');\n const openLen = opensWithCRLF ? 5 : 4;\n const closeLen = opensWithCRLF ? 7 : 5;\n const yamlText = original.slice(openLen, fm.bodyStart - closeLen);\n\n const doc = parseDocument(yamlText, { keepSourceTokens: true });\n\n for (const [k, v] of Object.entries(input.patch)) {\n const existing = doc.has(k);\n if (v === null) {\n if (existing) {\n doc.delete(k);\n keysRemoved.push(k);\n }\n } else if (existing) {\n doc.set(k, v);\n keysChanged.push(k);\n } else {\n doc.set(k, v);\n keysAdded.push(k);\n }\n }\n\n const head = opensWithCRLF ? '---\\r\\n' : '---\\n';\n const tail = opensWithCRLF ? '---\\r\\n' : '---\\n';\n newContent = `${head}${doc.toString({ lineWidth: 0 })}${tail}${fm.body}`;\n }\n\n await journalWrite(ctx, 'patch_frontmatter', input.path, original, newContent);\n await atomicWrite(absPath, newContent);\n\n // Update in-memory cache.\n const cached = ctx.notes.get(input.path);\n if (cached) {\n const updated = parseFrontmatter(newContent);\n cached.raw = newContent;\n cached.fmKeys = updated.keys.join(' ');\n }\n\n return {\n path: input.path,\n keysChanged,\n keysAdded,\n keysRemoved,\n contentHash: contentHash(newContent),\n };\n}\n","import { readFile } from 'node:fs/promises';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport { buildOutline } from '@seekstone/core/outline';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { journalWrite } from '../journal.js';\nimport { assertWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const PatchNoteInput = z.object({\n path: z.string().describe('Vault-relative path to the note.'),\n target: z\n .union([\n z.object({ heading: z.string().describe('Heading text (without # markers).') }),\n z.object({ block: z.string().describe('Block reference ID (without the ^ prefix).') }),\n ])\n .describe('Target section. Provide exactly one of heading or block.'),\n operation: z\n .enum(['append', 'prepend', 'replace'])\n .describe(\n 'append: insert after section content. prepend: insert after heading line. replace: swap section content.',\n ),\n content: z.string().min(1).describe('Content to insert or replace with.'),\n createIfMissing: z\n .boolean()\n .default(false)\n .describe(\n 'If the heading target is not found, append a new heading (level 2) + content. Only valid for heading targets.',\n ),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n ),\n});\nexport type PatchNoteInput = z.infer<typeof PatchNoteInput>;\n\nexport interface PatchNoteResult {\n path: string;\n bytesWritten: number;\n targetResolvedAt: { line: number; byteOffset: number };\n frontmatterUnchanged: true;\n /** sha-256 (hex) of the new content — usable as prevHash for a chained edit. */\n contentHash: string;\n}\n\n/** Character offset of the start of the next line after `offset`. */\nfunction lineEnd(raw: string, offset: number): number {\n const nl = raw.indexOf('\\n', offset);\n return nl === -1 ? raw.length : nl + 1;\n}\n\n/** Character offset of the start of the line that contains `offset`. */\nfunction lineStart(raw: string, offset: number): number {\n if (offset === 0) return 0;\n const prev = raw.lastIndexOf('\\n', offset - 1);\n return prev === -1 ? 0 : prev + 1;\n}\n\nexport async function patchNote(\n ctx: ServerContext,\n input: PatchNoteInput,\n): Promise<PatchNoteResult> {\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n assertWritable(ctx.policy, input.path);\n\n const raw = await readFile(absPath, 'utf8');\n if (input.prevHash !== undefined) assertHashMatch(raw, input.prevHash, input.path);\n const fm = parseFrontmatter(raw);\n const originalFmRegion = raw.slice(0, fm.bodyStart);\n const outline = buildOutline(raw, { includeBlocks: true });\n\n let contentStart: number;\n let contentEnd: number;\n let resolvedAt: { line: number; byteOffset: number };\n\n if ('heading' in input.target) {\n const targetText = input.target.heading;\n const heading = outline.headings.find((h) => h.text.toLowerCase() === targetText.toLowerCase());\n\n if (!heading) {\n if (input.createIfMissing) {\n const sep = raw.endsWith('\\n\\n') ? '' : raw.endsWith('\\n') ? '\\n' : '\\n\\n';\n const contentNl = input.content.endsWith('\\n') ? '' : '\\n';\n const newContent = `${raw}${sep}## ${targetText}\\n\\n${input.content}${contentNl}`;\n await journalWrite(ctx, 'patch_note', input.path, raw, newContent);\n await atomicWrite(absPath, newContent);\n await verifyFrontmatter(absPath, originalFmRegion);\n updateCache(ctx, input.path, newContent, fm.bodyStart);\n const headingOffset = raw.length + sep.length;\n return {\n path: input.path,\n bytesWritten: Buffer.byteLength(newContent, 'utf8'),\n targetResolvedAt: {\n line: newContent.slice(0, headingOffset).split('\\n').length,\n byteOffset: headingOffset,\n },\n frontmatterUnchanged: true,\n contentHash: contentHash(newContent),\n };\n }\n throw new Error(\n JSON.stringify({\n error: 'heading_not_found',\n target: targetText,\n available: outline.headings.map((h) => h.text),\n }),\n );\n }\n\n const headingLineEnd = lineEnd(raw, heading.byteOffset);\n const nextSibling = outline.headings.find(\n (h) => h.byteOffset > heading.byteOffset && h.level <= heading.level,\n );\n contentStart = headingLineEnd;\n contentEnd = nextSibling?.byteOffset ?? raw.length;\n resolvedAt = { line: heading.line, byteOffset: heading.byteOffset };\n } else {\n const targetId = input.target.block;\n const block = outline.blocks.find((b) => b.id === targetId);\n if (!block) {\n throw new Error(\n JSON.stringify({\n error: 'block_not_found',\n target: targetId,\n available: outline.blocks.map((b) => b.id),\n }),\n );\n }\n contentStart = lineStart(raw, block.byteOffset);\n contentEnd = lineEnd(raw, block.byteOffset);\n resolvedAt = { line: block.line, byteOffset: block.byteOffset };\n }\n\n const before = raw.slice(0, contentStart);\n const section = raw.slice(contentStart, contentEnd);\n const after = raw.slice(contentEnd);\n\n let newContent: string;\n switch (input.operation) {\n case 'prepend': {\n const sep = input.content.endsWith('\\n') ? '' : '\\n';\n newContent = `${before}${input.content}${sep}${section}${after}`;\n break;\n }\n case 'append': {\n const sectionNl = section.endsWith('\\n') ? '' : '\\n';\n const contentNl = input.content.endsWith('\\n') ? '' : '\\n';\n newContent = `${before}${section}${sectionNl}${input.content}${contentNl}${after}`;\n break;\n }\n case 'replace': {\n const contentNl = input.content.endsWith('\\n') ? '' : '\\n';\n newContent = `${before}${input.content}${contentNl}${after}`;\n break;\n }\n default:\n throw new Error(`Unknown operation: ${String(input.operation)}`);\n }\n\n await journalWrite(ctx, 'patch_note', input.path, raw, newContent);\n await atomicWrite(absPath, newContent);\n await verifyFrontmatter(absPath, originalFmRegion);\n updateCache(ctx, input.path, newContent, fm.bodyStart);\n\n return {\n path: input.path,\n bytesWritten: Buffer.byteLength(newContent, 'utf8'),\n targetResolvedAt: resolvedAt,\n frontmatterUnchanged: true,\n contentHash: contentHash(newContent),\n };\n}\n\nasync function verifyFrontmatter(absPath: string, originalFmRegion: string): Promise<void> {\n const written = await readFile(absPath, 'utf8');\n if (written.slice(0, originalFmRegion.length) !== originalFmRegion) {\n throw new Error('Write-safety violation: frontmatter region changed unexpectedly');\n }\n}\n\nfunction updateCache(\n ctx: ServerContext,\n path: string,\n newContent: string,\n bodyStart: number,\n): void {\n const cached = ctx.notes.get(path);\n if (cached) {\n cached.body = newContent.slice(bodyStart);\n cached.raw = newContent;\n cached.sizeBytes = Buffer.byteLength(newContent, 'utf8');\n }\n}\n","import { access, mkdir, readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { buildDoc, upsertDoc } from '../index/doc.js';\nimport { journalWrite } from '../journal.js';\nimport { assertWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\n// ── Period type ───────────────────────────────────────────────────────────────\n\nconst PERIOD = z.enum(['daily', 'weekly', 'monthly', 'quarterly', 'yearly']);\ntype Period = z.infer<typeof PERIOD>;\n\n// ── Config shapes (read from .obsidian on disk) ───────────────────────────────\n\ninterface PeriodicEntry {\n folder?: string;\n format?: string;\n template?: string;\n}\n\ninterface DailyNotesJson extends PeriodicEntry {}\n\ninterface PeriodicNotesJson {\n daily?: PeriodicEntry;\n weekly?: PeriodicEntry;\n monthly?: PeriodicEntry;\n quarterly?: PeriodicEntry;\n yearly?: PeriodicEntry;\n}\n\nconst DEFAULTS: Record<Period, Required<PeriodicEntry>> = {\n daily: { folder: '', format: 'YYYY-MM-DD', template: '' },\n weekly: { folder: '', format: 'gggg-[W]ww', template: '' },\n monthly: { folder: '', format: 'YYYY-MM', template: '' },\n quarterly: { folder: '', format: 'YYYY-[Q]Q', template: '' },\n yearly: { folder: '', format: 'YYYY', template: '' },\n};\n\nasync function readJson<T>(absPath: string): Promise<T | null> {\n try {\n return JSON.parse(await readFile(absPath, 'utf8')) as T;\n } catch {\n return null;\n }\n}\n\nasync function resolveConfig(vaultRoot: string, period: Period): Promise<Required<PeriodicEntry>> {\n const defaults = DEFAULTS[period];\n\n if (period === 'daily') {\n const cfg = await readJson<DailyNotesJson>(join(vaultRoot, '.obsidian', 'daily-notes.json'));\n return {\n folder: cfg?.folder ?? defaults.folder,\n format: cfg?.format ?? defaults.format,\n template: cfg?.template ?? defaults.template,\n };\n }\n\n const cfg = await readJson<PeriodicNotesJson>(\n join(vaultRoot, '.obsidian', 'plugins', 'periodic-notes', 'data.json'),\n );\n const entry = cfg?.[period];\n return {\n folder: entry?.folder ?? defaults.folder,\n format: entry?.format ?? defaults.format,\n template: entry?.template ?? defaults.template,\n };\n}\n\n// ── Moment-style date formatting (no external dep) ───────────────────────────\n\nfunction isoWeekAndYear(date: Date): { week: number; year: number } {\n const d = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n const day = d.getUTCDay() || 7; // Mon=1 … Sun=7\n d.setUTCDate(d.getUTCDate() + 4 - day); // nearest Thursday\n const jan1 = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\n const week = Math.ceil(((d.getTime() - jan1.getTime()) / 86_400_000 + 1) / 7);\n return { week, year: d.getUTCFullYear() };\n}\n\nexport function formatMomentDate(date: Date, format: string): string {\n // Use UTC accessors: ISO date strings (YYYY-MM-DD) parse as UTC midnight,\n // so local-time accessors would return the previous day in negative-offset\n // timezones (EST, PST, etc.).\n const year = date.getUTCFullYear();\n const month = date.getUTCMonth() + 1;\n const day = date.getUTCDate();\n const quarter = Math.ceil(month / 3);\n const { week: isoWeek, year: isoYear } = isoWeekAndYear(date);\n\n // Protect literal text in square brackets from token substitution.\n const PLACEHOLDER = '\\x00';\n const literals: string[] = [];\n let s = format.replace(/\\[([^\\]]*)\\]/g, (_, lit) => {\n literals.push(lit);\n return `${PLACEHOLDER}${literals.length - 1}${PLACEHOLDER}`;\n });\n\n // Substitute longest tokens first to avoid partial matches (e.g. YYYY before YY).\n s = s\n .replace(/gggg/g, String(isoYear).padStart(4, '0'))\n .replace(/YYYY/g, String(year).padStart(4, '0'))\n .replace(/YY/g, String(year).slice(-2))\n .replace(/MM/g, String(month).padStart(2, '0'))\n .replace(/M/g, String(month))\n .replace(/DD/g, String(day).padStart(2, '0'))\n .replace(/D/g, String(day))\n .replace(/ww/g, String(isoWeek).padStart(2, '0'))\n .replace(/W/g, String(isoWeek))\n .replace(/Q/g, String(quarter));\n\n // Restore literals. Built via RegExp constructor because the placeholder is a\n // control char (\\x00) that Biome disallows in a regex literal; Codacy's\n // non-literal-RegExp pattern is disabled repo-wide for this safe internal use.\n return s.replace(\n new RegExp(`${PLACEHOLDER}(\\\\d+)${PLACEHOLDER}`, 'g'),\n (_, i) => literals[+i] ?? '',\n );\n}\n\n// ── Resolve a note path from config + date ────────────────────────────────────\n\nexport function resolveNotePath(cfg: Required<PeriodicEntry>, date: Date): string {\n const filename = `${formatMomentDate(date, cfg.format)}.md`;\n return cfg.folder ? `${cfg.folder}/${filename}` : filename;\n}\n\n// ── Tool: get_periodic_note ───────────────────────────────────────────────────\n\nexport const GetPeriodicNoteInput = z.object({\n period: PERIOD.default('daily').describe(\n 'Period type: daily (default), weekly, monthly, quarterly, or yearly.',\n ),\n date: z\n .string()\n .optional()\n .describe('ISO date string (YYYY-MM-DD). Defaults to today when omitted.'),\n createIfMissing: z\n .boolean()\n .default(false)\n .describe(\n 'Create the note from the configured template if it does not exist. Default false — reports missing without creating.',\n ),\n});\nexport type GetPeriodicNoteInput = z.input<typeof GetPeriodicNoteInput>;\n\nexport interface GetPeriodicNoteResult {\n path: string;\n existed: boolean;\n created: boolean;\n /** sha-256 (hex) of the created content; only set when created is true. */\n contentHash?: string;\n}\n\nexport async function getPeriodicNote(\n ctx: ServerContext,\n rawInput: GetPeriodicNoteInput,\n): Promise<GetPeriodicNoteResult> {\n const input = GetPeriodicNoteInput.parse(rawInput);\n const date = input.date ? new Date(input.date) : new Date();\n const cfg = await resolveConfig(ctx.vaultRoot, input.period);\n const path = resolveNotePath(cfg, date);\n const abs = resolveVaultPath(ctx.vaultRoot, path);\n\n let existed = false;\n try {\n await access(abs);\n existed = true;\n } catch {}\n\n if (existed) return { path, existed: true, created: false };\n\n if (!input.createIfMissing) return { path, existed: false, created: false };\n\n // About to write: this \"read\" tool creates the note here, so the write\n // policy applies (dispatch also strips createIfMissing in read-only mode).\n assertWritable(ctx.policy, path);\n\n // Read template if configured.\n let body = '';\n if (cfg.template) {\n try {\n const templateAbs = resolveVaultPath(\n ctx.vaultRoot,\n cfg.template.endsWith('.md') ? cfg.template : `${cfg.template}.md`,\n );\n body = await readFile(templateAbs, 'utf8');\n } catch {}\n }\n\n await mkdir(dirname(abs), { recursive: true });\n await journalWrite(ctx, 'get_periodic_note', path, null, body);\n await atomicWrite(abs, body);\n upsertDoc(ctx, buildDoc(path, body));\n\n return { path, existed: false, created: true, contentHash: contentHash(body) };\n}\n\n// ── Tool: append_periodic_note ────────────────────────────────────────────────\n\nexport const AppendPeriodicNoteInput = z.object({\n period: PERIOD.default('daily').describe('Period type. Default: daily.'),\n date: z.string().optional().describe('ISO date string (YYYY-MM-DD). Defaults to today.'),\n content: z\n .string()\n .min(1)\n .describe('Text to append to the note body. Separated from existing content by a blank line.'),\n createIfMissing: z\n .boolean()\n .default(true)\n .describe('Create the note if it does not exist before appending. Default true.'),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard: the contentHash from a prior read of the resolved periodic note. Fails with hash_conflict if it changed since.',\n ),\n});\nexport type AppendPeriodicNoteInput = z.input<typeof AppendPeriodicNoteInput>;\n\nexport interface AppendPeriodicNoteResult {\n path: string;\n bytesWritten: number;\n /** sha-256 (hex) of the new content — usable as prevHash for a chained edit. */\n contentHash: string;\n}\n\nexport async function appendPeriodicNote(\n ctx: ServerContext,\n rawInput: AppendPeriodicNoteInput,\n): Promise<AppendPeriodicNoteResult> {\n const input = AppendPeriodicNoteInput.parse(rawInput);\n const date = input.date ? new Date(input.date) : new Date();\n const cfg = await resolveConfig(ctx.vaultRoot, input.period);\n const path = resolveNotePath(cfg, date);\n const abs = resolveVaultPath(ctx.vaultRoot, path);\n assertWritable(ctx.policy, path);\n\n let original = '';\n try {\n original = await readFile(abs, 'utf8');\n if (input.prevHash !== undefined) assertHashMatch(original, input.prevHash, path);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n if (input.prevHash !== undefined) {\n // The caller pinned a version that no longer exists — conflict, not create.\n throw new Error(\n JSON.stringify({\n error: 'hash_conflict',\n path,\n expected: input.prevHash,\n actual: null,\n hint: 'The periodic note no longer exists on disk. Re-read before retrying.',\n }),\n );\n }\n if (!input.createIfMissing) throw new Error(`Periodic note not found: ${path}`);\n await mkdir(dirname(abs), { recursive: true });\n await journalWrite(ctx, 'append_periodic_note', path, null, input.content);\n await atomicWrite(abs, input.content);\n upsertDoc(ctx, buildDoc(path, input.content));\n return {\n path,\n bytesWritten: Buffer.byteLength(input.content, 'utf8'),\n contentHash: contentHash(input.content),\n };\n }\n\n // Preserve frontmatter, append to body.\n const fm = parseFrontmatter(original);\n const body = fm.body.endsWith('\\n') ? fm.body : `${fm.body}\\n`;\n const separator = body.endsWith('\\n\\n') ? '' : '\\n';\n const newBody = `${body}${separator}${input.content}`;\n const header = original.slice(0, fm.bodyStart);\n const newRaw = `${header}${newBody}`;\n\n await journalWrite(ctx, 'append_periodic_note', path, original, newRaw);\n await atomicWrite(abs, newRaw);\n\n const cached = ctx.notes.get(path);\n if (cached) {\n cached.body = newBody;\n cached.raw = newRaw;\n }\n\n return {\n path,\n bytesWritten: Buffer.byteLength(newRaw, 'utf8'),\n contentHash: contentHash(newRaw),\n };\n}\n","import { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { basenameNoExt } from './search.js';\n\nconst OPS_WITHOUT_VALUE = new Set(['exists', 'missing']);\n\nconst Predicate = z\n .object({\n key: z.string().min(1).describe('Frontmatter key to test (top-level).'),\n op: z\n .enum(['eq', 'ne', 'contains', 'exists', 'missing', 'gt', 'gte', 'lt', 'lte'])\n .describe(\n 'eq/ne compare scalars; contains matches array membership or substring; ' +\n 'exists/missing test key presence; gt/gte/lt/lte compare numbers or strings (ISO dates sort correctly).',\n ),\n value: z\n .union([z.string(), z.number(), z.boolean()])\n .optional()\n .describe('Comparison value. Required for every op except exists/missing.'),\n })\n .refine((p) => OPS_WITHOUT_VALUE.has(p.op) || p.value !== undefined, {\n message: 'value is required for this op',\n });\n\nconst ISO_DATE = z\n .string()\n .refine((s) => !Number.isNaN(Date.parse(s)), { message: 'not a parseable date' });\n\nexport const QueryNotesInput = z.object({\n where: z\n .array(Predicate)\n .max(20)\n .default([])\n .describe('Frontmatter predicates. All must match (AND).'),\n folder: z\n .string()\n .optional()\n .describe('Restrict to notes under this vault-relative folder prefix.'),\n tag: z.string().optional().describe('Restrict to notes with this tag (# prefix optional).'),\n modifiedAfter: ISO_DATE.optional().describe(\n 'Only notes modified at or after this ISO 8601 date/time.',\n ),\n modifiedBefore: ISO_DATE.optional().describe(\n 'Only notes modified before this ISO 8601 date/time.',\n ),\n minSizeBytes: z.number().int().min(0).optional().describe('Only notes at least this many bytes.'),\n maxSizeBytes: z.number().int().min(0).optional().describe('Only notes at most this many bytes.'),\n select: z\n .array(z.string())\n .max(20)\n .default([])\n .describe(\n 'Extra fields to return per hit: frontmatter keys, or the specials \"mtime\", \"size\", \"tags\". ' +\n 'Default returns only path + title, keeping the payload minimal.',\n ),\n sort: z.enum(['path', 'title', 'mtime', 'size']).default('path').describe('Sort field.'),\n order: z.enum(['asc', 'desc']).default('asc').describe('Sort order.'),\n limit: z.number().int().min(1).max(500).default(100).describe('Maximum number of results.'),\n});\nexport type QueryNotesInput = z.infer<typeof QueryNotesInput>;\n\nexport interface QueryHit {\n path: string;\n /** Omitted when it equals the path's basename (recoverable from `path`). */\n title?: string;\n /** ISO 8601 mtime — present only when \"mtime\" is selected. */\n mtime?: string;\n /** Present only when \"size\" is selected. */\n sizeBytes?: number;\n /** Present only when \"tags\" is selected and the note has tags. */\n tags?: string[];\n /** Selected frontmatter keys — present only when the note has at least one of them. */\n fm?: Record<string, unknown>;\n}\n\ntype Scalar = string | number | boolean;\n\n/** Loose scalar equality: strict first, then string-form — so `5` matches \"5\" and dates match. */\nfunction scalarEq(a: unknown, b: Scalar): boolean {\n if (a === b) return true;\n if (a === null || a === undefined || typeof a === 'object') return false;\n return String(a) === String(b);\n}\n\n/** Numeric when both sides coerce to finite numbers, else lexicographic (ISO dates sort correctly). */\nfunction compare(a: unknown, b: Scalar): number | undefined {\n if (a === null || a === undefined || typeof a === 'object' || typeof a === 'boolean') {\n return undefined;\n }\n const an = Number(a);\n const bn = Number(b);\n if (Number.isFinite(an) && Number.isFinite(bn)) return an - bn;\n const as = String(a);\n const bs = String(b);\n return as < bs ? -1 : as > bs ? 1 : 0;\n}\n\nfunction matches(fm: Record<string, unknown> | null, p: z.infer<typeof Predicate>): boolean {\n const val = fm?.[p.key];\n switch (p.op) {\n case 'exists':\n return val !== undefined;\n case 'missing':\n return val === undefined;\n case 'eq':\n return scalarEq(val, p.value as Scalar);\n // `ne` requires the key to exist — notes without the key don't match.\n case 'ne':\n return val !== undefined && !scalarEq(val, p.value as Scalar);\n case 'contains': {\n if (Array.isArray(val)) return val.some((v) => scalarEq(v, p.value as Scalar));\n if (typeof val === 'string') {\n return val.toLowerCase().includes(String(p.value).toLowerCase());\n }\n return false;\n }\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const c = compare(val, p.value as Scalar);\n if (c === undefined) return false;\n if (p.op === 'gt') return c > 0;\n if (p.op === 'gte') return c >= 0;\n if (p.op === 'lt') return c < 0;\n return c <= 0;\n }\n }\n}\n\nexport function queryNotes(ctx: ServerContext, input: QueryNotesInput): QueryHit[] {\n const tag = input.tag?.replace(/^#/, '');\n const after = input.modifiedAfter ? Date.parse(input.modifiedAfter) : undefined;\n const before = input.modifiedBefore ? Date.parse(input.modifiedBefore) : undefined;\n const fmKeys = input.select.filter((s) => s !== 'mtime' && s !== 'size' && s !== 'tags');\n\n const hits: { hit: QueryHit; note: { title: string; mtimeMs: number; sizeBytes: number } }[] = [];\n\n for (const [path, note] of ctx.notes) {\n if (input.folder && !path.startsWith(input.folder)) continue;\n if (tag && !note.tags.split(' ').filter(Boolean).includes(tag)) continue;\n if (after !== undefined && note.mtimeMs < after) continue;\n if (before !== undefined && note.mtimeMs >= before) continue;\n if (input.minSizeBytes !== undefined && note.sizeBytes < input.minSizeBytes) continue;\n if (input.maxSizeBytes !== undefined && note.sizeBytes > input.maxSizeBytes) continue;\n if (!input.where.every((p) => matches(note.fm, p))) continue;\n\n const hit: QueryHit = { path };\n // Omit redundant/empty metadata to keep the payload lean (recoverable from `path`).\n if (note.title && note.title !== basenameNoExt(path)) hit.title = note.title;\n if (input.select.includes('mtime')) hit.mtime = new Date(note.mtimeMs).toISOString();\n if (input.select.includes('size')) hit.sizeBytes = note.sizeBytes;\n if (input.select.includes('tags')) {\n const noteTags = note.tags.split(' ').filter(Boolean);\n if (noteTags.length > 0) hit.tags = noteTags;\n }\n if (fmKeys.length > 0 && note.fm) {\n const fm: Record<string, unknown> = {};\n for (const k of fmKeys) {\n if (note.fm[k] !== undefined) fm[k] = note.fm[k];\n }\n if (Object.keys(fm).length > 0) hit.fm = fm;\n }\n hits.push({ hit, note });\n }\n\n const dir = input.order === 'desc' ? -1 : 1;\n hits.sort((a, b) => {\n switch (input.sort) {\n case 'mtime':\n return (a.note.mtimeMs - b.note.mtimeMs) * dir;\n case 'size':\n return (a.note.sizeBytes - b.note.sizeBytes) * dir;\n case 'title':\n return a.note.title.localeCompare(b.note.title) * dir;\n default:\n return a.hit.path.localeCompare(b.hit.path) * dir;\n }\n });\n\n return hits.slice(0, input.limit).map((h) => h.hit);\n}\n","import { readFile } from 'node:fs/promises';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport { buildOutline } from '@seekstone/core/outline';\nimport { z } from 'zod';\nimport { contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const ReadNoteInput = z\n .object({\n path: z.string().describe('Vault-relative path to the note, e.g. \"Daily Notes/2026-05-29.md\".'),\n section: z\n .string()\n .optional()\n .describe('Return only this heading section (heading text, # prefix optional).'),\n block: z\n .string()\n .optional()\n .describe('Return only the block anchored by this id (^ prefix optional).'),\n lines: z\n .object({\n from: z.number().int().min(1).describe('First line (1-indexed, inclusive).'),\n to: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe('Last line (1-indexed, inclusive). Defaults to end of file.'),\n })\n .optional()\n .describe('Return only this line range (1-indexed, inclusive).'),\n includeFrontmatter: z\n .boolean()\n .optional()\n .describe(\n 'Include frontmatter in span results. Default false for section/block spans. No effect on lines or whole-note reads.',\n ),\n })\n .refine((v) => [v.section, v.block, v.lines].filter((x) => x !== undefined).length <= 1, {\n message: 'At most one of section, block, or lines may be specified.',\n });\nexport type ReadNoteInput = z.infer<typeof ReadNoteInput>;\n\nexport interface ReadNoteResult {\n path: string;\n content: string;\n /** Bytes in the returned content (UTF-8). */\n bytesReturned: number;\n /** Total UTF-8 byte size of the source file. */\n noteBytes: number;\n /** sha-256 (hex) of the whole file — pass as prevHash to edit tools for compare-and-swap. */\n contentHash: string;\n /** Character offsets of the returned span in the raw file. Absent for whole-note reads. */\n span?: { charStart: number; charEnd: number };\n}\n\nexport async function readNote(ctx: ServerContext, input: ReadNoteInput): Promise<ReadNoteResult> {\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n\n const raw = await readFile(absPath, 'utf8');\n const noteBytes = Buffer.byteLength(raw, 'utf8');\n // Always the whole file's hash, even for span reads — it identifies the\n // on-disk version an edit's prevHash is compared against.\n const hash = contentHash(raw);\n\n // Whole-note read — no selector\n if (input.section === undefined && input.block === undefined && input.lines === undefined) {\n return {\n path: input.path,\n content: raw,\n bytesReturned: noteBytes,\n noteBytes,\n contentHash: hash,\n };\n }\n\n const fm = parseFrontmatter(raw);\n const outline = buildOutline(raw, { includeBlocks: true });\n\n let charStart: number;\n let charEnd: number;\n\n if (input.section !== undefined) {\n const target = input.section.replace(/^#+\\s*/, '').trim();\n const heading = outline.headings.find((h) => h.text === target);\n if (!heading) {\n throw new Error(\n JSON.stringify({\n error: 'section_not_found',\n target,\n available: outline.headings.map((h) => h.text),\n }),\n );\n }\n const nextSibling = outline.headings.find(\n (h) => h.byteOffset > heading.byteOffset && h.level <= heading.level,\n );\n charStart = heading.byteOffset;\n charEnd = nextSibling?.byteOffset ?? raw.length;\n } else if (input.block !== undefined) {\n const targetId = input.block.replace(/^\\^/, '');\n const block = outline.blocks.find((b) => b.id === targetId);\n if (!block) {\n throw new Error(\n JSON.stringify({\n error: 'block_not_found',\n target: targetId,\n available: outline.blocks.map((b) => b.id),\n }),\n );\n }\n const lineS = block.byteOffset === 0 ? 0 : raw.lastIndexOf('\\n', block.byteOffset - 1) + 1;\n const nlAfter = raw.indexOf('\\n', block.byteOffset);\n const lineE = nlAfter === -1 ? raw.length : nlAfter + 1;\n charStart = lineS;\n charEnd = lineE;\n } else {\n // lines selector\n const linesRange = input.lines;\n if (linesRange === undefined) throw new Error('internal: unreachable');\n const { from, to } = linesRange;\n const rawLines = raw.split('\\n');\n const fromIdx = from - 1; // 0-indexed\n const toIdxInclusive =\n to !== undefined ? Math.min(to - 1, rawLines.length - 1) : rawLines.length - 1;\n\n let offset = 0;\n charStart = 0;\n charEnd = raw.length;\n\n for (const [i, line] of rawLines.entries()) {\n if (i === fromIdx) charStart = offset;\n offset += line.length + 1; // +1 for the \\n consumed by split\n if (i === toIdxInclusive) {\n charEnd = Math.min(offset, raw.length);\n break;\n }\n }\n }\n\n // Build content — prepend FM if requested (section/block only)\n let content: string;\n if (input.includeFrontmatter === true && input.lines === undefined) {\n const fmRegion = raw.slice(0, fm.bodyStart);\n const spanContent = raw.slice(charStart, charEnd);\n // Avoid duplicating FM if the span already covers it (e.g. section at bodyStart)\n content = charStart < fm.bodyStart ? spanContent : `${fmRegion}${spanContent}`;\n } else {\n content = raw.slice(charStart, charEnd);\n }\n\n return {\n path: input.path,\n content,\n bytesReturned: Buffer.byteLength(content, 'utf8'),\n noteBytes,\n contentHash: hash,\n span: { charStart, charEnd },\n };\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport { buildOutline } from '@seekstone/core/outline';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { addNoteBacklinks, removeNoteBacklinks } from '../index/backlinks.js';\nimport { buildDoc, upsertDoc } from '../index/doc.js';\nimport { resolveLink } from '../index/resolve.js';\nimport { assertWritable, isWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\nimport { mapUnfencedLines } from './rewrite_links.js';\n\nexport const RenameHeadingInput = z.object({\n path: z.string().describe('Vault-relative path of the note containing the heading.'),\n oldHeading: z\n .string()\n .min(1)\n .describe(\n 'Current heading text, without # markers. Matched case-insensitively; if the note has duplicate headings the first one wins, mirroring Obsidian link resolution.',\n ),\n newHeading: z\n .string()\n .min(1)\n .refine((s) => !/[\\n[\\]|#]/.test(s), {\n message:\n 'newHeading must not contain newlines, \"[\", \"]\", \"|\", or \"#\" — those break [[note#heading]] link syntax.',\n })\n .describe('New heading text, without # markers.'),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard: the contentHash from a prior read of this note. Fails with hash_conflict if the note changed since.',\n ),\n});\nexport type RenameHeadingInput = z.input<typeof RenameHeadingInput>;\n\nexport interface RenameHeadingResult {\n path: string;\n oldHeading: string;\n newHeading: string;\n /** 1-based line of the renamed heading. */\n line: number;\n /**\n * Notes with at least one reference rewritten — includes the renamed note\n * itself when it linked to its own heading. The heading rename alone does\n * not count.\n */\n notesRewritten: number;\n /** Individual [[…#heading]] links and embeds rewritten across the vault. */\n linksRewritten: number;\n /** Referencing notes left untouched because SEEKSTONE_WRITE_PATHS excludes them. */\n skipped?: string[];\n /** sha-256 (hex) of the renamed note's new content — usable as prevHash for a chained edit. */\n contentHash: string;\n}\n\n// Heading-link shape: optional embed bang, optional target (empty = same-note\n// anchor like [[#Heading]]), required #fragment, optional |alias. Bounds\n// mirror LINK_WITH_LINES_RE in @seekstone/core/extract.\nconst HEADING_LINK_RE = /(!?)\\[\\[([^\\]|#\\n]{0,512})(#[^\\]|\\n]{1,512})(\\|[^\\]\\n]{1,512})?\\]\\]/g;\n\n/**\n * Rewrite `[[target#fragment]]` links on unfenced lines. `matchesTarget`\n * decides whether a link's target refers to the renamed note; the fragment\n * must equal `oldHeading` case-insensitively (Obsidian heading links are\n * case-insensitive). Block refs (`#^id`) and nested heading paths (`#A#B`)\n * are never touched.\n */\nfunction rewriteHeadingLinks(\n raw: string,\n oldHeading: string,\n newHeading: string,\n matchesTarget: (target: string) => boolean,\n): { content: string; count: number } {\n const oldLower = oldHeading.toLowerCase();\n let count = 0;\n const content = mapUnfencedLines(raw, (line) =>\n line.replace(\n HEADING_LINK_RE,\n (full, bang: string, target: string, frag: string, alias?: string) => {\n const fragText = frag.slice(1);\n if (fragText.startsWith('^') || fragText.includes('#')) return full;\n if (fragText.trim().toLowerCase() !== oldLower) return full;\n if (!matchesTarget(target.trim())) return full;\n count++;\n return `${bang}[[${target}#${newHeading}${alias ?? ''}]]`;\n },\n ),\n );\n return { content, count };\n}\n\nexport async function renameHeading(\n ctx: ServerContext,\n rawInput: RenameHeadingInput,\n): Promise<RenameHeadingResult> {\n // Parse here (not only in dispatch) so validation applies to direct callers\n // too — same pattern as move_note.\n const input = RenameHeadingInput.parse(rawInput);\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n assertWritable(ctx.policy, input.path);\n\n let raw: string;\n try {\n raw = await readFile(absPath, 'utf8');\n } catch {\n throw new Error(`Note not found: ${input.path}`);\n }\n if (input.prevHash !== undefined) assertHashMatch(raw, input.prevHash, input.path);\n\n const outline = buildOutline(raw, { includeBlocks: false });\n const heading = outline.headings.find(\n (h) => h.text.toLowerCase() === input.oldHeading.toLowerCase(),\n );\n if (!heading) {\n throw new Error(\n JSON.stringify({\n error: 'heading_not_found',\n target: input.oldHeading,\n available: outline.headings.map((h) => h.text),\n }),\n );\n }\n\n // Rename the heading line surgically by offset, preserving the marker run,\n // the whitespace after it, and any trailing whitespace (incl. CR).\n const nl = raw.indexOf('\\n', heading.byteOffset);\n const lineEnd = nl === -1 ? raw.length : nl;\n const lineText = raw.slice(heading.byteOffset, lineEnd);\n const markerPrefix = /^#{1,6}\\s+/.exec(lineText)?.[0] ?? '';\n const trailing = /\\s*$/.exec(lineText)?.[0] ?? '';\n const newLineText = `${markerPrefix}${input.newHeading}${trailing}`;\n let newRaw = raw.slice(0, heading.byteOffset) + newLineText + raw.slice(lineEnd);\n\n // Rewrite the note's own references to the renamed heading — same-note\n // anchors ([[#Heading]]) and self-links by name — in the body region only,\n // so the frontmatter stays byte-identical.\n const fm = parseFrontmatter(newRaw);\n const bodyRegion = newRaw.slice(fm.bodyStart);\n const selfRewrite = rewriteHeadingLinks(\n bodyRegion,\n input.oldHeading,\n input.newHeading,\n (target) => target === '' || resolveLink(target, ctx.notes) === input.path,\n );\n newRaw = newRaw.slice(0, fm.bodyStart) + selfRewrite.content;\n\n // Referencing notes come straight off the warm backlink index — no scan.\n // Heading links are wikilinks/embeds, which the index fully covers\n // (markdown anchors like [t](note.md#h) are out of scope, as documented).\n // Rewrites are computed before any disk write so the whole rename is\n // journaled under one seq (undo restores every touched file or none).\n const candidates = new Set<string>();\n for (const ref of ctx.backlinks.get(input.path) ?? []) candidates.add(ref.path);\n candidates.delete(input.path);\n\n const rewrites: { path: string; pre: string; content: string; count: number }[] = [];\n const skipped: string[] = [];\n for (const path of [...candidates].sort()) {\n const doc = ctx.notes.get(path);\n if (doc === undefined) continue;\n const { content, count } = rewriteHeadingLinks(\n doc.raw,\n input.oldHeading,\n input.newHeading,\n (target) => target !== '' && resolveLink(target, ctx.notes) === input.path,\n );\n if (count === 0) continue;\n if (!isWritable(ctx.policy, path)) {\n // Out of write scope: leave the note untouched but report it, so the\n // caller knows which references were NOT updated.\n skipped.push(path);\n continue;\n }\n rewrites.push({ path, pre: doc.raw, content, count });\n }\n\n if (ctx.journal) {\n const txn = ctx.journal.begin('rename_heading');\n await txn.add(input.path, raw, newRaw);\n for (const r of rewrites) await txn.add(r.path, r.pre, r.content);\n await txn.commit();\n }\n\n const originalFmRegion = raw.slice(0, fm.bodyStart);\n await atomicWrite(absPath, newRaw);\n const written = await readFile(absPath, 'utf8');\n if (written.slice(0, originalFmRegion.length) !== originalFmRegion) {\n throw new Error('Write-safety violation: frontmatter region changed unexpectedly');\n }\n\n // Refresh the renamed note's index entry. removeNoteBacklinks reads the old\n // raw out of ctx.notes, so it must run before upsertDoc replaces the entry.\n removeNoteBacklinks(ctx, input.path);\n upsertDoc(ctx, buildDoc(input.path, newRaw));\n addNoteBacklinks(ctx, input.path, newRaw);\n\n let notesRewritten = selfRewrite.count > 0 ? 1 : 0;\n let linksRewritten = selfRewrite.count;\n\n for (const { path, content, count } of rewrites) {\n await atomicWrite(join(ctx.vaultRoot, path), content);\n // Fragment rewrites change neither link resolution nor line numbers, so\n // the backlink index needs no refresh — only the notes/search entries.\n upsertDoc(ctx, buildDoc(path, content));\n notesRewritten++;\n linksRewritten += count;\n }\n\n const result: RenameHeadingResult = {\n path: input.path,\n oldHeading: input.oldHeading,\n newHeading: input.newHeading,\n line: heading.line,\n notesRewritten,\n linksRewritten,\n contentHash: contentHash(newRaw),\n };\n if (skipped.length > 0) result.skipped = skipped;\n return result;\n}\n","import { readFile } from 'node:fs/promises';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { journalWrite } from '../journal.js';\nimport { assertWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const ReplaceInNoteInput = z.object({\n path: z.string().describe('Vault-relative path to the note.'),\n find: z\n .string()\n .min(1)\n .max(1000)\n .describe('Text or pattern to find (max 1000 chars; bounds regex-mode pattern size).'),\n replace: z\n .string()\n .describe('Replacement text. Supports $1, $2, … backreferences in regex mode.'),\n regex: z.boolean().default(false).describe('Treat find as a regular expression.'),\n caseSensitive: z.boolean().default(false).describe('Case-sensitive matching.'),\n wholeWord: z.boolean().default(false).describe('Match whole words only (\\\\b word-boundary).'),\n limit: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe('Maximum number of replacements. Omit to replace all.'),\n dryRun: z.boolean().default(false).describe('If true, report matches without writing anything.'),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n ),\n});\nexport type ReplaceInNoteInput = z.infer<typeof ReplaceInNoteInput>;\n\nexport interface MatchPosition {\n line: number;\n byteOffset: number;\n}\n\nexport interface ReplaceInNoteResult {\n path: string;\n replacements: number;\n matches: MatchPosition[];\n bytesWritten?: number;\n frontmatterUnchanged: true;\n /** sha-256 (hex) of the file content after the call — the new content after a write, the unchanged content on dry runs and zero-match calls. Always usable as prevHash for a chained edit. */\n contentHash: string;\n}\n\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction buildRegex(\n find: string,\n opts: { regex: boolean; caseSensitive: boolean; wholeWord: boolean },\n): RegExp {\n let pattern = opts.regex ? find : escapeRegex(find);\n if (opts.wholeWord) pattern = `\\\\b(?:${pattern})\\\\b`;\n const flags = `g${opts.caseSensitive ? '' : 'i'}`;\n return new RegExp(pattern, flags);\n}\n\nexport async function replaceInNote(\n ctx: ServerContext,\n input: ReplaceInNoteInput,\n): Promise<ReplaceInNoteResult> {\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n assertWritable(ctx.policy, input.path);\n\n // Validate regex before any IO.\n let re: RegExp;\n try {\n re = buildRegex(input.find, {\n regex: input.regex,\n caseSensitive: input.caseSensitive,\n wholeWord: input.wholeWord,\n });\n } catch (err) {\n throw new Error(`Invalid regex: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n const raw = await readFile(absPath, 'utf8');\n if (input.prevHash !== undefined) assertHashMatch(raw, input.prevHash, input.path);\n const fm = parseFrontmatter(raw);\n const originalFmRegion = raw.slice(0, fm.bodyStart);\n const body = raw.slice(fm.bodyStart);\n\n const allMatches = [...body.matchAll(re)];\n const toReplace = input.limit !== undefined ? allMatches.slice(0, input.limit) : allMatches;\n\n const matches: MatchPosition[] = toReplace.map((m) => {\n const fileOffset = fm.bodyStart + (m.index ?? 0);\n const line = raw.slice(0, fileOffset).split('\\n').length;\n return { line, byteOffset: fileOffset };\n });\n\n if (input.dryRun || toReplace.length === 0) {\n return {\n path: input.path,\n replacements: toReplace.length,\n matches,\n frontmatterUnchanged: true,\n // Nothing was written — hash the content as read, so chained edits can\n // proceed from a dry run without a re-read.\n contentHash: contentHash(raw),\n };\n }\n\n // Apply replacements left-to-right, resolving backreferences per match.\n const singleRe = new RegExp(re.source, re.flags.replace('g', ''));\n let newBody = '';\n let lastIndex = 0;\n for (const m of toReplace) {\n const matchIndex = m.index ?? 0;\n newBody += body.slice(lastIndex, matchIndex);\n newBody += input.regex ? m[0].replace(singleRe, input.replace) : input.replace;\n lastIndex = matchIndex + m[0].length;\n }\n newBody += body.slice(lastIndex);\n\n const newContent = `${originalFmRegion}${newBody}`;\n await journalWrite(ctx, 'replace_in_note', input.path, raw, newContent);\n await atomicWrite(absPath, newContent);\n\n const written = await readFile(absPath, 'utf8');\n if (written.slice(0, originalFmRegion.length) !== originalFmRegion) {\n throw new Error('Write-safety violation: frontmatter region changed unexpectedly');\n }\n\n const cached = ctx.notes.get(input.path);\n if (cached) {\n cached.body = newBody;\n cached.raw = newContent;\n cached.sizeBytes = Buffer.byteLength(newContent, 'utf8');\n }\n\n return {\n path: input.path,\n replacements: toReplace.length,\n matches,\n bytesWritten: Buffer.byteLength(newContent, 'utf8'),\n frontmatterUnchanged: true,\n contentHash: contentHash(newContent),\n };\n}\n","import { mkdir, readFile, rm } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { addNoteBacklinks, removeNoteBacklinks } from '../index/backlinks.js';\nimport { buildDoc, upsertDoc } from '../index/doc.js';\nimport type { JournalEntry } from '../journal.js';\nimport { assertWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const UndoWriteInput = z.object({\n seq: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe(\n 'Journal entry to revert (from list_writes). Defaults to the most recent undoable write.',\n ),\n force: z\n .boolean()\n .default(false)\n .describe(\n 'Restore even if a file changed after the journaled write. The clobbered state is journaled first, so nothing is lost. Defaults to false — conflicts are refused.',\n ),\n});\nexport type UndoWriteInput = z.input<typeof UndoWriteInput>;\n\nexport interface UndoConflict {\n path: string;\n /** Hash the file had right after the journaled write (null = did not exist). */\n expectedHash: string | null;\n /** Hash the file has now (null = does not exist). */\n actualHash: string | null;\n expectedBytes: number | null;\n actualBytes: number | null;\n}\n\nexport interface UndoWriteResult {\n /** The entry that was reverted. */\n seq: number;\n /** The journal entry recording this undo — undo it to redo. */\n undoSeq: number;\n tool: string;\n restored: { path: string; restoredHash: string | null }[];\n /** Conflicts overridden with force: true (their clobbered state is journaled under undoSeq). */\n overrode?: UndoConflict[];\n}\n\n/**\n * Revert a journaled write by restoring every touched file's pre-image.\n * All-or-nothing: the current state of every file is checked against the\n * entry's postHash first (CAS against the journal), and any mismatch refuses\n * the whole undo with a structured `undo_conflict` unless `force` is set.\n * The undo is itself journaled, so undoing the undo redoes the write.\n */\nexport async function undoWrite(\n ctx: ServerContext,\n rawInput: UndoWriteInput,\n): Promise<UndoWriteResult> {\n const input = UndoWriteInput.parse(rawInput);\n const journal = ctx.journal;\n if (!journal) {\n throw new Error('Write journal is disabled (SEEKSTONE_HISTORY=0); nothing to undo.');\n }\n\n let entry: JournalEntry | undefined;\n if (input.seq === undefined) {\n entry = journal.latestUndoable();\n if (!entry) throw new Error('No undoable writes in the journal.');\n } else {\n entry = journal.get(input.seq);\n if (!entry) throw new Error(`Journal entry ${input.seq} not found.`);\n if (!journal.isUndoable(entry)) {\n throw new Error(\n JSON.stringify({\n error: 'entry_evicted',\n seq: entry.seq,\n hint: 'Its pre-image was evicted by the retention cap (SEEKSTONE_HISTORY_MAX_SIZE); it can no longer be undone.',\n }),\n );\n }\n }\n\n // Policy applies to every path the undo will write, before anything moves.\n for (const f of entry.files) assertWritable(ctx.policy, f.path);\n\n // Current state vs. what the journal says the write left behind.\n const current = new Map<string, string | null>();\n const conflicts: UndoConflict[] = [];\n for (const f of entry.files) {\n const abs = resolveVaultPath(ctx.vaultRoot, f.path);\n let cur: string | null = null;\n try {\n cur = await readFile(abs, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n current.set(f.path, cur);\n const actualHash = cur === null ? null : contentHash(cur);\n if (actualHash !== f.postHash) {\n conflicts.push({\n path: f.path,\n expectedHash: f.postHash,\n actualHash,\n expectedBytes: f.postHash === null ? null : await postBytes(journal, f.postHash),\n actualBytes: cur === null ? null : Buffer.byteLength(cur, 'utf8'),\n });\n }\n }\n if (conflicts.length > 0 && !input.force) {\n throw new Error(\n JSON.stringify({\n error: 'undo_conflict',\n seq: entry.seq,\n conflicts,\n hint: 'A file changed after this write (by you or another tool). Re-check it, then pass force: true to restore anyway — the current state is journaled first.',\n }),\n );\n }\n\n // Load every pre-image before touching disk so a missing blob aborts cleanly.\n const preimages = new Map<string, string | null>();\n for (const f of entry.files) {\n preimages.set(f.path, f.preHash === null ? null : await journal.preimage(f.preHash));\n }\n\n // Journal the undo (current state → pre-image) — undoing it redoes the write.\n const txn = journal.begin('undo_write', entry.seq);\n for (const f of entry.files) {\n await txn.add(f.path, current.get(f.path) ?? null, preimages.get(f.path) ?? null);\n }\n const undoEntry = await txn.commit();\n\n const restored: UndoWriteResult['restored'] = [];\n for (const f of entry.files) {\n const abs = resolveVaultPath(ctx.vaultRoot, f.path);\n const pre = preimages.get(f.path) ?? null;\n if (pre === null) {\n await rm(abs, { force: true });\n removeNoteBacklinks(ctx, f.path);\n if (ctx.notes.has(f.path)) {\n ctx.index.discard(f.path);\n ctx.notes.delete(f.path);\n }\n restored.push({ path: f.path, restoredHash: null });\n } else {\n await mkdir(dirname(abs), { recursive: true });\n await atomicWrite(abs, pre);\n if (f.path.endsWith('.md')) {\n removeNoteBacklinks(ctx, f.path);\n upsertDoc(ctx, buildDoc(f.path, pre));\n addNoteBacklinks(ctx, f.path, pre);\n }\n restored.push({ path: f.path, restoredHash: contentHash(pre) });\n }\n }\n\n const result: UndoWriteResult = {\n seq: entry.seq,\n undoSeq: undoEntry.seq,\n tool: entry.tool,\n restored,\n };\n if (conflicts.length > 0) result.overrode = conflicts;\n return result;\n}\n\n/**\n * Byte count of the post-write state, if the journal still holds it (it does\n * whenever a later entry journaled that state as ITS pre-image); otherwise\n * null — the diff summary is best-effort metadata.\n */\nasync function postBytes(\n journal: NonNullable<ServerContext['journal']>,\n hash: string,\n): Promise<number | null> {\n try {\n return Buffer.byteLength(await journal.preimage(hash), 'utf8');\n } catch {\n return null;\n }\n}\n","import { type AuditFile, type AuditRecord, classifyError } from './audit.js';\nimport type { ServerContext } from './context.js';\nimport type { Logger } from './log.js';\nimport { AppendNoteInput, appendNote } from './tools/append_note.js';\nimport { ContextPackInput, contextPack } from './tools/context_pack.js';\nimport { CreateNoteInput, createNote } from './tools/create_note.js';\nimport { DeleteNoteInput, deleteNote } from './tools/delete_note.js';\nimport { GetBacklinksInput, getBacklinks } from './tools/get_backlinks.js';\nimport { GetLinksInput, getLinks } from './tools/get_links.js';\nimport { ListNotesInput, listNotes } from './tools/list_notes.js';\nimport { ListTagsInput, listTags } from './tools/list_tags.js';\nimport { ListWritesInput, listWrites } from './tools/list_writes.js';\nimport { MoveNoteInput, moveNote } from './tools/move_note.js';\nimport { OutlineNoteInput, outlineNote } from './tools/outline_note.js';\nimport { PatchFrontmatterInput, patchFrontmatter } from './tools/patch_frontmatter.js';\nimport { PatchNoteInput, patchNote } from './tools/patch_note.js';\nimport {\n AppendPeriodicNoteInput,\n appendPeriodicNote,\n GetPeriodicNoteInput,\n getPeriodicNote,\n} from './tools/periodic_note.js';\nimport { QueryNotesInput, queryNotes } from './tools/query_notes.js';\nimport { ReadNoteInput, readNote } from './tools/read_note.js';\nimport { RenameHeadingInput, renameHeading } from './tools/rename_heading.js';\nimport { ReplaceInNoteInput, replaceInNote } from './tools/replace_in_note.js';\nimport { SearchInput, search } from './tools/search.js';\nimport { UndoWriteInput, undoWrite } from './tools/undo_write.js';\n\nexport type ToolResult = {\n content: { type: 'text'; text: string }[];\n isError?: boolean;\n /**\n * Op-specific audit metadata set by write-tool cases (paths, counts,\n * flags — never content). Consumed and stripped by dispatch; absent means\n * \"nothing to audit\" (e.g. get_periodic_note that did not create).\n */\n audit?: Record<string, unknown>;\n};\n\n/** Tool names this dispatcher handles — kept in sync with the server's tool list. */\nexport const HANDLED_TOOLS = [\n 'search',\n 'query_notes',\n 'context_pack',\n 'read_note',\n 'list_notes',\n 'list_tags',\n 'create_note',\n 'delete_note',\n 'move_note',\n 'rename_heading',\n 'append_note',\n 'patch_frontmatter',\n 'outline_note',\n 'patch_note',\n 'get_backlinks',\n 'get_links',\n 'replace_in_note',\n 'get_periodic_note',\n 'append_periodic_note',\n 'list_writes',\n 'undo_write',\n] as const;\n\n/**\n * Tools that mutate the vault. Enforced here at dispatch (read-only mode\n * rejects them) and mirrored by tool-list.ts, which unregisters them from\n * tools/list — a new write tool must be added to this set to ship.\n */\nexport const WRITE_TOOLS: ReadonlySet<string> = new Set([\n 'create_note',\n 'delete_note',\n 'move_note',\n 'rename_heading',\n 'append_note',\n 'patch_frontmatter',\n 'patch_note',\n 'replace_in_note',\n 'append_periodic_note',\n 'undo_write',\n]);\n\n// Metadata-safe keys: logged at info. Note content (`content`, `frontmatter`,\n// `patch`) and the raw `query` string are intentionally excluded — they only\n// reach logs via the debug-level `args` dump.\nconst META_KEYS = [\n 'path',\n 'from',\n 'to',\n 'folder',\n 'tag',\n 'mode',\n 'limit',\n 'overwrite',\n 'pattern',\n 'minCount',\n 'sort',\n 'order',\n 'select',\n 'modifiedAfter',\n 'modifiedBefore',\n 'minSizeBytes',\n 'maxSizeBytes',\n 'period',\n 'date',\n 'permanent',\n 'prevHash',\n 'budgetBytes',\n 'seq',\n 'force',\n] as const;\n\nfunction safeMeta(args: unknown): Record<string, unknown> {\n if (typeof args !== 'object' || args === null) return {};\n const a = args as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const k of META_KEYS) {\n if (a[k] !== undefined) out[k] = a[k];\n }\n if (typeof a.query === 'string') out.queryLen = a.query.length; // not the query itself\n if (Array.isArray(a.where)) out.whereCount = a.where.length; // predicate values may be personal\n return out;\n}\n\nfunction resultBytes(r: ToolResult): number {\n let n = 0;\n for (const c of r.content) n += Buffer.byteLength(c.text);\n return n;\n}\n\n/**\n * Route a tool call to its handler, logging the outcome. Returns an MCP tool\n * result; failures are converted to `{ isError: true }` (never thrown) so the\n * transport stays alive, and are logged at `error` with a stack.\n */\nexport async function dispatch(\n ctx: ServerContext,\n name: string,\n args: unknown,\n log: Logger,\n): Promise<ToolResult> {\n const start = performance.now();\n const meta = safeMeta(args);\n log.debug('tool start', { tool: name, args }); // full args (may include content) — debug only\n if (ctx.policy.readOnly && WRITE_TOOLS.has(name)) {\n // Unregistered from tools/list, but a client can still send the call.\n log.info('tool rejected (read-only)', { tool: name, ...meta });\n const rejected: ToolResult = {\n content: [\n {\n type: 'text',\n text: 'Error: Server is read-only (SEEKSTONE_READ_ONLY=1); write tools are disabled.',\n },\n ],\n isError: true,\n };\n return audit(ctx, log, rejected, {\n v: 1,\n ts: new Date().toISOString(),\n tool: name,\n outcome: 'policy_denied',\n policy: 'read_only',\n error: 'read_only',\n durationMs: 0,\n ...pathMeta(meta),\n });\n }\n if (ctx.policy.readOnly && name === 'get_periodic_note') {\n // The one read tool with a write side-effect: force createIfMissing off.\n if (typeof args === 'object' && args !== null) {\n args = { ...(args as Record<string, unknown>), createIfMissing: false };\n }\n }\n const isWrite = WRITE_TOOLS.has(name) || name === 'get_periodic_note';\n const seqBefore = ctx.journal?.lastSeq ?? 0;\n const ts = new Date().toISOString();\n try {\n const { audit: detail, ...result } = await run(ctx, name, args);\n const durationMs = Math.round((performance.now() - start) * 100) / 100;\n log.info('tool ok', { tool: name, durationMs, resultBytes: resultBytes(result), ...meta });\n if (!isWrite || detail === undefined) return result;\n return audit(ctx, log, result, {\n v: 1,\n ts,\n tool: name,\n outcome: 'ok',\n durationMs,\n ...journalFiles(ctx, seqBefore, detail),\n ...detail,\n });\n } catch (err) {\n const durationMs = Math.round((performance.now() - start) * 100) / 100;\n const message = err instanceof Error ? err.message : String(err);\n log.error('tool error', {\n tool: name,\n durationMs,\n error: message,\n stack: err instanceof Error ? err.stack : undefined,\n ...meta,\n });\n const failed: ToolResult = {\n content: [{ type: 'text', text: `Error: ${message}` }],\n isError: true,\n };\n if (!isWrite) return failed;\n return audit(ctx, log, failed, {\n v: 1,\n ts,\n tool: name,\n ...classifyError(message),\n durationMs,\n ...pathMeta(meta),\n });\n }\n}\n\n/** Path-shaped metadata (path / from / to / seq) for records of calls that never reached a result. */\nfunction pathMeta(meta: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const k of ['path', 'from', 'to', 'seq'] as const)\n if (meta[k] !== undefined) out[k] = meta[k];\n return out;\n}\n\n/**\n * The hash-pair spine of an ok record: files + seq from the journal entry\n * this call committed; with the journal off, only the after-hash the tool\n * result carries.\n */\nfunction journalFiles(\n ctx: ServerContext,\n seqBefore: number,\n detail: Record<string, unknown>,\n): { seq?: number; files?: AuditFile[] } {\n const entry = ctx.journal?.since(seqBefore).at(-1);\n if (entry !== undefined) {\n return {\n seq: entry.seq,\n files: entry.files.map((f) => ({\n path: f.path,\n hashBefore: f.preHash,\n hashAfter: f.postHash,\n })),\n };\n }\n if (typeof detail.path === 'string' && typeof detail.contentHash === 'string') {\n return { files: [{ path: detail.path, hashAfter: detail.contentHash }] };\n }\n return {};\n}\n\n/**\n * Append the record when auditing is on. A failed append turns the (already\n * completed) call into a structured audit_failed error so an unauditable\n * write is never reported as a clean success.\n */\nfunction audit(ctx: ServerContext, log: Logger, result: ToolResult, rec: AuditRecord): ToolResult {\n if (!ctx.audit) return result;\n try {\n ctx.audit.record(rec);\n return result;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n log.error('audit write failed', { tool: rec.tool, error: message });\n return {\n content: [\n {\n type: 'text',\n text: `Error: ${JSON.stringify({\n error: 'audit_failed',\n tool: rec.tool,\n outcome: rec.outcome,\n hint: `The audit record could not be written (${message}). The vault operation itself ${\n rec.outcome === 'ok' ? 'DID complete' : 'did not run'\n }; fix SEEKSTONE_AUDIT_FILE before continuing.`,\n })}`,\n },\n ],\n isError: true,\n };\n }\n}\n\nasync function run(ctx: ServerContext, name: string, args: unknown): Promise<ToolResult> {\n switch (name) {\n case 'search': {\n const input = SearchInput.parse(args);\n const hits = search(ctx, input);\n // Minified: search is the headline context-tax metric — indentation is pure tax.\n return { content: [{ type: 'text', text: JSON.stringify(hits) }] };\n }\n case 'query_notes': {\n const input = QueryNotesInput.parse(args);\n const hits = queryNotes(ctx, input);\n // Minified like search — a second search mode, same context-tax discipline.\n return { content: [{ type: 'text', text: JSON.stringify(hits) }] };\n }\n case 'context_pack': {\n const input = ContextPackInput.parse(args);\n const pack = contextPack(ctx, input);\n // Minified: the assembler meters its byte budget against exactly this serialization.\n return { content: [{ type: 'text', text: JSON.stringify(pack) }] };\n }\n case 'read_note': {\n const input = ReadNoteInput.parse(args);\n const result = await readNote(ctx, input);\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };\n }\n case 'list_notes': {\n const input = ListNotesInput.parse(args);\n const entries = listNotes(ctx, input);\n return { content: [{ type: 'text', text: JSON.stringify(entries, null, 2) }] };\n }\n case 'list_tags': {\n const input = ListTagsInput.parse(args);\n const result = listTags(ctx, input);\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };\n }\n case 'create_note': {\n const input = CreateNoteInput.parse(args);\n const result = await createNote(ctx, input);\n return {\n content: [\n {\n type: 'text',\n text: `Created ${result.path} (${result.bytesWritten} bytes). contentHash: ${result.contentHash}`,\n },\n ],\n audit: {\n path: result.path,\n contentHash: result.contentHash,\n bytesWritten: result.bytesWritten,\n overwrite: input.overwrite,\n },\n };\n }\n case 'delete_note': {\n const input = DeleteNoteInput.parse(args);\n const result = await deleteNote(ctx, input);\n const text = result.trashedTo\n ? `Moved ${result.path} to ${result.trashedTo} (recoverable — restore by moving it back).`\n : `Permanently deleted ${result.path}.`;\n const audit: Record<string, unknown> = {\n path: result.path,\n contentHash: result.contentHash,\n permanent: result.permanent,\n };\n if (result.trashedTo !== undefined) audit.trashedTo = result.trashedTo;\n return { content: [{ type: 'text', text }], audit };\n }\n case 'move_note': {\n const input = MoveNoteInput.parse(args);\n const result = await moveNote(ctx, input);\n let text = `Moved ${result.from} → ${result.to}. Rewrote ${result.linksRewritten} link${\n result.linksRewritten === 1 ? '' : 's'\n } in ${result.notesRewritten} note${result.notesRewritten === 1 ? '' : 's'}.`;\n if (result.skipped?.length) {\n text += ` Skipped (outside SEEKSTONE_WRITE_PATHS): ${result.skipped.join(', ')}.`;\n }\n return {\n content: [{ type: 'text', text }],\n audit: {\n from: result.from,\n to: result.to,\n contentHash: result.contentHash,\n notesRewritten: result.notesRewritten,\n linksRewritten: result.linksRewritten,\n ...(result.skipped?.length ? { skipped: result.skipped } : {}),\n },\n };\n }\n case 'rename_heading': {\n const input = RenameHeadingInput.parse(args);\n const result = await renameHeading(ctx, input);\n let text = `Renamed heading \"${result.oldHeading}\" → \"${result.newHeading}\" in ${result.path} (line ${result.line}). Rewrote ${result.linksRewritten} link${\n result.linksRewritten === 1 ? '' : 's'\n } in ${result.notesRewritten} note${result.notesRewritten === 1 ? '' : 's'}. contentHash: ${result.contentHash}`;\n if (result.skipped?.length) {\n text += ` Skipped (outside SEEKSTONE_WRITE_PATHS): ${result.skipped.join(', ')}.`;\n }\n return {\n content: [{ type: 'text', text }],\n audit: {\n path: result.path,\n contentHash: result.contentHash,\n line: result.line,\n notesRewritten: result.notesRewritten,\n linksRewritten: result.linksRewritten,\n ...(result.skipped?.length ? { skipped: result.skipped } : {}),\n },\n };\n }\n case 'append_note': {\n const input = AppendNoteInput.parse(args);\n const result = await appendNote(ctx, input);\n return {\n content: [\n {\n type: 'text',\n text: `Appended ${result.bytesWritten} bytes to ${result.path}. contentHash: ${result.contentHash}`,\n },\n ],\n audit: {\n path: result.path,\n contentHash: result.contentHash,\n bytesWritten: result.bytesWritten,\n },\n };\n }\n case 'patch_frontmatter': {\n const input = PatchFrontmatterInput.parse(args);\n const result = await patchFrontmatter(ctx, input);\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n // Key NAMES only — values are note content and never leave the tool.\n audit: {\n path: result.path,\n contentHash: result.contentHash,\n keysChanged: result.keysChanged,\n keysAdded: result.keysAdded,\n keysRemoved: result.keysRemoved,\n },\n };\n }\n case 'outline_note': {\n const input = OutlineNoteInput.parse(args);\n const result = await outlineNote(ctx, input);\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };\n }\n case 'patch_note': {\n const input = PatchNoteInput.parse(args);\n const result = await patchNote(ctx, input);\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n audit: {\n path: result.path,\n contentHash: result.contentHash,\n bytesWritten: result.bytesWritten,\n operation: input.operation,\n targetLine: result.targetResolvedAt.line,\n },\n };\n }\n case 'get_backlinks': {\n const input = GetBacklinksInput.parse(args);\n const result = getBacklinks(ctx, input);\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };\n }\n case 'get_links': {\n const input = GetLinksInput.parse(args);\n const result = getLinks(ctx, input);\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };\n }\n case 'replace_in_note': {\n const input = ReplaceInNoteInput.parse(args);\n const result = await replaceInNote(ctx, input);\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n audit: {\n path: result.path,\n contentHash: result.contentHash,\n replacements: result.replacements,\n dryRun: input.dryRun,\n },\n };\n }\n case 'get_periodic_note': {\n const input = GetPeriodicNoteInput.parse(args);\n const result = await getPeriodicNote(ctx, input);\n const out: ToolResult = {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n };\n // Only the create side-effect is a write worth auditing.\n if (result.created) {\n out.audit = { path: result.path, contentHash: result.contentHash, created: true };\n }\n return out;\n }\n case 'append_periodic_note': {\n const input = AppendPeriodicNoteInput.parse(args);\n const result = await appendPeriodicNote(ctx, input);\n return {\n content: [\n {\n type: 'text',\n text: `Appended ${result.bytesWritten} bytes to ${result.path}. contentHash: ${result.contentHash}`,\n },\n ],\n audit: {\n path: result.path,\n contentHash: result.contentHash,\n bytesWritten: result.bytesWritten,\n },\n };\n }\n case 'list_writes': {\n const input = ListWritesInput.parse(args);\n const result = listWrites(ctx, input);\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };\n }\n case 'undo_write': {\n const input = UndoWriteInput.parse(args);\n const result = await undoWrite(ctx, input);\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n audit: {\n undoOf: result.seq,\n restored: result.restored.length,\n ...(result.overrode ? { forced: true, overrode: result.overrode.length } : {}),\n },\n };\n }\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n}\n","import { readFile } from 'node:fs/promises';\nimport { basename, extname } from 'node:path';\nimport { extractInlineTags, extractLinksWithLines, frontmatterTags } from '@seekstone/core/extract';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport { walkVault } from '@seekstone/core/walk';\nimport MiniSearch from 'minisearch';\nimport type { BacklinkRef } from '../context.js';\nimport { buildResolveMaps, resolveLink } from './resolve.js';\nimport type { IndexedNote } from './types.js';\n\nexport type VaultIndex = MiniSearch<IndexedNote>;\n\nexport interface BuildResult {\n index: VaultIndex;\n notes: Map<string, IndexedNote>;\n backlinks: Map<string, BacklinkRef[]>;\n buildMs: number;\n}\n\nexport async function buildIndex(vaultRoot: string): Promise<BuildResult> {\n const t0 = Date.now();\n\n const index = new MiniSearch<IndexedNote>({\n idField: 'id',\n fields: ['title', 'body', 'tags', 'fmKeys'],\n storeFields: ['id', 'title', 'tags', 'sizeBytes', 'mtimeMs'],\n searchOptions: {\n boost: { title: 3, tags: 2, body: 1 },\n fuzzy: 0.2,\n prefix: true,\n },\n });\n\n const entries = await walkVault(vaultRoot);\n const noteEntries = entries.filter((e) => e.kind === 'note');\n\n const docs: IndexedNote[] = [];\n const notes = new Map<string, IndexedNote>();\n\n await Promise.all(\n noteEntries.map(async (entry) => {\n try {\n const raw = await readFile(entry.absPath, 'utf8');\n const fm = parseFrontmatter(raw);\n const inlineTags = extractInlineTags(fm.body);\n const fmTags = frontmatterTags(fm.data);\n const allTags = [...new Set([...inlineTags, ...fmTags])];\n\n const title =\n typeof fm.data?.title === 'string' && fm.data.title\n ? fm.data.title\n : basename(entry.relPath, extname(entry.relPath));\n\n const doc: IndexedNote = {\n id: entry.relPath,\n title,\n body: fm.body,\n tags: allTags.join(' '),\n fmKeys: fm.keys.join(' '),\n fm: fm.data,\n raw,\n sizeBytes: entry.sizeBytes,\n mtimeMs: entry.mtimeMs,\n };\n docs.push(doc);\n notes.set(entry.relPath, doc);\n } catch {\n // Unreadable note — skip silently; index what we can.\n }\n }),\n );\n\n index.addAll(docs);\n\n const backlinks = buildBacklinks(notes);\n\n return { index, notes, backlinks, buildMs: Date.now() - t0 };\n}\n\nfunction buildBacklinks(notes: Map<string, IndexedNote>): Map<string, BacklinkRef[]> {\n const result = new Map<string, BacklinkRef[]>();\n const resolveMaps = buildResolveMaps(notes);\n for (const [srcPath, doc] of notes) {\n const seen = new Set<string>();\n for (const link of extractLinksWithLines(doc.raw)) {\n const resolved = resolveLink(link.target, notes, resolveMaps);\n if (resolved === undefined) continue;\n // De-duplicate: one entry per (source, resolved-target) pair\n const dedupeKey = `${srcPath}\\0${resolved}`;\n if (seen.has(dedupeKey)) continue;\n seen.add(dedupeKey);\n let arr = result.get(resolved);\n if (arr === undefined) {\n arr = [];\n result.set(resolved, arr);\n }\n arr.push({ path: srcPath, line: link.line, linkType: link.linkType });\n }\n }\n for (const arr of result.values()) {\n arr.sort((a, b) => a.path.localeCompare(b.path));\n }\n return result;\n}\n","import { stat } from 'node:fs/promises';\nimport { extname, join, relative, sep } from 'node:path';\nimport fg from 'fast-glob';\n\n/**\n * Categories we care about. Anything else falls into `other`.\n * Excalidraw saves as `.excalidraw` (sometimes `.excalidraw.md` — handled in classify()).\n */\nexport type FileKind =\n | 'note'\n | 'image'\n | 'pdf'\n | 'excalidraw'\n | 'canvas'\n | 'video'\n | 'audio'\n | 'other';\n\nexport interface FileEntry {\n absPath: string;\n relPath: string;\n topDir: string;\n ext: string;\n kind: FileKind;\n sizeBytes: number;\n mtimeMs: number;\n}\n\nconst IMAGE_EXTS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.bmp', '.heic']);\nconst VIDEO_EXTS = new Set(['.mp4', '.mov', '.webm', '.mkv', '.avi']);\nconst AUDIO_EXTS = new Set(['.mp3', '.m4a', '.wav', '.flac', '.ogg']);\n\n/**\n * Obsidian's own dot-directories plus VCS noise. We deliberately don't ignore\n * dotfiles at the *file* level — users sometimes commit `.gitkeep` etc. — but\n * any top-level dotted directory is treated as non-vault content.\n */\nconst IGNORE_GLOBS = [\n '**/.obsidian/**',\n '**/.trash/**',\n '**/.seekstone/**',\n '**/.git/**',\n '**/.DS_Store',\n '**/node_modules/**',\n];\n\nexport function classify(relPath: string): FileKind {\n // Excalidraw plugin sometimes writes `.excalidraw.md` — keep those as notes\n // (they still have YAML frontmatter and links), but pure `.excalidraw` is canvas-like.\n if (relPath.endsWith('.excalidraw.md')) return 'note';\n if (relPath.endsWith('.excalidraw')) return 'excalidraw';\n const ext = extname(relPath).toLowerCase();\n if (ext === '.md') return 'note';\n if (ext === '.canvas') return 'canvas';\n if (ext === '.pdf') return 'pdf';\n if (IMAGE_EXTS.has(ext)) return 'image';\n if (VIDEO_EXTS.has(ext)) return 'video';\n if (AUDIO_EXTS.has(ext)) return 'audio';\n return 'other';\n}\n\nexport async function walkVault(vaultRoot: string): Promise<FileEntry[]> {\n // We use fast-glob with `stats: true` so we can avoid an extra stat() round per file.\n const matches = await fg('**/*', {\n cwd: vaultRoot,\n absolute: true,\n onlyFiles: true,\n followSymbolicLinks: false,\n dot: true, // include dotfiles so the ignore globs are the only gate\n ignore: IGNORE_GLOBS,\n stats: true,\n suppressErrors: true,\n });\n\n const entries: FileEntry[] = [];\n for (const m of matches) {\n // fast-glob with stats: true returns objects; without, strings. Narrow here.\n const absPath = typeof m === 'string' ? m : m.path;\n const stats = typeof m === 'string' ? await stat(absPath) : m.stats;\n if (!stats) continue;\n // Index keys are forward-slash vault-relative paths on every platform —\n // the watcher, wikilink resolution, and MCP tool inputs all assume `/`.\n const relPath = relative(vaultRoot, absPath).split(sep).join('/');\n const topDir = relPath.split('/')[0] ?? '';\n entries.push({\n absPath,\n relPath,\n topDir,\n ext: extname(relPath).toLowerCase(),\n kind: classify(relPath),\n sizeBytes: stats.size,\n mtimeMs: stats.mtimeMs,\n });\n }\n return entries;\n}\n\nexport function _testJoin(...parts: string[]): string {\n return join(...parts);\n}\n","// execFileSync is used (not exec/execSync) because it bypasses the shell\n// entirely — it exec's the named binary directly. There is no shell injection\n// risk. Socket.dev flags the child_process import as \"shellAccess\" regardless\n// of which function is used; that score penalty is accepted. See SHA-139.\nimport { execFileSync } from 'node:child_process';\nimport type { Dirent } from 'node:fs';\nimport { access, copyFile, mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';\nimport path, { dirname, join } from 'node:path';\n\n/**\n * `seekstone init` — a guided setup helper. Validates an Obsidian vault and\n * prints (or, with --write, patches) the MCP config for the chosen client\n * (Claude Desktop, Claude Code, Cursor) so a user doesn't have to hand-edit\n * JSON or guess paths.\n *\n * The pure helpers (arg parsing, config-path resolution, additive merge,\n * command string) are exported and unit-tested. `runInit` wires them to the\n * filesystem and console.\n */\n\nexport interface InitOptions {\n vault?: string;\n write: boolean;\n client: 'desktop' | 'code' | 'cursor' | 'vscode';\n /** Set when --client was given an unrecognized value; runInit errors on it. */\n invalidClient?: string;\n}\n\nexport function parseInitArgs(argv: readonly string[]): InitOptions {\n const opts: InitOptions = { write: false, client: 'desktop' };\n // argv is everything after the `init` subcommand.\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === '--write') opts.write = true;\n else if (a === '--vault') opts.vault = argv[++i];\n else if (a === '--client') {\n const v = argv[++i];\n if (v === 'desktop' || v === 'code' || v === 'cursor' || v === 'vscode') opts.client = v;\n // Record the bad value instead of silently falling back to desktop —\n // agents run init non-interactively and would otherwise configure the\n // wrong client without anyone noticing.\n else opts.invalidClient = v ?? '(missing)';\n }\n }\n return opts;\n}\n\n/** The server config object that goes under `mcpServers.seekstone`. */\nexport function seekstoneServerConfig(vaultPath: string): {\n command: string;\n args: string[];\n env: Record<string, string>;\n} {\n return {\n command: 'npx',\n args: ['-y', 'seekstone'],\n env: { SEEKSTONE_VAULT: vaultPath },\n };\n}\n\n/** The `claude mcp add` one-liner for Claude Code. */\nexport function mcpAddCommand(vaultPath: string): string {\n return `claude mcp add seekstone --env SEEKSTONE_VAULT=${vaultPath} -- npx -y seekstone`;\n}\n\n/**\n * Resolve the Claude Desktop config path for a platform. Pure — takes the\n * platform and a home/APPDATA lookup so it can be tested without touching the\n * real environment.\n */\nexport function claudeDesktopConfigPath(\n platform: NodeJS.Platform,\n env: { home?: string; appData?: string },\n): string {\n // Use the target platform's path semantics, not the host's, so the result is\n // correct in production AND deterministic in tests on any CI OS.\n if (platform === 'win32') {\n const j = path.win32.join;\n const base = env.appData ?? j(env.home ?? '', 'AppData', 'Roaming');\n return j(base, 'Claude', 'claude_desktop_config.json');\n }\n const j = path.posix.join;\n const home = env.home ?? '';\n if (platform === 'darwin') {\n return j(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');\n }\n // Linux / other\n return j(home, '.config', 'Claude', 'claude_desktop_config.json');\n}\n\n/**\n * Resolve Cursor's global MCP config path for a platform. Cursor reads\n * `~/.cursor/mcp.json` on every OS (home-relative, no APPDATA) and uses the\n * same `mcpServers` shape as Claude Desktop. Pure, like claudeDesktopConfigPath.\n */\nexport function cursorConfigPath(platform: NodeJS.Platform, env: { home?: string }): string {\n const j = platform === 'win32' ? path.win32.join : path.posix.join;\n return j(env.home ?? '', '.cursor', 'mcp.json');\n}\n\n/**\n * VS Code (GitHub Copilot) workspace MCP config: `.vscode/mcp.json` under the\n * given working directory. Workspace-level on purpose — the user-global config\n * has no stable documented path (VS Code's \"MCP: Open User Configuration\"\n * command owns it), and workspace config takes precedence anyway. Host path\n * semantics (unlike the other path helpers) because it resolves the *real*\n * cwd of the running process, not a target-platform location.\n */\nexport function vscodeMcpConfigPath(cwd: string): string {\n return join(cwd, '.vscode', 'mcp.json');\n}\n\n/**\n * Resolve the Obsidian vault registry path for a platform. Pure — mirrors the\n * claudeDesktopConfigPath pattern so it can be tested without real filesystem.\n */\nexport function obsidianRegistryPath(\n platform: NodeJS.Platform,\n env: { home?: string; appData?: string },\n): string {\n if (platform === 'win32') {\n const j = path.win32.join;\n const base = env.appData ?? j(env.home ?? '', 'AppData', 'Roaming');\n return j(base, 'obsidian', 'obsidian.json');\n }\n const j = path.posix.join;\n const home = env.home ?? '';\n if (platform === 'darwin') {\n return j(home, 'Library', 'Application Support', 'obsidian', 'obsidian.json');\n }\n return j(home, '.config', 'obsidian', 'obsidian.json');\n}\n\nexport type ObsidianVaultEntry = { path: string; open?: boolean };\n\n/**\n * Parse Obsidian's obsidian.json vault registry. Tolerant of missing/extra\n * keys and malformed JSON — always returns an array. Sorted: open vault first,\n * then lexically by path for determinism across runs.\n */\nexport function parseObsidianVaults(json: string): ObsidianVaultEntry[] {\n let data: unknown;\n try {\n data = JSON.parse(json);\n } catch {\n return [];\n }\n if (!data || typeof data !== 'object') return [];\n const raw = (data as Record<string, unknown>).vaults;\n if (!raw || typeof raw !== 'object') return [];\n const entries: ObsidianVaultEntry[] = [];\n for (const v of Object.values(raw as Record<string, unknown>)) {\n if (v && typeof v === 'object') {\n const entry = v as Record<string, unknown>;\n if (typeof entry.path === 'string') {\n entries.push({ path: entry.path, open: entry.open === true });\n }\n }\n }\n return entries.sort((a, b) => {\n if (a.open !== b.open) return a.open ? -1 : 1;\n return a.path.localeCompare(b.path);\n });\n}\n\ntype McpConfig = { mcpServers?: Record<string, unknown> } & Record<string, unknown>;\n\n/**\n * Additively merge the seekstone server into an existing Claude config object.\n * Never removes or alters other servers or top-level keys. Idempotent: running\n * it again with the same vault produces an identical object. Returns a new\n * object (does not mutate the input).\n */\nexport function mergeSeekstoneConfig(existing: McpConfig | null, vaultPath: string): McpConfig {\n const base: McpConfig = existing ? structuredClone(existing) : {};\n const servers = { ...(base.mcpServers ?? {}) };\n servers.seekstone = seekstoneServerConfig(vaultPath);\n return { ...base, mcpServers: servers };\n}\n\ntype VsCodeMcpConfig = { servers?: Record<string, unknown> } & Record<string, unknown>;\n\n/** The server entry for VS Code, which requires an explicit `\"type\": \"stdio\"`. */\nexport function vscodeServerConfig(vaultPath: string): {\n type: 'stdio';\n command: string;\n args: string[];\n env: Record<string, string>;\n} {\n return { type: 'stdio', ...seekstoneServerConfig(vaultPath) };\n}\n\n/**\n * VS Code variant of mergeSeekstoneConfig. Same additive/idempotent contract,\n * but VS Code's mcp.json is the one client config keyed `\"servers\"` (not\n * `\"mcpServers\"`) and requires `\"type\": \"stdio\"` on each entry.\n */\nexport function mergeSeekstoneConfigVsCode(\n existing: VsCodeMcpConfig | null,\n vaultPath: string,\n): VsCodeMcpConfig {\n const base: VsCodeMcpConfig = existing ? structuredClone(existing) : {};\n const servers = { ...(base.servers ?? {}) };\n servers.seekstone = vscodeServerConfig(vaultPath);\n return { ...base, servers };\n}\n\nexport interface VaultCheck {\n ok: boolean;\n noteCount?: number;\n error?: string;\n}\n\n/** Validate that `vaultPath` looks like an Obsidian vault and count .md notes. */\nexport async function validateVault(vaultPath: string): Promise<VaultCheck> {\n try {\n const st = await stat(vaultPath);\n if (!st.isDirectory()) return { ok: false, error: `Not a directory: ${vaultPath}` };\n } catch {\n return { ok: false, error: `Path does not exist: ${vaultPath}` };\n }\n // An Obsidian vault has a .obsidian/ config folder.\n try {\n await access(join(vaultPath, '.obsidian'));\n } catch {\n return {\n ok: false,\n error: `No \".obsidian\" folder found in ${vaultPath} — this doesn't look like an Obsidian vault. Open the folder in Obsidian once to initialize it, or pass the correct --vault path.`,\n };\n }\n return { ok: true, noteCount: await countMarkdown(vaultPath) };\n}\n\nasync function countMarkdown(root: string): Promise<number> {\n let count = 0;\n async function walk(dir: string): Promise<void> {\n let entries: Dirent[];\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n if (e.name.startsWith('.')) continue; // skip .obsidian, .git, .trash\n const full = join(dir, e.name);\n if (e.isDirectory()) await walk(full);\n else if (e.name.endsWith('.md')) count++;\n }\n }\n await walk(root);\n return count;\n}\n\nexport interface InitResult {\n ok: boolean;\n /** Lines to print to stdout. */\n output: string[];\n /** Process exit code. */\n exitCode: number;\n /** Set when --write patched Claude Desktop config. */\n wrotePath?: string;\n backupPath?: string;\n /** Set when --write --client code successfully ran `claude mcp add`. */\n ranClaudeMcpAdd?: boolean;\n}\n\n/**\n * Run the init flow. `deps` are injectable for testing (env, platform, clock).\n * Performs filesystem reads always; only writes when `opts.write` is true.\n */\nexport async function runInit(\n opts: InitOptions,\n deps: {\n env: Record<string, string | undefined>;\n platform: NodeJS.Platform;\n /** ISO timestamp for the backup filename (injected for determinism in tests). */\n timestamp: string;\n /** Working directory for workspace-level configs (vscode); defaults to process.cwd(). */\n cwd?: string;\n /** Injectable for testing; defaults to fs/promises readFile. */\n readFile?: (p: string, enc: 'utf8') => Promise<string>;\n /**\n * Injectable for testing; defaults to execFileSync('claude', args).\n * Returns ok:true on success, ok:false with an error string on failure.\n */\n spawnClaudeMcp?: (args: string[]) => { ok: boolean; error?: string };\n },\n): Promise<InitResult> {\n if (opts.invalidClient !== undefined) {\n return {\n ok: false,\n exitCode: 1,\n output: [\n `✗ Unknown --client: ${opts.invalidClient}. Known clients: desktop, code, cursor, vscode.`,\n ],\n };\n }\n\n const rf = deps.readFile ?? readFile;\n let vaultPath = opts.vault ?? deps.env.SEEKSTONE_VAULT;\n\n if (!vaultPath) {\n // Auto-detect from Obsidian's vault registry.\n const registryPath = obsidianRegistryPath(deps.platform, {\n home: deps.env.HOME,\n appData: deps.env.APPDATA,\n });\n let vaults: ObsidianVaultEntry[] = [];\n try {\n vaults = parseObsidianVaults(await rf(registryPath, 'utf8'));\n } catch {\n // Registry missing or unreadable — fall through to error.\n }\n\n if (vaults.length === 0) {\n return {\n ok: false,\n exitCode: 1,\n output: [\n 'No vault specified. Pass --vault <path> or set SEEKSTONE_VAULT.',\n 'Example: seekstone init --vault \"/Users/you/Obsidian/My Vault\"',\n ],\n };\n }\n\n if (vaults.length === 1) {\n const [first] = vaults;\n vaultPath = first?.path ?? '';\n } else {\n const list = vaults\n .map((v, i) => ` ${i + 1}. ${v.path}${v.open ? ' (currently open)' : ''}`)\n .join('\\n');\n return {\n ok: false,\n exitCode: 1,\n output: [\n 'Multiple Obsidian vaults found. Re-run with --vault to pick one:',\n '',\n list,\n '',\n 'Example: seekstone init --vault \"/path/to/vault\"',\n ],\n };\n }\n }\n\n // Resolve to absolute before validating or writing config: clients spawn the\n // server from their own working directory, so a relative SEEKSTONE_VAULT in\n // the written config would silently point at the wrong place.\n vaultPath = path.resolve(deps.cwd ?? process.cwd(), vaultPath);\n\n const check = await validateVault(vaultPath);\n if (!check.ok) {\n return { ok: false, exitCode: 1, output: [`✗ ${check.error}`] };\n }\n\n const out: string[] = [\n `✓ Vault looks good: ${vaultPath}`,\n ` ${check.noteCount} markdown note${check.noteCount === 1 ? '' : 's'} found.`,\n '',\n ];\n\n if (opts.client === 'code') {\n if (opts.write) {\n const spawn =\n deps.spawnClaudeMcp ??\n ((args: string[]) => {\n try {\n // Runs `claude mcp add …` — the canonical way to register an MCP\n // server with Claude Code. execFileSync (no shell) is intentional;\n // writing ~/.claude.json directly would couple us to an internal\n // format Anthropic can change without notice.\n execFileSync('claude', args, { stdio: 'inherit' });\n return { ok: true };\n } catch (err) {\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n });\n\n const mcpArgs = [\n 'mcp',\n 'add',\n 'seekstone',\n '--env',\n `SEEKSTONE_VAULT=${vaultPath}`,\n '--',\n 'npx',\n '-y',\n 'seekstone',\n ];\n const result = spawn(mcpArgs);\n\n if (result.ok) {\n out.push('✓ seekstone added to Claude Code.', '', 'Restart Claude Code to load seekstone.');\n return { ok: true, exitCode: 0, output: out, ranClaudeMcpAdd: true };\n }\n\n // claude not on PATH or command failed — fall back to manual instructions.\n out.push(\n '⚠ Could not run `claude mcp add` automatically.',\n result.error ? ` ${result.error}` : '',\n '',\n 'Run this command manually instead:',\n '',\n ` ${mcpAddCommand(vaultPath)}`,\n '',\n );\n return { ok: false, exitCode: 1, output: out };\n }\n\n out.push('Add to Claude Code by running:', '', ` ${mcpAddCommand(vaultPath)}`, '');\n return { ok: true, exitCode: 0, output: out };\n }\n\n // File-config clients: Claude Desktop and Cursor share the same\n // `mcpServers` JSON shape; VS Code uses `servers` + explicit `type: stdio`.\n // Only the config path, JSON shape, and restart hint differ.\n const clientLabel =\n opts.client === 'cursor'\n ? 'Cursor'\n : opts.client === 'vscode'\n ? 'VS Code (GitHub Copilot)'\n : 'Claude Desktop';\n const configPath =\n opts.client === 'vscode'\n ? vscodeMcpConfigPath(deps.cwd ?? process.cwd())\n : opts.client === 'cursor'\n ? cursorConfigPath(deps.platform, { home: deps.env.HOME })\n : claudeDesktopConfigPath(deps.platform, {\n home: deps.env.HOME,\n appData: deps.env.APPDATA,\n });\n const block =\n opts.client === 'vscode'\n ? JSON.stringify({ servers: { seekstone: vscodeServerConfig(vaultPath) } }, null, 2)\n : JSON.stringify({ mcpServers: { seekstone: seekstoneServerConfig(vaultPath) } }, null, 2);\n const restartHint =\n opts.client === 'vscode'\n ? 'Reload VS Code, then open Copilot Chat in Agent mode — seekstone appears in the tools picker.'\n : `Restart ${clientLabel} to load seekstone.`;\n\n if (!opts.write) {\n out.push(\n `Add this to your ${clientLabel} config:`,\n ` ${configPath}`,\n ...(opts.client === 'vscode'\n ? [\n ' (workspace config — run from your project root, or use the Command Palette\\'s \"MCP: Open User Configuration\" for user-global)',\n ]\n : []),\n '',\n block,\n '',\n `${restartHint} Or re-run with --write to patch it automatically.`,\n );\n return { ok: true, exitCode: 0, output: out };\n }\n\n // --write: additive, backed-up patch.\n let existing: McpConfig | null = null;\n let existingRaw: string | null = null;\n try {\n existingRaw = await rf(configPath, 'utf8');\n existing = JSON.parse(existingRaw) as McpConfig;\n } catch (err) {\n if (existingRaw !== null) {\n // File exists but isn't valid JSON — refuse rather than clobber.\n return {\n ok: false,\n exitCode: 1,\n output: [\n `✗ ${configPath} exists but is not valid JSON; not modifying it.`,\n ` ${err instanceof Error ? err.message : String(err)}`,\n ],\n };\n }\n existing = null; // file simply doesn't exist yet\n }\n\n const merged =\n opts.client === 'vscode'\n ? mergeSeekstoneConfigVsCode(existing, vaultPath)\n : mergeSeekstoneConfig(existing, vaultPath);\n let backupPath: string | undefined;\n await mkdir(dirname(configPath), { recursive: true });\n if (existingRaw !== null) {\n backupPath = `${configPath}.backup-${deps.timestamp}`;\n await copyFile(configPath, backupPath);\n }\n await writeFile(configPath, `${JSON.stringify(merged, null, 2)}\\n`, 'utf8');\n\n out.push(\n `✓ Patched ${configPath}`,\n backupPath ? ` Backup saved to ${backupPath}` : ' (created a new config file)',\n '',\n restartHint,\n );\n return { ok: true, exitCode: 0, output: out, wrotePath: configPath, backupPath };\n}\n","import type { Logger } from './log.js';\n\n/**\n * Install a process-level safety net for the long-lived stdio server session.\n *\n * The server's known async paths (dispatch, watcher) already guard themselves,\n * so a stray `unhandledRejection` is unexpected — but crashing the whole MCP\n * session (and discarding the in-memory index, which is expensive to rebuild)\n * is a worse outcome than logging it and staying up. So we log via stderr and\n * keep running. `uncaughtException` is deliberately left to Node's default\n * crash behaviour: continuing after a truly uncaught throw risks corrupt state.\n *\n * Returns a disposer that removes the listener (used by tests to avoid leaking\n * handlers across cases).\n */\nexport function installProcessGuards(log: Logger): () => void {\n const onUnhandledRejection = (reason: unknown): void => {\n const error = reason instanceof Error ? reason.message : String(reason);\n log.error('unhandled promise rejection (server kept alive)', { error });\n };\n\n process.on('unhandledRejection', onUnhandledRejection);\n\n return () => {\n process.off('unhandledRejection', onUnhandledRejection);\n };\n}\n","/**\n * Paragraph-window chunking for note embedding.\n *\n * Notes are split on blank lines (single newlines are hard-wrap artifacts and\n * stay inside their paragraph), then adjacent paragraphs are merged greedily\n * into ~250–400-word windows. A single mean-pooled vector over a very large\n * note dilutes every topic in it — the fixture vault's tail runs to 832 KB —\n * so retrieval scores each chunk and max-pools per note.\n *\n * Each chunk also carries its `[start, end)` character span in the\n * CRLF-normalized body, so consumers (chunk-aware excerpts) can slice the\n * matching passage without re-chunking the note.\n */\n\nexport interface Chunk {\n /** Embedding input: note title, blank line, window text. */\n text: string;\n /** Word count of the window body (excludes the title). */\n words: number;\n /** Start offset of the window in the CRLF-normalized body. */\n start: number;\n /** End offset (exclusive) of the window in the CRLF-normalized body. */\n end: number;\n}\n\ninterface Paragraph {\n text: string;\n words: number;\n start: number;\n end: number;\n}\n\nconst MIN_WINDOW_WORDS = 250;\nconst MAX_WINDOW_WORDS = 400;\n\nexport function chunkNote(title: string, body: string): Chunk[] {\n const normalized = body.replace(/\\r\\n/g, '\\n');\n const paragraphs = splitParagraphs(normalized).flatMap(splitOversized);\n\n if (paragraphs.length === 0) return [{ text: title, words: 0, start: 0, end: 0 }];\n\n const chunks: Chunk[] = [];\n let window: Paragraph[] = [];\n let windowWords = 0;\n const flush = () => {\n const first = window[0];\n const last = window[window.length - 1];\n if (!first || !last) return;\n chunks.push({\n text: `${title}\\n\\n${window.map((p) => p.text).join('\\n\\n')}`,\n words: windowWords,\n start: first.start,\n end: last.end,\n });\n window = [];\n windowWords = 0;\n };\n for (const para of paragraphs) {\n if (windowWords >= MIN_WINDOW_WORDS || windowWords + para.words > MAX_WINDOW_WORDS) flush();\n window.push(para);\n windowWords += para.words;\n }\n flush();\n return chunks;\n}\n\n/** Blank-line-delimited paragraphs with trimmed text and exact spans. */\nfunction splitParagraphs(normalized: string): Paragraph[] {\n const out: Paragraph[] = [];\n const push = (rawStart: number, raw: string) => {\n const text = raw.trim();\n if (text.length === 0) return;\n const start = rawStart + (raw.length - raw.trimStart().length);\n out.push({ text, words: countWords(text), start, end: start + text.length });\n };\n const sep = /\\n[ \\t]*\\n+/g;\n let prev = 0;\n for (const m of normalized.matchAll(sep)) {\n push(prev, normalized.slice(prev, m.index));\n prev = m.index + m[0].length;\n }\n push(prev, normalized.slice(prev));\n return out;\n}\n\n/**\n * Hard-split a paragraph longer than the window cap on word boundaries.\n * Piece text joins words with single spaces (identical embedding input to\n * the pre-span implementation); spans stay exact via word offsets.\n */\nfunction splitOversized(para: Paragraph): Paragraph[] {\n if (para.words <= MAX_WINDOW_WORDS) return [para];\n const words = [...para.text.matchAll(/\\S+/g)];\n const pieces: Paragraph[] = [];\n for (let i = 0; i < words.length; i += MAX_WINDOW_WORDS) {\n const slice = words.slice(i, i + MAX_WINDOW_WORDS);\n const first = slice[0];\n const last = slice[slice.length - 1];\n if (!first || !last) continue;\n pieces.push({\n text: slice.map((w) => w[0]).join(' '),\n words: slice.length,\n start: para.start + first.index,\n end: para.start + last.index + last[0].length,\n });\n }\n return pieces;\n}\n\nfunction countWords(text: string): number {\n const m = text.match(/\\S+/g);\n return m ? m.length : 0;\n}\n","/**\n * Static late-interaction MaxSim scorer (SHA-314).\n *\n * ColBERT's late-interaction mechanism over static token vectors: for each\n * query token, take the max cosine similarity over the candidate chunk's\n * tokens, then aggregate across query tokens. Token vectors come from the\n * already-loaded Model2Vec embedding matrix (TokenEmbedder.tokenEmbed), so\n * this recovers term-level evidence (\"lead\", \"sulphate\") that mean-pooling\n * dilutes — with zero new dependencies and no storage change.\n *\n * Rows in both TokenEmbeddings are L2-normalized by contract (see types.ts),\n * so the inner loop is a plain dot product. A zero row (zero embedding) never\n * wins a max against any positive similarity and contributes 0 if the chunk\n * is all-zero — degrading gracefully rather than throwing.\n */\nimport type { TokenEmbedding } from './types.js';\n\n/**\n * How per-query-token maxima combine:\n * - `sum`: Σ wᵢ·maxᵢ — rewards queries with more matched tokens (ColBERT's choice).\n * - `mean`: Σ wᵢ·maxᵢ / Σ wᵢ — length-invariant, comparable across queries.\n */\nexport type MaxSimAggregate = 'sum' | 'mean';\n\nexport interface MaxSimOptions {\n aggregate?: MaxSimAggregate;\n /**\n * Per-query-token weights (e.g. IDF down-weighting of common tokens).\n * Length must equal the query token count. Defaults to all-ones.\n */\n weights?: ArrayLike<number>;\n}\n\n/**\n * MaxSim score of `doc` against `query`. Returns 0 when either side has no\n * tokens (empty text) or when `mean` aggregation has zero total weight.\n */\nexport function maxsimScore(\n query: TokenEmbedding,\n doc: TokenEmbedding,\n opts: MaxSimOptions = {},\n): number {\n if (query.dim !== doc.dim) {\n throw new Error(`maxsim: query dim ${query.dim} does not match doc dim ${doc.dim}`);\n }\n const n = query.ids.length;\n const weights = opts.weights;\n if (weights !== undefined && weights.length !== n) {\n throw new Error(`maxsim: ${weights.length} weights for ${n} query tokens`);\n }\n const m = doc.ids.length;\n if (n === 0 || m === 0) return 0;\n const { dim } = query;\n const q = query.vectors;\n const d = doc.vectors;\n let sum = 0;\n let weightSum = 0;\n for (let i = 0; i < n; i++) {\n const qBase = i * dim;\n let best = -Infinity;\n for (let c = 0; c < m; c++) {\n const dBase = c * dim;\n let dot = 0;\n for (let j = 0; j < dim; j++) {\n dot += (q[qBase + j] as number) * (d[dBase + j] as number);\n }\n if (dot > best) best = dot;\n }\n const w = weights === undefined ? 1 : (weights[i] as number);\n sum += w * best;\n weightSum += w;\n }\n if ((opts.aggregate ?? 'sum') === 'mean') {\n return weightSum > 0 ? sum / weightSum : 0;\n }\n return sum;\n}\n\n/**\n * MaxSim of MANY docs against one query — same math as calling\n * `maxsimScore` per doc, but each (query token × vocab token) similarity is\n * computed once and memoized by vocab id across all docs. Candidate chunks\n * share most of their vocabulary, so this collapses the O(q·d·dim) dot work\n * to O(q·unique(d)·dim) per query — the difference between ~115 ms and a\n * single-digit rerank at depth 50 (SHA-314 latency budget).\n *\n * Assumes equal token ids carry identical vectors in every doc — true for\n * any table-gather embedder (tokenEmbed reads the same matrix row).\n */\nexport function maxsimScoreAll(\n query: TokenEmbedding,\n docs: ReadonlyArray<TokenEmbedding>,\n opts: MaxSimOptions = {},\n): number[] {\n const n = query.ids.length;\n const weights = opts.weights;\n if (weights !== undefined && weights.length !== n) {\n throw new Error(`maxsim: ${weights.length} weights for ${n} query tokens`);\n }\n const mean = (opts.aggregate ?? 'sum') === 'mean';\n const out = new Array<number>(docs.length).fill(0);\n if (n === 0) return out;\n const { dim } = query;\n const q = query.vectors;\n /** vocab id → similarity against each query token, computed on first sight. */\n const simCache = new Map<number, Float64Array>();\n const best = new Float64Array(n);\n for (let d = 0; d < docs.length; d++) {\n const doc = docs[d] as TokenEmbedding;\n if (doc.dim !== dim) {\n throw new Error(`maxsim: query dim ${dim} does not match doc dim ${doc.dim}`);\n }\n const m = doc.ids.length;\n if (m === 0) continue;\n best.fill(Number.NEGATIVE_INFINITY);\n for (let t = 0; t < m; t++) {\n const id = doc.ids[t] as number;\n let sims = simCache.get(id);\n if (sims === undefined) {\n sims = new Float64Array(n);\n const dBase = t * dim;\n for (let i = 0; i < n; i++) {\n const qBase = i * dim;\n let dot = 0;\n for (let j = 0; j < dim; j++) {\n dot += (q[qBase + j] as number) * (doc.vectors[dBase + j] as number);\n }\n sims[i] = dot;\n }\n simCache.set(id, sims);\n }\n for (let i = 0; i < n; i++) {\n const s = sims[i] as number;\n if (s > (best[i] as number)) best[i] = s;\n }\n }\n let sum = 0;\n let weightSum = 0;\n for (let i = 0; i < n; i++) {\n const w = weights === undefined ? 1 : (weights[i] as number);\n sum += w * (best[i] as number);\n weightSum += w;\n }\n out[d] = mean ? (weightSum > 0 ? sum / weightSum : 0) : sum;\n }\n return out;\n}\n\n/**\n * MaxSim over token-ID docs with lazy vector gather: `tokenVector(id)` is\n * called once per unique id across ALL docs, and the (query token × vocab\n * token) similarities are memoized alongside. This skips materializing the\n * ~450 per-token vectors of every candidate chunk — the depth-50 rerank\n * gathers only the candidate set's few thousand unique tokens per query.\n * Scores are bit-identical to `maxsimScoreAll` over `tokenEmbed`ed docs.\n */\nexport function maxsimScoreTokens(\n query: TokenEmbedding,\n docs: ReadonlyArray<ArrayLike<number>>,\n tokenVector: (id: number) => Float32Array,\n opts: MaxSimOptions = {},\n): number[] {\n const n = query.ids.length;\n const weights = opts.weights;\n if (weights !== undefined && weights.length !== n) {\n throw new Error(`maxsim: ${weights.length} weights for ${n} query tokens`);\n }\n const mean = (opts.aggregate ?? 'sum') === 'mean';\n const out = new Array<number>(docs.length).fill(0);\n if (n === 0) return out;\n const { dim } = query;\n const q = query.vectors;\n const simCache = new Map<number, Float64Array>();\n const best = new Float64Array(n);\n for (let d = 0; d < docs.length; d++) {\n const ids = docs[d] as ArrayLike<number>;\n const m = ids.length;\n if (m === 0) continue;\n best.fill(Number.NEGATIVE_INFINITY);\n for (let t = 0; t < m; t++) {\n const id = ids[t] as number;\n let sims = simCache.get(id);\n if (sims === undefined) {\n sims = new Float64Array(n);\n const vec = tokenVector(id);\n if (vec.length !== dim) {\n throw new Error(`maxsim: token vector dim ${vec.length} does not match query dim ${dim}`);\n }\n for (let i = 0; i < n; i++) {\n const qBase = i * dim;\n let dot = 0;\n for (let j = 0; j < dim; j++) {\n dot += (q[qBase + j] as number) * (vec[j] as number);\n }\n sims[i] = dot;\n }\n simCache.set(id, sims);\n }\n for (let i = 0; i < n; i++) {\n const s = sims[i] as number;\n if (s > (best[i] as number)) best[i] = s;\n }\n }\n let sum = 0;\n let weightSum = 0;\n for (let i = 0; i < n; i++) {\n const w = weights === undefined ? 1 : (weights[i] as number);\n sum += w * (best[i] as number);\n weightSum += w;\n }\n out[d] = mean ? (weightSum > 0 ? sum / weightSum : 0) : sum;\n }\n return out;\n}\n\n/**\n * BM25-form IDF of each query token over the candidate docs' token-id sets:\n * `ln(1 + (N − df + 0.5) / (df + 0.5))`. Computed over the CANDIDATE SET at\n * query time — no corpus-wide statistics, no index/cache change. A token in\n * every candidate gets a near-zero weight; a token in one candidate\n * dominates (SHA-314 R3).\n */\nexport function candidateSetIdf(\n queryIds: ArrayLike<number>,\n docs: ReadonlyArray<ArrayLike<number>>,\n): number[] {\n const n = docs.length;\n const docSets: Array<Set<number>> = [];\n for (const doc of docs) {\n const set = new Set<number>();\n for (let t = 0; t < doc.length; t++) set.add(doc[t] as number);\n docSets.push(set);\n }\n const out = new Array<number>(queryIds.length);\n for (let i = 0; i < queryIds.length; i++) {\n const id = queryIds[i] as number;\n let df = 0;\n for (const set of docSets) {\n if (set.has(id)) df++;\n }\n out[i] = Math.log(1 + (n - df + 0.5) / (df + 0.5));\n }\n return out;\n}\n","/**\n * Model2Vec static-embedding inference: tokenize → gather rows from the\n * embedding matrix → mean-pool → L2-normalize. Zipf token weighting is baked\n * into the matrix at distillation time, so inference is exactly this simple —\n * no ONNX runtime, no native code, no network.\n *\n * Special tokens are excluded from the pool with one exception: [UNK] rows\n * carry real signal in Model2Vec models and are kept, matching the reference\n * implementation (which strips the [CLS]/[SEP] post-processor and pools\n * whatever the tokenizer emits).\n *\n * The loader also exposes `tokenEmbed()` (SHA-314 MaxSim rerank): the same\n * token filter, but returning each kept token's matrix row individually,\n * L2-normalized per row — no second copy of the matrix, rows are gathered\n * from the same in-memory table `embed()` pools from.\n */\nimport { readFile } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\nimport { readSafetensors } from './safetensors.js';\nimport { loadWordPieceTokenizer } from './tokenizer.js';\nimport type { TokenEmbedder, TokenEmbedding } from './types.js';\n\ninterface Model2VecConfig {\n hidden_dim?: number;\n normalize?: boolean;\n}\n\nconst TENSOR_NAME = 'embeddings';\n\nexport async function loadModel2Vec(modelDir: string): Promise<TokenEmbedder> {\n const [configRaw, tokenizerRaw, weights] = await Promise.all([\n readFile(join(modelDir, 'config.json'), 'utf8'),\n readFile(join(modelDir, 'tokenizer.json'), 'utf8'),\n readFile(join(modelDir, 'model.safetensors')),\n ]);\n const config = JSON.parse(configRaw) as Model2VecConfig;\n const tokenizer = loadWordPieceTokenizer(JSON.parse(tokenizerRaw));\n\n const tensors = readSafetensors(weights);\n const tensor =\n tensors.get(TENSOR_NAME) ?? (tensors.size === 1 ? [...tensors.values()][0] : undefined);\n if (!tensor) {\n throw new Error(\n `model2vec: no \"${TENSOR_NAME}\" tensor in ${modelDir}; found: ${[...tensors.keys()].join(', ')}`,\n );\n }\n if (tensor.shape.length !== 2) {\n throw new Error(`model2vec: expected a 2-D embedding matrix, got [${tensor.shape.join(', ')}]`);\n }\n const [rows, dim] = tensor.shape as [number, number];\n if (rows !== tokenizer.vocabSize) {\n throw new Error(\n `model2vec: embedding rows (${rows}) do not match tokenizer vocab size (${tokenizer.vocabSize})`,\n );\n }\n if (config.hidden_dim !== undefined && config.hidden_dim !== dim) {\n throw new Error(\n `model2vec: config hidden_dim ${config.hidden_dim} does not match tensor dim ${dim}`,\n );\n }\n\n const table = tensor.data;\n\n /** Token ids `embed()` would pool: specials skipped, [UNK] kept. */\n function pooledIds(text: string): number[] {\n const ids: number[] = [];\n for (const id of tokenizer.encode(text)) {\n if (tokenizer.specialIds.has(id) && id !== tokenizer.unkId) continue;\n ids.push(id);\n }\n return ids;\n }\n\n return {\n id: basename(modelDir),\n dim,\n embed(text: string): Float32Array {\n const out = new Float32Array(dim);\n const ids = pooledIds(text);\n for (const id of ids) {\n const base = id * dim;\n for (let j = 0; j < dim; j++) {\n out[j] = (out[j] as number) + (table[base + j] as number);\n }\n }\n const pooled = ids.length;\n if (pooled === 0) return out;\n let sumSquares = 0;\n for (let j = 0; j < dim; j++) {\n const mean = (out[j] as number) / pooled;\n out[j] = mean;\n sumSquares += mean * mean;\n }\n const norm = Math.sqrt(sumSquares);\n if (norm > 0) {\n for (let j = 0; j < dim; j++) out[j] = (out[j] as number) / norm;\n }\n return out;\n },\n tokenEmbed(text: string): TokenEmbedding {\n const ids = pooledIds(text);\n const vectors = new Float32Array(ids.length * dim);\n for (let t = 0; t < ids.length; t++) {\n writeNormalizedRow(ids[t] as number, vectors, t * dim);\n }\n return { ids, dim, vectors };\n },\n tokenIds: pooledIds,\n tokenVector(id: number): Float32Array {\n if (!Number.isInteger(id) || id < 0 || id >= tokenizer.vocabSize) {\n throw new Error(`model2vec: token id ${id} outside vocab [0, ${tokenizer.vocabSize})`);\n }\n const out = new Float32Array(dim);\n writeNormalizedRow(id, out, 0);\n return out;\n },\n };\n\n /** Copy row `id` of the table into `out` at `offset`, L2-normalized (zero rows stay zero). */\n function writeNormalizedRow(id: number, out: Float32Array, offset: number): void {\n const base = id * dim;\n let sumSquares = 0;\n for (let j = 0; j < dim; j++) {\n const x = table[base + j] as number;\n out[offset + j] = x;\n sumSquares += x * x;\n }\n const norm = Math.sqrt(sumSquares);\n if (norm > 0) {\n for (let j = 0; j < dim; j++) {\n out[offset + j] = (out[offset + j] as number) / norm;\n }\n }\n }\n}\n","/**\n * Minimal safetensors reader — just enough for Model2Vec model files, which\n * hold a single F32 embedding matrix. Format: 8-byte little-endian header\n * length, JSON header mapping tensor name → { dtype, shape, data_offsets },\n * then the raw tensor data (offsets relative to the end of the header).\n *\n * F32 only by design; quantized (I8) Model2Vec variants are a documented\n * future case and fail loudly here rather than decode garbage.\n */\n\nexport interface SafeTensor {\n dtype: string;\n shape: number[];\n data: Float32Array;\n}\n\ninterface TensorMeta {\n dtype: string;\n shape: number[];\n data_offsets: [number, number];\n}\n\nexport function readSafetensors(buf: Uint8Array): Map<string, SafeTensor> {\n if (buf.byteLength < 8) {\n throw new Error(`safetensors: buffer too small (${buf.byteLength} bytes) to hold a header`);\n }\n const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);\n const headerLen = Number(view.getBigUint64(0, true));\n if (8 + headerLen > buf.byteLength) {\n throw new Error(\n `safetensors: header length ${headerLen} exceeds buffer (${buf.byteLength} bytes)`,\n );\n }\n const header = JSON.parse(new TextDecoder().decode(buf.subarray(8, 8 + headerLen))) as Record<\n string,\n TensorMeta\n >;\n const dataStart = 8 + headerLen;\n\n const out = new Map<string, SafeTensor>();\n const unsupported: string[] = [];\n for (const [name, meta] of Object.entries(header)) {\n if (name === '__metadata__') continue;\n if (meta.dtype !== 'F32') {\n unsupported.push(`${name} (${meta.dtype})`);\n continue;\n }\n const [begin, end] = meta.data_offsets;\n const byteLen = end - begin;\n const elems = meta.shape.reduce((a, b) => a * b, 1);\n if (byteLen !== elems * 4) {\n throw new Error(\n `safetensors: tensor \"${name}\" data span ${byteLen} B does not match shape [${meta.shape.join(', ')}]`,\n );\n }\n if (dataStart + end > buf.byteLength) {\n throw new Error(`safetensors: tensor \"${name}\" extends past the end of the buffer`);\n }\n // Float32Array views require 4-byte alignment, and 8 + headerLen (or the\n // source Uint8Array's own byteOffset) may not provide it. Copy explicitly\n // when misaligned — Buffer.slice() is a view, not a copy, so it can't help.\n const absStart = buf.byteOffset + dataStart + begin;\n let data: Float32Array;\n if (absStart % 4 === 0) {\n data = new Float32Array(buf.buffer, absStart, elems);\n } else {\n const copy = new Uint8Array(byteLen);\n copy.set(buf.subarray(dataStart + begin, dataStart + end));\n data = new Float32Array(copy.buffer);\n }\n out.set(name, { dtype: meta.dtype, shape: meta.shape, data });\n }\n if (unsupported.length > 0) {\n throw new Error(`safetensors: only F32 tensors are supported; found ${unsupported.join(', ')}`);\n }\n return out;\n}\n","/**\n * Minimal WordPiece tokenizer for Model2Vec models — implements the subset of\n * the HF `tokenizer.json` contract the potion models use: BertNormalizer →\n * BertPreTokenizer → WordPiece. The [CLS]/[SEP] post-processor is deliberately\n * NOT applied: Model2Vec pools raw word tokens only.\n */\n\ninterface BertNormalizerJson {\n type?: string;\n clean_text?: boolean;\n handle_chinese_chars?: boolean;\n strip_accents?: boolean | null;\n lowercase?: boolean;\n}\n\ninterface WordPieceModelJson {\n type?: string;\n unk_token?: string;\n continuing_subword_prefix?: string;\n max_input_chars_per_word?: number;\n vocab?: Record<string, number>;\n}\n\ninterface TokenizerJson {\n normalizer?: BertNormalizerJson | null;\n added_tokens?: Array<{ id: number; content: string; special?: boolean }>;\n model?: WordPieceModelJson;\n}\n\nexport interface WordPieceTokenizer {\n encode(text: string): number[];\n readonly vocabSize: number;\n readonly unkId: number;\n /** Ids of tokens flagged `special` in tokenizer.json ([PAD], [UNK], [CLS], …). */\n readonly specialIds: ReadonlySet<number>;\n}\n\nexport function loadWordPieceTokenizer(tokenizerJson: unknown): WordPieceTokenizer {\n const tj = tokenizerJson as TokenizerJson;\n const model = tj?.model;\n if (model?.type !== 'WordPiece' || !model.vocab) {\n throw new Error(\n `tokenizer: unsupported model type \"${model?.type ?? 'missing'}\" (only WordPiece is implemented)`,\n );\n }\n const vocab = new Map(Object.entries(model.vocab));\n const unkToken = model.unk_token ?? '[UNK]';\n const unkId = vocab.get(unkToken);\n if (unkId === undefined) {\n throw new Error(`tokenizer: unk_token \"${unkToken}\" is not in the vocab`);\n }\n const prefix = model.continuing_subword_prefix ?? '##';\n const maxChars = model.max_input_chars_per_word ?? 100;\n const norm: BertNormalizerJson = tj.normalizer ?? {};\n const cleanText = norm.clean_text ?? true;\n const handleCjk = norm.handle_chinese_chars ?? true;\n const lowercase = norm.lowercase ?? true;\n // HF BertNormalizer: when strip_accents is unset it follows `lowercase`.\n const stripAccents = norm.strip_accents ?? lowercase;\n const specialIds: ReadonlySet<number> = new Set(\n (tj.added_tokens ?? []).filter((t) => t.special).map((t) => t.id),\n );\n\n function normalize(text: string): string {\n let out = cleanText ? doCleanText(text) : text;\n if (handleCjk) out = padCjkChars(out);\n if (stripAccents) out = out.normalize('NFD').replace(/\\p{Mn}/gu, '');\n if (lowercase) out = out.toLowerCase();\n return out;\n }\n\n function wordPiece(word: string): number[] {\n const chars = [...word];\n if (chars.length > maxChars) return [unkId as number];\n const ids: number[] = [];\n let start = 0;\n while (start < chars.length) {\n let end = chars.length;\n let id: number | undefined;\n while (start < end) {\n const piece = (start > 0 ? prefix : '') + chars.slice(start, end).join('');\n const found = vocab.get(piece);\n if (found !== undefined) {\n id = found;\n break;\n }\n end--;\n }\n // BERT semantics: any unmatchable remainder makes the whole word [UNK].\n if (id === undefined) return [unkId as number];\n ids.push(id);\n start = end;\n }\n return ids;\n }\n\n return {\n vocabSize: vocab.size,\n unkId,\n specialIds,\n encode(text: string): number[] {\n const ids: number[] = [];\n for (const word of preTokenize(normalize(text))) {\n for (const id of wordPiece(word)) ids.push(id);\n }\n return ids;\n },\n };\n}\n\n/** BertPreTokenizer: split on whitespace; every punctuation char is its own token. */\nfunction preTokenize(text: string): string[] {\n const words: string[] = [];\n let cur = '';\n for (const ch of text) {\n const cp = ch.codePointAt(0) as number;\n if (isWhitespace(ch, cp)) {\n if (cur) {\n words.push(cur);\n cur = '';\n }\n } else if (isPunctuation(ch, cp)) {\n if (cur) {\n words.push(cur);\n cur = '';\n }\n words.push(ch);\n } else {\n cur += ch;\n }\n }\n if (cur) words.push(cur);\n return words;\n}\n\n/** Drop control chars and U+0000/U+FFFD; fold all whitespace to a plain space. */\nfunction doCleanText(text: string): string {\n let out = '';\n for (const ch of text) {\n const cp = ch.codePointAt(0) as number;\n if (cp === 0 || cp === 0xfffd || isControl(ch, cp)) continue;\n out += isWhitespace(ch, cp) ? ' ' : ch;\n }\n return out;\n}\n\n/** Surround CJK ideographs with spaces so each is tokenized in isolation. */\nfunction padCjkChars(text: string): string {\n let out = '';\n for (const ch of text) {\n out += isCjk(ch.codePointAt(0) as number) ? ` ${ch} ` : ch;\n }\n return out;\n}\n\nfunction isWhitespace(ch: string, cp: number): boolean {\n if (cp === 0x20 || cp === 0x09 || cp === 0x0a || cp === 0x0d) return true;\n return /\\p{Zs}/u.test(ch);\n}\n\nfunction isControl(ch: string, cp: number): boolean {\n if (cp === 0x09 || cp === 0x0a || cp === 0x0d) return false;\n return /\\p{Cc}|\\p{Cf}/u.test(ch);\n}\n\nfunction isPunctuation(ch: string, cp: number): boolean {\n // BERT treats all ASCII non-alphanumeric printables as punctuation, even\n // those Unicode classes as symbols ($, +, <, =, >, ^, `, |, ~).\n if (\n (cp >= 33 && cp <= 47) ||\n (cp >= 58 && cp <= 64) ||\n (cp >= 91 && cp <= 96) ||\n (cp >= 123 && cp <= 126)\n ) {\n return true;\n }\n return /\\p{P}/u.test(ch);\n}\n\nfunction isCjk(cp: number): boolean {\n return (\n (cp >= 0x4e00 && cp <= 0x9fff) ||\n (cp >= 0x3400 && cp <= 0x4dbf) ||\n (cp >= 0x20000 && cp <= 0x2a6df) ||\n (cp >= 0x2a700 && cp <= 0x2b73f) ||\n (cp >= 0x2b740 && cp <= 0x2b81f) ||\n (cp >= 0x2b820 && cp <= 0x2ceaf) ||\n (cp >= 0xf900 && cp <= 0xfaff) ||\n (cp >= 0x2f800 && cp <= 0x2fa1f)\n );\n}\n","/**\n * Chunk → note score pooling (SHA-313).\n *\n * A note is embedded as many chunk vectors; retrieval scores every chunk and\n * must reduce them to one note score. Every pooling here consumes the SAME\n * per-chunk dot products — the choice changes aggregation only, never the\n * multiply count, so query latency is identical across poolings.\n *\n * - `max`: the single best chunk. A hub note with hundreds of chunks holds\n * hundreds of lottery tickets, so giant articles crowd out precise ones.\n * - `top2mean`: mean of the two best chunks (a single-chunk note keeps its\n * full score) — demands sustained relevance from large notes.\n * - `logdiscount`: best chunk minus `lambda · ln(chunkCount)` — a direct\n * length penalty; risks burying long notes that ARE the answer.\n * - `softmax`: softmax-weighted mean of chunk scores at `temperature` —\n * approaches max as τ→0 and the plain mean as τ→∞; a lucky lone chunk\n * is diluted by the note's many weak ones, while a note whose best\n * chunks agree keeps its score.\n *\n * The winning chunk (for excerpts / spans) is always the max-scoring chunk,\n * whatever pooling ranks the note — the excerpt should show the passage\n * that matched best.\n */\n\nexport type ChunkPooling =\n | 'max'\n | 'top2mean'\n | { kind: 'logdiscount'; lambda: number }\n | { kind: 'softmax'; temperature: number };\n\n/** Human-readable id for reports and condition names, e.g. `softmax-t0.1`. */\nexport function poolingId(p: ChunkPooling): string {\n if (typeof p === 'string') return p;\n return p.kind === 'logdiscount' ? `logdiscount-l${p.lambda}` : `softmax-t${p.temperature}`;\n}\n\n/**\n * Streaming per-note accumulator: feed each chunk's score (with its index),\n * then `pool()` for the note score. Tracks only O(1) state per note so the\n * scan stays a single pass over the packed vectors.\n */\nexport class PoolAccumulator {\n top = Number.NEGATIVE_INFINITY;\n second = Number.NEGATIVE_INFINITY;\n bestChunk = 0;\n count = 0;\n /** Σ w_i and Σ s_i·w_i with w_i = exp((s_i − 1) / τ); shift keeps exp() ≤ 1. */\n private sumW = 0;\n private sumSW = 0;\n private readonly invTemp: number;\n\n constructor(pooling: ChunkPooling) {\n this.invTemp =\n typeof pooling === 'object' && pooling.kind === 'softmax' ? 1 / pooling.temperature : 0;\n }\n\n add(score: number, chunkIndex: number): void {\n this.count++;\n if (score > this.top) {\n this.second = this.top;\n this.top = score;\n this.bestChunk = chunkIndex;\n } else if (score > this.second) {\n this.second = score;\n }\n if (this.invTemp > 0) {\n const w = Math.exp((score - 1) * this.invTemp);\n this.sumW += w;\n this.sumSW += score * w;\n }\n }\n\n pool(pooling: ChunkPooling): number {\n if (this.count === 0) return Number.NEGATIVE_INFINITY;\n if (pooling === 'max') return this.top;\n if (pooling === 'top2mean') {\n return this.second === Number.NEGATIVE_INFINITY ? this.top : (this.top + this.second) / 2;\n }\n if (pooling.kind === 'logdiscount') return this.top - pooling.lambda * Math.log(this.count);\n // softmax: sumW > 0 whenever count > 0 (exp never underflows to 0 for cosines).\n return this.sumW > 0 ? this.sumSW / this.sumW : this.top;\n }\n}\n\nexport function assertValidPooling(p: ChunkPooling): void {\n // Captured before narrowing: in the unknown-kind branches `p` is `never`\n // for well-typed callers, but JS callers can still pass junk.\n const raw: unknown = p;\n if (typeof p === 'string') {\n if (p !== 'max' && p !== 'top2mean') throw new Error(`pooling: unknown kind \"${String(raw)}\"`);\n return;\n }\n if (p.kind === 'logdiscount') {\n if (!(p.lambda >= 0))\n throw new Error(`pooling: logdiscount lambda must be ≥ 0 (got ${p.lambda})`);\n } else if (p.kind === 'softmax') {\n if (!(p.temperature > 0)) {\n throw new Error(`pooling: softmax temperature must be > 0 (got ${p.temperature})`);\n }\n } else {\n const kind = typeof raw === 'object' && raw !== null ? (raw as { kind?: unknown }).kind : raw;\n throw new Error(`pooling: unknown kind \"${String(kind)}\"`);\n }\n}\n","/**\n * The embedding seam: everything downstream (chunk index, cosine scan,\n * retrieval eval) depends only on this interface, so alternative runtimes\n * (transformers.js, bring-your-own-model) can slot in behind it later.\n */\nexport interface Embedder {\n /** Stable identifier, e.g. \"potion-base-8M\". */\n readonly id: string;\n /** Output dimensionality. */\n readonly dim: number;\n /**\n * L2-normalized embedding of `text`. Returns the zero vector when the\n * input produces no poolable tokens (empty or whitespace-only text).\n * Pure CPU, synchronous.\n */\n embed(text: string): Float32Array;\n}\n\n/**\n * Packed per-token vectors for late-interaction scoring: `ids.length` rows\n * of `dim` floats in `vectors` (row t at `t * dim`). Each row is\n * L2-normalized so a dot product between rows is cosine similarity; an\n * all-zero embedding row stays zero.\n */\nexport interface TokenEmbedding {\n /** Vocab id per kept token, in input order. */\n readonly ids: number[];\n readonly dim: number;\n /** Packed row-major matrix, length `ids.length * dim`. */\n readonly vectors: Float32Array;\n}\n\n/**\n * An Embedder that can also expose per-token vectors from its (already\n * loaded) embedding matrix. Token filtering matches `embed()` exactly:\n * special tokens are skipped except [UNK], which carries real signal in\n * Model2Vec models.\n */\nexport interface TokenEmbedder extends Embedder {\n tokenEmbed(text: string): TokenEmbedding;\n /** The token ids `tokenEmbed` would embed — tokenization only, no gather. */\n tokenIds(text: string): number[];\n /**\n * One token's L2-normalized matrix row (a fresh array per call — callers\n * that loop should memoize by id; equal ids always yield equal rows).\n */\n tokenVector(id: number): Float32Array;\n}\n\n/** Narrow an Embedder to TokenEmbedder when the runtime provides token vectors. */\nexport function isTokenEmbedder(e: Embedder): e is TokenEmbedder {\n return typeof (e as TokenEmbedder).tokenEmbed === 'function';\n}\n","import { createHash } from 'node:crypto';\nimport { mkdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { NoteVectors } from './store.js';\n\n/**\n * Persisted embedding cache so restarts don't re-embed the vault: one flat\n * binary (all packed Float32 chunk vectors, then all Uint32 chunk spans)\n * plus a JSON manifest keyed by (path, contentHash). Lives under the cache\n * dir, never inside the vault, in a per-vault subdirectory (sha of the vault\n * root) so multiple vaults never collide.\n *\n * Load is best-effort: any mismatch (version, model, dim, byte lengths)\n * silently invalidates the cache — the build just re-embeds. Writes are\n * temp-file + rename (binary first, then the manifest that describes it),\n * so a crash leaves either the old cache or the new one.\n */\n\n/** Bump when the on-disk layout OR the chunker semantics change. */\nconst CACHE_VERSION = 2;\n\nexport interface CachePaths {\n dir: string;\n bin: string;\n manifest: string;\n}\n\ninterface CacheManifest {\n version: number;\n modelId: string;\n dim: number;\n entries: Array<{ path: string; contentHash: string; chunks: number }>;\n}\n\nexport interface CacheData {\n vectors: Map<string, NoteVectors>;\n hashes: Map<string, string>;\n}\n\nexport function cachePathsFor(cacheDir: string, vaultRoot: string, modelId: string): CachePaths {\n const vaultKey = createHash('sha256').update(vaultRoot).digest('hex').slice(0, 16);\n const dir = join(cacheDir, 'embeddings', vaultKey);\n return { dir, bin: join(dir, `${modelId}.bin`), manifest: join(dir, `${modelId}.json`) };\n}\n\nexport async function loadCache(\n paths: CachePaths,\n modelId: string,\n dim: number,\n): Promise<CacheData | undefined> {\n try {\n const manifest = JSON.parse(await readFile(paths.manifest, 'utf8')) as CacheManifest;\n if (\n manifest.version !== CACHE_VERSION ||\n manifest.modelId !== modelId ||\n manifest.dim !== dim\n ) {\n return undefined;\n }\n const buf = await readFile(paths.bin);\n const totalChunks = manifest.entries.reduce((a, e) => a + e.chunks, 0);\n const vectorBytes = totalChunks * dim * 4;\n const spanBytes = totalChunks * 2 * 4;\n if (buf.byteLength !== vectorBytes + spanBytes) return undefined;\n // Buffers can be unaligned for typed-array views — copy to a fresh buffer.\n const aligned = new Uint8Array(buf.byteLength);\n aligned.set(buf);\n const floats = new Float32Array(aligned.buffer, 0, totalChunks * dim);\n const spans = new Uint32Array(aligned.buffer, vectorBytes, totalChunks * 2);\n const vectors = new Map<string, NoteVectors>();\n const hashes = new Map<string, string>();\n let chunkOffset = 0;\n for (const e of manifest.entries) {\n if (e.chunks <= 0) return undefined;\n vectors.set(e.path, {\n packed: floats.subarray(chunkOffset * dim, (chunkOffset + e.chunks) * dim),\n spans: spans.subarray(chunkOffset * 2, (chunkOffset + e.chunks) * 2),\n });\n hashes.set(e.path, e.contentHash);\n chunkOffset += e.chunks;\n }\n return { vectors, hashes };\n } catch {\n return undefined;\n }\n}\n\nexport async function saveCache(\n paths: CachePaths,\n modelId: string,\n dim: number,\n notes: Iterable<[string, NoteVectors]>,\n hashes: ReadonlyMap<string, string>,\n): Promise<void> {\n const entries: CacheManifest['entries'] = [];\n const kept: NoteVectors[] = [];\n let totalChunks = 0;\n for (const [path, note] of notes) {\n const contentHash = hashes.get(path);\n if (!contentHash) continue; // still being (re-)embedded — skip this round\n const chunks = note.packed.length / dim;\n entries.push({ path, contentHash, chunks });\n kept.push(note);\n totalChunks += chunks;\n }\n const bin = new Uint8Array(totalChunks * dim * 4 + totalChunks * 2 * 4);\n const floats = new Float32Array(bin.buffer, 0, totalChunks * dim);\n const spans = new Uint32Array(bin.buffer, totalChunks * dim * 4, totalChunks * 2);\n let floatOffset = 0;\n let spanOffset = 0;\n for (const note of kept) {\n floats.set(note.packed, floatOffset);\n spans.set(note.spans, spanOffset);\n floatOffset += note.packed.length;\n spanOffset += note.spans.length;\n }\n const manifest: CacheManifest = { version: CACHE_VERSION, modelId, dim, entries };\n\n await mkdir(paths.dir, { recursive: true });\n // Binary first, manifest last: the manifest is the commit point, and load\n // validates byte lengths, so a torn state just invalidates the cache.\n await atomicWriteBytes(paths.bin, bin);\n await atomicWriteBytes(paths.manifest, new TextEncoder().encode(JSON.stringify(manifest)));\n}\n\nasync function atomicWriteBytes(absPath: string, bytes: Uint8Array): Promise<void> {\n const tmpPath = `${absPath}.seekstone-cache-tmp`;\n await writeFile(tmpPath, bytes);\n await rename(tmpPath, absPath);\n}\n","import {\n chunkNote,\n type Embedder,\n isTokenEmbedder,\n loadModel2Vec,\n type TokenEmbedder,\n} from '@seekstone/core/embed';\nimport { contentHash } from '../content-hash.js';\nimport type { IndexedNote } from '../index/types.js';\nimport type { Logger } from '../log.js';\nimport { type CachePaths, cachePathsFor, loadCache, saveCache } from './cache.js';\nimport { fetchCommandFor, type SemanticConfig } from './config.js';\nimport { maxsimRerankHits } from './rerank.js';\nimport { type SemanticHit, SemanticStore } from './store.js';\n\nexport type SemanticProgress =\n | { state: 'building'; done: number; total: number }\n | { state: 'ready' };\n\n/** The slice of ServerContext the semantic index needs (avoids an import cycle). */\nexport interface SemanticCtx {\n vaultRoot: string;\n notes: Map<string, IndexedNote>;\n}\n\nexport interface SemanticDeps {\n log?: Logger;\n /** Per-note re-embed debounce (ms). */\n debounceMs?: number;\n /** Cache re-save debounce after watcher-driven changes (ms). */\n saveDebounceMs?: number;\n /** Yield to the event loop after this many freshly-embedded notes. */\n yieldEvery?: number;\n /** Test seam; defaults to loadModel2Vec. */\n loadModel?: (modelDir: string) => Promise<Embedder>;\n}\n\n/**\n * The live semantic index: embeds every note's chunks at boot (in the\n * background, off the hot path — queries during the build get a structured\n * progress error), keeps a per-vault (path, contentHash)-keyed cache so\n * restarts skip re-embedding, and re-embeds individual notes as the watcher\n * reports changes (debounced; the watcher's index update already refreshed\n * ctx.notes by then, so re-embeds read from memory, not disk).\n */\nexport class Semantic {\n readonly embedder: Embedder;\n readonly store: SemanticStore;\n progress: SemanticProgress;\n\n private readonly ctx: SemanticCtx;\n private readonly paths: CachePaths;\n private readonly log?: Logger;\n private readonly debounceMs: number;\n private readonly saveDebounceMs: number;\n private readonly yieldEvery: number;\n private readonly hashes = new Map<string, string>();\n /**\n * Lazy per-note chunk token ids for the MaxSim rerank (SHA-314): filled on\n * first rerank touch, dropped whenever the note changes or is removed.\n * Only queried candidates are ever tokenized, so the memo stays a small\n * fraction of the vault; it lives in memory only — the cache file format\n * is untouched.\n */\n private readonly tokenIdCache = new Map<string, Uint32Array[]>();\n private readonly tokenEmbedder: TokenEmbedder | undefined;\n private readonly pending = new Map<string, NodeJS.Timeout>();\n private saveTimer: NodeJS.Timeout | undefined;\n private stopped = false;\n\n private constructor(\n embedder: Embedder,\n ctx: SemanticCtx,\n cfg: SemanticConfig,\n deps: SemanticDeps,\n ) {\n this.embedder = embedder;\n this.tokenEmbedder = isTokenEmbedder(embedder) ? embedder : undefined;\n this.store = new SemanticStore(embedder.dim);\n this.ctx = ctx;\n this.paths = cachePathsFor(cfg.cacheDir, ctx.vaultRoot, embedder.id);\n this.log = deps.log;\n this.debounceMs = deps.debounceMs ?? 300;\n this.saveDebounceMs = deps.saveDebounceMs ?? 5000;\n this.yieldEvery = deps.yieldEvery ?? 8;\n this.progress = { state: 'building', done: 0, total: ctx.notes.size };\n }\n\n /**\n * Load the model and kick off the background index build. Rejects with an\n * actionable message when the model files are missing — the user enabled\n * the feature explicitly, so a broken setup should fail loudly at boot.\n */\n static async start(\n ctx: SemanticCtx,\n cfg: SemanticConfig,\n deps: SemanticDeps = {},\n ): Promise<Semantic> {\n let embedder: Embedder;\n try {\n embedder = await (deps.loadModel ?? loadModel2Vec)(cfg.modelDir);\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n throw new Error(\n `semantic search: could not load the embedding model ${cfg.modelId} from ${cfg.modelDir} — ` +\n `run \\`${fetchCommandFor(cfg.modelId)}\\` to download it, or point SEEKSTONE_MODEL_PATH at a Model2Vec model directory (${reason})`,\n );\n }\n const semantic = new Semantic(embedder, ctx, cfg, deps);\n void semantic.build();\n return semantic;\n }\n\n /** Resolves when the initial build has finished (tests and progress checks). */\n private buildDone: Promise<void> = Promise.resolve();\n\n ready(): Promise<void> {\n return this.buildDone;\n }\n\n private build(): Promise<void> {\n this.buildDone = this.buildInner().catch((err) => {\n this.log?.error('semantic build failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n });\n return this.buildDone;\n }\n\n private async buildInner(): Promise<void> {\n const t0 = performance.now();\n const cached = await loadCache(this.paths, this.embedder.id, this.embedder.dim);\n const ids = [...this.ctx.notes.keys()];\n this.progress = { state: 'building', done: 0, total: ids.length };\n let reused = 0;\n let sinceYield = 0;\n for (const id of ids) {\n if (this.stopped) return;\n // A watcher-driven re-embed may have processed this note already;\n // never overwrite fresh vectors with build-time ones.\n if (!this.hashes.has(id)) {\n const note = this.ctx.notes.get(id);\n if (note) {\n const current = contentHash(note.raw);\n const cachedVecs =\n cached?.hashes.get(id) === current ? cached.vectors.get(id) : undefined;\n if (cachedVecs !== undefined && cachedVecs.packed.length > 0) {\n this.store.setNote(id, cachedVecs.packed, cachedVecs.spans);\n reused++;\n } else {\n const { packed, spans } = this.embedNote(note);\n this.store.setNote(id, packed, spans);\n if (++sinceYield >= this.yieldEvery) {\n sinceYield = 0;\n await new Promise((r) => setImmediate(r));\n }\n }\n this.hashes.set(id, current);\n }\n }\n if (this.progress.state === 'building') this.progress.done++;\n }\n this.progress = { state: 'ready' };\n this.log?.info('semantic index ready', {\n notes: this.store.noteCount,\n chunks: this.store.chunkCount,\n reusedFromCache: reused,\n buildMs: Math.round(performance.now() - t0),\n });\n if (reused < this.store.noteCount) await this.save();\n }\n\n private embedNote(note: Pick<IndexedNote, 'title' | 'body'>): {\n packed: Float32Array;\n spans: Uint32Array;\n } {\n const chunks = chunkNote(note.title, note.body);\n const dim = this.embedder.dim;\n const packed = new Float32Array(chunks.length * dim);\n const spans = new Uint32Array(chunks.length * 2);\n for (let i = 0; i < chunks.length; i++) {\n const chunk = chunks[i] as { text: string; start: number; end: number };\n packed.set(this.embedder.embed(chunk.text), i * dim);\n spans[i * 2] = chunk.start;\n spans[i * 2 + 1] = chunk.end;\n }\n return { packed, spans };\n }\n\n embedQuery(query: string): Float32Array {\n return this.embedder.embed(query);\n }\n\n /**\n * MaxSim-rerank stage-1 candidates (SHA-314). Pass-through when the\n * embedder exposes no token vectors (alternative runtimes) — semantic\n * search then ships stage-1 order unchanged.\n */\n rerank(query: string, hits: ReadonlyArray<SemanticHit>): SemanticHit[] {\n const embedder = this.tokenEmbedder;\n if (!embedder) return [...hits];\n return maxsimRerankHits(embedder, query, hits, (hit) => {\n const ids = this.chunkTokenIds(hit.path);\n return ids?.[hit.chunkIndex];\n });\n }\n\n private chunkTokenIds(path: string): Uint32Array[] | undefined {\n const cached = this.tokenIdCache.get(path);\n if (cached) return cached;\n const embedder = this.tokenEmbedder;\n const note = this.ctx.notes.get(path);\n if (!embedder || !note) return undefined;\n const ids = chunkNote(note.title, note.body).map((chunk) =>\n Uint32Array.from(embedder.tokenIds(chunk.text)),\n );\n this.tokenIdCache.set(path, ids);\n return ids;\n }\n\n /** Watcher hook: a note was added or changed (ctx.notes is already fresh). */\n noteChanged(path: string): void {\n if (this.stopped) return;\n // ctx.notes already holds the new body — memoized token ids are stale now,\n // not just after the debounced re-embed.\n this.tokenIdCache.delete(path);\n const existing = this.pending.get(path);\n if (existing) clearTimeout(existing);\n const timer = setTimeout(() => {\n this.pending.delete(path);\n this.reembed(path);\n }, this.debounceMs);\n timer.unref?.();\n this.pending.set(path, timer);\n }\n\n /** Watcher hook: a note was deleted. */\n noteRemoved(path: string): void {\n const existing = this.pending.get(path);\n if (existing) {\n clearTimeout(existing);\n this.pending.delete(path);\n }\n this.tokenIdCache.delete(path);\n if (this.hashes.has(path) || this.store.getNote(path)) {\n this.store.removeNote(path);\n this.hashes.delete(path);\n this.scheduleSave();\n }\n }\n\n private reembed(path: string): void {\n const note = this.ctx.notes.get(path);\n if (!note) return;\n // Cache-staleness check, not a secret comparison — content hashes are\n // public fingerprints of vault bytes (Codacy's timing-attack rule\n // pattern-matches the identifier name, hence \"current\"/\"prior\").\n const current = contentHash(note.raw);\n const prior = this.hashes.get(path);\n if (prior === current) return;\n const { packed, spans } = this.embedNote(note);\n this.store.setNote(path, packed, spans);\n this.hashes.set(path, current);\n this.log?.debug('semantic re-embed', { path });\n this.scheduleSave();\n }\n\n private scheduleSave(): void {\n if (this.saveTimer) clearTimeout(this.saveTimer);\n this.saveTimer = setTimeout(() => {\n this.saveTimer = undefined;\n void this.save();\n }, this.saveDebounceMs);\n this.saveTimer.unref?.();\n }\n\n private async save(): Promise<void> {\n if (this.stopped) return;\n try {\n await saveCache(\n this.paths,\n this.embedder.id,\n this.embedder.dim,\n this.store.entries(),\n this.hashes,\n );\n this.log?.debug('semantic cache saved', { notes: this.store.noteCount });\n } catch (err) {\n // Cache persistence is an optimization — never let it break the server.\n this.log?.warn('semantic cache save failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n /** Tear down timers (tests; the process otherwise runs for the session). */\n stop(): void {\n this.stopped = true;\n for (const timer of this.pending.values()) clearTimeout(timer);\n this.pending.clear();\n if (this.saveTimer) clearTimeout(this.saveTimer);\n this.saveTimer = undefined;\n }\n}\n","/**\n * SHA-314: MaxSim late-interaction rerank of the semantic top-50.\n *\n * Stage 1 (pooled cosine over chunk vectors) picks candidates; this stage\n * re-scores each candidate's best chunk with token-level MaxSim — per query\n * token, max cosine over the chunk's token vectors — recovering\n * discriminating terms that mean pooling dilutes. Query tokens are\n * IDF-weighted over the candidate set and the MaxSim score is fused with\n * stage 1's by min-max weighted sum. Dev-split winner (idf-b50):\n * mean aggregation, candidate-set IDF, beta 0.5 — semantic hit@5\n * 70.4 → 85.2 with lexical routing untouched.\n *\n * The hit's chunkIndex/span are NOT changed: the excerpt keeps showing the\n * stage-1 best-matching passage; only the note ORDER (and score) moves.\n */\nimport { candidateSetIdf, maxsimScoreTokens, type TokenEmbedder } from '@seekstone/core/embed';\nimport type { SemanticHit } from './store.js';\n\n/** Fusion weight on the MaxSim score (0 = stage-1 only). Dev-split tuned. */\nexport const MAXSIM_BETA = 0.5;\n\nconst EMPTY: ArrayLike<number> = [];\n\n/**\n * Re-rank `hits` (stage-1 order). `tokenIdsFor` supplies each hit's best\n * chunk's token ids; `undefined` (note changed inside the re-embed debounce\n * window) contributes only its stage-1 score, like the harness fusion.\n * Returns a new array; input hits are not mutated.\n */\nexport function maxsimRerankHits(\n embedder: TokenEmbedder,\n query: string,\n hits: ReadonlyArray<SemanticHit>,\n tokenIdsFor: (hit: SemanticHit) => ArrayLike<number> | undefined,\n beta: number = MAXSIM_BETA,\n): SemanticHit[] {\n if (hits.length < 2 || beta <= 0) return [...hits];\n const qTok = embedder.tokenEmbed(query);\n if (qTok.ids.length === 0) return [...hits];\n const docs = hits.map((h) => tokenIdsFor(h) ?? EMPTY);\n const weights = candidateSetIdf(qTok.ids, docs);\n const maxsim = maxsimScoreTokens(qTok, docs, (id) => embedder.tokenVector(id), {\n aggregate: 'mean',\n weights,\n });\n const stage1 = normalize(hits.map((h) => h.score));\n const rerank = normalize(maxsim);\n return hits\n .map((h, i) => ({\n ...h,\n score: (1 - beta) * (stage1[i] as number) + beta * (rerank[i] as number),\n }))\n .sort((a, b) => b.score - a.score || (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));\n}\n\n/** Min-max normalize to [0, 1]; a constant list maps to all-1 (wsumFuse parity). */\nfunction normalize(scores: readonly number[]): number[] {\n let min = Number.POSITIVE_INFINITY;\n let max = Number.NEGATIVE_INFINITY;\n for (const s of scores) {\n if (s < min) min = s;\n if (s > max) max = s;\n }\n const span = max - min;\n return scores.map((s) => (span > 0 ? (s - min) / span : 1));\n}\n","/**\n * Mutable chunk-vector store for the live server: one packed Float32Array of\n * chunk embeddings per note (plus each chunk's [start, end) span in the\n * note's normalized body), so a watcher-driven re-embed replaces a single\n * map entry (the harness's append-only VectorSet can't mutate). Scanning\n * iterates note arrays with the same tight dot-product loop — ~10k map\n * entries of overhead on top of the identical multiply count.\n *\n * Vectors are L2-normalized, so dot product == cosine similarity. A note's\n * score is its pooled chunk score (see @seekstone/core pooling.ts — the\n * server's default is the recipe the SHA-313 dev-split eval chose), and the\n * best-scoring chunk's span is returned so the excerpt can be sliced from the\n * matching passage without re-chunking the note.\n */\n\nimport { assertValidPooling, type ChunkPooling, PoolAccumulator } from '@seekstone/core/embed';\n\n/** The shipped pooling; overridable per store for evals and tests. */\nexport const DEFAULT_POOLING: ChunkPooling = 'max';\n\nexport interface NoteVectors {\n /** chunkCount × dim floats, row-major. */\n packed: Float32Array;\n /** chunkCount × 2 uint32s: [start, end) body offsets per chunk. */\n spans: Uint32Array;\n}\n\nexport interface SemanticHit {\n path: string;\n score: number;\n /** Index of the note's best-scoring chunk (chunkNote() order). */\n chunkIndex: number;\n /** Body span of the best chunk (CRLF-normalized offsets). */\n start: number;\n end: number;\n}\n\nexport class SemanticStore {\n readonly dim: number;\n readonly pooling: ChunkPooling;\n private readonly notes = new Map<string, NoteVectors>();\n private chunks = 0;\n\n constructor(dim: number, pooling: ChunkPooling = DEFAULT_POOLING) {\n if (!Number.isInteger(dim) || dim <= 0) {\n throw new Error(`semantic store: invalid dim ${dim}`);\n }\n assertValidPooling(pooling);\n this.dim = dim;\n this.pooling = pooling;\n }\n\n /** Total chunk vectors across all notes. */\n get chunkCount(): number {\n return this.chunks;\n }\n\n get noteCount(): number {\n return this.notes.size;\n }\n\n /** Replace (or insert) a note's packed chunk vectors and spans. */\n setNote(path: string, packed: Float32Array, spans: Uint32Array): void {\n if (packed.length === 0 || packed.length % this.dim !== 0) {\n throw new Error(\n `semantic store: packed length ${packed.length} is not a positive multiple of dim ${this.dim} (${path})`,\n );\n }\n const n = packed.length / this.dim;\n if (spans.length !== n * 2) {\n throw new Error(\n `semantic store: spans length ${spans.length} does not match ${n} chunks (${path})`,\n );\n }\n const prev = this.notes.get(path);\n if (prev) this.chunks -= prev.packed.length / this.dim;\n this.notes.set(path, { packed, spans });\n this.chunks += n;\n }\n\n removeNote(path: string): void {\n const prev = this.notes.get(path);\n if (!prev) return;\n this.chunks -= prev.packed.length / this.dim;\n this.notes.delete(path);\n }\n\n getNote(path: string): NoteVectors | undefined {\n return this.notes.get(path);\n }\n\n /** Iterate (path, note vectors) — cache serialization uses this. */\n entries(): IterableIterator<[string, NoteVectors]> {\n return this.notes.entries();\n }\n\n /**\n * Top `k` notes by pooled chunk cosine, ties broken path-ascending. The\n * returned chunk/span is always the note's single best chunk, whatever\n * pooling ranked the note.\n */\n topNotes(query: Float32Array, k: number): SemanticHit[] {\n if (query.length !== this.dim) {\n throw new Error(`semantic store: query dim ${query.length} does not match ${this.dim}`);\n }\n const hits: SemanticHit[] = [];\n for (const [path, vectors] of this.notes) {\n hits.push(this.scoreVectors(path, vectors, query));\n }\n return hits\n .sort((a, b) => b.score - a.score || (a.path < b.path ? -1 : a.path > b.path ? 1 : 0))\n .slice(0, Math.max(0, k));\n }\n\n /**\n * Score a single note's cached chunk vectors against the query (SHA-315\n * graph expansion gates candidates on this). Same pooling and best-chunk\n * span as topNotes; undefined when the note has no vectors.\n */\n scoreNote(path: string, query: Float32Array): SemanticHit | undefined {\n if (query.length !== this.dim) {\n throw new Error(`semantic store: query dim ${query.length} does not match ${this.dim}`);\n }\n const vectors = this.notes.get(path);\n return vectors === undefined ? undefined : this.scoreVectors(path, vectors, query);\n }\n\n private scoreVectors(\n path: string,\n { packed, spans }: NoteVectors,\n query: Float32Array,\n ): SemanticHit {\n const dim = this.dim;\n const pooling = this.pooling;\n const acc = new PoolAccumulator(pooling);\n const n = packed.length / dim;\n for (let c = 0; c < n; c++) {\n const base = c * dim;\n let score = 0;\n for (let j = 0; j < dim; j++) {\n score += (packed[base + j] as number) * (query[j] as number);\n }\n acc.add(score, c);\n }\n const bestChunk = acc.bestChunk;\n return {\n path,\n score: acc.pool(pooling),\n chunkIndex: bestChunk,\n start: spans[bestChunk * 2] as number,\n end: spans[bestChunk * 2 + 1] as number,\n };\n }\n}\n","import type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { WRITE_TOOLS } from './dispatch.js';\nimport type { WritePolicy } from './policy.js';\n\nconst READ_ONLY_ANNOTATIONS = {\n readOnlyHint: true,\n openWorldHint: false,\n} as const satisfies ToolAnnotations;\n\nconst ADDITIVE_WRITE_ANNOTATIONS = {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n} as const satisfies ToolAnnotations;\n\nconst DESTRUCTIVE_WRITE_ANNOTATIONS = {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: false,\n openWorldHint: false,\n} as const satisfies ToolAnnotations;\n\nconst IDEMPOTENT_DESTRUCTIVE_WRITE_ANNOTATIONS = {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: true,\n openWorldHint: false,\n} as const satisfies ToolAnnotations;\n\n/**\n * The full tool list served to MCP clients, extracted verbatim from the\n * ListTools handler so it can be filtered by policy and unit-tested.\n * Keep in sync with HANDLED_TOOLS in dispatch.ts.\n */\nexport const ALL_TOOLS = [\n {\n name: 'search',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n 'Full-text search across the vault. Returns ranked excerpts (~120 chars, tunable) — not full notes — to minimise context usage. Supports fuzzy matching and prefix search; with SEEKSTONE_SEMANTIC=1, mode \"semantic\"/\"hybrid\" searches by meaning via a local embedding model.',\n inputSchema: {\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Search query.' },\n mode: {\n type: 'string',\n enum: ['lexical', 'semantic', 'hybrid'],\n description:\n 'lexical = keyword search (default). semantic = meaning-based search (requires SEEKSTONE_SEMANTIC=1). hybrid = exact-title lookups go lexical, everything else semantic.',\n },\n limit: { type: 'number', description: 'Max results (1–50, default 10).' },\n folder: { type: 'string', description: 'Restrict to a vault-relative folder prefix.' },\n tag: { type: 'string', description: 'Restrict to notes with this tag.' },\n excerptLength: {\n type: 'number',\n description: 'Max characters of match context per hit (20–2000, default 120).',\n },\n },\n required: ['query'],\n },\n },\n {\n name: 'query_notes',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n 'Structured metadata query — filter notes by frontmatter key/value predicates, tag, folder, modified time, and size. Returns compact rows (path + title by default; opt into more via select), not note content. Use this instead of search when filtering by properties rather than text.',\n inputSchema: {\n type: 'object',\n properties: {\n where: {\n type: 'array',\n description: 'Frontmatter predicates — all must match (AND).',\n items: {\n type: 'object',\n properties: {\n key: { type: 'string', description: 'Frontmatter key to test.' },\n op: {\n type: 'string',\n enum: ['eq', 'ne', 'contains', 'exists', 'missing', 'gt', 'gte', 'lt', 'lte'],\n description:\n 'eq/ne compare scalars; contains matches array membership or substring; exists/missing test key presence; gt/gte/lt/lte compare numbers or strings (ISO dates sort correctly).',\n },\n value: {\n description: 'Comparison value. Required for every op except exists/missing.',\n },\n },\n required: ['key', 'op'],\n },\n },\n folder: { type: 'string', description: 'Restrict to a vault-relative folder prefix.' },\n tag: { type: 'string', description: 'Restrict to notes with this tag (# optional).' },\n modifiedAfter: {\n type: 'string',\n description: 'Only notes modified at or after this ISO 8601 date/time.',\n },\n modifiedBefore: {\n type: 'string',\n description: 'Only notes modified before this ISO 8601 date/time.',\n },\n minSizeBytes: { type: 'number', description: 'Only notes at least this many bytes.' },\n maxSizeBytes: { type: 'number', description: 'Only notes at most this many bytes.' },\n select: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Extra fields per hit: frontmatter keys, or \"mtime\", \"size\", \"tags\". Default returns only path + title.',\n },\n sort: {\n type: 'string',\n enum: ['path', 'title', 'mtime', 'size'],\n description: 'Sort field (default path).',\n },\n order: {\n type: 'string',\n enum: ['asc', 'desc'],\n description: 'Sort order (default asc).',\n },\n limit: { type: 'number', description: 'Max results (1–500, default 100).' },\n },\n required: [],\n },\n },\n {\n name: 'context_pack',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n 'Assemble everything needed to ANSWER a natural-language question in one call, under a strict byte budget (default 2048): ranked excerpts, linked neighbor notes (backlinks/outlinks) with one-line summaries, and follow-up source paths. Use search to locate notes and query_notes for metadata filters; use context_pack when you want answer-ready context without multiple round-trips. Empty excerpts with confidence \"none\" or \"low\" means the vault lacks coverage — do not infer content.',\n inputSchema: {\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Natural-language question or topic.' },\n budgetBytes: {\n type: 'number',\n description: 'Hard cap on response JSON bytes (256–16384, default 2048).',\n },\n },\n required: ['query'],\n },\n },\n {\n name: 'read_note',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n 'Read a note or a span of it — by heading section, block reference, or line range. Returns structured JSON with the content, bytes returned, total note size, and a contentHash to pass as prevHash to edit tools for compare-and-swap. Use search or outline_note first to find the right path and section names.',\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Vault-relative path, e.g. \"Daily Notes/2026-05-29.md\".',\n },\n section: {\n type: 'string',\n description:\n 'Return only this heading section (heading text, # prefix optional). First match wins.',\n },\n block: {\n type: 'string',\n description: 'Return only the line anchored by this block id (^ prefix optional).',\n },\n lines: {\n type: 'object',\n description: 'Return only this line range (1-indexed, inclusive).',\n properties: {\n from: { type: 'number', description: 'First line (1-indexed).' },\n to: {\n type: 'number',\n description: 'Last line (1-indexed, inclusive). Defaults to EOF.',\n },\n },\n required: ['from'],\n },\n includeFrontmatter: {\n type: 'boolean',\n description:\n 'Prepend frontmatter to section/block span results. Default false for spans.',\n },\n },\n required: ['path'],\n },\n },\n {\n name: 'list_notes',\n annotations: READ_ONLY_ANNOTATIONS,\n description: 'List notes, optionally filtered by folder prefix or tag.',\n inputSchema: {\n type: 'object',\n properties: {\n folder: { type: 'string', description: 'Vault-relative folder prefix.' },\n tag: { type: 'string', description: 'Filter by tag (# prefix optional).' },\n limit: { type: 'number', description: 'Max results (1–500, default 100).' },\n },\n required: [],\n },\n },\n {\n name: 'list_tags',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n 'List all tags in the vault with usage counts. Supports substring filtering, minimum count threshold, and sort order. Nested tags (e.g. area/work) include a parent field.',\n inputSchema: {\n type: 'object',\n properties: {\n pattern: {\n type: 'string',\n description:\n 'Substring filter on tag name. Example: \"work\" matches \"work\" and \"area/work\".',\n },\n minCount: {\n type: 'number',\n description: 'Only return tags used in at least this many notes.',\n },\n sort: {\n type: 'string',\n enum: ['count', 'name'],\n description: 'Sort by usage count descending (default) or alphabetically.',\n },\n },\n required: [],\n },\n },\n {\n name: 'create_note',\n annotations: DESTRUCTIVE_WRITE_ANNOTATIONS,\n description:\n 'Create a new note at a vault-relative path. Optionally sets frontmatter and body content. Parent directories are created automatically. Fails if the note already exists unless overwrite is true (prevHash may guard the overwrite).',\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Vault-relative path, e.g. \"Daily Notes/2026-06-01.md\".',\n },\n content: { type: 'string', description: 'Body content for the note.' },\n frontmatter: {\n type: 'object',\n description: 'Frontmatter key-value pairs.',\n additionalProperties: true,\n },\n overwrite: {\n type: 'boolean',\n description: 'Overwrite an existing note. Defaults to false.',\n },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n },\n },\n required: ['path'],\n },\n },\n {\n name: 'delete_note',\n annotations: DESTRUCTIVE_WRITE_ANNOTATIONS,\n description:\n 'Delete a note. By default it is moved to the vault .trash/ folder (recoverable by moving it back); pass permanent: true to remove it outright.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Vault-relative path of the note to delete.' },\n permanent: {\n type: 'boolean',\n description: 'Permanently remove instead of moving to .trash/. Defaults to false.',\n },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since — so you never delete content you have not seen.',\n },\n },\n required: ['path'],\n },\n },\n {\n name: 'move_note',\n annotations: DESTRUCTIVE_WRITE_ANNOTATIONS,\n description:\n 'Move or rename a note to a new vault-relative path, rewriting wikilinks and markdown links in other notes that point at it so nothing breaks (links inside fenced code blocks are left alone). Parent directories at the destination are created automatically. Fails if the destination already exists unless overwrite is true.',\n inputSchema: {\n type: 'object',\n properties: {\n from: { type: 'string', description: 'Vault-relative source path.' },\n to: { type: 'string', description: 'Vault-relative destination path.' },\n overwrite: {\n type: 'boolean',\n description: 'Overwrite destination if it exists. Defaults to false.',\n },\n rewriteLinks: {\n type: 'boolean',\n description:\n 'Rewrite references in other notes to follow the move. Defaults to true; pass false to move the file only.',\n },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard on the source note: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n },\n },\n required: ['from', 'to'],\n },\n },\n {\n name: 'rename_heading',\n annotations: DESTRUCTIVE_WRITE_ANNOTATIONS,\n description:\n 'Rename a heading in a note and rewrite every [[note#heading]] wikilink and embed across the vault so references keep working — aliases preserved, fenced code blocks left alone. Served from the warm backlink index, no vault scan. Heading matching is case-insensitive; with duplicate headings the first match wins, mirroring Obsidian link resolution.',\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Vault-relative path of the note containing the heading.',\n },\n oldHeading: {\n type: 'string',\n description:\n 'Current heading text, without # markers. Case-insensitive; first match wins.',\n },\n newHeading: {\n type: 'string',\n description:\n 'New heading text, without # markers. Must not contain newlines, \"[\", \"]\", \"|\", or \"#\".',\n },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n },\n },\n required: ['path', 'oldHeading', 'newHeading'],\n },\n },\n {\n name: 'append_note',\n annotations: ADDITIVE_WRITE_ANNOTATIONS,\n description:\n 'Append text to a note body without touching the frontmatter. Safe for meeting notes, daily logs, and append-only workflows.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Vault-relative path to the note.' },\n content: { type: 'string', description: 'Text to append.' },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n },\n },\n required: ['path', 'content'],\n },\n },\n {\n name: 'patch_frontmatter',\n annotations: IDEMPOTENT_DESTRUCTIVE_WRITE_ANNOTATIONS,\n description:\n 'Set, update, or delete frontmatter keys without reordering existing keys or changing quote style. Pass null as a value to delete a key.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Vault-relative path to the note.' },\n patch: {\n type: 'object',\n description: 'Key-value pairs to set. Null value removes the key.',\n additionalProperties: true,\n },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n },\n },\n required: ['path', 'patch'],\n },\n },\n {\n name: 'outline_note',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n \"Return a note's structure — heading tree with offsets, block-reference anchors, and frontmatter key list — without returning any prose. Use this before section reads or patches to discover what sections exist at a fraction of the cost of reading the full note.\",\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Vault-relative path to the note.' },\n includeBlocks: {\n type: 'boolean',\n description: 'Include block-reference anchors (^id). Default true.',\n },\n includeSizes: {\n type: 'boolean',\n description: 'Include per-section character length in each heading entry. Default false.',\n },\n },\n required: ['path'],\n },\n },\n {\n name: 'patch_note',\n annotations: DESTRUCTIVE_WRITE_ANNOTATIONS,\n description:\n 'Surgically edit a section of a note — targeted by heading or block reference — without rewriting the whole file. Operations: append (add after section), prepend (add after heading line), replace (swap section content). Frontmatter is never touched.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Vault-relative path to the note.' },\n target: {\n type: 'object',\n description:\n 'Exactly one of: { heading: \"Section Title\" } or { block: \"block-id\" } (without the ^ prefix).',\n },\n operation: {\n type: 'string',\n enum: ['append', 'prepend', 'replace'],\n description:\n 'append: insert after section content. prepend: insert after heading line. replace: swap section content.',\n },\n content: { type: 'string', description: 'Content to insert or replace with.' },\n createIfMissing: {\n type: 'boolean',\n description:\n 'If the heading target is not found, append a new heading (level 2) + content. Only valid for heading targets. Default false.',\n },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n },\n },\n required: ['path', 'target', 'operation', 'content'],\n },\n },\n {\n name: 'get_backlinks',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n 'Return every note that links to the target note, with the source line and an optional excerpt. Results come from the pre-built reverse-link index so this is a fast, pure index lookup. Sort order: source path ascending.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Vault-relative path to the target note.' },\n includeContext: {\n type: 'boolean',\n description: 'Include a short excerpt (~200 chars) from the linking line. Default true.',\n },\n limit: {\n type: 'number',\n description: 'Max backlinks to return (1–500). Default 50.',\n },\n },\n required: ['path'],\n },\n },\n {\n name: 'get_links',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n 'Return all outgoing wikilinks and embeds from a note. Each link is marked resolved (with target path) or unresolved. Duplicate targets are de-duplicated; results sorted by line number.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Vault-relative path to the note.' },\n },\n required: ['path'],\n },\n },\n {\n name: 'replace_in_note',\n annotations: DESTRUCTIVE_WRITE_ANNOTATIONS,\n description:\n 'Find and replace text within a note body. Supports literal and regex search, case sensitivity, whole-word matching, and a replacement limit. Frontmatter is never touched. Use dryRun to preview matches before writing.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Vault-relative path to the note.' },\n find: { type: 'string', description: 'Text or pattern to find.' },\n replace: {\n type: 'string',\n description: 'Replacement text. Supports $1, $2, … backreferences in regex mode.',\n },\n regex: {\n type: 'boolean',\n description: 'Treat find as a regular expression. Default false.',\n },\n caseSensitive: {\n type: 'boolean',\n description: 'Case-sensitive matching. Default false.',\n },\n wholeWord: {\n type: 'boolean',\n description: 'Match whole words only (\\\\b boundary). Default false.',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of replacements. Omit to replace all.',\n },\n dryRun: {\n type: 'boolean',\n description: 'If true, report matches without writing. Default false.',\n },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n },\n },\n required: ['path', 'find', 'replace'],\n },\n },\n {\n name: 'get_periodic_note',\n annotations: ADDITIVE_WRITE_ANNOTATIONS,\n description:\n 'Get the path and existence status of a periodic note (daily, weekly, monthly, quarterly, or yearly) for a given date. Reads folder/format config from .obsidian/daily-notes.json (daily) or the periodic-notes plugin data.json. Optionally creates the note from the configured template if it is missing.',\n inputSchema: {\n type: 'object',\n properties: {\n period: {\n type: 'string',\n enum: ['daily', 'weekly', 'monthly', 'quarterly', 'yearly'],\n description: 'Period type. Default: daily.',\n },\n date: {\n type: 'string',\n description: 'ISO date string (YYYY-MM-DD). Defaults to today when omitted.',\n },\n createIfMissing: {\n type: 'boolean',\n description:\n 'Create the note from the configured template if it does not exist. Default false.',\n },\n },\n required: [],\n },\n },\n {\n name: 'append_periodic_note',\n annotations: ADDITIVE_WRITE_ANNOTATIONS,\n description:\n 'Append text to a periodic note (daily, weekly, monthly, quarterly, or yearly). Preserves existing frontmatter exactly. Creates the note first (from template if configured) when createIfMissing is true (default).',\n inputSchema: {\n type: 'object',\n properties: {\n period: {\n type: 'string',\n enum: ['daily', 'weekly', 'monthly', 'quarterly', 'yearly'],\n description: 'Period type. Default: daily.',\n },\n date: {\n type: 'string',\n description: 'ISO date string (YYYY-MM-DD). Defaults to today when omitted.',\n },\n content: {\n type: 'string',\n description: 'Text to append to the note body.',\n },\n createIfMissing: {\n type: 'boolean',\n description: 'Create the note if it does not exist before appending. Default true.',\n },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n },\n },\n required: ['content'],\n },\n },\n {\n name: 'list_writes',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n 'List recent writes from the journal — every write tool records the pre-image of each file it touches, so any of them can be reverted with undo_write. Returns compact metadata rows (seq, timestamp, tool, paths, undoable), never note content.',\n inputSchema: {\n type: 'object',\n properties: {\n limit: {\n type: 'number',\n description: 'Max entries to return, newest first (1–200, default 20).',\n },\n path: {\n type: 'string',\n description: 'Only entries that touched this vault-relative path.',\n },\n },\n },\n },\n {\n name: 'undo_write',\n annotations: DESTRUCTIVE_WRITE_ANNOTATIONS,\n description:\n 'Revert a journaled write: restores every file it touched to its byte-identical pre-write state (a multi-file move or heading rename is restored whole; a delete is restored even if it was permanent). Defaults to the most recent undoable write. Refuses with undo_conflict if a file changed since that write, unless force: true. The undo is itself journaled — undo it to redo.',\n inputSchema: {\n type: 'object',\n properties: {\n seq: {\n type: 'number',\n description:\n 'Journal entry to revert (from list_writes). Defaults to the most recent undoable write.',\n },\n force: {\n type: 'boolean',\n description:\n 'Restore even if a file changed after the journaled write; the clobbered state is journaled first so nothing is lost. Defaults to false.',\n },\n },\n },\n },\n];\n\n/**\n * The tools visible to the client under a policy. In read-only mode write\n * tools are unregistered entirely (not just failing) — better for context\n * economy and honest about what the session can do. Dispatch still rejects\n * write calls independently; unregistering is presentation, not enforcement.\n */\nexport function visibleTools(policy: WritePolicy) {\n if (!policy.readOnly) return ALL_TOOLS;\n return ALL_TOOLS.filter((t) => !WRITE_TOOLS.has(t.name));\n}\n","import { realpathSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join, relative, sep } from 'node:path';\nimport chokidar from 'chokidar';\nimport type { ServerContext } from './context.js';\nimport { addNoteBacklinks, removeNoteBacklinks } from './index/backlinks.js';\nimport { buildDoc, upsertDoc } from './index/doc.js';\nimport type { Logger } from './log.js';\n\n/**\n * Watch the vault for .md changes and keep the in-memory index in sync.\n *\n * Uses chokidar rather than `fs.watch(..., { recursive: true })`: recursive\n * native watching is unsupported on Linux, where fs.watch silently misses\n * nested changes. chokidar gives reliable, recursive, cross-platform events.\n *\n * Returns `stop()` to tear down the watcher and a `ready` promise that\n * resolves once chokidar has finished its initial scan and is live.\n */\nexport interface WatcherHandle {\n /**\n * Close the watcher. Returns chokidar's close promise so callers that need\n * deterministic teardown (tests, especially under usePolling where every\n * watched path holds a live stat-poll timer) can await full shutdown;\n * fire-and-forget callers may ignore the result.\n */\n stop: () => Promise<void>;\n ready: Promise<void>;\n}\n\nexport interface WatcherOptions {\n /**\n * Stat-poll instead of using native OS file events. Slower but reliable on\n * filesystems where native events are unreliable (network mounts, WSL, some\n * containers) and deterministic under load. Defaults to false, or true when\n * SEEKSTONE_WATCH_POLL=1.\n */\n usePolling?: boolean;\n /**\n * Stat-poll interval in ms; only meaningful with usePolling. Overrides\n * SEEKSTONE_WATCH_POLL_INTERVAL and the default. Tests pass a small value\n * here so the suite stays fast without dragging production polling down\n * with it.\n */\n pollInterval?: number;\n /**\n * Diagnostic hook fired for every raw chokidar event, before .md filtering\n * and before the index is updated. Receives the chokidar event name, the\n * absolute path as chokidar reported it, and the vault-relative key as\n * computed by toRel(). Use in tests only to capture what chokidar actually\n * emits when a failure needs investigation.\n */\n onRawEvent?: (event: 'add' | 'change' | 'unlink', absPath: string, relPath: string) => void;\n}\n\n/**\n * Default stat-poll interval (ms) under SEEKSTONE_WATCH_POLL=1. Deliberately\n * slow: poll cost scales with vault size ÷ interval, and on the network/9p\n * mounts where polling is needed at all, a 50ms sweep pinned ~25% of a CPU\n * core per instance (GH #280). Only pickup of *external* edits waits on this —\n * seekstone's own writes update the index in-process.\n */\nexport const DEFAULT_POLL_INTERVAL_MS = 10_000;\n\n/**\n * Resolve the stat-poll interval: explicit option → SEEKSTONE_WATCH_POLL_INTERVAL\n * (positive integer, ms) → default. A malformed env value warns and falls back\n * rather than throwing — a bad tuning knob shouldn't keep the server down.\n */\nexport function resolvePollInterval(\n optValue: number | undefined,\n envValue: string | undefined,\n log?: Logger,\n): number {\n if (optValue !== undefined) return optValue;\n if (envValue === undefined || envValue === '') return DEFAULT_POLL_INTERVAL_MS;\n const parsed = Number(envValue);\n if (!Number.isInteger(parsed) || parsed <= 0) {\n log?.warn('invalid SEEKSTONE_WATCH_POLL_INTERVAL, using default', {\n value: envValue,\n defaultMs: DEFAULT_POLL_INTERVAL_MS,\n });\n return DEFAULT_POLL_INTERVAL_MS;\n }\n return parsed;\n}\n\nexport function startWatcher(\n ctx: ServerContext,\n log?: Logger,\n opts?: WatcherOptions,\n): WatcherHandle {\n const usePolling = opts?.usePolling ?? process.env.SEEKSTONE_WATCH_POLL === '1';\n const pollInterval = resolvePollInterval(\n opts?.pollInterval,\n process.env.SEEKSTONE_WATCH_POLL_INTERVAL,\n log,\n );\n\n // chokidar's followSymlinks=true (the default) calls fs.realpath() on the\n // watched path, so events arrive with the real (resolved) path. On Windows,\n // os.tmpdir() can return 8.3 short paths (e.g. RUNNER~1) while realpath()\n // expands them to the long form. Without pre-resolving here, relative()\n // inside the ignored predicate and toRel() would produce \"..\" segments;\n // \"..\" starts with \".\" and trips the dot-directory filter, silencing every\n // event — the root cause of the flaky \"vault path containing spaces\" test.\n let vaultRoot = ctx.vaultRoot;\n try {\n vaultRoot = realpathSync(ctx.vaultRoot);\n } catch {\n // Vault doesn't exist yet or can't be resolved — keep original path.\n }\n\n // Index keys are forward-slash vault-relative paths on every platform.\n const toRel = (abs: string): string => relative(vaultRoot, abs).split(sep).join('/');\n\n async function upsert(relPath: string, op: 'add' | 'change'): Promise<void> {\n try {\n const raw = await readFile(join(vaultRoot, relPath), 'utf8');\n removeNoteBacklinks(ctx, relPath);\n upsertDoc(ctx, buildDoc(relPath, raw));\n addNoteBacklinks(ctx, relPath, raw);\n // Semantic re-embeds are debounced internally and read the fresh\n // ctx.notes entry — never the disk — so this stays off the hot path.\n ctx.semantic?.noteChanged(relPath);\n log?.debug('index updated', { path: relPath, op });\n } catch {\n // File vanished between event and read — ignore; an unlink will follow.\n }\n }\n\n function remove(relPath: string): void {\n if (ctx.notes.has(relPath)) {\n removeNoteBacklinks(ctx, relPath);\n ctx.index.discard(relPath);\n ctx.notes.delete(relPath);\n ctx.semantic?.noteRemoved(relPath);\n log?.debug('index removed', { path: relPath, op: 'delete' });\n }\n }\n\n const onUpsert = (op: 'add' | 'change') => (abs: string) => {\n const relPath = toRel(abs);\n opts?.onRawEvent?.(op, abs, relPath);\n if (relPath.endsWith('.md')) void upsert(relPath, op);\n };\n\n const watcher = chokidar.watch(vaultRoot, {\n // The startup index build already covers existing files.\n ignoreInitial: true,\n usePolling,\n interval: pollInterval,\n binaryInterval: pollInterval * 2,\n // Skip dot-dirs (.obsidian, .git, .trash, …) regardless of where the vault\n // lives — matched on the path relative to the vault root.\n ignored: (p: string) => {\n const rel = relative(vaultRoot, p);\n if (!rel || rel === '.') return false;\n // Exclude \"..\" — it means \"outside the vault root\" (a path normalisation\n // mismatch), not a dotfile. Treating \"..\" as a dot-segment would silence\n // all events if the ignored predicate ever receives an out-of-root path.\n return rel\n .split(sep)\n .filter(Boolean)\n .some((seg) => seg.startsWith('.') && seg !== '..');\n },\n });\n\n watcher\n .on('add', onUpsert('add'))\n .on('change', onUpsert('change'))\n .on('unlink', (abs: string) => {\n const relPath = toRel(abs);\n opts?.onRawEvent?.('unlink', abs, relPath);\n if (relPath.endsWith('.md')) remove(relPath);\n });\n\n const ready = new Promise<void>((resolve) => {\n watcher.once('ready', () => {\n resolve();\n });\n });\n\n return {\n stop: () => watcher.close(),\n ready,\n };\n}\n"],"mappings":"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","names":["join","homedir","createHash","mkdir","readFile","writeFile","join","resolve","appendFileSync","renameSync","statSync","writeFile","DEFAULT_MAX_SIZE","path","statSync","appendFileSync","renameSync","readFile","path","rename","rename","vaultRoot","log","path","ctx","policy","vaultRoot","ctx","readFile","z","notes","path","z","path","z","path","ctx","z","ctx","path","mkdir","readFile","z","ctx","z","ctx","readFile","mkdir","access","mkdir","readFile","rename","rm","basename","extname","join","z","ctx","z","vaultRoot","extname","access","join","ctx","readFile","rm","mkdir","basename","rename","z","z","ctx","backlinks","z","z","ctx","z","ctx","path","z","ctx","z","ctx","mkdir","readFile","rename","dirname","join","z","matches","z","ctx","readFile","path","mkdir","dirname","rename","join","readFile","z","z","ctx","readFile","readFile","parseDocument","z","z","ctx","readFile","parseDocument","readFile","z","z","ctx","readFile","sep","newContent","path","access","mkdir","readFile","dirname","join","z","z","readFile","vaultRoot","cfg","join","ctx","path","access","mkdir","dirname","z","z","ctx","path","readFile","z","z","ctx","readFile","readFile","join","z","z","ctx","readFile","lineEnd","path","join","readFile","z","z","ctx","readFile","matches","mkdir","readFile","rm","dirname","z","z","ctx","readFile","rm","mkdir","dirname","ctx","log","audit","readFile","basename","extname","stat","extname","join","sep","vaultRoot","matches","vaultRoot","index","notes","readFile","basename","extname","backlinks","access","mkdir","readdir","readFile","stat","writeFile","dirname","join","j","log","sep","readFile","basename","join","normalize","readFile","join","basename","createHash","mkdir","readFile","rename","writeFile","join","vaultRoot","notes","path","contentHash","path","ctx","path","policy","readFile","join","relative","sep","log","ctx","vaultRoot","relative","sep","readFile","join","watcher","resolve","runFetchModel","homedir","resolve"]}
1
+ {"version":3,"sources":["../src/semantic/model-manifest.ts","../src/semantic/config.ts","../src/semantic/fetch-model.ts","../src/index.ts","../src/audit.ts","../src/log.ts","../src/cli-args.ts","../src/tools/append_note.ts","../../core/src/frontmatter.ts","../src/atomic-write.ts","../src/content-hash.ts","../src/journal.ts","../src/policy.ts","../src/vault-path.ts","../../core/src/extract.ts","../src/tools/context_pack.ts","../src/index/excerpt.ts","../src/index/resolve.ts","../src/tools/search.ts","../src/semantic/excerpt.ts","../src/semantic/route.ts","../src/tools/create_note.ts","../src/index/doc.ts","../src/tools/delete_note.ts","../src/index/backlinks.ts","../src/tools/get_backlinks.ts","../src/tools/get_links.ts","../src/tools/list_notes.ts","../src/tools/list_tags.ts","../src/tools/list_writes.ts","../src/tools/move_note.ts","../src/tools/rewrite_links.ts","../src/tools/outline_note.ts","../../core/src/outline.ts","../src/tools/patch_frontmatter.ts","../src/tools/patch_note.ts","../src/tools/periodic_note.ts","../src/tools/query_notes.ts","../src/tools/read_note.ts","../src/tools/rename_heading.ts","../src/tools/replace_in_note.ts","../src/tools/undo_write.ts","../src/dispatch.ts","../src/index/build.ts","../../core/src/walk.ts","../src/init.ts","../src/process-guards.ts","../src/semantic/bundled-model.ts","../../core/src/embed/chunk.ts","../../core/src/embed/maxsim.ts","../../core/src/embed/model2vec.ts","../../core/src/embed/safetensors.ts","../../core/src/embed/tokenizer.ts","../../core/src/embed/pooling.ts","../../core/src/embed/types.ts","../src/semantic/cache.ts","../src/semantic/state.ts","../src/semantic/rerank.ts","../src/semantic/store.ts","../src/tool-list.ts","../src/watcher.ts"],"sourcesContent":["/**\n * Pinned download manifests for the supported embedding models. The network\n * URLs are used ONLY by the `seekstone fetch-model` subcommand — an explicit,\n * out-of-band CLI action; the hashes are additionally the verification source\n * for the semantic .mcpb variant's disk-only shard reassembly (bundled-model.ts)\n * and for scripts/build-mcpb.mjs when it stages those shards. The MCP server\n * itself never touches the network (no-network.test.ts).\n *\n * Hashes mirror packages/harness/fixtures/models/manifest.json (the harness\n * evals run against the same files).\n */\n\nexport interface ModelFile {\n name: string;\n url: string;\n sha256: string;\n bytes: number;\n}\n\nexport interface ModelManifest {\n id: string;\n license: string;\n /** Embedding width — the cache is keyed on it so models never mix. */\n dim: number;\n files: ModelFile[];\n}\n\nfunction hfFiles(\n repo: string,\n hashes: { safetensors: [string, number]; tokenizer: [string, number]; config: [string, number] },\n): ModelFile[] {\n const base = `https://huggingface.co/minishlab/${repo}/resolve/main`;\n return [\n {\n name: 'model.safetensors',\n url: `${base}/model.safetensors`,\n sha256: hashes.safetensors[0],\n bytes: hashes.safetensors[1],\n },\n {\n name: 'tokenizer.json',\n url: `${base}/tokenizer.json`,\n sha256: hashes.tokenizer[0],\n bytes: hashes.tokenizer[1],\n },\n {\n name: 'config.json',\n url: `${base}/config.json`,\n sha256: hashes.config[0],\n bytes: hashes.config[1],\n },\n ];\n}\n\n/** The shipped default: ~30 MB, 256-dim, warm p95 ≈ 14 ms @ 10k notes. */\nexport const DEFAULT_MODEL: ModelManifest = {\n id: 'potion-base-8M',\n license: 'MIT (https://huggingface.co/minishlab/potion-base-8M)',\n dim: 256,\n files: hfFiles('potion-base-8M', {\n safetensors: ['f65d0f325faadc1e121c319e2faa41170d3fa07d8c89abd48ca5358d9a223de2', 30236760],\n tokenizer: ['e67e803f624fb4d67dea1c730d06e1067e1b14d830e2c2202569e3ef0f70bb50', 683666],\n config: ['2a6ac0e9aaa356a68a5688070db78fc3a464fefe85d2f06a1905ce3718687553', 202],\n }),\n};\n\n/**\n * Opt-in bigger model (SHA-310): ~129 MB, 512-dim, +13 pts hit@5 on the\n * semantic golden subset at roughly 2× the query latency. Same Model2Vec\n * inference path — the loader derives vocab size from tokenizer.json.\n */\nexport const RETRIEVAL_32M_MODEL: ModelManifest = {\n id: 'potion-retrieval-32M',\n license: 'MIT (https://huggingface.co/minishlab/potion-retrieval-32M)',\n dim: 512,\n files: hfFiles('potion-retrieval-32M', {\n safetensors: ['07609e5bd33aad37900b3fd62f4ec96f6daec88ca4d46b9d8b928bfababf6ea0', 129210456],\n tokenizer: ['7d75cbc54318138807c401b0f0c9721117c628b39de8e8e0edb6cb17e0ee7d18', 1493150],\n config: ['63c00d90824c832c04ec1d02b6a983fb90489bf049f29fbff15ba481b8a432ee', 202],\n }),\n};\n\n/** Every model `fetch-model --model <id>` / `SEEKSTONE_SEMANTIC_MODEL` accepts. */\nexport const MODELS: readonly ModelManifest[] = [DEFAULT_MODEL, RETRIEVAL_32M_MODEL];\n\nexport const MODEL_IDS: readonly string[] = MODELS.map((m) => m.id);\n\nexport function findModel(id: string): ModelManifest | undefined {\n return MODELS.find((m) => m.id === id);\n}\n","import { join } from 'node:path';\nimport { DEFAULT_MODEL, findModel, MODEL_IDS, type ModelManifest } from './model-manifest.js';\n\n/**\n * Semantic-search configuration, resolved from env at boot.\n *\n * - `SEEKSTONE_SEMANTIC=1` enables the feature (off by default).\n * - `SEEKSTONE_SEMANTIC_MODEL` picks which fetched model to load\n * (`potion-base-8M` default, or the opt-in `potion-retrieval-32M`).\n * - `SEEKSTONE_MODEL_PATH` overrides where the Model2Vec model dir lives;\n * default is `<cache>/models/<model id>`, where `seekstone fetch-model`\n * puts it.\n * - `SEEKSTONE_CACHE_DIR` overrides the cache root (default `~/.cache/seekstone`),\n * which holds both downloaded models and per-vault embedding caches.\n *\n * The server itself NEVER downloads anything — the model is fetched\n * out-of-band by the `fetch-model` subcommand, preserving the zero-network\n * guarantee (no-network.test.ts).\n */\n\nexport const DEFAULT_MODEL_ID = DEFAULT_MODEL.id;\n\nexport interface SemanticConfig {\n /** Manifest id of the selected model (drives the default dir + error hints). */\n modelId: string;\n modelDir: string;\n cacheDir: string;\n}\n\nexport function defaultCacheDir(env: NodeJS.ProcessEnv, homedir: string): string {\n return env.SEEKSTONE_CACHE_DIR || join(homedir, '.cache', 'seekstone');\n}\n\n/**\n * Validate `SEEKSTONE_SEMANTIC_MODEL` (or the given override) against the\n * pinned manifests. Throws a config error naming the accepted values so a\n * typo fails loudly at boot / fetch time instead of silently loading 8M.\n */\nexport function resolveModel(raw: string | undefined): ModelManifest {\n const id = raw?.trim();\n if (!id) return DEFAULT_MODEL;\n const manifest = findModel(id);\n if (!manifest) {\n throw new Error(\n `SEEKSTONE_SEMANTIC_MODEL: unknown model \"${id}\" — expected one of ${MODEL_IDS.join(', ')}`,\n );\n }\n return manifest;\n}\n\nexport function resolveModelId(raw: string | undefined): string {\n return resolveModel(raw).id;\n}\n\n/** The `fetch-model` command that installs the given model. */\nexport function fetchCommandFor(modelId: string): string {\n return modelId === DEFAULT_MODEL_ID\n ? 'npx -y seekstone fetch-model'\n : `npx -y seekstone fetch-model --model ${modelId}`;\n}\n\nexport function resolveSemanticConfig(\n env: NodeJS.ProcessEnv,\n homedir: string,\n): SemanticConfig | undefined {\n if (env.SEEKSTONE_SEMANTIC !== '1') return undefined;\n const modelId = resolveModelId(env.SEEKSTONE_SEMANTIC_MODEL);\n const cacheDir = defaultCacheDir(env, homedir);\n const modelDir = env.SEEKSTONE_MODEL_PATH || join(cacheDir, 'models', modelId);\n return { modelId, modelDir, cacheDir };\n}\n","import { createHash } from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { DEFAULT_MODEL_ID, defaultCacheDir, resolveModel } from './config.js';\nimport { MODEL_IDS, type ModelManifest } from './model-manifest.js';\n\n/**\n * `seekstone fetch-model` — the explicit, out-of-band download of the\n * embedding model that semantic search needs. This is a CLI subcommand that\n * exits before any MCP serving starts; the running server never fetches\n * (no-network.test.ts is the guarantee). Files are verified against pinned\n * SHA-256 hashes; already-present matching files are skipped.\n */\n\nexport interface FetchModelResult {\n output: string[];\n exitCode: number;\n}\n\nexport interface FetchModelDeps {\n env: NodeJS.ProcessEnv;\n homedir: string;\n /** Arguments after the `fetch-model` subcommand (`--model <id>`). */\n argv?: readonly string[];\n /** Test seam: bypass model selection entirely. */\n manifest?: ModelManifest;\n fetchFn?: typeof fetch;\n}\n\n/**\n * Pick the manifest: `--model <id>` wins, then `SEEKSTONE_SEMANTIC_MODEL`, then\n * the default — so `fetch-model` with no flags installs whatever the server\n * would try to load.\n */\nexport function selectManifest(argv: readonly string[], env: NodeJS.ProcessEnv): ModelManifest {\n let requested: string | undefined;\n for (let i = 0; i < argv.length; i++) {\n const arg = argv[i];\n if (arg === '--model') {\n requested = argv[i + 1];\n if (!requested || requested.startsWith('--')) {\n throw new Error(`--model needs a value: one of ${MODEL_IDS.join(', ')}`);\n }\n i++;\n } else if (arg?.startsWith('--model=')) {\n requested = arg.slice('--model='.length);\n } else {\n throw new Error(`fetch-model: unknown argument \"${arg}\" (usage: fetch-model [--model <id>])`);\n }\n }\n return resolveModel(requested ?? env.SEEKSTONE_SEMANTIC_MODEL);\n}\n\nexport async function runFetchModel(deps: FetchModelDeps): Promise<FetchModelResult> {\n const output: string[] = [];\n let manifest: ModelManifest;\n try {\n manifest = deps.manifest ?? selectManifest(deps.argv ?? [], deps.env);\n } catch (err) {\n output.push(`✗ ${err instanceof Error ? err.message : String(err)}`);\n return { output, exitCode: 1 };\n }\n const fetchFn = deps.fetchFn ?? fetch;\n const destDir =\n deps.env.SEEKSTONE_MODEL_PATH ||\n join(defaultCacheDir(deps.env, deps.homedir), 'models', manifest.id);\n output.push(`fetch-model: ${manifest.id} → ${destDir}`);\n try {\n await mkdir(destDir, { recursive: true });\n let fetched = 0;\n let skipped = 0;\n for (const file of manifest.files) {\n const dest = join(destDir, file.name);\n if (existsSync(dest) && sha256(await readFile(dest)) === file.sha256) {\n skipped++;\n continue;\n }\n output.push(`fetching ${file.name} (${file.bytes} bytes)…`);\n const res = await fetchFn(file.url);\n if (!res.ok) throw new Error(`fetch ${file.url} failed: ${res.status}`);\n const buf = Buffer.from(await res.arrayBuffer());\n const got = sha256(buf);\n if (got !== file.sha256) {\n throw new Error(`checksum mismatch for ${file.name}: expected ${file.sha256}, got ${got}`);\n }\n await writeFile(dest, buf);\n fetched++;\n }\n output.push(`✓ ${manifest.id}: ${fetched} fetched, ${skipped} already present (verified).`);\n output.push(\n manifest.id === DEFAULT_MODEL_ID\n ? 'Enable semantic search with SEEKSTONE_SEMANTIC=1 in your MCP server config, then restart the session.'\n : `Enable it with SEEKSTONE_SEMANTIC=1 and SEEKSTONE_SEMANTIC_MODEL=${manifest.id} in your MCP server config, then restart the session.`,\n );\n return { output, exitCode: 0 };\n } catch (err) {\n output.push(`✗ ${err instanceof Error ? err.message : String(err)}`);\n return { output, exitCode: 1 };\n }\n}\n\nfunction sha256(buf: Buffer): string {\n return createHash('sha256').update(buf).digest('hex');\n}\n","#!/usr/bin/env node\nimport { homedir } from 'node:os';\nimport { resolve } from 'node:path';\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n type CallToolResult,\n ListToolsRequestSchema,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { AuditLog, resolveAuditConfig } from './audit.js';\nimport { helpText, initHelpText, parseCliIntent } from './cli-args.js';\nimport type { ServerContext } from './context.js';\nimport { dispatch } from './dispatch.js';\nimport { buildIndex } from './index/build.js';\nimport { parseInitArgs, runInit } from './init.js';\nimport { Journal, resolveJournalConfig } from './journal.js';\nimport { createLogger } from './log.js';\nimport { parseWritePolicy } from './policy.js';\nimport { installProcessGuards } from './process-guards.js';\nimport { materializeBundledModel } from './semantic/bundled-model.js';\nimport { resolveSemanticConfig } from './semantic/config.js';\nimport { Semantic } from './semantic/state.js';\nimport { visibleTools } from './tool-list.js';\nimport { startWatcher } from './watcher.js';\n\n// Inlined at build time by tsup (see tsup.config.ts); falls back in tsx dev.\ndeclare const __SEEKSTONE_VERSION__: string;\nconst VERSION = typeof __SEEKSTONE_VERSION__ === 'string' ? __SEEKSTONE_VERSION__ : '0.0.0-dev';\n\n// CLI subcommands / flags exit before any server setup, printing to stdout\n// (these are explicit invocations, not the MCP stdio session).\nconst intent = parseCliIntent(process.argv.slice(2));\nif (intent === 'version') {\n process.stdout.write(`${VERSION}\\n`);\n process.exit(0);\n}\nif (intent === 'help') {\n process.stdout.write(`${helpText(VERSION)}\\n`);\n process.exit(0);\n}\nif (intent === 'init-help') {\n process.stdout.write(`${initHelpText(VERSION)}\\n`);\n process.exit(0);\n}\nif (intent === 'init') {\n const result = await runInit(parseInitArgs(process.argv.slice(3)), {\n env: process.env,\n platform: process.platform,\n timestamp: new Date().toISOString().replace(/[:.]/g, '-'),\n cwd: process.cwd(),\n });\n process.stdout.write(`${result.output.join('\\n')}\\n`);\n process.exit(result.exitCode);\n}\nif (intent === 'fetch-model') {\n const { runFetchModel } = await import('./semantic/fetch-model.js');\n const { homedir } = await import('node:os');\n const result = await runFetchModel({\n env: process.env,\n homedir: homedir(),\n argv: process.argv.slice(3),\n });\n process.stdout.write(`${result.output.join('\\n')}\\n`);\n process.exit(result.exitCode);\n}\n\nconst log = createLogger();\n\n// Long-lived stdio session: keep the server alive (and its in-memory index)\n// on a stray unhandled rejection rather than crashing the user's session.\ninstallProcessGuards(log);\n\nconst rawVaultRoot = process.env.SEEKSTONE_VAULT;\nif (!rawVaultRoot) {\n log.error('SEEKSTONE_VAULT env var is required');\n process.exit(1);\n}\n// Normalize once so the containment guard (vault-path.ts) compares against a\n// canonical absolute path — a relative or trailing-slash SEEKSTONE_VAULT must\n// not weaken the prefix boundary.\nconst vaultRoot = resolve(rawVaultRoot);\n\nconst policy = parseWritePolicy(process.env);\nif (policy.readOnly) log.info('read-only mode', { env: 'SEEKSTONE_READ_ONLY' });\nif (policy.writeGlobs) log.info('write paths scoped', { globs: policy.writeGlobs });\n\nlog.info('building index', { vault: vaultRoot });\nconst { index, notes, backlinks, buildMs } = await buildIndex(vaultRoot);\nlog.info('index ready', { notes: notes.size, buildMs });\n\nconst ctx: ServerContext = { vaultRoot, index, notes, backlinks, policy };\n\n// Write journal: pre-images under <vault>/.seekstone/history so every write\n// is reversible via undo_write. Read-only mode never writes, so it never\n// journals either — the journal is only opened when writes are possible.\nconst journalCfg = resolveJournalConfig(process.env);\nif (journalCfg && !policy.readOnly) {\n try {\n ctx.journal = await Journal.open(vaultRoot, journalCfg, { log });\n log.info('write journal ready', {\n entries: ctx.journal.list({ limit: 1 }).total,\n maxBytes: journalCfg.maxBytes,\n });\n } catch (err) {\n // A journal that cannot be opened means writes cannot be made reversible;\n // fail loudly rather than silently run without undo.\n log.error(`write journal failed to open: ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n} else if (!journalCfg) {\n log.info('write journal disabled', { env: 'SEEKSTONE_HISTORY' });\n}\n\n// Audit log: one JSONL record per write-tool call. Opt-in; an unwritable\n// path fails boot because an unauditable write must never pass silently.\nconst auditCfg = resolveAuditConfig(process.env);\nif (auditCfg) {\n try {\n ctx.audit = AuditLog.open(auditCfg);\n log.info('audit log ready', { file: auditCfg.path, maxBytes: auditCfg.maxBytes });\n } catch (err) {\n log.error(\n `audit log ${auditCfg.path} is not writable: ${err instanceof Error ? err.message : String(err)}`,\n );\n process.exit(1);\n }\n}\n\nconst semanticCfg = resolveSemanticConfig(process.env, homedir());\nif (semanticCfg) {\n try {\n // The semantic .mcpb variant ships the model as shards inside the bundle;\n // reassemble them into the fetch-model location first (disk-only, pinned\n // hashes — see semantic/bundled-model.ts). No-op for every other install.\n await materializeBundledModel(semanticCfg, process.env.SEEKSTONE_BUNDLED_MODEL_DIR, { log });\n // Model load is fast (~30 MB read); the index build continues in the\n // background — semantic queries report progress until it finishes.\n ctx.semantic = await Semantic.start(ctx, semanticCfg, { log });\n log.info('semantic search enabled', {\n model: ctx.semantic.embedder.id,\n dim: ctx.semantic.embedder.dim,\n notes: notes.size,\n });\n } catch (err) {\n // The user enabled the feature explicitly — a broken setup fails loudly.\n log.error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n}\n\nconst watcher = startWatcher(ctx, log);\n// Exit handlers must stay synchronous — kick off the close; nothing awaits it.\nprocess.on('exit', () => void watcher.stop());\n\nconst server = new Server({ name: 'seekstone', version: VERSION }, { capabilities: { tools: {} } });\n\nserver.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: visibleTools(ctx.policy),\n}));\n\nserver.setRequestHandler(CallToolRequestSchema, async (req): Promise<CallToolResult> => {\n const { name, arguments: args } = req.params;\n return dispatch(ctx, name, args, log);\n});\n\nconst transport = new StdioServerTransport();\nawait server.connect(transport);\nlog.info('ready', { tools: visibleTools(ctx.policy).length, transport: 'stdio' });\n\nprocess.stderr.write(\n `seekstone: add to Claude Desktop:\\n${JSON.stringify(\n {\n mcpServers: {\n seekstone: {\n command: 'npx',\n args: ['-y', 'seekstone'],\n env: { SEEKSTONE_VAULT: vaultRoot },\n },\n },\n },\n null,\n 2,\n )}\\n`,\n);\n","import {\n appendFileSync,\n closeSync,\n fsyncSync,\n openSync,\n renameSync,\n statSync,\n writeSync,\n} from 'node:fs';\nimport { parseSize } from './log.js';\n\n/**\n * Structured audit log — an append-only JSONL trail of every write-tool\n * invocation, successful or refused. Opt-in via SEEKSTONE_AUDIT_FILE.\n *\n * One record per write call:\n *\n * { v: 1, ts, tool, outcome, durationMs, seq?, files: [{ path, hashBefore,\n * hashAfter }], ...opDetail, error? }\n *\n * `outcome` is `ok`, `hash_conflict`, `undo_conflict`, `policy_denied`, or\n * `error`. Hashes are the same sha-256 values `read_note` returns as\n * `contentHash`, so a user can verify a record against their vault. When the\n * write journal is on, `files` and `seq` come from the journal entry the call\n * committed (so the audit row indexes straight into `undo_write`); otherwise\n * only the after-hash from the tool result is known.\n *\n * Privacy: records carry paths, hashes, byte counts, and op metadata — never\n * note content, frontmatter values, or search queries. Safe to attach to a\n * bug report.\n *\n * Durability: each record is appended and fsync'd AFTER the vault write\n * commits (a crash loses at most the in-flight record; earlier records are\n * never touched). Rotation renames `<file>` → `<file>.1` when the next\n * record would exceed SEEKSTONE_AUDIT_MAX_SIZE (default 10 MB). If a record\n * cannot be written, the tool call is reported as failed with a structured\n * `audit_failed` error — an unauditable write does not pass silently, even\n * though the vault write itself has already landed.\n */\n\nexport type AuditOutcome = 'ok' | 'hash_conflict' | 'undo_conflict' | 'policy_denied' | 'error';\n\nexport interface AuditFile {\n path: string;\n /** sha-256 of the bytes before the call; null = did not exist; undefined = unknown (journal off). */\n hashBefore?: string | null;\n /** sha-256 of the bytes after the call; null = does not exist. */\n hashAfter: string | null;\n}\n\nexport interface AuditRecord {\n v: 1;\n ts: string;\n tool: string;\n outcome: AuditOutcome;\n durationMs: number;\n /** Journal seq of the entry this call committed (when the journal is on). */\n seq?: number;\n files?: AuditFile[];\n /** Which policy refused a `policy_denied` call. */\n policy?: 'read_only' | 'write_paths';\n /**\n * Error CODE for non-ok outcomes (`hash_conflict`, `heading_not_found`,\n * `not_found`, `exists`, `invalid_input`, …) — never the message: tool\n * messages can echo headings, patterns, or frontmatter keys, which are\n * content. The full message is in the server log (SEEKSTONE_LOG_FILE).\n */\n error?: string;\n /** Op-specific metadata from the tool result — counts, destinations, flags; never content. */\n [detail: string]: unknown;\n}\n\nconst DEFAULT_MAX_SIZE = 10 * 1e6;\n\nexport interface AuditConfig {\n path: string;\n maxBytes: number;\n}\n\n/** Undefined unless SEEKSTONE_AUDIT_FILE is set. */\nexport function resolveAuditConfig(\n env: Record<string, string | undefined>,\n): AuditConfig | undefined {\n const path = (env.SEEKSTONE_AUDIT_FILE ?? '').trim();\n if (path === '') return undefined;\n return { path, maxBytes: parseSize(env.SEEKSTONE_AUDIT_MAX_SIZE, DEFAULT_MAX_SIZE) };\n}\n\nexport class AuditLog {\n readonly path: string;\n private readonly maxBytes: number;\n private bytes: number;\n\n private constructor(path: string, maxBytes: number, bytes: number) {\n this.path = path;\n this.maxBytes = maxBytes;\n this.bytes = bytes;\n }\n\n /**\n * Open (create if missing) the audit file, verifying it is writable now so\n * an unwritable path fails at boot rather than on the first write.\n */\n static open(config: AuditConfig): AuditLog {\n let bytes = 0;\n try {\n bytes = statSync(config.path).size;\n } catch {\n bytes = 0;\n }\n appendFileSync(config.path, '');\n return new AuditLog(config.path, config.maxBytes, bytes);\n }\n\n /** Append one record durably. Throws if the append or fsync fails. */\n record(rec: AuditRecord): void {\n const line = `${JSON.stringify(rec)}\\n`;\n const len = Buffer.byteLength(line);\n if (this.bytes > 0 && this.bytes + len > this.maxBytes) {\n renameSync(this.path, `${this.path}.1`);\n this.bytes = 0;\n }\n const fd = openSync(this.path, 'a');\n try {\n writeSync(fd, line);\n fsyncSync(fd);\n } finally {\n closeSync(fd);\n }\n this.bytes += len;\n }\n}\n\n/**\n * Classify a thrown tool error into an audit outcome plus a content-free\n * error code. Structured errors are JSON strings with an `error` field\n * (their code is kept verbatim); policy refusals are plain messages from\n * policy.ts; everything else maps to a coarse code — the raw message is\n * deliberately NOT recorded because tool messages can quote note content\n * (available headings, regex patterns, frontmatter keys).\n */\nexport function classifyError(message: string): {\n outcome: AuditOutcome;\n policy?: AuditRecord['policy'];\n error: string;\n} {\n if (message.startsWith('{')) {\n try {\n const parsed = JSON.parse(message) as { error?: unknown };\n if (typeof parsed.error === 'string') {\n if (parsed.error === 'hash_conflict')\n return { outcome: 'hash_conflict', error: parsed.error };\n if (parsed.error === 'undo_conflict')\n return { outcome: 'undo_conflict', error: parsed.error };\n return { outcome: 'error', error: parsed.error };\n }\n } catch {\n /* not JSON after all — fall through */\n }\n }\n if (message.startsWith('Server is read-only')) {\n return { outcome: 'policy_denied', policy: 'read_only', error: 'read_only' };\n }\n if (message.startsWith('Write not permitted')) {\n return { outcome: 'policy_denied', policy: 'write_paths', error: 'write_paths' };\n }\n if (/ENOENT|not found/i.test(message)) return { outcome: 'error', error: 'not_found' };\n if (/already exists/i.test(message)) return { outcome: 'error', error: 'exists' };\n if (/^Invalid regex/.test(message)) return { outcome: 'error', error: 'invalid_regex' };\n if (/^Write-safety violation/.test(message))\n return { outcome: 'error', error: 'write_safety_violation' };\n if (/^\\[\\s*\\{/.test(message) || /invalid_type|Required|Expected|expected/.test(message)) {\n return { outcome: 'error', error: 'invalid_input' };\n }\n return { outcome: 'error', error: 'error' };\n}\n","import { appendFileSync, renameSync, statSync } from 'node:fs';\n\n/**\n * A tiny zero-dependency leveled logger for the MCP server.\n *\n * Two sinks, never stdout (stdout carries the JSON-RPC stdio transport):\n * - stderr: concise human-readable lines, always on (Claude Desktop captures it).\n * - file: JSON-lines, opt-in via SEEKSTONE_LOG_FILE, size-rotated.\n *\n * Privacy: callers pass metadata fields at info/warn/error and only attach note\n * content (bodies, frontmatter values, raw queries) at `debug`. The logger does\n * not inspect or redact fields — that contract lives at the call sites.\n *\n * Note: file writes use appendFileSync. File logging is opt-in and the per-line\n * cost is sub-millisecond, comfortably inside tool latency budgets; the default\n * (stderr-only) path does no disk I/O. An async write queue is a future option.\n */\n\nexport type LogLevel = 'error' | 'warn' | 'info' | 'debug';\n\nconst ORDER: readonly LogLevel[] = ['error', 'warn', 'info', 'debug'] as const;\nconst DEFAULT_MAX_SIZE = 5 * 1024 * 1024;\n\nexport interface Logger {\n readonly level: LogLevel;\n error(msg: string, fields?: Record<string, unknown>): void;\n warn(msg: string, fields?: Record<string, unknown>): void;\n info(msg: string, fields?: Record<string, unknown>): void;\n debug(msg: string, fields?: Record<string, unknown>): void;\n}\n\nexport interface LoggerOptions {\n /** Env to read SEEKSTONE_LOG_* from. Defaults to process.env. */\n env?: Record<string, string | undefined>;\n /** stderr sink — injectable for tests. Defaults to process.stderr. Never stdout. */\n stderr?: (line: string) => void;\n /** Clock — injectable for deterministic tests. */\n now?: () => Date;\n}\n\nfunction parseLevel(raw: string | undefined, onBad: (m: string) => void): LogLevel {\n if (raw === undefined || raw === '') return 'info';\n const v = raw.trim().toLowerCase();\n for (const lvl of ORDER) {\n if (lvl === v) return lvl;\n }\n onBad(`invalid SEEKSTONE_LOG_LEVEL=${JSON.stringify(raw)}; using \"info\"`);\n return 'info';\n}\n\n/** Parse a human size (`10mb`, `512kb`, `1.5gb`, bare bytes); falls back to `fallback`. */\nexport function parseSize(raw: string | undefined, fallback = DEFAULT_MAX_SIZE): number {\n if (raw === undefined) return fallback;\n const m = /^(\\d+(?:\\.\\d+)?)(b|kb|mb|gb)?$/i.exec(raw.trim());\n if (m === null) return fallback;\n const num = Number(m[1]);\n const unit = (m[2] ?? 'b').toLowerCase();\n const mult = unit === 'gb' ? 1e9 : unit === 'mb' ? 1e6 : unit === 'kb' ? 1e3 : 1;\n return Math.max(1, Math.floor(num * mult));\n}\n\nfunction fmtFields(fields: Record<string, unknown>): string {\n const parts: string[] = [];\n for (const [k, v] of Object.entries(fields)) {\n if (v === undefined) continue;\n parts.push(`${k}=${typeof v === 'string' ? v : JSON.stringify(v)}`);\n }\n return parts.length > 0 ? ` ${parts.join(' ')}` : '';\n}\n\nexport function createLogger(opts: LoggerOptions = {}): Logger {\n const env = opts.env ?? process.env;\n // Default sink is stderr — deliberately never process.stdout.\n const stderr = opts.stderr ?? ((line: string): void => void process.stderr.write(line));\n const now = opts.now ?? ((): Date => new Date());\n\n const level = parseLevel(env.SEEKSTONE_LOG_LEVEL, (m) => {\n stderr(`WARN ${now().toISOString()} ${m}\\n`);\n });\n const threshold = ORDER.indexOf(level);\n\n const filePath = env.SEEKSTONE_LOG_FILE;\n const maxSize = parseSize(env.SEEKSTONE_LOG_MAX_SIZE);\n let fileOk = false;\n let bytes = 0;\n if (filePath !== undefined && filePath !== '') {\n try {\n try {\n bytes = statSync(filePath).size;\n } catch {\n bytes = 0;\n }\n appendFileSync(filePath, ''); // verify writable / create\n fileOk = true;\n } catch (err) {\n const m = err instanceof Error ? err.message : String(err);\n stderr(\n `WARN ${now().toISOString()} cannot write log file ${filePath}: ${m}; file logging disabled\\n`,\n );\n }\n }\n\n function writeFile(record: Record<string, unknown>): void {\n if (!fileOk || filePath === undefined) return;\n const line = `${JSON.stringify(record)}\\n`;\n const len = Buffer.byteLength(line);\n try {\n if (bytes > 0 && bytes + len > maxSize) {\n renameSync(filePath, `${filePath}.1`);\n bytes = 0;\n }\n appendFileSync(filePath, line);\n bytes += len;\n } catch {\n fileOk = false; // stop trying; logging must never crash the request path\n }\n }\n\n function emit(lvl: LogLevel, msg: string, fields?: Record<string, unknown>): void {\n if (ORDER.indexOf(lvl) > threshold) return; // below threshold: do no work\n const ts = now().toISOString();\n const f = fields ?? {};\n stderr(`${lvl.toUpperCase().padEnd(5)} ${ts} ${msg}${fmtFields(f)}\\n`);\n writeFile({ t: ts, level: lvl, msg, ...f });\n }\n\n return {\n level,\n error: (m, f) => {\n emit('error', m, f);\n },\n warn: (m, f) => {\n emit('warn', m, f);\n },\n info: (m, f) => {\n emit('info', m, f);\n },\n debug: (m, f) => {\n emit('debug', m, f);\n },\n };\n}\n","/**\n * Tiny argument handling for the `seekstone` bin. Kept pure (no process exit,\n * no IO) so it can be unit-tested. The MCP server itself takes no arguments —\n * these are just the conventional `--version` / `--help` niceties expected of a\n * CLI installed via `npx`.\n */\n\nexport type CliIntent = 'version' | 'help' | 'init' | 'init-help' | 'fetch-model' | 'run';\n\nexport function parseCliIntent(argv: readonly string[]): CliIntent {\n // A subcommand, if present, is the first non-flag token. A help flag after\n // the subcommand asks for the subcommand's help, so it must be recognised\n // here — before the init run path — not swallowed by init's own arg parsing.\n if (argv[0] === 'init') {\n for (const arg of argv.slice(1)) {\n if (arg === '--help' || arg === '-h') return 'init-help';\n }\n return 'init';\n }\n if (argv[0] === 'fetch-model') return 'fetch-model';\n for (const arg of argv) {\n if (arg === '--version' || arg === '-v') return 'version';\n if (arg === '--help' || arg === '-h') return 'help';\n }\n return 'run';\n}\n\n// Shared between the top-level help and `seekstone init --help` so the two\n// can't drift apart.\nconst initOptionLines = ` --vault <path> Vault to use (auto-detected from Obsidian if omitted; fallback: $SEEKSTONE_VAULT)\n --client <name> desktop (default) | code | cursor | vscode\n --write Patch the client config in place (backs it up first)`;\n\nexport function helpText(version: string): string {\n return `seekstone ${version} — an Obsidian MCP server (filesystem-direct, low context-tax)\n\nSeekstone runs as a Model Context Protocol stdio server. It is normally\nlaunched by an MCP client (Claude Desktop, Claude Code, Cursor, …), not run by hand.\n\nUsage:\n seekstone Start the MCP server (reads from stdin/stdout)\n seekstone init Validate a vault and print/patch the client MCP config\n seekstone fetch-model Download the local embedding model for semantic search\n (--model potion-base-8M | potion-retrieval-32M)\n seekstone --version Print the version and exit\n seekstone --help Print this help and exit\n\n\"seekstone init\" options:\n${initOptionLines}\n\nRequired environment:\n SEEKSTONE_VAULT Absolute path to your Obsidian vault\n\nOptional environment:\n SEEKSTONE_LOG_LEVEL error | warn | info (default) | debug\n SEEKSTONE_LOG_FILE Absolute path; append JSON-line logs here\n SEEKSTONE_WATCH_POLL Set to 1 to poll for changes (network drives, WSL)\n SEEKSTONE_WATCH_POLL_INTERVAL Poll interval in ms (default 10000)\n SEEKSTONE_SEMANTIC Set to 1 to enable semantic search (needs fetch-model first)\n SEEKSTONE_SEMANTIC_MODEL potion-base-8M (default) | potion-retrieval-32M (bigger, more accurate)\n SEEKSTONE_MODEL_PATH Override the embedding-model directory\n SEEKSTONE_CACHE_DIR Override the cache root (default ~/.cache/seekstone)\n\nAdd to Claude Code:\n claude mcp add seekstone --env SEEKSTONE_VAULT=/path/to/vault -- npx -y seekstone\n\nDocs: https://github.com/shaqmughal/seekstone`;\n}\n\nexport function initHelpText(version: string): string {\n return `seekstone ${version} — seekstone init\n\nValidate an Obsidian vault and print (or, with --write, patch) the MCP config\nfor the chosen client (Claude Desktop, Claude Code, Cursor, VS Code).\n\nUsage:\n seekstone init [options]\n\nOptions:\n${initOptionLines}\n --help, -h Print this help and exit\n\nExamples:\n seekstone init\n seekstone init --vault \"/Users/you/Obsidian/My Vault\" --client code --write\n\nDocs: https://github.com/shaqmughal/seekstone`;\n}\n","import { readFile } from 'node:fs/promises';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { journalWrite } from '../journal.js';\nimport { assertWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const AppendNoteInput = z.object({\n path: z.string().describe('Vault-relative path to the note.'),\n content: z\n .string()\n .min(1)\n .describe(\n 'Text to append to the note body. Will be separated from existing content by a blank line.',\n ),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n ),\n});\nexport type AppendNoteInput = z.infer<typeof AppendNoteInput>;\n\nexport interface AppendNoteResult {\n path: string;\n bytesWritten: number;\n /** sha-256 (hex) of the new content — usable as prevHash for a chained edit. */\n contentHash: string;\n}\n\n/**\n * Append text to a note body without touching the frontmatter.\n *\n * The write contract:\n * - The frontmatter block (if any) is preserved byte-for-byte.\n * - A blank line is inserted before the appended content if the body\n * does not already end with one (keeps Obsidian's visual spacing).\n * - The file is written atomically (temp file + rename).\n */\nexport async function appendNote(\n ctx: ServerContext,\n input: AppendNoteInput,\n): Promise<AppendNoteResult> {\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n assertWritable(ctx.policy, input.path);\n\n const original = await readFile(absPath, 'utf8');\n if (input.prevHash !== undefined) assertHashMatch(original, input.prevHash, input.path);\n const fm = parseFrontmatter(original);\n\n // Ensure body ends with exactly one trailing newline before appending.\n const body = fm.body.endsWith('\\n') ? fm.body : `${fm.body}\\n`;\n const separator = body.endsWith('\\n\\n') ? '' : '\\n';\n const newBody = `${body}${separator}${input.content}`;\n\n // Reconstruct: original header (FM + delimiters) + new body.\n const header = original.slice(0, fm.bodyStart);\n const newContent = `${header}${newBody}`;\n\n await journalWrite(ctx, 'append_note', input.path, original, newContent);\n await atomicWrite(absPath, newContent);\n\n // Update the in-memory index entry so subsequent searches reflect the change.\n const cached = ctx.notes.get(input.path);\n if (cached) {\n cached.body = newBody;\n cached.raw = newContent;\n }\n\n return {\n path: input.path,\n bytesWritten: Buffer.byteLength(newContent, 'utf8'),\n contentHash: contentHash(newContent),\n };\n}\n","import { parse as parseYaml } from 'yaml';\n\nexport interface FrontmatterResult {\n /** true if the note starts with a YAML block delimited by `---` lines. */\n present: boolean;\n /** Parsed object (null if not present or parse error or block empty). */\n data: Record<string, unknown> | null;\n /** Distinct top-level keys (empty if absent or malformed). */\n keys: string[];\n /** True if a `---` block exists but yaml.parse threw. */\n malformed: boolean;\n /** Byte offset where the body (post-frontmatter) starts. */\n bodyStart: number;\n /** Body text, frontmatter stripped. */\n body: string;\n}\n\n/**\n * Split a note into frontmatter + body without round-tripping through any\n * YAML stringifier. We need to know the *bytes* of the FM block so writers\n * can be byte-faithful — that's the write-safety contract.\n *\n * Obsidian's rule: a YAML block is present iff the file starts with `---`\n * on its own line (no leading whitespace, no BOM stripped silently — though\n * we tolerate a leading BOM since Windows users exist).\n */\nexport function parseFrontmatter(text: string): FrontmatterResult {\n let offset = 0;\n if (text.charCodeAt(0) === 0xfeff) offset = 1; // BOM\n\n // Must start with `---\\n` or `---\\r\\n`\n const head = text.slice(offset, offset + 4);\n if (head !== '---\\n' && text.slice(offset, offset + 5) !== '---\\r\\n') {\n return {\n present: false,\n data: null,\n keys: [],\n malformed: false,\n bodyStart: 0,\n body: text,\n };\n }\n const fmStart = offset + (head === '---\\n' ? 4 : 5);\n\n // Find closing `\\n---\\n` (or CRLF variant) — Obsidian requires `---` on its own line.\n // We search line-by-line from fmStart.\n const closeLF = text.indexOf('\\n---\\n', fmStart - 1);\n const closeCRLF = text.indexOf('\\r\\n---\\r\\n', fmStart - 1);\n let closeIdx = -1;\n let closeLen = 0;\n if (closeLF !== -1 && (closeCRLF === -1 || closeLF < closeCRLF)) {\n closeIdx = closeLF;\n closeLen = 5;\n } else if (closeCRLF !== -1) {\n closeIdx = closeCRLF;\n closeLen = 7;\n }\n if (closeIdx === -1) {\n // Unterminated frontmatter — count as malformed, treat whole file as body.\n return {\n present: true,\n data: null,\n keys: [],\n malformed: true,\n bodyStart: 0,\n body: text,\n };\n }\n\n const yamlText = text.slice(fmStart, closeIdx + 1); // include trailing \\n before ---\n const bodyStart = closeIdx + closeLen;\n const body = text.slice(bodyStart);\n\n let data: Record<string, unknown> | null = null;\n let malformed = false;\n try {\n const parsed = parseYaml(yamlText);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n data = parsed as Record<string, unknown>;\n } else {\n // YAML parsed but isn't a mapping — Obsidian also treats this as malformed-for-our-purposes.\n malformed = parsed !== null && parsed !== undefined;\n }\n } catch {\n malformed = true;\n }\n\n return {\n present: true,\n data,\n keys: data ? Object.keys(data) : [],\n malformed,\n bodyStart,\n body,\n };\n}\n","import { rename, writeFile } from 'node:fs/promises';\n\n/**\n * Crash-safe file write: write to a same-directory temp file, then rename\n * over the destination. A crash mid-write leaves either the old content or\n * the new content on disk — never a torn file. rename-over-existing works on\n * the full CI OS matrix (proven by patch_note's original implementation).\n *\n * Not a lock: two seekstone processes writing the same note share this temp\n * suffix and can race each other — same exposure as any two writers on one\n * file. CAS (content-hash.ts) is the conflict-detection layer above this.\n */\nexport async function atomicWrite(absPath: string, content: string): Promise<void> {\n const tmpPath = `${absPath}.seekstone-tmp`;\n await writeFile(tmpPath, content, 'utf8');\n await rename(tmpPath, absPath);\n}\n","import { createHash } from 'node:crypto';\n\n/**\n * Content hashing for optional compare-and-swap edits.\n *\n * The hash is sha-256 (hex) of the exact raw string a tool read from disk —\n * disk bytes are the version identity. `read_note` and every mutating tool\n * return `contentHash`; edit tools accept `prevHash` and refuse to write when\n * the note changed since it was read. This is conflict DETECTION, not\n * locking: the window between check and rename is the same one the OS gives\n * any two writers. node:crypto is fully offline — the zero-network guarantee\n * is unaffected.\n */\nexport function contentHash(raw: string | Buffer): string {\n return createHash('sha256').update(raw).digest('hex');\n}\n\n/**\n * Throw the structured hash_conflict error when `prevHash` no longer matches\n * the freshly-read content. Call immediately after the disk read, before any\n * edit is computed.\n */\nexport function assertHashMatch(raw: string, prevHash: string, path: string): void {\n const actual = contentHash(raw);\n if (actual !== prevHash) {\n throw new Error(\n JSON.stringify({\n error: 'hash_conflict',\n path,\n expected: prevHash,\n actual,\n hint: 'Note changed on disk since it was read. Re-read it and retry with the new contentHash.',\n }),\n );\n }\n}\n","import { timingSafeEqual } from 'node:crypto';\nimport { mkdir, open, readdir, readFile, rename, rm, stat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { contentHash } from './content-hash.js';\nimport type { Logger } from './log.js';\nimport { parseSize } from './log.js';\n\n/**\n * Write journal — the pre-image store behind `list_writes` / `undo_write`.\n *\n * Before any content-modifying write commits, the tool hands the journal the\n * bytes it is about to replace. The journal stores them under\n * `<vault>/.seekstone/history/blobs/<sha256>` (content-addressed: identical\n * states dedupe for free) and appends one JSONL line to\n * `<vault>/.seekstone/history/manifest.jsonl`:\n *\n * { seq, ts, tool, files: [{ path, preHash, postHash }], undoOf? }\n *\n * `preHash: null` = the file did not exist before (a create); `postHash:\n * null` = it does not exist after (a delete or move-away). Only pre-images\n * are stored — the post-state is what is on disk.\n *\n * Durability: blobs and the manifest line are fsync'd before the tool is\n * allowed to touch the vault. A crash after the journal commit but before\n * the vault write leaves an entry whose postHash does not match disk —\n * undo_write reports that as a conflict rather than restoring blindly. A\n * journal failure throws, which aborts the vault write — an unjournalable\n * write does not proceed while the journal is enabled.\n *\n * Retention is size-capped (`SEEKSTONE_HISTORY_MAX_SIZE`, default 50 MB of\n * blobs) and count-capped (`SEEKSTONE_HISTORY_MAX_ENTRIES`, default 1000).\n * Eviction drops the oldest entries' blobs; the entry stays listed with\n * `undoable: false` rather than vanishing silently. `SEEKSTONE_HISTORY=0`\n * disables the journal entirely (ctx.journal is undefined; tools skip it).\n */\n\nexport interface JournalFile {\n /** Vault-relative path. */\n path: string;\n /** sha-256 of the bytes before the write; null when the file did not exist. */\n preHash: string | null;\n /** sha-256 of the bytes after the write; null when the file no longer exists. */\n postHash: string | null;\n}\n\nexport interface JournalEntry {\n /** Monotonic, 1-based, never reused within a vault's journal. */\n seq: number;\n /** ISO-8601 timestamp of the commit. */\n ts: string;\n /** Tool that performed the write (`undo_write` for undos). */\n tool: string;\n files: JournalFile[];\n /** For undo entries: the seq this entry reverted. */\n undoOf?: number;\n}\n\n/** A listed entry: the manifest row plus whether its pre-images are still on disk. */\nexport interface JournalListRow {\n seq: number;\n ts: string;\n tool: string;\n paths: string[];\n undoable: boolean;\n undoOf?: number;\n}\n\nexport interface JournalConfig {\n maxBytes: number;\n maxEntries: number;\n}\n\nconst DEFAULT_MAX_BYTES = 50 * 1e6;\nconst DEFAULT_MAX_ENTRIES = 1000;\n\n/** Vault-relative directory the journal lives in — excluded from indexing like `.trash/`. */\nexport const HISTORY_DIR = '.seekstone/history';\n\n/**\n * Read the journal settings from env. Returns undefined when the journal is\n * disabled (`SEEKSTONE_HISTORY=0|false`).\n */\nexport function resolveJournalConfig(\n env: Record<string, string | undefined>,\n): JournalConfig | undefined {\n const flag = (env.SEEKSTONE_HISTORY ?? '').trim().toLowerCase();\n if (flag === '0' || flag === 'false' || flag === 'off') return undefined;\n const maxEntriesRaw = Number.parseInt(env.SEEKSTONE_HISTORY_MAX_ENTRIES ?? '', 10);\n return {\n maxBytes: parseSize(env.SEEKSTONE_HISTORY_MAX_SIZE, DEFAULT_MAX_BYTES),\n maxEntries:\n Number.isFinite(maxEntriesRaw) && maxEntriesRaw > 0 ? maxEntriesRaw : DEFAULT_MAX_ENTRIES,\n };\n}\n\n/** Write `content` to `dest` durably: temp file, fsync, rename over. */\nasync function writeDurable(dest: string, content: string): Promise<void> {\n const tmp = `${dest}.seekstone-tmp`;\n const fh = await open(tmp, 'w');\n try {\n await fh.writeFile(content, 'utf8');\n await fh.sync();\n } finally {\n await fh.close();\n }\n await rename(tmp, dest);\n}\n\n/** Append one line to `dest` durably (fsync before returning). */\nasync function appendDurable(dest: string, line: string): Promise<void> {\n const fh = await open(dest, 'a');\n try {\n await fh.writeFile(line, 'utf8');\n await fh.sync();\n } finally {\n await fh.close();\n }\n}\n\n/**\n * One tool call's worth of journaling. `add` stores each file's pre-image;\n * `commit` appends the manifest line. Tools call both BEFORE the first vault\n * byte changes. Multi-file tools (move_note, rename_heading) add every\n * touched file under one seq so undo restores all of them or none.\n */\nexport interface JournalTxn {\n add(path: string, pre: string | null, post: string | null): Promise<void>;\n commit(): Promise<JournalEntry>;\n}\n\nexport class Journal {\n readonly config: JournalConfig;\n private readonly dir: string;\n private readonly blobDir: string;\n private readonly manifestPath: string;\n private readonly log?: Logger;\n private entries: JournalEntry[];\n private nextSeq: number;\n /** Blob hash → byte size, for every blob currently on disk. */\n private readonly blobSizes: Map<string, number>;\n private totalBytes: number;\n /** Serialises commits so seq assignment and eviction never interleave. */\n private chain: Promise<unknown> = Promise.resolve();\n\n private constructor(\n vaultRoot: string,\n config: JournalConfig,\n entries: JournalEntry[],\n blobSizes: Map<string, number>,\n log?: Logger,\n ) {\n this.config = config;\n this.dir = join(vaultRoot, HISTORY_DIR);\n this.blobDir = join(this.dir, 'blobs');\n this.manifestPath = join(this.dir, 'manifest.jsonl');\n this.entries = entries;\n this.nextSeq = (entries.at(-1)?.seq ?? 0) + 1;\n this.blobSizes = blobSizes;\n this.totalBytes = 0;\n for (const n of blobSizes.values()) this.totalBytes += n;\n this.log = log;\n }\n\n /** Open (or create) the journal under `vaultRoot`, loading the manifest into memory. */\n static async open(\n vaultRoot: string,\n config: JournalConfig,\n opts: { log?: Logger } = {},\n ): Promise<Journal> {\n const dir = join(vaultRoot, HISTORY_DIR);\n const blobDir = join(dir, 'blobs');\n await mkdir(blobDir, { recursive: true });\n\n const entries: JournalEntry[] = [];\n let manifest = '';\n try {\n manifest = await readFile(join(dir, 'manifest.jsonl'), 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n let lastSeq = 0;\n for (const line of manifest.split('\\n')) {\n if (line.trim() === '') continue;\n let parsed: unknown;\n try {\n parsed = JSON.parse(line);\n } catch {\n // A torn trailing line from a crash mid-append — the write it\n // described simply is not listed. Never fail boot over it.\n opts.log?.warn('journal: skipping malformed manifest line');\n continue;\n }\n if (!isEntry(parsed) || parsed.seq <= lastSeq) {\n opts.log?.warn('journal: skipping invalid manifest entry');\n continue;\n }\n entries.push(parsed);\n lastSeq = parsed.seq;\n }\n\n const blobSizes = new Map<string, number>();\n for (const name of await readdir(blobDir)) {\n if (!/^[0-9a-f]{64}$/.test(name)) continue;\n try {\n blobSizes.set(name, (await stat(join(blobDir, name))).size);\n } catch {\n /* vanished between readdir and stat — treat as absent */\n }\n }\n return new Journal(vaultRoot, config, entries, blobSizes, opts.log);\n }\n\n begin(tool: string, undoOf?: number): JournalTxn {\n const files: JournalFile[] = [];\n let committed = false;\n return {\n add: async (path, pre, post) => {\n if (committed) throw new Error('journal: add after commit');\n const preHash = pre === null ? null : await this.storeBlob(pre);\n files.push({ path, preHash, postHash: post === null ? null : contentHash(post) });\n },\n commit: async () => {\n if (committed) throw new Error('journal: double commit');\n committed = true;\n return this.enqueue(() => this.commit(tool, files, undoOf));\n },\n };\n }\n\n /** Newest-first rows for `list_writes`. */\n list(opts: { limit?: number; path?: string } = {}): { writes: JournalListRow[]; total: number } {\n const limit = opts.limit ?? 20;\n const filtered =\n opts.path === undefined\n ? this.entries\n : this.entries.filter((e) => e.files.some((f) => f.path === opts.path));\n const writes: JournalListRow[] = [];\n for (let i = filtered.length - 1; i >= 0 && writes.length < limit; i--) {\n const e = filtered[i] as JournalEntry;\n const row: JournalListRow = {\n seq: e.seq,\n ts: e.ts,\n tool: e.tool,\n paths: e.files.map((f) => f.path),\n undoable: this.isUndoable(e),\n };\n if (e.undoOf !== undefined) row.undoOf = e.undoOf;\n writes.push(row);\n }\n return { writes, total: filtered.length };\n }\n\n /** Seq of the newest entry (0 when empty). */\n get lastSeq(): number {\n return this.nextSeq - 1;\n }\n\n /** Entries committed after `seq`, oldest first. */\n since(seq: number): JournalEntry[] {\n return this.entries.filter((e) => e.seq > seq);\n }\n\n get(seq: number): JournalEntry | undefined {\n return this.entries.find((e) => e.seq === seq);\n }\n\n /**\n * The most recent write that is still in effect and restorable — the\n * default target of `undo_write`. Undo entries and writes they reverted are\n * skipped (so repeated default undos walk backwards instead of ping-ponging\n * undo/redo); an undo that was itself undone re-exposes its target. Redo is\n * always explicit: `undo_write({ seq: <the undo's seq> })`.\n */\n latestUndoable(): JournalEntry | undefined {\n const cancelled = new Set<number>();\n for (let i = this.entries.length - 1; i >= 0; i--) {\n const e = this.entries[i] as JournalEntry;\n if (cancelled.has(e.seq)) continue;\n if (e.undoOf !== undefined) {\n cancelled.add(e.undoOf);\n continue;\n }\n if (this.isUndoable(e)) return e;\n }\n return undefined;\n }\n\n isUndoable(entry: JournalEntry): boolean {\n return entry.files.every((f) => f.preHash === null || this.blobSizes.has(f.preHash));\n }\n\n /** Read a stored pre-image by hash. Throws if evicted. */\n async preimage(hash: string): Promise<string> {\n const raw = await readFile(join(this.blobDir, hash), 'utf8');\n // Integrity check on the stored blob (not a secret comparison); the\n // constant-time compare is free and keeps static analysis quiet.\n const actual = Buffer.from(contentHash(raw), 'hex');\n const expected = Buffer.from(hash, 'hex');\n if (actual.length !== expected.length || !timingSafeEqual(actual, expected)) {\n throw new Error(`journal: blob ${hash} is corrupt (hash mismatch)`);\n }\n return raw;\n }\n\n /** Bytes of pre-images currently stored (for diagnostics/tests). */\n get storedBytes(): number {\n return this.totalBytes;\n }\n\n private enqueue<T>(fn: () => Promise<T>): Promise<T> {\n const next = this.chain.then(fn, fn);\n this.chain = next.catch(() => undefined);\n return next;\n }\n\n private async storeBlob(content: string): Promise<string> {\n const hash = contentHash(content);\n if (this.blobSizes.has(hash)) return hash;\n await writeDurable(join(this.blobDir, hash), content);\n const size = Buffer.byteLength(content, 'utf8');\n this.blobSizes.set(hash, size);\n this.totalBytes += size;\n return hash;\n }\n\n private async commit(tool: string, files: JournalFile[], undoOf?: number): Promise<JournalEntry> {\n const entry: JournalEntry = { seq: this.nextSeq, ts: new Date().toISOString(), tool, files };\n if (undoOf !== undefined) entry.undoOf = undoOf;\n await appendDurable(this.manifestPath, `${JSON.stringify(entry)}\\n`);\n this.nextSeq++;\n this.entries.push(entry);\n await this.evict();\n return entry;\n }\n\n /**\n * Enforce the caps. Blobs are reference-counted across entries, so a\n * pre-image shared by an old and a new entry survives the old one's\n * eviction. Over the entry cap, the oldest rows are dropped and the\n * manifest rewritten atomically; over the byte cap, the oldest entries'\n * blobs are removed but the rows stay (listed as undoable: false).\n */\n private async evict(): Promise<void> {\n const refs = new Map<string, number>();\n for (const e of this.entries) {\n for (const f of e.files) {\n if (f.preHash !== null) refs.set(f.preHash, (refs.get(f.preHash) ?? 0) + 1);\n }\n }\n const dropBlobs = async (e: JournalEntry): Promise<void> => {\n for (const f of e.files) {\n if (f.preHash === null) continue;\n const n = (refs.get(f.preHash) ?? 1) - 1;\n refs.set(f.preHash, n);\n if (n > 0 || !this.blobSizes.has(f.preHash)) continue;\n await rm(join(this.blobDir, f.preHash), { force: true });\n this.totalBytes -= this.blobSizes.get(f.preHash) ?? 0;\n this.blobSizes.delete(f.preHash);\n }\n };\n\n let rewrite = false;\n while (this.entries.length > this.config.maxEntries) {\n const oldest = this.entries.shift() as JournalEntry;\n await dropBlobs(oldest);\n rewrite = true;\n }\n // Never evict the entry just committed — a write must be undoable at\n // least until the next one lands, whatever the cap.\n for (let i = 0; this.totalBytes > this.config.maxBytes && i < this.entries.length - 1; i++) {\n await dropBlobs(this.entries[i] as JournalEntry);\n }\n if (rewrite) {\n await writeDurable(\n this.manifestPath,\n this.entries.map((e) => `${JSON.stringify(e)}\\n`).join(''),\n );\n this.log?.debug('journal: manifest compacted', { entries: this.entries.length });\n }\n }\n}\n\nfunction isEntry(v: unknown): v is JournalEntry {\n if (typeof v !== 'object' || v === null) return false;\n const e = v as Record<string, unknown>;\n return (\n typeof e.seq === 'number' &&\n typeof e.ts === 'string' &&\n typeof e.tool === 'string' &&\n Array.isArray(e.files) &&\n e.files.every(\n (f: unknown) =>\n typeof f === 'object' &&\n f !== null &&\n typeof (f as JournalFile).path === 'string' &&\n ((f as JournalFile).preHash === null || typeof (f as JournalFile).preHash === 'string') &&\n ((f as JournalFile).postHash === null || typeof (f as JournalFile).postHash === 'string'),\n )\n );\n}\n\n/**\n * Single-file convenience for the write tools: journal one pre/post pair\n * before the vault write. No-op when the journal is disabled.\n */\nexport async function journalWrite(\n ctx: { journal?: Journal },\n tool: string,\n path: string,\n pre: string | null,\n post: string | null,\n): Promise<void> {\n if (!ctx.journal) return;\n const txn = ctx.journal.begin(tool);\n await txn.add(path, pre, post);\n await txn.commit();\n}\n","import picomatch from 'picomatch';\n\n/**\n * Write policy — read-only mode and write-path scoping, parsed once at boot\n * and enforced at the dispatch layer (tool visibility + rejection) and inside\n * every write handler at the point the final vault-relative path is known\n * (`assertWritable`). Two env vars:\n *\n * SEEKSTONE_READ_ONLY=1 — write tools are unregistered from\n * tools/list AND rejected at dispatch.\n * SEEKSTONE_WRITE_PATHS=<glob,>— comma-separated vault-relative globs;\n * writes are permitted only under matching\n * paths (e.g. \"journal/**,inbox/*.md\").\n *\n * Read-only wins over write paths. Unset write paths = everything writable.\n */\nexport interface WritePolicy {\n readOnly: boolean;\n /** Vault-relative glob allowlist; undefined = all paths writable. */\n writeGlobs?: string[];\n}\n\n/** Default policy for contexts built without env config (tests, benches). */\nexport const PERMISSIVE_POLICY: WritePolicy = { readOnly: false };\n\nexport function parseWritePolicy(env: Record<string, string | undefined>): WritePolicy {\n const ro = (env.SEEKSTONE_READ_ONLY ?? '').toLowerCase();\n const readOnly = ro === '1' || ro === 'true';\n const globs = (env.SEEKSTONE_WRITE_PATHS ?? '')\n .split(',')\n .map((g) => g.trim())\n .filter((g) => g.length > 0);\n return globs.length > 0 ? { readOnly, writeGlobs: globs } : { readOnly };\n}\n\n/** Normalize a vault-relative path for glob matching (Windows separators, ./). */\nfunction normalizeRel(relPath: string): string {\n let p = relPath.replaceAll('\\\\', '/');\n while (p.startsWith('./')) p = p.slice(2);\n return p;\n}\n\nexport function isWritable(policy: WritePolicy, relPath: string): boolean {\n if (policy.readOnly) return false;\n if (!policy.writeGlobs) return true;\n // dot:true so notes under dot-folders still match `**` patterns.\n return picomatch(policy.writeGlobs, { dot: true })(normalizeRel(relPath));\n}\n\n/**\n * Throw with an actionable message when the policy forbids writing `relPath`.\n * Call from write handlers with the final vault-relative path — after any\n * internal path computation (e.g. periodic-note date resolution).\n */\nexport function assertWritable(policy: WritePolicy, relPath: string): void {\n if (policy.readOnly) {\n throw new Error('Server is read-only (SEEKSTONE_READ_ONLY=1); write tools are disabled.');\n }\n if (!isWritable(policy, relPath)) {\n throw new Error(\n `Write not permitted: \"${relPath}\" is outside SEEKSTONE_WRITE_PATHS (${policy.writeGlobs?.join(', ')}).`,\n );\n }\n}\n","import { resolve, sep } from 'node:path';\n\n/**\n * Resolve a vault-relative path to an absolute path, guaranteeing the result\n * stays inside the vault. This is the single containment guard for every tool\n * handler — the previous inline `join(...).startsWith(vaultRoot)` checks had\n * no separator boundary, so with a vault at `/home/u/vault` the input\n * `../vault-backup/x.md` resolved to `/home/u/vault-backup/x.md` and passed.\n *\n * `resolve` (not `join`) also normalizes an absolute `input` instead of\n * concatenating it, so absolute-path inputs are contained too.\n *\n * @throws Error `Path outside vault: <input>` when the resolved path escapes.\n */\nexport function resolveVaultPath(vaultRoot: string, inputPath: string): string {\n const abs = resolve(vaultRoot, inputPath);\n if (abs !== vaultRoot && !abs.startsWith(vaultRoot + sep)) {\n throw new Error(`Path outside vault: ${inputPath}`);\n }\n return abs;\n}\n","/**\n * Link / URL / tag extractors. Most run on note *bodies* (post-frontmatter)\n * so frontmatter values don't double-count as inline content;\n * `extractLinksWithLines` takes the full raw note and handles the\n * frontmatter block YAML-aware.\n *\n * Heuristics here intentionally lean toward \"what Obsidian sees\" rather than\n * full CommonMark parsing — we're profiling shape, not rendering. The regexes\n * are deliberately tolerant of code-fence content; counts are reported with\n * that caveat in the README.\n */\nimport { parseDocument, visit } from 'yaml';\nimport { parseFrontmatter } from './frontmatter.js';\n\nexport interface Wikilink {\n /** Raw target before `#` and `|`. May include path segments. */\n target: string;\n /** Optional heading/block reference (`#heading` or `#^block`). */\n fragment: string | null;\n /** Optional display alias. */\n alias: string | null;\n}\n\n// Quantifiers are bounded at 512 chars — well above any real Obsidian note name\n// or heading (~255 byte OS limit) — to eliminate O(n²) backtracking on\n// pathological inputs where many [[... sequences appear with no closing ]].\nconst WIKILINK_RE = /\\[\\[([^\\]|#\\n]{1,512})(#[^\\]|\\n]{1,512})?(\\|[^\\]\\n]{1,512})?\\]\\]/g;\n\n// Matches both embeds (![[...]]) and plain wikilinks ([[...]]).\nconst LINK_WITH_LINES_RE =\n /(!?\\[\\[)([^\\]|#\\n]{1,512})(#[^\\]|\\n]{1,512})?(\\|[^\\]\\n]{1,512})?(\\]\\])/g;\n\nexport type LinkType = 'wikilink' | 'embed';\n\nexport interface LinkRecord {\n /**\n * Full raw match, e.g. \"[[Note Name|alias]]\" or \"![[embed.png]]\". For links\n * found inside folded frontmatter scalars this is the *parsed* (unfolded)\n * text, which may differ from the source bytes.\n */\n raw: string;\n /** Raw target before `#` and `|`. */\n target: string;\n fragment: string | null;\n alias: string | null;\n linkType: LinkType;\n /**\n * 1-indexed line number in the source file. Links inside multi-line\n * frontmatter scalars are attributed to the line where the scalar begins.\n */\n line: number;\n}\n\n/**\n * Extract all wikilinks and embeds from a raw note (including frontmatter),\n * annotating each with its 1-indexed line number.\n *\n * The frontmatter block is parsed as YAML and its string values walked, so\n * links split across lines by scalar folding (yaml's default 80-col wrap —\n * hand edits, other tools, or pre-0.12.1 seekstone) still extract: folding\n * turns the newline back into a space on parse. Malformed frontmatter falls\n * back to per-line regex over the block, matching the body treatment.\n */\nexport function extractLinksWithLines(raw: string): LinkRecord[] {\n const fm = parseFrontmatter(raw);\n // bodyStart 0 covers both \"no frontmatter\" and \"unterminated frontmatter\"\n // (where the whole file is treated as body).\n if (!fm.present || fm.bodyStart === 0) return linksFromLines(raw, 1);\n\n const fmRegion = raw.slice(0, fm.bodyStart);\n const out = frontmatterLinks(fmRegion, fm.malformed);\n const bodyFirstLine = countNewlines(fmRegion) + 1;\n linksFromLinesInto(out, fm.body, bodyFirstLine);\n return out;\n}\n\nfunction linksFromLines(text: string, firstLine: number): LinkRecord[] {\n const out: LinkRecord[] = [];\n linksFromLinesInto(out, text, firstLine);\n return out;\n}\n\nfunction linksFromLinesInto(out: LinkRecord[], text: string, firstLine: number): void {\n const lines = text.split('\\n');\n for (const [lineIdx, lineText] of lines.entries()) {\n matchLinksInto(out, lineText, firstLine + lineIdx);\n }\n}\n\nfunction matchLinksInto(out: LinkRecord[], text: string, line: number): void {\n for (const m of text.matchAll(LINK_WITH_LINES_RE)) {\n const prefix = m[1] ?? '';\n out.push({\n raw: m[0] ?? '',\n target: (m[2] ?? '').trim(),\n fragment: m[3] ? m[3].slice(1).trim() : null,\n alias: m[4] ? m[4].slice(1).trim() : null,\n linkType: prefix.startsWith('!') ? 'embed' : 'wikilink',\n line,\n });\n }\n}\n\n/**\n * Walk the frontmatter block's string values via the YAML AST. `fmRegion` is\n * the full block including both `---` delimiter lines. Keys are skipped —\n * Obsidian doesn't treat property names as links.\n */\nfunction frontmatterLinks(fmRegion: string, malformed: boolean): LinkRecord[] {\n if (malformed) return linksFromLines(fmRegion, 1);\n\n // Strip the delimiters: yaml content starts after the opening `---` line and\n // ends before the closing `---` line (parseDocument would read a bare `---`\n // as a document marker).\n const yamlStart = fmRegion.indexOf('\\n') + 1;\n const closeLen = fmRegion.endsWith('---\\r\\n') ? 5 : 4;\n const yamlText = fmRegion.slice(yamlStart, fmRegion.length - closeLen);\n\n const doc = parseDocument(yamlText);\n if (doc.errors.length > 0) return linksFromLines(fmRegion, 1);\n\n const out: LinkRecord[] = [];\n visit(doc, {\n Scalar(key, node) {\n if (key === 'key') return;\n if (typeof node.value !== 'string' || node.range == null) return;\n // Opening `---` is line 1, so yamlText's first line is file line 2.\n const line = 2 + countNewlines(yamlText.slice(0, node.range[0]));\n matchLinksInto(out, node.value, line);\n },\n });\n return out;\n}\n\nfunction countNewlines(text: string): number {\n let n = 0;\n for (let i = text.indexOf('\\n'); i !== -1; i = text.indexOf('\\n', i + 1)) n++;\n return n;\n}\nconst URL_RE = /https?:\\/\\/[^\\s<>\"')]+/g;\n// Obsidian inline tag: must start with letter or underscore, then word chars, /, -.\n// Must not be immediately preceded by `]` (avoids matching `]#` from links) or be\n// inside a numeric-only token like `#123` (Obsidian rejects pure-digit tags).\nconst INLINE_TAG_RE = /(?:^|[^\\w\\]/])#([A-Za-z_][\\w/-]*)/g;\n\nexport function extractWikilinks(body: string): Wikilink[] {\n const out: Wikilink[] = [];\n for (const m of body.matchAll(WIKILINK_RE)) {\n out.push({\n target: (m[1] ?? '').trim(),\n fragment: m[2] ? m[2].slice(1).trim() : null,\n alias: m[3] ? m[3].slice(1).trim() : null,\n });\n }\n return out;\n}\n\nexport function extractUrls(body: string): string[] {\n const TRAILING_PUNCT = '.,;:!?)';\n const out: string[] = [];\n for (const m of body.matchAll(URL_RE)) {\n // Strip trailing punctuation with a backward walk — avoids the O(n²)\n // backtracking that /[.,;:!?)]+$/ exhibits on strings with many punct chars.\n const raw = m[0] ?? '';\n let end = raw.length;\n while (end > 0 && TRAILING_PUNCT.includes(raw.charAt(end - 1))) end--;\n out.push(raw.slice(0, end));\n }\n return out;\n}\n\nexport function extractInlineTags(body: string): string[] {\n const out: string[] = [];\n for (const m of body.matchAll(INLINE_TAG_RE)) {\n if (m[1]) out.push(m[1]);\n }\n return out;\n}\n\n/**\n * Pull tags out of a parsed frontmatter object. Obsidian accepts `tags:` or\n * `tag:`, as either a string (space- or comma-separated) or a list.\n */\nexport function frontmatterTags(fm: Record<string, unknown> | null): string[] {\n if (!fm) return [];\n const raw = fm.tags ?? fm.tag;\n if (raw == null) return [];\n if (Array.isArray(raw)) {\n return raw.filter((t): t is string => typeof t === 'string').map((t) => t.replace(/^#/, ''));\n }\n if (typeof raw === 'string') {\n return raw\n .split(/[\\s,]+/)\n .filter(Boolean)\n .map((t) => t.replace(/^#/, ''));\n }\n return [];\n}\n","import { extractLinksWithLines } from '@seekstone/core/extract';\nimport { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { extractExcerpt } from '../index/excerpt.js';\nimport { resolveLink } from '../index/resolve.js';\nimport type { SearchHit } from '../index/types.js';\nimport { retrieve } from './search.js';\n\nexport const ContextPackInput = z.object({\n query: z.string().min(1).describe('Natural-language question or topic to assemble context for.'),\n budgetBytes: z\n .number()\n .int()\n .min(256)\n .max(16384)\n .default(2048)\n .describe('Hard cap on the response JSON size in bytes. The pack never exceeds it.'),\n mode: z\n .enum(['lexical', 'semantic', 'hybrid'])\n .optional()\n .describe(\n 'lexical = keyword search (default). semantic = meaning-based search over local embeddings (requires SEEKSTONE_SEMANTIC=1 and a fetched model). hybrid = exact-title lookups go lexical, everything else semantic. A question asked in words the note does not use needs semantic or hybrid.',\n ),\n folder: z\n .string()\n .optional()\n .describe('Restrict results to notes under this vault-relative folder prefix.'),\n tag: z.string().optional().describe('Restrict results to notes containing this tag.'),\n});\nexport type ContextPackInput = z.infer<typeof ContextPackInput>;\n\nconst MAX_CANDIDATES = 10;\nconst NEIGHBOR_HITS = 3;\nconst MAX_NEIGHBORS = 5;\nconst NEIGHBOR_SUMMARY_LEN = 100;\nconst MIN_EXCERPT_LEN = 60;\nconst FM_MAX_BYTES = 120;\nconst SOURCES_MAX = 8;\n\nexport interface ContextPackExcerpt {\n path: string;\n title?: string;\n score: number;\n excerpt: string;\n tags?: string[];\n /** Scalar frontmatter values, in key order, capped at FM_MAX_BYTES serialized. */\n fm?: Record<string, unknown>;\n}\n\nexport interface ContextPackNeighbor {\n path: string;\n rel: 'backlink' | 'outlink' | 'both';\n /** Line in the neighbor where it links to a hit (backlinks only). */\n line?: number;\n summary: string;\n}\n\nexport interface ContextPackSource {\n path: string;\n line?: number;\n}\n\nexport interface ContextPackResult {\n excerpts: ContextPackExcerpt[];\n neighborhood: ContextPackNeighbor[];\n /** Overflow refs only — matches and neighbors that did not fit the budget. */\n sources: ContextPackSource[];\n totalMatches: number;\n confidence: 'high' | 'low' | 'none';\n truncated?: true;\n}\n\n/** Serialized cost of one array entry, +1 for the separating comma (conservative). */\nfunction entryCost(entry: unknown): number {\n return Buffer.byteLength(JSON.stringify(entry), 'utf8') + 1;\n}\n\n/** Pick scalar frontmatter values in key order until the serialized subset exceeds the cap. */\nfunction pickFm(fm: Record<string, unknown> | null): Record<string, unknown> | undefined {\n if (!fm) return undefined;\n const out: Record<string, unknown> = {};\n let picked = 0;\n for (const key of Object.keys(fm)) {\n const v = fm[key];\n const t = typeof v;\n if (t !== 'string' && t !== 'number' && t !== 'boolean') continue;\n const candidate = { ...out, [key]: v };\n if (Buffer.byteLength(JSON.stringify(candidate), 'utf8') > FM_MAX_BYTES) break;\n out[key] = v;\n picked += 1;\n }\n return picked > 0 ? out : undefined;\n}\n\nfunction clamp(n: number, lo: number, hi: number): number {\n return Math.min(hi, Math.max(lo, n));\n}\n\nexport function contextPack(ctx: ServerContext, input: ContextPackInput): ContextPackResult {\n const excerptLen = clamp(Math.floor(input.budgetBytes / 10), 80, 400);\n const { hits: results, totalCandidates } = retrieve(ctx, {\n query: input.query,\n mode: input.mode,\n folder: input.folder,\n tag: input.tag,\n limit: MAX_CANDIDATES,\n excerptLength: excerptLen,\n });\n const totalMatches = totalCandidates;\n if (results.length === 0) {\n return { excerpts: [], neighborhood: [], sources: [], totalMatches, confidence: 'none' };\n }\n\n const terms = input.query\n .toLowerCase()\n .split(/\\s+/)\n .filter((t) => t.length > 1);\n\n const scoreByPath = new Map<string, number>();\n for (const r of results) scoreByPath.set(r.path, r.score);\n\n // Meter the fixed envelope with worst-case flags so emitting them later can\n // never break the cap. Entries are metered against the same minified\n // serialization dispatch ships, so the budget is exact, not an estimate.\n const budget = input.budgetBytes;\n let used = Buffer.byteLength(\n JSON.stringify({\n excerpts: [],\n neighborhood: [],\n sources: [],\n totalMatches,\n confidence: 'high',\n truncated: true,\n }),\n 'utf8',\n );\n\n // Phase 1 — excerpts: greedy fill in rank order, holding back a soft reserve\n // for the neighborhood. On the first non-fit, shrink the excerpt (half, then\n // the floor); a shrunk entry ends the phase so the pack isn't all fragments.\n const reserve = Math.min(Math.floor(budget / 4), 600);\n const candidates = results.slice(0, MAX_CANDIDATES);\n const excerpts: ContextPackExcerpt[] = [];\n const overflowHits: ContextPackSource[] = [];\n let droppedForBudget = false;\n\n const buildEntry = (h: SearchHit, len: number): ContextPackExcerpt => {\n const note = ctx.notes.get(h.path);\n const entry: ContextPackExcerpt = {\n path: h.path,\n score: h.score,\n excerpt: h.excerpt.length > len ? extractExcerpt(h.excerpt, terms, len) : h.excerpt,\n };\n if (h.title) entry.title = h.title;\n if (h.tags && h.tags.length > 0) entry.tags = h.tags;\n const fm = pickFm(note?.fm ?? null);\n if (fm) entry.fm = fm;\n return entry;\n };\n\n const excerptCap = budget - reserve;\n let phaseOpen = true;\n for (const r of candidates) {\n if (!phaseOpen) {\n overflowHits.push({ path: r.path });\n continue;\n }\n let placed = false;\n const shrinkLens = [\n ...new Set([\n excerptLen,\n Math.max(Math.floor(excerptLen / 2), MIN_EXCERPT_LEN),\n MIN_EXCERPT_LEN,\n ]),\n ];\n for (const len of shrinkLens) {\n const entry = buildEntry(r, len);\n const cost = entryCost(entry);\n if (used + cost <= excerptCap) {\n excerpts.push(entry);\n used += cost;\n placed = true;\n // A shrunk excerpt means the budget is nearly spent — stop before\n // packing many useless fragments.\n if (len !== excerptLen) phaseOpen = false;\n break;\n }\n }\n if (!placed) {\n phaseOpen = false;\n droppedForBudget = true;\n overflowHits.push({ path: r.path });\n }\n }\n\n // Phase 2 — neighborhood: backlinks + outlinks of the top included hits.\n // The reserve is released; entries fill whatever budget remains.\n const includedPaths = new Set(excerpts.map((e) => e.path));\n const seeds = excerpts.slice(0, NEIGHBOR_HITS).map((e) => e.path);\n const agg = new Map<\n string,\n { rels: Set<'backlink' | 'outlink'>; seedPaths: Set<string>; line?: number }\n >();\n const connect = (\n neighborPath: string,\n seed: string,\n rel: 'backlink' | 'outlink',\n line?: number,\n ) => {\n if (neighborPath === seed || includedPaths.has(neighborPath)) return; // excerpt wins dedup\n if (!ctx.notes.has(neighborPath)) return;\n let entry = agg.get(neighborPath);\n if (!entry) {\n entry = { rels: new Set(), seedPaths: new Set() };\n agg.set(neighborPath, entry);\n }\n entry.rels.add(rel);\n entry.seedPaths.add(seed);\n if (rel === 'backlink' && entry.line === undefined && line !== undefined) entry.line = line;\n };\n for (const seed of seeds) {\n for (const ref of ctx.backlinks.get(seed) ?? []) {\n connect(ref.path, seed, 'backlink', ref.line);\n }\n const note = ctx.notes.get(seed);\n if (!note) continue;\n for (const link of extractLinksWithLines(note.raw)) {\n const target = resolveLink(link.target, ctx.notes);\n if (target !== undefined) connect(target, seed, 'outlink');\n }\n }\n\n const ranked = [...agg.entries()].sort((a, b) => {\n const conn = b[1].seedPaths.size - a[1].seedPaths.size;\n if (conn !== 0) return conn;\n const score = (scoreByPath.get(b[0]) ?? 0) - (scoreByPath.get(a[0]) ?? 0);\n if (score !== 0) return score;\n return a[0] < b[0] ? -1 : 1;\n });\n\n const neighborhood: ContextPackNeighbor[] = [];\n const overflowNeighbors: ContextPackSource[] = [];\n for (const [path, info] of ranked) {\n if (neighborhood.length >= MAX_NEIGHBORS) {\n overflowNeighbors.push(info.line !== undefined ? { path, line: info.line } : { path });\n continue;\n }\n const note = ctx.notes.get(path);\n const entry: ContextPackNeighbor = {\n path,\n rel: info.rels.size === 2 ? 'both' : info.rels.has('backlink') ? 'backlink' : 'outlink',\n summary: extractExcerpt(note?.body ?? '', terms, NEIGHBOR_SUMMARY_LEN),\n };\n if (info.line !== undefined) entry.line = info.line;\n const cost = entryCost(entry);\n if (used + cost > budget) {\n droppedForBudget = true;\n overflowNeighbors.push(info.line !== undefined ? { path, line: info.line } : { path });\n // First non-fit ends the phase — later entries rank lower anyway.\n for (const [p, i] of ranked.slice(ranked.findIndex(([rp]) => rp === path) + 1)) {\n overflowNeighbors.push(i.line !== undefined ? { path: p, line: i.line } : { path: p });\n }\n break;\n }\n neighborhood.push(entry);\n used += cost;\n }\n\n // Phase 3 — sources: overflow refs (\"read these next\"), deduped, best-first.\n const sources: ContextPackSource[] = [];\n const sourcePaths = new Set<string>();\n for (const ref of [...overflowHits, ...overflowNeighbors]) {\n if (sources.length >= SOURCES_MAX) break;\n if (includedPaths.has(ref.path) || sourcePaths.has(ref.path)) continue;\n const cost = entryCost(ref);\n if (used + cost > budget) break;\n sources.push(ref);\n sourcePaths.add(ref.path);\n used += cost;\n }\n\n const hasTermInExcerpt = excerpts.some((e) =>\n terms.some((t) => e.excerpt.toLowerCase().includes(t)),\n );\n const confidence: ContextPackResult['confidence'] =\n excerpts.length === 0 || (terms.length > 0 && !hasTermInExcerpt) ? 'low' : 'high';\n\n const result: ContextPackResult = { excerpts, neighborhood, sources, totalMatches, confidence };\n if (droppedForBudget) result.truncated = true;\n return result;\n}\n","/**\n * Extract a short excerpt centred on the first occurrence of any query term.\n * Returns at most `maxLen` characters with leading/trailing ellipsis as needed.\n *\n * This is the core context-tax reduction: instead of returning the full note\n * (~7 KB mean, ~70 KB p99), we return ~200 chars of relevant context.\n */\nexport function extractExcerpt(text: string, terms: string[], maxLen = 200): string {\n const lower = text.toLowerCase();\n let bestIdx = -1;\n\n for (const term of terms) {\n const idx = lower.indexOf(term.toLowerCase());\n if (idx !== -1 && (bestIdx === -1 || idx < bestIdx)) {\n bestIdx = idx;\n }\n }\n\n if (bestIdx === -1) {\n // No term found in body (hit may have been in title/tags) — return the start.\n return truncate(text.trimStart(), maxLen);\n }\n\n const half = Math.floor(maxLen / 2);\n const start = Math.max(0, bestIdx - half);\n const end = Math.min(text.length, bestIdx + half + (terms[0]?.length ?? 0));\n const slice = text.slice(start, end).trim();\n\n return `${start > 0 ? '…' : ''}${slice}${end < text.length ? '…' : ''}`;\n}\n\nfunction truncate(s: string, max: number): string {\n if (s.length <= max) return s;\n return `${s.slice(0, max).trimEnd()}…`;\n}\n","/**\n * Resolve a wikilink target string to a vault-relative note path.\n *\n * Uses Obsidian's loose resolution: exact match → add .md → basename match\n * → path-without-extension match. Returns undefined if no note matches.\n *\n * Ambiguity (two notes sharing a basename, or case-variant paths) resolves to\n * the lexicographically smallest note path — deterministic regardless of how\n * the notes map was populated.\n */\n\nexport interface ResolveMaps {\n /** lowercased basename (no .md) → winning note path */\n byBasename: Map<string, string>;\n /** lowercased path without .md → winning note path */\n byPathNoExt: Map<string, string>;\n}\n\n/**\n * Precompute the loose-resolution lookup maps for a notes map. Build once per\n * batch (index build, watcher event) and pass to resolveLink so each loose\n * resolution is O(1) instead of a scan of every note.\n */\nexport function buildResolveMaps(notes: Map<string, unknown>): ResolveMaps {\n const byBasename = new Map<string, string>();\n const byPathNoExt = new Map<string, string>();\n for (const path of notes.keys()) {\n const pathNoExt = path.replace(/\\.md$/i, '').toLowerCase();\n const base = pathNoExt.split('/').pop() ?? pathNoExt;\n const prevBase = byBasename.get(base);\n if (prevBase === undefined || path < prevBase) byBasename.set(base, path);\n const prevPath = byPathNoExt.get(pathNoExt);\n if (prevPath === undefined || path < prevPath) byPathNoExt.set(pathNoExt, path);\n }\n return { byBasename, byPathNoExt };\n}\n\nexport function resolveLink(\n target: string,\n notes: Map<string, unknown>,\n maps?: ResolveMaps,\n): string | undefined {\n if (notes.has(target)) return target;\n const withMd = `${target}.md`;\n if (notes.has(withMd)) return withMd;\n\n const m = maps ?? buildResolveMaps(notes);\n const targetLower = target.toLowerCase();\n const targetBase = targetLower.split('/').pop() ?? targetLower;\n return m.byBasename.get(targetBase) ?? m.byPathNoExt.get(targetLower);\n}\n","import { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { extractExcerpt } from '../index/excerpt.js';\nimport type { SearchHit } from '../index/types.js';\nimport { chunkExcerpt } from '../semantic/excerpt.js';\nimport { MAX_ROUTE_WORDS, queryWords, routeToLexical } from '../semantic/route.js';\nimport type { Semantic } from '../semantic/state.js';\n\nexport const SearchInput = z.object({\n query: z.string().min(1).describe('Search query. Supports fuzzy matching and prefix search.'),\n // Optional (not .default()) so the inferred type keeps existing direct\n // callers compiling; search() itself defaults it to 'lexical'.\n mode: z\n .enum(['lexical', 'semantic', 'hybrid'])\n .optional()\n .describe(\n 'lexical = keyword search (default). semantic = meaning-based search over local embeddings (requires SEEKSTONE_SEMANTIC=1 and a fetched model). hybrid = exact-title lookups go lexical, everything else semantic.',\n ),\n limit: z\n .number()\n .int()\n .min(1)\n .max(50)\n .default(10)\n .describe('Maximum number of results to return.'),\n folder: z\n .string()\n .optional()\n .describe('Restrict results to notes under this vault-relative folder prefix.'),\n tag: z.string().optional().describe('Restrict results to notes containing this tag.'),\n excerptLength: z\n .number()\n .int()\n .min(20)\n .max(2000)\n .optional()\n .describe(\n 'Max characters of match context per hit (default 120). Lower trims payload; higher gives more context.',\n ),\n});\nexport type SearchInput = z.infer<typeof SearchInput>;\n\n/** Semantic candidates fetched before folder/tag filtering (the schema's limit max). */\nconst SEMANTIC_CANDIDATES = 50;\n\n/** Basename without extension — the title is omitted from a hit when it matches this. */\nexport function basenameNoExt(path: string): string {\n const base = path.slice(path.lastIndexOf('/') + 1);\n const dot = base.lastIndexOf('.');\n return dot > 0 ? base.slice(0, dot) : base;\n}\n\nexport interface Retrieval {\n hits: SearchHit[];\n totalCandidates: number;\n}\n\nexport function retrieve(ctx: ServerContext, input: SearchInput): Retrieval {\n // Direct in-process callers bypass the zod defaults — normalize here.\n const mode = input.mode ?? 'lexical';\n if (mode === 'lexical') return lexicalSearch(ctx, input);\n\n const semantic = requireSemantic(ctx);\n if (mode === 'semantic') return semanticSearch(ctx, semantic, input);\n\n // hybrid: an exact-title lookup goes lexical; everything else semantic.\n // Long queries can't plausibly be a title, so they skip MiniSearch entirely\n // (fuzzy matching on long queries is the expensive path).\n const words = queryWords(input.query);\n if (words.length > 0 && words.length <= MAX_ROUTE_WORDS) {\n const lex = lexicalSearch(ctx, input);\n if (\n routeToLexical(\n input.query,\n lex.hits.map((h) => h.path),\n )\n )\n return lex;\n }\n return semanticSearch(ctx, semantic, input);\n}\n\nexport function search(ctx: ServerContext, input: SearchInput): SearchHit[] {\n return retrieve(ctx, input).hits;\n}\n\nfunction requireSemantic(ctx: ServerContext): Semantic {\n if (!ctx.semantic) {\n throw new Error(\n JSON.stringify({\n error: 'semantic_unavailable',\n hint: 'Semantic search is not enabled. Set SEEKSTONE_SEMANTIC=1 in the server env and run `npx -y seekstone fetch-model` once to download the local embedding model, then restart the session. Meanwhile, mode: \"lexical\" works.',\n }),\n );\n }\n const progress = ctx.semantic.progress;\n if (progress.state === 'building') {\n throw new Error(\n JSON.stringify({\n error: 'semantic_building',\n done: progress.done,\n total: progress.total,\n hint: 'The semantic index is still embedding this vault (first run only — later runs load a cache). Retry shortly, or use mode: \"lexical\".',\n }),\n );\n }\n return ctx.semantic;\n}\n\nfunction searchTerms(query: string): string[] {\n return query\n .toLowerCase()\n .split(/\\s+/)\n .filter((t) => t.length > 1);\n}\n\nfunction lexicalSearch(ctx: ServerContext, input: SearchInput): Retrieval {\n const results = ctx.index.search(input.query, {\n boost: { title: 3, tags: 2, body: 1 },\n fuzzy: 0.2,\n prefix: true,\n });\n const terms = searchTerms(input.query);\n\n const hits: SearchHit[] = [];\n for (const r of results) {\n const note = filterNote(ctx, input, r.id);\n if (!note) continue;\n const hit: SearchHit = {\n path: r.id,\n // Round the raw MiniSearch score: 2 decimals preserve relevance gaps without 17-digit float tax.\n score: Math.round(r.score * 100) / 100,\n excerpt: extractExcerpt(note.body, terms, input.excerptLength ?? 120),\n };\n decorate(hit, r.title as string, note.tags);\n hits.push(hit);\n if (hits.length >= input.limit) break;\n }\n return { hits, totalCandidates: results.length };\n}\n\nfunction semanticSearch(ctx: ServerContext, semantic: Semantic, input: SearchInput): Retrieval {\n const queryVec = semantic.embedQuery(input.query);\n // Stage 1: pooled cosine top-50; stage 2: MaxSim rerank (SHA-314).\n // 1-hop graph expansion (semantic/expand.ts) is deliberately NOT wired in:\n // the SHA-315 dev-split eval could not measure a gain on the committed\n // fixture (its links are random by design) — see EXPANSION-SHA-315.md.\n const candidates = semantic.rerank(\n input.query,\n semantic.store.topNotes(queryVec, SEMANTIC_CANDIDATES),\n );\n const terms = searchTerms(input.query);\n\n const hits: SearchHit[] = [];\n for (const c of candidates) {\n const note = filterNote(ctx, input, c.path);\n if (!note) continue;\n const hit: SearchHit = {\n path: c.path,\n // Cosine similarity ∈ [-1, 1]: 3 decimals keep the ranking legible.\n score: Math.round(c.score * 1000) / 1000,\n excerpt: chunkExcerpt(note.body, c, terms, input.excerptLength ?? 120),\n };\n decorate(hit, note.title, note.tags);\n hits.push(hit);\n if (hits.length >= input.limit) break;\n }\n return { hits, totalCandidates: candidates.length };\n}\n\n/** Apply folder/tag filters; returns the note when it passes, else undefined. */\nfunction filterNote(ctx: ServerContext, input: SearchInput, path: string) {\n if (input.folder && !path.startsWith(input.folder)) return undefined;\n const note = ctx.notes.get(path);\n if (!note) return undefined;\n if (input.tag) {\n const noteTags = note.tags.split(' ');\n if (!noteTags.some((t) => t === input.tag || t === input.tag?.replace(/^#/, ''))) {\n return undefined;\n }\n }\n return note;\n}\n\nfunction decorate(hit: SearchHit, title: string, tags: string): void {\n // Omit redundant/empty metadata to keep the payload lean (both are recoverable).\n if (title && title !== basenameNoExt(hit.path)) hit.title = title;\n const noteTags = tags ? tags.split(' ').filter(Boolean) : [];\n if (noteTags.length > 0) hit.tags = noteTags;\n}\n","import { extractExcerpt } from '../index/excerpt.js';\n\n/**\n * Excerpt for a semantic hit: slice the winning chunk's span out of the\n * note's in-memory body (spans were recorded at embed time, so there is no\n * re-chunking on the query path) and excerpt within it. Query terms often\n * don't literally appear in a semantic match, in which case extractExcerpt\n * falls back to the START of the matching chunk — the relevant passage —\n * instead of the head of the note.\n */\nexport function chunkExcerpt(\n body: string,\n span: { start: number; end: number },\n terms: string[],\n maxLen: number,\n): string {\n // Spans are offsets into the CRLF-normalized body (chunkNote normalizes).\n const normalized = body.includes('\\r') ? body.replace(/\\r\\n/g, '\\n') : body;\n // The note may have changed inside the re-embed debounce window — clamp.\n const start = Math.min(span.start, normalized.length);\n const end = Math.min(Math.max(span.end, start), normalized.length);\n const text = start === end ? normalized : normalized.slice(start, end);\n return extractExcerpt(text, terms, maxLen);\n}\n","/**\n * Hybrid-mode query routing, the recipe the SHA-307 golden-set eval chose\n * over RRF and score-weighted fusion: a query goes to lexical search only\n * when it IS a top lexical hit's title — the hit's basename words and the\n * query words are the same set. Exact-name lookups are what MiniSearch's 3×\n * title boost wins; a query that merely *contains* a title (\"green\n * gemstones\" vs a note titled \"Green\") is describing, not naming, and stays\n * semantic. (The same rule lives in the harness's retrieval/fusion.ts, where\n * the eval that picked it runs.)\n */\n\n/** Queries longer than this cannot plausibly be a title — skip lexical entirely. */\nexport const MAX_ROUTE_WORDS = 6;\n\nexport function queryWords(query: string): string[] {\n return query.toLowerCase().split(/\\W+/).filter(Boolean);\n}\n\nexport function routeToLexical(query: string, topPaths: readonly string[], topN = 3): boolean {\n const words = new Set(queryWords(query));\n if (words.size === 0) return false;\n return topPaths.slice(0, topN).some((path) => {\n const base = (path.split('/').pop() ?? '').replace(/\\.md$/, '').toLowerCase();\n const parts = new Set(base.split(/\\W+/).filter(Boolean));\n return parts.size === words.size && [...parts].every((p) => words.has(p));\n });\n}\n","import { access, mkdir, readFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { stringify as stringifyYaml } from 'yaml';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { buildDoc, upsertDoc } from '../index/doc.js';\nimport { journalWrite } from '../journal.js';\nimport { assertWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const CreateNoteInput = z\n .object({\n path: z\n .string()\n .describe(\n 'Vault-relative path for the new note, e.g. \"Daily Notes/2026-06-01.md\". Parent directories are created automatically.',\n ),\n content: z.string().default('').describe('Body content for the note.'),\n frontmatter: z\n .record(z.string(), z.unknown())\n .optional()\n .describe('Frontmatter key-value pairs to write as a YAML block at the top of the note.'),\n overwrite: z\n .boolean()\n .default(false)\n .describe(\n 'Overwrite an existing note. Defaults to false — throws if the note already exists.',\n ),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard for overwrite: true — the contentHash of the note being replaced. Fails with hash_conflict if it changed since it was read.',\n ),\n })\n .refine((v) => v.prevHash === undefined || v.overwrite === true, {\n message:\n 'prevHash only makes sense with overwrite: true (a fresh create has no prior version).',\n });\nexport type CreateNoteInput = z.input<typeof CreateNoteInput>;\n\nexport interface CreateNoteResult {\n path: string;\n bytesWritten: number;\n /** sha-256 (hex) of the written content — usable as prevHash for a chained edit. */\n contentHash: string;\n}\n\nexport async function createNote(\n ctx: ServerContext,\n rawInput: CreateNoteInput,\n): Promise<CreateNoteResult> {\n const input = CreateNoteInput.parse(rawInput);\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n assertWritable(ctx.policy, input.path);\n\n // Pre-image for the journal: the note being overwritten, or null for a\n // fresh create (undo then removes the file).\n let existing: string | null = null;\n if (!input.overwrite) {\n try {\n await access(absPath);\n throw new Error(`Note already exists: ${input.path}. Pass overwrite: true to replace it.`);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n } else {\n try {\n existing = await readFile(absPath, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n if (input.prevHash !== undefined) {\n // CAS on the note being replaced; a missing file is a conflict too\n // (the version the caller read no longer exists).\n throw new Error(\n JSON.stringify({\n error: 'hash_conflict',\n path: input.path,\n expected: input.prevHash,\n actual: null,\n hint: 'The note no longer exists on disk. Re-check before overwriting.',\n }),\n );\n }\n }\n if (existing !== null && input.prevHash !== undefined) {\n assertHashMatch(existing, input.prevHash, input.path);\n }\n }\n\n let raw = '';\n if (input.frontmatter && Object.keys(input.frontmatter).length > 0) {\n raw = `---\\n${stringifyYaml(input.frontmatter, { lineWidth: 0 })}---\\n`;\n }\n raw += input.content ?? '';\n\n await mkdir(dirname(absPath), { recursive: true });\n await journalWrite(ctx, 'create_note', input.path, existing, raw);\n await atomicWrite(absPath, raw);\n\n // Sync in-memory index so the new note is immediately searchable.\n upsertDoc(ctx, buildDoc(input.path, raw));\n\n return {\n path: input.path,\n bytesWritten: Buffer.byteLength(raw, 'utf8'),\n contentHash: contentHash(raw),\n };\n}\n","import { basename, extname } from 'node:path';\nimport { extractInlineTags, frontmatterTags } from '@seekstone/core/extract';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport type { IndexedNote } from './types.js';\n\n/** Build an IndexedNote from a vault-relative path and raw file content. */\nexport function buildDoc(relPath: string, raw: string): IndexedNote {\n const fm = parseFrontmatter(raw);\n const allTags = [...new Set([...extractInlineTags(fm.body), ...frontmatterTags(fm.data)])];\n const title =\n typeof fm.data?.title === 'string' && fm.data.title\n ? fm.data.title\n : basename(relPath, extname(relPath));\n return {\n id: relPath,\n title,\n body: fm.body,\n tags: allTags.join(' '),\n fmKeys: fm.keys.join(' '),\n fm: fm.data,\n raw,\n sizeBytes: Buffer.byteLength(raw, 'utf8'),\n mtimeMs: Date.now(),\n };\n}\n\n/** Upsert a document into the context index. Discards any stale entry first. */\nexport function upsertDoc(\n ctx: {\n index: { discard(id: string): void; add(doc: IndexedNote): void };\n notes: Map<string, IndexedNote>;\n },\n doc: IndexedNote,\n): void {\n if (ctx.notes.has(doc.id)) ctx.index.discard(doc.id);\n ctx.notes.set(doc.id, doc);\n ctx.index.add(doc);\n}\n","import { access, mkdir, readFile, rename, rm } from 'node:fs/promises';\nimport { basename, extname, join } from 'node:path';\nimport { z } from 'zod';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { removeNoteBacklinks } from '../index/backlinks.js';\nimport { journalWrite } from '../journal.js';\nimport { assertWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const DeleteNoteInput = z.object({\n path: z.string().describe('Vault-relative path of the note to delete.'),\n permanent: z\n .boolean()\n .default(false)\n .describe(\n 'Permanently remove the note instead of moving it to the vault .trash/ folder. Defaults to false — deletes are recoverable.',\n ),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since — so you never delete content you have not seen.',\n ),\n});\nexport type DeleteNoteInput = z.input<typeof DeleteNoteInput>;\n\nexport interface DeleteNoteResult {\n path: string;\n /** Vault-relative path the note was moved to, when not permanent. */\n trashedTo?: string;\n permanent: boolean;\n /** sha-256 (hex) of the deleted content — for a recoverable delete this is the hash of the byte-identical file now in .trash/. */\n contentHash: string;\n}\n\n/** Find a free destination name inside .trash/, suffixing before the extension on collision. */\nasync function freeTrashPath(vaultRoot: string, noteBase: string): Promise<string> {\n const ext = extname(noteBase);\n const stem = noteBase.slice(0, noteBase.length - ext.length);\n let candidate = `.trash/${noteBase}`;\n for (;;) {\n try {\n await access(join(vaultRoot, candidate));\n } catch {\n return candidate;\n }\n // Epoch-ms suffix; loop guards the (test-speed) case of two collisions in one ms.\n candidate = `.trash/${stem}.${Date.now()}${ext}`;\n }\n}\n\nexport async function deleteNote(\n ctx: ServerContext,\n rawInput: DeleteNoteInput,\n): Promise<DeleteNoteResult> {\n const input = DeleteNoteInput.parse(rawInput);\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n // Policy applies to the note being deleted; the .trash/ destination is the\n // safety mechanism itself, not a user write.\n assertWritable(ctx.policy, input.path);\n\n // Read before deleting: ENOENT propagates for a missing note (same shape rm\n // gave), the bytes are the CAS identity, and the hash documents exactly\n // what was deleted (byte-identical to the .trash/ copy when recoverable).\n const raw = await readFile(absPath, 'utf8');\n if (input.prevHash !== undefined) assertHashMatch(raw, input.prevHash, input.path);\n\n // Journaled whether or not the delete is permanent: undo_write restores\n // the bytes from the journal, so even permanent: true is reversible.\n await journalWrite(ctx, 'delete_note', input.path, raw, null);\n\n let trashedTo: string | undefined;\n if (input.permanent) {\n await rm(absPath);\n } else {\n await mkdir(join(ctx.vaultRoot, '.trash'), { recursive: true });\n trashedTo = await freeTrashPath(ctx.vaultRoot, basename(input.path));\n // Same-volume rename: atomic, byte-identical, and invisible to the index —\n // the walker and watcher both exclude .trash/.\n await rename(absPath, join(ctx.vaultRoot, trashedTo));\n }\n\n // Clear the note's own outgoing refs while its entry is still readable.\n removeNoteBacklinks(ctx, input.path);\n if (ctx.notes.has(input.path)) {\n ctx.index.discard(input.path);\n ctx.notes.delete(input.path);\n }\n\n const result: DeleteNoteResult = {\n path: input.path,\n permanent: input.permanent,\n contentHash: contentHash(raw),\n };\n if (trashedTo !== undefined) result.trashedTo = trashedTo;\n return result;\n}\n","import { extractLinksWithLines } from '@seekstone/core/extract';\nimport type { BacklinkRef, ServerContext } from '../context.js';\nimport { buildResolveMaps, resolveLink } from './resolve.js';\n\n/**\n * Incremental backlink-index maintenance, shared by the watcher and the\n * link-aware move path. Remove BEFORE mutating the note's entry in ctx.notes\n * (it reads the old raw); add AFTER the entry is current.\n */\n\nexport function removeNoteBacklinks(ctx: ServerContext, relPath: string): void {\n const oldDoc = ctx.notes.get(relPath);\n if (oldDoc === undefined) return;\n const links = extractLinksWithLines(oldDoc.raw);\n if (links.length === 0) return;\n const maps = buildResolveMaps(ctx.notes);\n for (const link of links) {\n const resolved = resolveLink(link.target, ctx.notes, maps);\n if (resolved === undefined) continue;\n const arr = ctx.backlinks.get(resolved);\n if (arr === undefined) continue;\n const filtered = arr.filter((r) => r.path !== relPath);\n ctx.backlinks.set(resolved, filtered);\n }\n}\n\nexport function addNoteBacklinks(ctx: ServerContext, relPath: string, raw: string): void {\n const seen = new Set<string>();\n const links = extractLinksWithLines(raw);\n if (links.length === 0) return;\n const maps = buildResolveMaps(ctx.notes);\n for (const link of links) {\n const resolved = resolveLink(link.target, ctx.notes, maps);\n if (resolved === undefined) continue;\n const dedupeKey = `${relPath}\\0${resolved}`;\n if (seen.has(dedupeKey)) continue;\n seen.add(dedupeKey);\n let arr = ctx.backlinks.get(resolved);\n if (arr === undefined) {\n arr = [];\n ctx.backlinks.set(resolved, arr);\n }\n const ref: BacklinkRef = { path: relPath, line: link.line, linkType: link.linkType };\n arr.push(ref);\n arr.sort((a, b) => a.path.localeCompare(b.path));\n }\n}\n","import { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const GetBacklinksInput = z.object({\n path: z.string().describe('Vault-relative path to the target note.'),\n includeContext: z\n .boolean()\n .optional()\n .describe('Include a short excerpt (~200 chars) from the linking line. Default true.'),\n limit: z\n .number()\n .int()\n .min(1)\n .max(500)\n .optional()\n .describe('Max backlinks to return. Default 50.'),\n});\nexport type GetBacklinksInput = z.infer<typeof GetBacklinksInput>;\n\nexport interface BacklinkEntry {\n path: string;\n line: number;\n excerpt?: string;\n linkType: 'wikilink' | 'embed';\n}\n\nexport interface GetBacklinksResult {\n target: string;\n backlinks: BacklinkEntry[];\n total: number;\n}\n\nconst EXCERPT_MAX = 200;\n\nexport function getBacklinks(ctx: ServerContext, input: GetBacklinksInput): GetBacklinksResult {\n resolveVaultPath(ctx.vaultRoot, input.path); // containment validation only\n\n const includeContext = input.includeContext ?? true;\n const limit = input.limit ?? 50;\n\n const refs = ctx.backlinks.get(input.path) ?? [];\n const total = refs.length;\n const limited = refs.slice(0, limit);\n\n const backlinks: BacklinkEntry[] = [];\n for (const ref of limited) {\n const entry: BacklinkEntry = { path: ref.path, line: ref.line, linkType: ref.linkType };\n if (includeContext) {\n const srcNote = ctx.notes.get(ref.path);\n if (srcNote !== undefined) {\n const rawLines = srcNote.raw.split('\\n');\n const lineText = rawLines[ref.line - 1];\n if (lineText !== undefined) {\n entry.excerpt =\n lineText.length > EXCERPT_MAX ? `${lineText.slice(0, EXCERPT_MAX)}…` : lineText;\n }\n }\n }\n backlinks.push(entry);\n }\n\n return { target: input.path, backlinks, total };\n}\n","import type { LinkType } from '@seekstone/core/extract';\nimport { extractLinksWithLines } from '@seekstone/core/extract';\nimport { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { resolveLink } from '../index/resolve.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const GetLinksInput = z.object({\n path: z.string().describe('Vault-relative path to the note.'),\n});\nexport type GetLinksInput = z.infer<typeof GetLinksInput>;\n\nexport interface GetLinksEntry {\n raw: string;\n /** Resolved vault-relative path. Absent when unresolved. */\n target?: string;\n resolved: boolean;\n linkType: LinkType;\n line: number;\n}\n\nexport interface GetLinksResult {\n path: string;\n links: GetLinksEntry[];\n}\n\nexport function getLinks(ctx: ServerContext, input: GetLinksInput): GetLinksResult {\n resolveVaultPath(ctx.vaultRoot, input.path); // containment validation only\n const note = ctx.notes.get(input.path);\n if (note === undefined) throw new Error(`Note not found: ${input.path}`);\n\n const rawLinks = extractLinksWithLines(note.raw);\n\n // De-duplicate: one entry per (target string) — keep first occurrence by line\n const seen = new Set<string>();\n const links: GetLinksEntry[] = [];\n for (const link of rawLinks) {\n if (seen.has(link.target)) continue;\n seen.add(link.target);\n const resolvedPath = resolveLink(link.target, ctx.notes);\n const entry: GetLinksEntry = {\n raw: link.raw,\n resolved: resolvedPath !== undefined,\n linkType: link.linkType,\n line: link.line,\n };\n if (resolvedPath !== undefined) entry.target = resolvedPath;\n links.push(entry);\n }\n\n links.sort((a, b) => a.line - b.line);\n\n return { path: input.path, links };\n}\n","import { z } from 'zod';\nimport type { ServerContext } from '../context.js';\n\nexport const ListNotesInput = z.object({\n folder: z\n .string()\n .optional()\n .describe(\n 'Vault-relative folder prefix to list. Omit for all notes. Example: \"Daily Notes/2026\".',\n ),\n tag: z.string().optional().describe('Filter by tag. Include or omit the leading #.'),\n limit: z.number().int().min(1).max(500).default(100).describe('Maximum number of results.'),\n});\nexport type ListNotesInput = z.infer<typeof ListNotesInput>;\n\nexport interface NoteEntry {\n path: string;\n title: string;\n tags: string[];\n sizeBytes: number;\n}\n\nexport function listNotes(ctx: ServerContext, input: ListNotesInput): NoteEntry[] {\n const tag = input.tag?.replace(/^#/, '');\n const results: NoteEntry[] = [];\n\n for (const [path, note] of ctx.notes) {\n if (input.folder && !path.startsWith(input.folder)) continue;\n if (tag) {\n const noteTags = note.tags.split(' ').filter(Boolean);\n if (!noteTags.includes(tag)) continue;\n }\n results.push({\n path,\n title: note.title,\n tags: note.tags.split(' ').filter(Boolean),\n sizeBytes: note.sizeBytes,\n });\n if (results.length >= input.limit) break;\n }\n\n return results.sort((a, b) => a.path.localeCompare(b.path));\n}\n","import { z } from 'zod';\nimport type { ServerContext } from '../context.js';\n\nexport const ListTagsInput = z.object({\n pattern: z\n .string()\n .optional()\n .describe('Substring filter on tag name. Example: \"work\" matches \"work\" and \"area/work\".'),\n minCount: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe('Only return tags used in at least this many notes.'),\n sort: z\n .enum(['count', 'name'])\n .default('count')\n .describe('Sort by usage count descending (default) or alphabetically.'),\n});\nexport type ListTagsInput = z.infer<typeof ListTagsInput>;\n\nexport interface TagEntry {\n tag: string;\n count: number;\n parent?: string;\n}\n\nexport interface ListTagsResult {\n tags: TagEntry[];\n total: number;\n}\n\nexport function listTags(ctx: ServerContext, input: ListTagsInput): ListTagsResult {\n const counts = new Map<string, number>();\n\n for (const note of ctx.notes.values()) {\n for (const tag of note.tags.split(' ').filter(Boolean)) {\n counts.set(tag, (counts.get(tag) ?? 0) + 1);\n }\n }\n\n const tags: TagEntry[] = [];\n for (const [tag, count] of counts) {\n if (input.pattern !== undefined && !tag.includes(input.pattern)) continue;\n if (input.minCount !== undefined && count < input.minCount) continue;\n const slashIdx = tag.lastIndexOf('/');\n const entry: TagEntry = { tag, count };\n if (slashIdx !== -1) entry.parent = tag.slice(0, slashIdx);\n tags.push(entry);\n }\n\n if (input.sort === 'name') {\n tags.sort((a, b) => a.tag.localeCompare(b.tag));\n } else {\n tags.sort((a, b) => b.count - a.count || a.tag.localeCompare(b.tag));\n }\n\n return { tags, total: tags.length };\n}\n","import { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport type { JournalListRow } from '../journal.js';\n\nexport const ListWritesInput = z.object({\n limit: z\n .number()\n .int()\n .min(1)\n .max(200)\n .default(20)\n .describe('Max entries to return, newest first (1–200, default 20).'),\n path: z.string().optional().describe('Only entries that touched this vault-relative path.'),\n});\nexport type ListWritesInput = z.input<typeof ListWritesInput>;\n\nexport interface ListWritesResult {\n /** Newest first. Metadata only — no note content. */\n writes: JournalListRow[];\n /** Total matching entries in the journal (before `limit`). */\n total: number;\n /** Present (true) only when the journal is disabled via SEEKSTONE_HISTORY=0. */\n disabled?: true;\n}\n\n/** Recent journal entries — what `undo_write` can revert. */\nexport function listWrites(ctx: ServerContext, rawInput: ListWritesInput): ListWritesResult {\n const input = ListWritesInput.parse(rawInput);\n if (!ctx.journal) return { writes: [], total: 0, disabled: true };\n const opts: { limit: number; path?: string } = { limit: input.limit };\n if (input.path !== undefined) opts.path = input.path;\n return ctx.journal.list(opts);\n}\n","import { mkdir, readFile, rename } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { addNoteBacklinks, removeNoteBacklinks } from '../index/backlinks.js';\nimport { buildDoc, upsertDoc } from '../index/doc.js';\nimport { assertWritable, isWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\nimport { hasMarkdownLinkTo, rewriteNoteLinks } from './rewrite_links.js';\n\nexport const MoveNoteInput = z.object({\n from: z.string().describe('Vault-relative path of the note to move.'),\n to: z.string().describe('Vault-relative destination path.'),\n overwrite: z\n .boolean()\n .default(false)\n .describe('Overwrite the destination if it exists. Defaults to false.'),\n rewriteLinks: z\n .boolean()\n .default(true)\n .describe(\n 'Rewrite wikilinks and markdown links in other notes that point at the moved note, so nothing breaks. Defaults to true; pass false to move the file only.',\n ),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard on the source note: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n ),\n});\nexport type MoveNoteInput = z.input<typeof MoveNoteInput>;\n\nexport interface MoveNoteResult {\n from: string;\n to: string;\n /** Referencing notes whose content was rewritten. */\n notesRewritten: number;\n /** Individual links rewritten across those notes. */\n linksRewritten: number;\n /** Referencing notes left untouched because SEEKSTONE_WRITE_PATHS excludes them. */\n skipped?: string[];\n /** sha-256 (hex) of the note at its new path — a move never changes content, so this is usable as prevHash for a chained edit at `to`. */\n contentHash: string;\n}\n\nexport async function moveNote(\n ctx: ServerContext,\n rawInput: MoveNoteInput,\n): Promise<MoveNoteResult> {\n // Parse here (not only in dispatch) so defaults like rewriteLinks apply to\n // direct callers too — same pattern as periodic_note.\n const input = MoveNoteInput.parse(rawInput);\n const absFrom = resolveVaultPath(ctx.vaultRoot, input.from);\n const absTo = resolveVaultPath(ctx.vaultRoot, input.to);\n assertWritable(ctx.policy, input.from);\n assertWritable(ctx.policy, input.to);\n\n // Read the source bytes up front: they are the CAS identity, the result\n // hash (a rename never changes content), and the truth the index entry at\n // the new path is rebuilt from (more reliable than a possibly-lagging\n // ctx.notes cache).\n let raw: string;\n try {\n raw = await readFile(absFrom, 'utf8');\n } catch {\n throw new Error(`Note not found: ${input.from}`);\n }\n if (input.prevHash !== undefined) assertHashMatch(raw, input.prevHash, input.from);\n\n // Pre-image of the destination (only ever non-null with overwrite: true).\n let existingAtTo: string | null = null;\n try {\n existingAtTo = await readFile(absTo, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n if (existingAtTo !== null && !input.overwrite) {\n throw new Error(`Destination already exists: ${input.to}. Pass overwrite: true to replace it.`);\n }\n\n // Snapshot pre-move state: link resolution before/after the move differs,\n // and the rewriter needs both views to rewrite only what breaks.\n const preNotes = new Map(ctx.notes);\n\n // Candidate referencing notes: wikilink sources from the backlink index,\n // plus a scan for markdown links (which the backlink index doesn't cover).\n // The moved note's own outgoing links are untouched by design — wikilinks\n // are path-independent, and rewriting its relative markdown links is a\n // separate concern from \"don't orphan the note in the graph\".\n const candidates = new Set<string>();\n if (input.rewriteLinks) {\n for (const ref of ctx.backlinks.get(input.from) ?? []) candidates.add(ref.path);\n for (const [path, doc] of preNotes) {\n if (path === input.from || candidates.has(path)) continue;\n if (hasMarkdownLinkTo(doc.raw, path, input.from)) candidates.add(path);\n }\n candidates.delete(input.from);\n }\n\n // Compute every link rewrite against the post-move resolution view BEFORE\n // touching disk, so the whole operation can be journaled under one seq\n // (undo restores all touched files or none) before the first byte changes.\n const postNotes = new Map(preNotes);\n postNotes.delete(input.from);\n postNotes.set(input.to, buildDoc(input.to, raw));\n\n const rewrites: { path: string; pre: string; content: string; count: number }[] = [];\n const skipped: string[] = [];\n for (const path of [...candidates].sort()) {\n const doc = preNotes.get(path);\n if (doc === undefined) continue;\n if (!isWritable(ctx.policy, path)) {\n // Out of write scope: leave the note untouched but report it, so the\n // caller knows which references were NOT updated.\n skipped.push(path);\n continue;\n }\n const { content, count } = rewriteNoteLinks(\n doc.raw,\n path,\n input.from,\n input.to,\n preNotes,\n postNotes,\n );\n rewrites.push({ path, pre: doc.raw, content, count });\n }\n\n if (ctx.journal) {\n const txn = ctx.journal.begin('move_note');\n await txn.add(input.from, raw, null);\n await txn.add(input.to, existingAtTo, raw);\n for (const r of rewrites) if (r.count > 0) await txn.add(r.path, r.pre, r.content);\n await txn.commit();\n }\n\n await mkdir(dirname(absTo), { recursive: true });\n await rename(absFrom, absTo);\n\n // Clear the moved note's own outgoing backlink refs while its old entry is\n // still readable — otherwise they stay registered under the stale source\n // path forever.\n removeNoteBacklinks(ctx, input.from);\n\n if (ctx.notes.has(input.from)) {\n ctx.index.discard(input.from);\n ctx.notes.delete(input.from);\n }\n upsertDoc(ctx, buildDoc(input.to, raw));\n addNoteBacklinks(ctx, input.to, raw);\n\n let notesRewritten = 0;\n let linksRewritten = 0;\n\n for (const { path, content, count } of rewrites) {\n const doc = ctx.notes.get(path);\n if (doc === undefined) continue;\n // Re-register this note's backlinks against post-move resolution even\n // when nothing was rewritten (basename links now resolve to the new\n // path); remove reads the old raw, so call it before updating the entry.\n removeNoteBacklinks(ctx, path);\n if (count > 0) {\n await atomicWrite(join(ctx.vaultRoot, path), content);\n upsertDoc(ctx, buildDoc(path, content));\n notesRewritten++;\n linksRewritten += count;\n addNoteBacklinks(ctx, path, content);\n } else {\n addNoteBacklinks(ctx, path, doc.raw);\n }\n }\n\n // Nothing resolves to the old path anymore — drop the stale key.\n ctx.backlinks.delete(input.from);\n\n const result: MoveNoteResult = {\n from: input.from,\n to: input.to,\n notesRewritten,\n linksRewritten,\n contentHash: contentHash(raw),\n };\n if (skipped.length > 0) result.skipped = skipped;\n return result;\n}\n","import { posix } from 'node:path';\nimport { resolveLink } from '../index/resolve.js';\n\n/**\n * Pure link-rewriting for link-aware moves: given a referencing note's raw\n * content, rewrite every wikilink, embed, and relative/vault-absolute markdown\n * link that pointed at `oldPath` so it points at `newPath`.\n *\n * Principles:\n * - **Rewrite only what breaks.** A link is left byte-identical when it still\n * resolves to the moved note after the move (Obsidian's shortest-unique-\n * basename semantics — e.g. `[[Italy]]` survives a folder move unchanged).\n * - **Preserve everything around the target**: embed `!`, `#fragment`,\n * `|alias`, `%20`-encoding and `<...>` wrapping in markdown links.\n * - **Skip fenced code blocks** (``` / ~~~). Inline backtick spans are NOT\n * skipped — consistent with the repo's deliberately loose link parsing.\n *\n * `preNotes` is the notes map as it was before the move (oldPath present),\n * `postNotes` after (newPath present) — both are needed to decide whether a\n * link used to point at the moved note and whether it still does.\n */\n\n// Mirrors LINK_WITH_LINES_RE in @seekstone/core/extract (same bounded\n// quantifiers), split into groups for reconstruction.\nconst WIKI_RE = /(!?)\\[\\[([^\\]|#\\n]{1,512})(#[^\\]|\\n]{1,512})?(\\|[^\\]\\n]{1,512})?\\]\\]/g;\n\n// Markdown links/embeds: target is everything to the first `)` (titles like\n// `[t](x \"title\")` are out of scope, matching the loose-parsing ethos).\nconst MD_RE = /(!?)\\[([^\\]\\n]*)\\]\\(([^)\\n]+)\\)/g;\n\nconst FENCE_RE = /^\\s*(```|~~~)/;\n\n/**\n * Map `fn` over every line outside fenced code blocks (``` / ~~~), leaving\n * fence delimiters and fenced content byte-identical. Shared by the move and\n * rename-heading rewriters.\n */\nexport function mapUnfencedLines(raw: string, fn: (line: string) => string): string {\n let inFence = false;\n return raw\n .split('\\n')\n .map((line) => {\n if (FENCE_RE.test(line)) {\n inFence = !inFence;\n return line;\n }\n return inFence ? line : fn(line);\n })\n .join('\\n');\n}\n\nexport interface RewriteNoteLinksResult {\n content: string;\n /** Number of individual links rewritten. */\n count: number;\n}\n\n/** Shortest target that still uniquely resolves to newPath: basename if unambiguous, else full path. */\nfunction wikiTargetFor(newPath: string, postNotes: Map<string, unknown>): string {\n const noExt = newPath.replace(/\\.md$/i, '');\n const base = noExt.split('/').pop() ?? noExt;\n // Count basename collisions directly — resolveLink breaks ties toward the\n // lexicographically smallest path, but \"resolves for us\" is not the same as\n // \"unambiguous in Obsidian\".\n const baseLower = base.toLowerCase();\n let matches = 0;\n for (const p of postNotes.keys()) {\n const pBase = (p.replace(/\\.md$/i, '').split('/').pop() ?? '').toLowerCase();\n if (pBase === baseLower && ++matches > 1) return noExt;\n }\n return base;\n}\n\n/** Interpret a markdown-link target as a vault-relative note path (or undefined). */\nfunction mdTargetToVaultPath(rawTarget: string, sourceDir: string): string | undefined {\n let t = rawTarget.trim();\n if (t.startsWith('<') && t.endsWith('>')) t = t.slice(1, -1);\n if (/^[a-z][a-z0-9+.-]*:/i.test(t)) return undefined; // http:, mailto:, obsidian:, …\n if (t.startsWith('#') || t === '') return undefined; // intra-note anchor\n const hashIdx = t.indexOf('#');\n if (hashIdx !== -1) t = t.slice(0, hashIdx);\n try {\n t = decodeURIComponent(t);\n } catch {\n /* malformed escape — use as-is */\n }\n const joined = posix.normalize(posix.join(sourceDir, t));\n if (joined.startsWith('..')) return undefined; // escapes the vault\n return joined;\n}\n\nexport function rewriteNoteLinks(\n raw: string,\n sourcePath: string,\n oldPath: string,\n newPath: string,\n preNotes: Map<string, unknown>,\n postNotes: Map<string, unknown>,\n): RewriteNoteLinksResult {\n const sourceDir = posix.dirname(sourcePath);\n const oldNoExt = oldPath.replace(/\\.md$/i, '');\n let count = 0;\n\n const rewriteWikiLine = (line: string): string =>\n line.replace(WIKI_RE, (full, bang: string, target: string, frag?: string, alias?: string) => {\n const t = target.trim();\n // Still resolves to the moved note → Obsidian keeps working; don't touch.\n if (resolveLink(t, postNotes) === newPath) return full;\n // Only rewrite links that used to point at the moved note.\n if (resolveLink(t, preNotes) !== oldPath) return full;\n count++;\n const next = wikiTargetFor(newPath, postNotes);\n return `${bang}[[${next}${frag ?? ''}${alias ?? ''}]]`;\n });\n\n const rewriteMdLine = (line: string): string =>\n line.replace(MD_RE, (full, bang: string, text: string, rawTarget: string) => {\n // Relative-to-source interpretation first, then vault-absolute.\n const asRelative = mdTargetToVaultPath(rawTarget, sourceDir);\n const asAbsolute = mdTargetToVaultPath(rawTarget, '.');\n let vaultAbsoluteStyle: boolean;\n if (asRelative === oldPath || asRelative === oldNoExt) vaultAbsoluteStyle = false;\n else if (asAbsolute === oldPath || asAbsolute === oldNoExt) vaultAbsoluteStyle = true;\n else return full;\n count++;\n\n const trimmed = rawTarget.trim();\n const wrapped = trimmed.startsWith('<') && trimmed.endsWith('>');\n const inner = wrapped ? trimmed.slice(1, -1) : trimmed;\n const hashIdx = inner.indexOf('#');\n const fragment = hashIdx === -1 ? '' : inner.slice(hashIdx);\n const hadExt = /\\.md(#|$)/i.test(inner);\n\n let next = vaultAbsoluteStyle ? newPath : posix.relative(sourceDir, newPath);\n if (!hadExt) next = next.replace(/\\.md$/i, '');\n // Preserve the original encoding style for spaces; wrap in <> when the\n // new path has spaces and the original used neither style.\n if (inner.includes('%20')) next = next.replaceAll(' ', '%20');\n const needsWrap = wrapped || next.includes(' ');\n const target = needsWrap ? `<${next}${fragment}>` : `${next}${fragment}`;\n return `${bang}[${text}](${target})`;\n });\n\n const content = mapUnfencedLines(raw, (line) => rewriteMdLine(rewriteWikiLine(line)));\n\n return { content, count };\n}\n\n/**\n * Scan a note's raw content for markdown links resolving to `targetPath` —\n * the candidate-discovery pass for referencing notes the backlink index can't\n * see (it only indexes wikilinks).\n */\nexport function hasMarkdownLinkTo(raw: string, sourcePath: string, targetPath: string): boolean {\n if (!raw.includes('](')) return false;\n const sourceDir = posix.dirname(sourcePath);\n const noExt = targetPath.replace(/\\.md$/i, '');\n for (const m of raw.matchAll(MD_RE)) {\n const rawTarget = m[3] ?? '';\n const asRelative = mdTargetToVaultPath(rawTarget, sourceDir);\n const asAbsolute = mdTargetToVaultPath(rawTarget, '.');\n if (\n asRelative === targetPath ||\n asRelative === noExt ||\n asAbsolute === targetPath ||\n asAbsolute === noExt\n ) {\n return true;\n }\n }\n return false;\n}\n","import { readFile } from 'node:fs/promises';\nimport { buildOutline } from '@seekstone/core/outline';\nimport { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const OutlineNoteInput = z.object({\n path: z.string().describe('Vault-relative path to the note.'),\n includeBlocks: z\n .boolean()\n .default(true)\n .describe('Include block-reference anchors (^id). Default true.'),\n includeSizes: z\n .boolean()\n .default(false)\n .describe('Include per-section character length in each heading entry. Default false.'),\n});\nexport type OutlineNoteInput = z.infer<typeof OutlineNoteInput>;\n\nexport async function outlineNote(ctx: ServerContext, input: OutlineNoteInput) {\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n\n const raw = await readFile(absPath, 'utf8');\n return buildOutline(raw, {\n includeBlocks: input.includeBlocks,\n includeSizes: input.includeSizes,\n });\n}\n","import { parseFrontmatter } from './frontmatter.js';\n\nexport interface HeadingEntry {\n text: string;\n level: number;\n /** 1-based line number in the file. */\n line: number;\n /** Character offset of the leading `#` in the raw file string. */\n byteOffset: number;\n /** Characters from this heading to the next (or end of file). Only present when includeSizes is true. */\n byteLength?: number;\n}\n\nexport interface BlockEntry {\n id: string;\n /** 1-based line number in the file. */\n line: number;\n /** Character offset of the `^` in the raw file string. */\n byteOffset: number;\n}\n\nexport interface NoteOutline {\n headings: HeadingEntry[];\n blocks: BlockEntry[];\n /** Top-level frontmatter keys in original order (empty if no frontmatter). */\n frontmatterKeys: string[];\n /** True UTF-8 byte length of the file. */\n totalBytes: number;\n}\n\nexport interface OutlineOptions {\n /** Include block-reference anchors (^id). Default true. */\n includeBlocks?: boolean;\n /** Include per-section character length in each heading entry. Default false. */\n includeSizes?: boolean;\n}\n\nconst HEADING_RE = /^(#{1,6})\\s+(.+)/;\nconst BLOCK_REF_RE = /\\^([a-zA-Z0-9-]+)$/;\n\n/**\n * Parse a note's structure — heading tree, block anchors, frontmatter keys —\n * without touching the prose. Shared by outline_note and patch_note.\n *\n * Offsets are character positions in the raw string (identical to UTF-8 byte\n * offsets for ASCII content, which covers the vast majority of vault notes).\n */\nexport function buildOutline(raw: string, options: OutlineOptions = {}): NoteOutline {\n const { includeBlocks = true, includeSizes = false } = options;\n\n const fm = parseFrontmatter(raw);\n const totalBytes = Buffer.byteLength(raw, 'utf8');\n const headings: HeadingEntry[] = [];\n const blocks: BlockEntry[] = [];\n\n let charOffset = 0;\n\n for (const [i, line] of raw.split('\\n').entries()) {\n const lineCharOffset = charOffset;\n const lineNum = i + 1;\n\n if (charOffset >= fm.bodyStart) {\n const hm = HEADING_RE.exec(line);\n if (hm) {\n headings.push({\n text: (hm[2] ?? '').trim(),\n level: (hm[1] ?? '').length,\n line: lineNum,\n byteOffset: lineCharOffset,\n });\n }\n\n if (includeBlocks) {\n const trimmed = line.trimEnd();\n const bm = BLOCK_REF_RE.exec(trimmed);\n if (bm) {\n const caretPos = trimmed.lastIndexOf('^');\n blocks.push({\n id: bm[1] ?? '',\n line: lineNum,\n byteOffset: lineCharOffset + caretPos,\n });\n }\n }\n }\n\n charOffset += line.length + 1; // +1 for the '\\n' consumed by split\n }\n\n if (includeSizes) {\n for (const [i, heading] of headings.entries()) {\n const next = headings[i + 1];\n heading.byteLength = (next?.byteOffset ?? raw.length) - heading.byteOffset;\n }\n }\n\n return { headings, blocks, frontmatterKeys: fm.keys, totalBytes };\n}\n","import { readFile } from 'node:fs/promises';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport { parseDocument } from 'yaml';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { journalWrite } from '../journal.js';\nimport { assertWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const PatchFrontmatterInput = z.object({\n path: z.string().describe('Vault-relative path to the note.'),\n patch: z\n .record(z.string(), z.unknown())\n .describe(\n 'Key-value pairs to set in the frontmatter. Existing keys not in the patch are unchanged. Pass null as a value to remove a key.',\n ),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n ),\n});\nexport type PatchFrontmatterInput = z.infer<typeof PatchFrontmatterInput>;\n\nexport interface PatchFrontmatterResult {\n path: string;\n keysChanged: string[];\n keysAdded: string[];\n keysRemoved: string[];\n /** sha-256 (hex) of the new content — usable as prevHash for a chained edit. */\n contentHash: string;\n}\n\n/**\n * Edit frontmatter values without reordering existing keys or changing\n * quote style. Uses yaml.parseDocument which preserves the CST, so round-trips\n * are byte-faithful for keys not touched by the patch.\n *\n * Patch semantics:\n * - Key present in patch, value non-null → set/update\n * - Key present in patch, value null → delete\n * - Key absent from patch → untouched\n *\n * If the note has no frontmatter, a new `---` block is created at the top.\n */\nexport async function patchFrontmatter(\n ctx: ServerContext,\n input: PatchFrontmatterInput,\n): Promise<PatchFrontmatterResult> {\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n assertWritable(ctx.policy, input.path);\n\n const original = await readFile(absPath, 'utf8');\n if (input.prevHash !== undefined) assertHashMatch(original, input.prevHash, input.path);\n const fm = parseFrontmatter(original);\n\n const keysChanged: string[] = [];\n const keysAdded: string[] = [];\n const keysRemoved: string[] = [];\n\n let newContent: string;\n\n if (!fm.present) {\n // No existing FM — create a minimal block with just the patch keys.\n const doc = parseDocument('');\n for (const [k, v] of Object.entries(input.patch)) {\n if (v !== null) {\n doc.set(k, v);\n keysAdded.push(k);\n }\n }\n newContent = `---\\n${doc.toString({ lineWidth: 0 })}---\\n${original}`;\n } else {\n // Parse the existing FM block preserving source tokens.\n const opensWithCRLF = original.startsWith('---\\r\\n');\n const openLen = opensWithCRLF ? 5 : 4;\n const closeLen = opensWithCRLF ? 7 : 5;\n const yamlText = original.slice(openLen, fm.bodyStart - closeLen);\n\n const doc = parseDocument(yamlText, { keepSourceTokens: true });\n\n for (const [k, v] of Object.entries(input.patch)) {\n const existing = doc.has(k);\n if (v === null) {\n if (existing) {\n doc.delete(k);\n keysRemoved.push(k);\n }\n } else if (existing) {\n doc.set(k, v);\n keysChanged.push(k);\n } else {\n doc.set(k, v);\n keysAdded.push(k);\n }\n }\n\n const head = opensWithCRLF ? '---\\r\\n' : '---\\n';\n const tail = opensWithCRLF ? '---\\r\\n' : '---\\n';\n newContent = `${head}${doc.toString({ lineWidth: 0 })}${tail}${fm.body}`;\n }\n\n await journalWrite(ctx, 'patch_frontmatter', input.path, original, newContent);\n await atomicWrite(absPath, newContent);\n\n // Update in-memory cache.\n const cached = ctx.notes.get(input.path);\n if (cached) {\n const updated = parseFrontmatter(newContent);\n cached.raw = newContent;\n cached.fmKeys = updated.keys.join(' ');\n }\n\n return {\n path: input.path,\n keysChanged,\n keysAdded,\n keysRemoved,\n contentHash: contentHash(newContent),\n };\n}\n","import { readFile } from 'node:fs/promises';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport { buildOutline } from '@seekstone/core/outline';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { journalWrite } from '../journal.js';\nimport { assertWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const PatchNoteInput = z.object({\n path: z.string().describe('Vault-relative path to the note.'),\n target: z\n .union([\n z.object({ heading: z.string().describe('Heading text (without # markers).') }),\n z.object({ block: z.string().describe('Block reference ID (without the ^ prefix).') }),\n ])\n .describe('Target section. Provide exactly one of heading or block.'),\n operation: z\n .enum(['append', 'prepend', 'replace'])\n .describe(\n 'append: insert after section content. prepend: insert after heading line. replace: swap section content.',\n ),\n content: z.string().min(1).describe('Content to insert or replace with.'),\n createIfMissing: z\n .boolean()\n .default(false)\n .describe(\n 'If the heading target is not found, append a new heading (level 2) + content. Only valid for heading targets.',\n ),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n ),\n});\nexport type PatchNoteInput = z.infer<typeof PatchNoteInput>;\n\nexport interface PatchNoteResult {\n path: string;\n bytesWritten: number;\n targetResolvedAt: { line: number; byteOffset: number };\n frontmatterUnchanged: true;\n /** sha-256 (hex) of the new content — usable as prevHash for a chained edit. */\n contentHash: string;\n}\n\n/** Character offset of the start of the next line after `offset`. */\nfunction lineEnd(raw: string, offset: number): number {\n const nl = raw.indexOf('\\n', offset);\n return nl === -1 ? raw.length : nl + 1;\n}\n\n/** Character offset of the start of the line that contains `offset`. */\nfunction lineStart(raw: string, offset: number): number {\n if (offset === 0) return 0;\n const prev = raw.lastIndexOf('\\n', offset - 1);\n return prev === -1 ? 0 : prev + 1;\n}\n\nexport async function patchNote(\n ctx: ServerContext,\n input: PatchNoteInput,\n): Promise<PatchNoteResult> {\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n assertWritable(ctx.policy, input.path);\n\n const raw = await readFile(absPath, 'utf8');\n if (input.prevHash !== undefined) assertHashMatch(raw, input.prevHash, input.path);\n const fm = parseFrontmatter(raw);\n const originalFmRegion = raw.slice(0, fm.bodyStart);\n const outline = buildOutline(raw, { includeBlocks: true });\n\n let contentStart: number;\n let contentEnd: number;\n let resolvedAt: { line: number; byteOffset: number };\n\n if ('heading' in input.target) {\n const targetText = input.target.heading;\n const heading = outline.headings.find((h) => h.text.toLowerCase() === targetText.toLowerCase());\n\n if (!heading) {\n if (input.createIfMissing) {\n const sep = raw.endsWith('\\n\\n') ? '' : raw.endsWith('\\n') ? '\\n' : '\\n\\n';\n const contentNl = input.content.endsWith('\\n') ? '' : '\\n';\n const newContent = `${raw}${sep}## ${targetText}\\n\\n${input.content}${contentNl}`;\n await journalWrite(ctx, 'patch_note', input.path, raw, newContent);\n await atomicWrite(absPath, newContent);\n await verifyFrontmatter(absPath, originalFmRegion);\n updateCache(ctx, input.path, newContent, fm.bodyStart);\n const headingOffset = raw.length + sep.length;\n return {\n path: input.path,\n bytesWritten: Buffer.byteLength(newContent, 'utf8'),\n targetResolvedAt: {\n line: newContent.slice(0, headingOffset).split('\\n').length,\n byteOffset: headingOffset,\n },\n frontmatterUnchanged: true,\n contentHash: contentHash(newContent),\n };\n }\n throw new Error(\n JSON.stringify({\n error: 'heading_not_found',\n target: targetText,\n available: outline.headings.map((h) => h.text),\n }),\n );\n }\n\n const headingLineEnd = lineEnd(raw, heading.byteOffset);\n const nextSibling = outline.headings.find(\n (h) => h.byteOffset > heading.byteOffset && h.level <= heading.level,\n );\n contentStart = headingLineEnd;\n contentEnd = nextSibling?.byteOffset ?? raw.length;\n resolvedAt = { line: heading.line, byteOffset: heading.byteOffset };\n } else {\n const targetId = input.target.block;\n const block = outline.blocks.find((b) => b.id === targetId);\n if (!block) {\n throw new Error(\n JSON.stringify({\n error: 'block_not_found',\n target: targetId,\n available: outline.blocks.map((b) => b.id),\n }),\n );\n }\n contentStart = lineStart(raw, block.byteOffset);\n contentEnd = lineEnd(raw, block.byteOffset);\n resolvedAt = { line: block.line, byteOffset: block.byteOffset };\n }\n\n const before = raw.slice(0, contentStart);\n const section = raw.slice(contentStart, contentEnd);\n const after = raw.slice(contentEnd);\n\n let newContent: string;\n switch (input.operation) {\n case 'prepend': {\n const sep = input.content.endsWith('\\n') ? '' : '\\n';\n newContent = `${before}${input.content}${sep}${section}${after}`;\n break;\n }\n case 'append': {\n const sectionNl = section.endsWith('\\n') ? '' : '\\n';\n const contentNl = input.content.endsWith('\\n') ? '' : '\\n';\n newContent = `${before}${section}${sectionNl}${input.content}${contentNl}${after}`;\n break;\n }\n case 'replace': {\n const contentNl = input.content.endsWith('\\n') ? '' : '\\n';\n newContent = `${before}${input.content}${contentNl}${after}`;\n break;\n }\n default:\n throw new Error(`Unknown operation: ${String(input.operation)}`);\n }\n\n await journalWrite(ctx, 'patch_note', input.path, raw, newContent);\n await atomicWrite(absPath, newContent);\n await verifyFrontmatter(absPath, originalFmRegion);\n updateCache(ctx, input.path, newContent, fm.bodyStart);\n\n return {\n path: input.path,\n bytesWritten: Buffer.byteLength(newContent, 'utf8'),\n targetResolvedAt: resolvedAt,\n frontmatterUnchanged: true,\n contentHash: contentHash(newContent),\n };\n}\n\nasync function verifyFrontmatter(absPath: string, originalFmRegion: string): Promise<void> {\n const written = await readFile(absPath, 'utf8');\n if (written.slice(0, originalFmRegion.length) !== originalFmRegion) {\n throw new Error('Write-safety violation: frontmatter region changed unexpectedly');\n }\n}\n\nfunction updateCache(\n ctx: ServerContext,\n path: string,\n newContent: string,\n bodyStart: number,\n): void {\n const cached = ctx.notes.get(path);\n if (cached) {\n cached.body = newContent.slice(bodyStart);\n cached.raw = newContent;\n cached.sizeBytes = Buffer.byteLength(newContent, 'utf8');\n }\n}\n","import { access, mkdir, readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { buildDoc, upsertDoc } from '../index/doc.js';\nimport { journalWrite } from '../journal.js';\nimport { assertWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\n// ── Period type ───────────────────────────────────────────────────────────────\n\nconst PERIOD = z.enum(['daily', 'weekly', 'monthly', 'quarterly', 'yearly']);\ntype Period = z.infer<typeof PERIOD>;\n\n// ── Config shapes (read from .obsidian on disk) ───────────────────────────────\n\ninterface PeriodicEntry {\n folder?: string;\n format?: string;\n template?: string;\n}\n\ninterface DailyNotesJson extends PeriodicEntry {}\n\ninterface PeriodicNotesJson {\n daily?: PeriodicEntry;\n weekly?: PeriodicEntry;\n monthly?: PeriodicEntry;\n quarterly?: PeriodicEntry;\n yearly?: PeriodicEntry;\n}\n\nconst DEFAULTS: Record<Period, Required<PeriodicEntry>> = {\n daily: { folder: '', format: 'YYYY-MM-DD', template: '' },\n weekly: { folder: '', format: 'gggg-[W]ww', template: '' },\n monthly: { folder: '', format: 'YYYY-MM', template: '' },\n quarterly: { folder: '', format: 'YYYY-[Q]Q', template: '' },\n yearly: { folder: '', format: 'YYYY', template: '' },\n};\n\nasync function readJson<T>(absPath: string): Promise<T | null> {\n try {\n return JSON.parse(await readFile(absPath, 'utf8')) as T;\n } catch {\n return null;\n }\n}\n\nasync function resolveConfig(vaultRoot: string, period: Period): Promise<Required<PeriodicEntry>> {\n const defaults = DEFAULTS[period];\n\n if (period === 'daily') {\n const cfg = await readJson<DailyNotesJson>(join(vaultRoot, '.obsidian', 'daily-notes.json'));\n return {\n folder: cfg?.folder ?? defaults.folder,\n format: cfg?.format ?? defaults.format,\n template: cfg?.template ?? defaults.template,\n };\n }\n\n const cfg = await readJson<PeriodicNotesJson>(\n join(vaultRoot, '.obsidian', 'plugins', 'periodic-notes', 'data.json'),\n );\n const entry = cfg?.[period];\n return {\n folder: entry?.folder ?? defaults.folder,\n format: entry?.format ?? defaults.format,\n template: entry?.template ?? defaults.template,\n };\n}\n\n// ── Moment-style date formatting (no external dep) ───────────────────────────\n\nfunction isoWeekAndYear(date: Date): { week: number; year: number } {\n const d = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));\n const day = d.getUTCDay() || 7; // Mon=1 … Sun=7\n d.setUTCDate(d.getUTCDate() + 4 - day); // nearest Thursday\n const jan1 = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));\n const week = Math.ceil(((d.getTime() - jan1.getTime()) / 86_400_000 + 1) / 7);\n return { week, year: d.getUTCFullYear() };\n}\n\nexport function formatMomentDate(date: Date, format: string): string {\n // Use UTC accessors: ISO date strings (YYYY-MM-DD) parse as UTC midnight,\n // so local-time accessors would return the previous day in negative-offset\n // timezones (EST, PST, etc.).\n const year = date.getUTCFullYear();\n const month = date.getUTCMonth() + 1;\n const day = date.getUTCDate();\n const quarter = Math.ceil(month / 3);\n const { week: isoWeek, year: isoYear } = isoWeekAndYear(date);\n\n // Protect literal text in square brackets from token substitution.\n const PLACEHOLDER = '\\x00';\n const literals: string[] = [];\n let s = format.replace(/\\[([^\\]]*)\\]/g, (_, lit) => {\n literals.push(lit);\n return `${PLACEHOLDER}${literals.length - 1}${PLACEHOLDER}`;\n });\n\n // Substitute longest tokens first to avoid partial matches (e.g. YYYY before YY).\n s = s\n .replace(/gggg/g, String(isoYear).padStart(4, '0'))\n .replace(/YYYY/g, String(year).padStart(4, '0'))\n .replace(/YY/g, String(year).slice(-2))\n .replace(/MM/g, String(month).padStart(2, '0'))\n .replace(/M/g, String(month))\n .replace(/DD/g, String(day).padStart(2, '0'))\n .replace(/D/g, String(day))\n .replace(/ww/g, String(isoWeek).padStart(2, '0'))\n .replace(/W/g, String(isoWeek))\n .replace(/Q/g, String(quarter));\n\n // Restore literals. Built via RegExp constructor because the placeholder is a\n // control char (\\x00) that Biome disallows in a regex literal; Codacy's\n // non-literal-RegExp pattern is disabled repo-wide for this safe internal use.\n return s.replace(\n new RegExp(`${PLACEHOLDER}(\\\\d+)${PLACEHOLDER}`, 'g'),\n (_, i) => literals[+i] ?? '',\n );\n}\n\n// ── Resolve a note path from config + date ────────────────────────────────────\n\nexport function resolveNotePath(cfg: Required<PeriodicEntry>, date: Date): string {\n const filename = `${formatMomentDate(date, cfg.format)}.md`;\n return cfg.folder ? `${cfg.folder}/${filename}` : filename;\n}\n\n// ── Tool: get_periodic_note ───────────────────────────────────────────────────\n\nexport const GetPeriodicNoteInput = z.object({\n period: PERIOD.default('daily').describe(\n 'Period type: daily (default), weekly, monthly, quarterly, or yearly.',\n ),\n date: z\n .string()\n .optional()\n .describe('ISO date string (YYYY-MM-DD). Defaults to today when omitted.'),\n createIfMissing: z\n .boolean()\n .default(false)\n .describe(\n 'Create the note from the configured template if it does not exist. Default false — reports missing without creating.',\n ),\n});\nexport type GetPeriodicNoteInput = z.input<typeof GetPeriodicNoteInput>;\n\nexport interface GetPeriodicNoteResult {\n path: string;\n existed: boolean;\n created: boolean;\n /** sha-256 (hex) of the created content; only set when created is true. */\n contentHash?: string;\n}\n\nexport async function getPeriodicNote(\n ctx: ServerContext,\n rawInput: GetPeriodicNoteInput,\n): Promise<GetPeriodicNoteResult> {\n const input = GetPeriodicNoteInput.parse(rawInput);\n const date = input.date ? new Date(input.date) : new Date();\n const cfg = await resolveConfig(ctx.vaultRoot, input.period);\n const path = resolveNotePath(cfg, date);\n const abs = resolveVaultPath(ctx.vaultRoot, path);\n\n let existed = false;\n try {\n await access(abs);\n existed = true;\n } catch {}\n\n if (existed) return { path, existed: true, created: false };\n\n if (!input.createIfMissing) return { path, existed: false, created: false };\n\n // About to write: this \"read\" tool creates the note here, so the write\n // policy applies (dispatch also strips createIfMissing in read-only mode).\n assertWritable(ctx.policy, path);\n\n // Read template if configured.\n let body = '';\n if (cfg.template) {\n try {\n const templateAbs = resolveVaultPath(\n ctx.vaultRoot,\n cfg.template.endsWith('.md') ? cfg.template : `${cfg.template}.md`,\n );\n body = await readFile(templateAbs, 'utf8');\n } catch {}\n }\n\n await mkdir(dirname(abs), { recursive: true });\n await journalWrite(ctx, 'get_periodic_note', path, null, body);\n await atomicWrite(abs, body);\n upsertDoc(ctx, buildDoc(path, body));\n\n return { path, existed: false, created: true, contentHash: contentHash(body) };\n}\n\n// ── Tool: append_periodic_note ────────────────────────────────────────────────\n\nexport const AppendPeriodicNoteInput = z.object({\n period: PERIOD.default('daily').describe('Period type. Default: daily.'),\n date: z.string().optional().describe('ISO date string (YYYY-MM-DD). Defaults to today.'),\n content: z\n .string()\n .min(1)\n .describe('Text to append to the note body. Separated from existing content by a blank line.'),\n createIfMissing: z\n .boolean()\n .default(true)\n .describe('Create the note if it does not exist before appending. Default true.'),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard: the contentHash from a prior read of the resolved periodic note. Fails with hash_conflict if it changed since.',\n ),\n});\nexport type AppendPeriodicNoteInput = z.input<typeof AppendPeriodicNoteInput>;\n\nexport interface AppendPeriodicNoteResult {\n path: string;\n bytesWritten: number;\n /** sha-256 (hex) of the new content — usable as prevHash for a chained edit. */\n contentHash: string;\n}\n\nexport async function appendPeriodicNote(\n ctx: ServerContext,\n rawInput: AppendPeriodicNoteInput,\n): Promise<AppendPeriodicNoteResult> {\n const input = AppendPeriodicNoteInput.parse(rawInput);\n const date = input.date ? new Date(input.date) : new Date();\n const cfg = await resolveConfig(ctx.vaultRoot, input.period);\n const path = resolveNotePath(cfg, date);\n const abs = resolveVaultPath(ctx.vaultRoot, path);\n assertWritable(ctx.policy, path);\n\n let original = '';\n try {\n original = await readFile(abs, 'utf8');\n if (input.prevHash !== undefined) assertHashMatch(original, input.prevHash, path);\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n if (input.prevHash !== undefined) {\n // The caller pinned a version that no longer exists — conflict, not create.\n throw new Error(\n JSON.stringify({\n error: 'hash_conflict',\n path,\n expected: input.prevHash,\n actual: null,\n hint: 'The periodic note no longer exists on disk. Re-read before retrying.',\n }),\n );\n }\n if (!input.createIfMissing) throw new Error(`Periodic note not found: ${path}`);\n await mkdir(dirname(abs), { recursive: true });\n await journalWrite(ctx, 'append_periodic_note', path, null, input.content);\n await atomicWrite(abs, input.content);\n upsertDoc(ctx, buildDoc(path, input.content));\n return {\n path,\n bytesWritten: Buffer.byteLength(input.content, 'utf8'),\n contentHash: contentHash(input.content),\n };\n }\n\n // Preserve frontmatter, append to body.\n const fm = parseFrontmatter(original);\n const body = fm.body.endsWith('\\n') ? fm.body : `${fm.body}\\n`;\n const separator = body.endsWith('\\n\\n') ? '' : '\\n';\n const newBody = `${body}${separator}${input.content}`;\n const header = original.slice(0, fm.bodyStart);\n const newRaw = `${header}${newBody}`;\n\n await journalWrite(ctx, 'append_periodic_note', path, original, newRaw);\n await atomicWrite(abs, newRaw);\n\n const cached = ctx.notes.get(path);\n if (cached) {\n cached.body = newBody;\n cached.raw = newRaw;\n }\n\n return {\n path,\n bytesWritten: Buffer.byteLength(newRaw, 'utf8'),\n contentHash: contentHash(newRaw),\n };\n}\n","import { z } from 'zod';\nimport type { ServerContext } from '../context.js';\nimport { basenameNoExt } from './search.js';\n\nconst OPS_WITHOUT_VALUE = new Set(['exists', 'missing']);\n\nconst Predicate = z\n .object({\n key: z.string().min(1).describe('Frontmatter key to test (top-level).'),\n op: z\n .enum(['eq', 'ne', 'contains', 'exists', 'missing', 'gt', 'gte', 'lt', 'lte'])\n .describe(\n 'eq/ne compare scalars; contains matches array membership or substring; ' +\n 'exists/missing test key presence; gt/gte/lt/lte compare numbers or strings (ISO dates sort correctly).',\n ),\n value: z\n .union([z.string(), z.number(), z.boolean()])\n .optional()\n .describe('Comparison value. Required for every op except exists/missing.'),\n })\n .refine((p) => OPS_WITHOUT_VALUE.has(p.op) || p.value !== undefined, {\n message: 'value is required for this op',\n });\n\nconst ISO_DATE = z\n .string()\n .refine((s) => !Number.isNaN(Date.parse(s)), { message: 'not a parseable date' });\n\nexport const QueryNotesInput = z.object({\n where: z\n .array(Predicate)\n .max(20)\n .default([])\n .describe('Frontmatter predicates. All must match (AND).'),\n folder: z\n .string()\n .optional()\n .describe('Restrict to notes under this vault-relative folder prefix.'),\n tag: z.string().optional().describe('Restrict to notes with this tag (# prefix optional).'),\n modifiedAfter: ISO_DATE.optional().describe(\n 'Only notes modified at or after this ISO 8601 date/time.',\n ),\n modifiedBefore: ISO_DATE.optional().describe(\n 'Only notes modified before this ISO 8601 date/time.',\n ),\n minSizeBytes: z.number().int().min(0).optional().describe('Only notes at least this many bytes.'),\n maxSizeBytes: z.number().int().min(0).optional().describe('Only notes at most this many bytes.'),\n select: z\n .array(z.string())\n .max(20)\n .default([])\n .describe(\n 'Extra fields to return per hit: frontmatter keys, or the specials \"mtime\", \"size\", \"tags\". ' +\n 'Default returns only path + title, keeping the payload minimal.',\n ),\n sort: z.enum(['path', 'title', 'mtime', 'size']).default('path').describe('Sort field.'),\n order: z.enum(['asc', 'desc']).default('asc').describe('Sort order.'),\n limit: z.number().int().min(1).max(500).default(100).describe('Maximum number of results.'),\n});\nexport type QueryNotesInput = z.infer<typeof QueryNotesInput>;\n\nexport interface QueryHit {\n path: string;\n /** Omitted when it equals the path's basename (recoverable from `path`). */\n title?: string;\n /** ISO 8601 mtime — present only when \"mtime\" is selected. */\n mtime?: string;\n /** Present only when \"size\" is selected. */\n sizeBytes?: number;\n /** Present only when \"tags\" is selected and the note has tags. */\n tags?: string[];\n /** Selected frontmatter keys — present only when the note has at least one of them. */\n fm?: Record<string, unknown>;\n}\n\ntype Scalar = string | number | boolean;\n\n/** Loose scalar equality: strict first, then string-form — so `5` matches \"5\" and dates match. */\nfunction scalarEq(a: unknown, b: Scalar): boolean {\n if (a === b) return true;\n if (a === null || a === undefined || typeof a === 'object') return false;\n return String(a) === String(b);\n}\n\n/** Numeric when both sides coerce to finite numbers, else lexicographic (ISO dates sort correctly). */\nfunction compare(a: unknown, b: Scalar): number | undefined {\n if (a === null || a === undefined || typeof a === 'object' || typeof a === 'boolean') {\n return undefined;\n }\n const an = Number(a);\n const bn = Number(b);\n if (Number.isFinite(an) && Number.isFinite(bn)) return an - bn;\n const as = String(a);\n const bs = String(b);\n return as < bs ? -1 : as > bs ? 1 : 0;\n}\n\nfunction matches(fm: Record<string, unknown> | null, p: z.infer<typeof Predicate>): boolean {\n const val = fm?.[p.key];\n switch (p.op) {\n case 'exists':\n return val !== undefined;\n case 'missing':\n return val === undefined;\n case 'eq':\n return scalarEq(val, p.value as Scalar);\n // `ne` requires the key to exist — notes without the key don't match.\n case 'ne':\n return val !== undefined && !scalarEq(val, p.value as Scalar);\n case 'contains': {\n if (Array.isArray(val)) return val.some((v) => scalarEq(v, p.value as Scalar));\n if (typeof val === 'string') {\n return val.toLowerCase().includes(String(p.value).toLowerCase());\n }\n return false;\n }\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte': {\n const c = compare(val, p.value as Scalar);\n if (c === undefined) return false;\n if (p.op === 'gt') return c > 0;\n if (p.op === 'gte') return c >= 0;\n if (p.op === 'lt') return c < 0;\n return c <= 0;\n }\n }\n}\n\nexport function queryNotes(ctx: ServerContext, input: QueryNotesInput): QueryHit[] {\n const tag = input.tag?.replace(/^#/, '');\n const after = input.modifiedAfter ? Date.parse(input.modifiedAfter) : undefined;\n const before = input.modifiedBefore ? Date.parse(input.modifiedBefore) : undefined;\n const fmKeys = input.select.filter((s) => s !== 'mtime' && s !== 'size' && s !== 'tags');\n\n const hits: { hit: QueryHit; note: { title: string; mtimeMs: number; sizeBytes: number } }[] = [];\n\n for (const [path, note] of ctx.notes) {\n if (input.folder && !path.startsWith(input.folder)) continue;\n if (tag && !note.tags.split(' ').filter(Boolean).includes(tag)) continue;\n if (after !== undefined && note.mtimeMs < after) continue;\n if (before !== undefined && note.mtimeMs >= before) continue;\n if (input.minSizeBytes !== undefined && note.sizeBytes < input.minSizeBytes) continue;\n if (input.maxSizeBytes !== undefined && note.sizeBytes > input.maxSizeBytes) continue;\n if (!input.where.every((p) => matches(note.fm, p))) continue;\n\n const hit: QueryHit = { path };\n // Omit redundant/empty metadata to keep the payload lean (recoverable from `path`).\n if (note.title && note.title !== basenameNoExt(path)) hit.title = note.title;\n if (input.select.includes('mtime')) hit.mtime = new Date(note.mtimeMs).toISOString();\n if (input.select.includes('size')) hit.sizeBytes = note.sizeBytes;\n if (input.select.includes('tags')) {\n const noteTags = note.tags.split(' ').filter(Boolean);\n if (noteTags.length > 0) hit.tags = noteTags;\n }\n if (fmKeys.length > 0 && note.fm) {\n const fm: Record<string, unknown> = {};\n for (const k of fmKeys) {\n if (note.fm[k] !== undefined) fm[k] = note.fm[k];\n }\n if (Object.keys(fm).length > 0) hit.fm = fm;\n }\n hits.push({ hit, note });\n }\n\n const dir = input.order === 'desc' ? -1 : 1;\n hits.sort((a, b) => {\n switch (input.sort) {\n case 'mtime':\n return (a.note.mtimeMs - b.note.mtimeMs) * dir;\n case 'size':\n return (a.note.sizeBytes - b.note.sizeBytes) * dir;\n case 'title':\n return a.note.title.localeCompare(b.note.title) * dir;\n default:\n return a.hit.path.localeCompare(b.hit.path) * dir;\n }\n });\n\n return hits.slice(0, input.limit).map((h) => h.hit);\n}\n","import { readFile } from 'node:fs/promises';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport { buildOutline } from '@seekstone/core/outline';\nimport { z } from 'zod';\nimport { contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const ReadNoteInput = z\n .object({\n path: z.string().describe('Vault-relative path to the note, e.g. \"Daily Notes/2026-05-29.md\".'),\n section: z\n .string()\n .optional()\n .describe('Return only this heading section (heading text, # prefix optional).'),\n block: z\n .string()\n .optional()\n .describe('Return only the block anchored by this id (^ prefix optional).'),\n lines: z\n .object({\n from: z.number().int().min(1).describe('First line (1-indexed, inclusive).'),\n to: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe('Last line (1-indexed, inclusive). Defaults to end of file.'),\n })\n .optional()\n .describe('Return only this line range (1-indexed, inclusive).'),\n includeFrontmatter: z\n .boolean()\n .optional()\n .describe(\n 'Include frontmatter in span results. Default false for section/block spans. No effect on lines or whole-note reads.',\n ),\n })\n .refine((v) => [v.section, v.block, v.lines].filter((x) => x !== undefined).length <= 1, {\n message: 'At most one of section, block, or lines may be specified.',\n });\nexport type ReadNoteInput = z.infer<typeof ReadNoteInput>;\n\nexport interface ReadNoteResult {\n path: string;\n content: string;\n /** Bytes in the returned content (UTF-8). */\n bytesReturned: number;\n /** Total UTF-8 byte size of the source file. */\n noteBytes: number;\n /** sha-256 (hex) of the whole file — pass as prevHash to edit tools for compare-and-swap. */\n contentHash: string;\n /** Character offsets of the returned span in the raw file. Absent for whole-note reads. */\n span?: { charStart: number; charEnd: number };\n}\n\nexport async function readNote(ctx: ServerContext, input: ReadNoteInput): Promise<ReadNoteResult> {\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n\n const raw = await readFile(absPath, 'utf8');\n const noteBytes = Buffer.byteLength(raw, 'utf8');\n // Always the whole file's hash, even for span reads — it identifies the\n // on-disk version an edit's prevHash is compared against.\n const hash = contentHash(raw);\n\n // Whole-note read — no selector\n if (input.section === undefined && input.block === undefined && input.lines === undefined) {\n return {\n path: input.path,\n content: raw,\n bytesReturned: noteBytes,\n noteBytes,\n contentHash: hash,\n };\n }\n\n const fm = parseFrontmatter(raw);\n const outline = buildOutline(raw, { includeBlocks: true });\n\n let charStart: number;\n let charEnd: number;\n\n if (input.section !== undefined) {\n const target = input.section.replace(/^#+\\s*/, '').trim();\n const heading = outline.headings.find((h) => h.text === target);\n if (!heading) {\n throw new Error(\n JSON.stringify({\n error: 'section_not_found',\n target,\n available: outline.headings.map((h) => h.text),\n }),\n );\n }\n const nextSibling = outline.headings.find(\n (h) => h.byteOffset > heading.byteOffset && h.level <= heading.level,\n );\n charStart = heading.byteOffset;\n charEnd = nextSibling?.byteOffset ?? raw.length;\n } else if (input.block !== undefined) {\n const targetId = input.block.replace(/^\\^/, '');\n const block = outline.blocks.find((b) => b.id === targetId);\n if (!block) {\n throw new Error(\n JSON.stringify({\n error: 'block_not_found',\n target: targetId,\n available: outline.blocks.map((b) => b.id),\n }),\n );\n }\n const lineS = block.byteOffset === 0 ? 0 : raw.lastIndexOf('\\n', block.byteOffset - 1) + 1;\n const nlAfter = raw.indexOf('\\n', block.byteOffset);\n const lineE = nlAfter === -1 ? raw.length : nlAfter + 1;\n charStart = lineS;\n charEnd = lineE;\n } else {\n // lines selector\n const linesRange = input.lines;\n if (linesRange === undefined) throw new Error('internal: unreachable');\n const { from, to } = linesRange;\n const rawLines = raw.split('\\n');\n const fromIdx = from - 1; // 0-indexed\n const toIdxInclusive =\n to !== undefined ? Math.min(to - 1, rawLines.length - 1) : rawLines.length - 1;\n\n let offset = 0;\n charStart = 0;\n charEnd = raw.length;\n\n for (const [i, line] of rawLines.entries()) {\n if (i === fromIdx) charStart = offset;\n offset += line.length + 1; // +1 for the \\n consumed by split\n if (i === toIdxInclusive) {\n charEnd = Math.min(offset, raw.length);\n break;\n }\n }\n }\n\n // Build content — prepend FM if requested (section/block only)\n let content: string;\n if (input.includeFrontmatter === true && input.lines === undefined) {\n const fmRegion = raw.slice(0, fm.bodyStart);\n const spanContent = raw.slice(charStart, charEnd);\n // Avoid duplicating FM if the span already covers it (e.g. section at bodyStart)\n content = charStart < fm.bodyStart ? spanContent : `${fmRegion}${spanContent}`;\n } else {\n content = raw.slice(charStart, charEnd);\n }\n\n return {\n path: input.path,\n content,\n bytesReturned: Buffer.byteLength(content, 'utf8'),\n noteBytes,\n contentHash: hash,\n span: { charStart, charEnd },\n };\n}\n","import { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport { buildOutline } from '@seekstone/core/outline';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { addNoteBacklinks, removeNoteBacklinks } from '../index/backlinks.js';\nimport { buildDoc, upsertDoc } from '../index/doc.js';\nimport { resolveLink } from '../index/resolve.js';\nimport { assertWritable, isWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\nimport { mapUnfencedLines } from './rewrite_links.js';\n\nexport const RenameHeadingInput = z.object({\n path: z.string().describe('Vault-relative path of the note containing the heading.'),\n oldHeading: z\n .string()\n .min(1)\n .describe(\n 'Current heading text, without # markers. Matched case-insensitively; if the note has duplicate headings the first one wins, mirroring Obsidian link resolution.',\n ),\n newHeading: z\n .string()\n .min(1)\n .refine((s) => !/[\\n[\\]|#]/.test(s), {\n message:\n 'newHeading must not contain newlines, \"[\", \"]\", \"|\", or \"#\" — those break [[note#heading]] link syntax.',\n })\n .describe('New heading text, without # markers.'),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard: the contentHash from a prior read of this note. Fails with hash_conflict if the note changed since.',\n ),\n});\nexport type RenameHeadingInput = z.input<typeof RenameHeadingInput>;\n\nexport interface RenameHeadingResult {\n path: string;\n oldHeading: string;\n newHeading: string;\n /** 1-based line of the renamed heading. */\n line: number;\n /**\n * Notes with at least one reference rewritten — includes the renamed note\n * itself when it linked to its own heading. The heading rename alone does\n * not count.\n */\n notesRewritten: number;\n /** Individual [[…#heading]] links and embeds rewritten across the vault. */\n linksRewritten: number;\n /** Referencing notes left untouched because SEEKSTONE_WRITE_PATHS excludes them. */\n skipped?: string[];\n /** sha-256 (hex) of the renamed note's new content — usable as prevHash for a chained edit. */\n contentHash: string;\n}\n\n// Heading-link shape: optional embed bang, optional target (empty = same-note\n// anchor like [[#Heading]]), required #fragment, optional |alias. Bounds\n// mirror LINK_WITH_LINES_RE in @seekstone/core/extract.\nconst HEADING_LINK_RE = /(!?)\\[\\[([^\\]|#\\n]{0,512})(#[^\\]|\\n]{1,512})(\\|[^\\]\\n]{1,512})?\\]\\]/g;\n\n/**\n * Rewrite `[[target#fragment]]` links on unfenced lines. `matchesTarget`\n * decides whether a link's target refers to the renamed note; the fragment\n * must equal `oldHeading` case-insensitively (Obsidian heading links are\n * case-insensitive). Block refs (`#^id`) and nested heading paths (`#A#B`)\n * are never touched.\n */\nfunction rewriteHeadingLinks(\n raw: string,\n oldHeading: string,\n newHeading: string,\n matchesTarget: (target: string) => boolean,\n): { content: string; count: number } {\n const oldLower = oldHeading.toLowerCase();\n let count = 0;\n const content = mapUnfencedLines(raw, (line) =>\n line.replace(\n HEADING_LINK_RE,\n (full, bang: string, target: string, frag: string, alias?: string) => {\n const fragText = frag.slice(1);\n if (fragText.startsWith('^') || fragText.includes('#')) return full;\n if (fragText.trim().toLowerCase() !== oldLower) return full;\n if (!matchesTarget(target.trim())) return full;\n count++;\n return `${bang}[[${target}#${newHeading}${alias ?? ''}]]`;\n },\n ),\n );\n return { content, count };\n}\n\nexport async function renameHeading(\n ctx: ServerContext,\n rawInput: RenameHeadingInput,\n): Promise<RenameHeadingResult> {\n // Parse here (not only in dispatch) so validation applies to direct callers\n // too — same pattern as move_note.\n const input = RenameHeadingInput.parse(rawInput);\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n assertWritable(ctx.policy, input.path);\n\n let raw: string;\n try {\n raw = await readFile(absPath, 'utf8');\n } catch {\n throw new Error(`Note not found: ${input.path}`);\n }\n if (input.prevHash !== undefined) assertHashMatch(raw, input.prevHash, input.path);\n\n const outline = buildOutline(raw, { includeBlocks: false });\n const heading = outline.headings.find(\n (h) => h.text.toLowerCase() === input.oldHeading.toLowerCase(),\n );\n if (!heading) {\n throw new Error(\n JSON.stringify({\n error: 'heading_not_found',\n target: input.oldHeading,\n available: outline.headings.map((h) => h.text),\n }),\n );\n }\n\n // Rename the heading line surgically by offset, preserving the marker run,\n // the whitespace after it, and any trailing whitespace (incl. CR).\n const nl = raw.indexOf('\\n', heading.byteOffset);\n const lineEnd = nl === -1 ? raw.length : nl;\n const lineText = raw.slice(heading.byteOffset, lineEnd);\n const markerPrefix = /^#{1,6}\\s+/.exec(lineText)?.[0] ?? '';\n const trailing = /\\s*$/.exec(lineText)?.[0] ?? '';\n const newLineText = `${markerPrefix}${input.newHeading}${trailing}`;\n let newRaw = raw.slice(0, heading.byteOffset) + newLineText + raw.slice(lineEnd);\n\n // Rewrite the note's own references to the renamed heading — same-note\n // anchors ([[#Heading]]) and self-links by name — in the body region only,\n // so the frontmatter stays byte-identical.\n const fm = parseFrontmatter(newRaw);\n const bodyRegion = newRaw.slice(fm.bodyStart);\n const selfRewrite = rewriteHeadingLinks(\n bodyRegion,\n input.oldHeading,\n input.newHeading,\n (target) => target === '' || resolveLink(target, ctx.notes) === input.path,\n );\n newRaw = newRaw.slice(0, fm.bodyStart) + selfRewrite.content;\n\n // Referencing notes come straight off the warm backlink index — no scan.\n // Heading links are wikilinks/embeds, which the index fully covers\n // (markdown anchors like [t](note.md#h) are out of scope, as documented).\n // Rewrites are computed before any disk write so the whole rename is\n // journaled under one seq (undo restores every touched file or none).\n const candidates = new Set<string>();\n for (const ref of ctx.backlinks.get(input.path) ?? []) candidates.add(ref.path);\n candidates.delete(input.path);\n\n const rewrites: { path: string; pre: string; content: string; count: number }[] = [];\n const skipped: string[] = [];\n for (const path of [...candidates].sort()) {\n const doc = ctx.notes.get(path);\n if (doc === undefined) continue;\n const { content, count } = rewriteHeadingLinks(\n doc.raw,\n input.oldHeading,\n input.newHeading,\n (target) => target !== '' && resolveLink(target, ctx.notes) === input.path,\n );\n if (count === 0) continue;\n if (!isWritable(ctx.policy, path)) {\n // Out of write scope: leave the note untouched but report it, so the\n // caller knows which references were NOT updated.\n skipped.push(path);\n continue;\n }\n rewrites.push({ path, pre: doc.raw, content, count });\n }\n\n if (ctx.journal) {\n const txn = ctx.journal.begin('rename_heading');\n await txn.add(input.path, raw, newRaw);\n for (const r of rewrites) await txn.add(r.path, r.pre, r.content);\n await txn.commit();\n }\n\n const originalFmRegion = raw.slice(0, fm.bodyStart);\n await atomicWrite(absPath, newRaw);\n const written = await readFile(absPath, 'utf8');\n if (written.slice(0, originalFmRegion.length) !== originalFmRegion) {\n throw new Error('Write-safety violation: frontmatter region changed unexpectedly');\n }\n\n // Refresh the renamed note's index entry. removeNoteBacklinks reads the old\n // raw out of ctx.notes, so it must run before upsertDoc replaces the entry.\n removeNoteBacklinks(ctx, input.path);\n upsertDoc(ctx, buildDoc(input.path, newRaw));\n addNoteBacklinks(ctx, input.path, newRaw);\n\n let notesRewritten = selfRewrite.count > 0 ? 1 : 0;\n let linksRewritten = selfRewrite.count;\n\n for (const { path, content, count } of rewrites) {\n await atomicWrite(join(ctx.vaultRoot, path), content);\n // Fragment rewrites change neither link resolution nor line numbers, so\n // the backlink index needs no refresh — only the notes/search entries.\n upsertDoc(ctx, buildDoc(path, content));\n notesRewritten++;\n linksRewritten += count;\n }\n\n const result: RenameHeadingResult = {\n path: input.path,\n oldHeading: input.oldHeading,\n newHeading: input.newHeading,\n line: heading.line,\n notesRewritten,\n linksRewritten,\n contentHash: contentHash(newRaw),\n };\n if (skipped.length > 0) result.skipped = skipped;\n return result;\n}\n","import { readFile } from 'node:fs/promises';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { assertHashMatch, contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { journalWrite } from '../journal.js';\nimport { assertWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const ReplaceInNoteInput = z.object({\n path: z.string().describe('Vault-relative path to the note.'),\n find: z\n .string()\n .min(1)\n .max(1000)\n .describe('Text or pattern to find (max 1000 chars; bounds regex-mode pattern size).'),\n replace: z\n .string()\n .describe('Replacement text. Supports $1, $2, … backreferences in regex mode.'),\n regex: z.boolean().default(false).describe('Treat find as a regular expression.'),\n caseSensitive: z.boolean().default(false).describe('Case-sensitive matching.'),\n wholeWord: z.boolean().default(false).describe('Match whole words only (\\\\b word-boundary).'),\n limit: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe('Maximum number of replacements. Omit to replace all.'),\n dryRun: z.boolean().default(false).describe('If true, report matches without writing anything.'),\n prevHash: z\n .string()\n .optional()\n .describe(\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n ),\n});\nexport type ReplaceInNoteInput = z.infer<typeof ReplaceInNoteInput>;\n\nexport interface MatchPosition {\n line: number;\n byteOffset: number;\n}\n\nexport interface ReplaceInNoteResult {\n path: string;\n replacements: number;\n matches: MatchPosition[];\n bytesWritten?: number;\n frontmatterUnchanged: true;\n /** sha-256 (hex) of the file content after the call — the new content after a write, the unchanged content on dry runs and zero-match calls. Always usable as prevHash for a chained edit. */\n contentHash: string;\n}\n\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction buildRegex(\n find: string,\n opts: { regex: boolean; caseSensitive: boolean; wholeWord: boolean },\n): RegExp {\n let pattern = opts.regex ? find : escapeRegex(find);\n if (opts.wholeWord) pattern = `\\\\b(?:${pattern})\\\\b`;\n const flags = `g${opts.caseSensitive ? '' : 'i'}`;\n return new RegExp(pattern, flags);\n}\n\nexport async function replaceInNote(\n ctx: ServerContext,\n input: ReplaceInNoteInput,\n): Promise<ReplaceInNoteResult> {\n const absPath = resolveVaultPath(ctx.vaultRoot, input.path);\n assertWritable(ctx.policy, input.path);\n\n // Validate regex before any IO.\n let re: RegExp;\n try {\n re = buildRegex(input.find, {\n regex: input.regex,\n caseSensitive: input.caseSensitive,\n wholeWord: input.wholeWord,\n });\n } catch (err) {\n throw new Error(`Invalid regex: ${err instanceof Error ? err.message : String(err)}`);\n }\n\n const raw = await readFile(absPath, 'utf8');\n if (input.prevHash !== undefined) assertHashMatch(raw, input.prevHash, input.path);\n const fm = parseFrontmatter(raw);\n const originalFmRegion = raw.slice(0, fm.bodyStart);\n const body = raw.slice(fm.bodyStart);\n\n const allMatches = [...body.matchAll(re)];\n const toReplace = input.limit !== undefined ? allMatches.slice(0, input.limit) : allMatches;\n\n const matches: MatchPosition[] = toReplace.map((m) => {\n const fileOffset = fm.bodyStart + (m.index ?? 0);\n const line = raw.slice(0, fileOffset).split('\\n').length;\n return { line, byteOffset: fileOffset };\n });\n\n if (input.dryRun || toReplace.length === 0) {\n return {\n path: input.path,\n replacements: toReplace.length,\n matches,\n frontmatterUnchanged: true,\n // Nothing was written — hash the content as read, so chained edits can\n // proceed from a dry run without a re-read.\n contentHash: contentHash(raw),\n };\n }\n\n // Apply replacements left-to-right, resolving backreferences per match.\n const singleRe = new RegExp(re.source, re.flags.replace('g', ''));\n let newBody = '';\n let lastIndex = 0;\n for (const m of toReplace) {\n const matchIndex = m.index ?? 0;\n newBody += body.slice(lastIndex, matchIndex);\n newBody += input.regex ? m[0].replace(singleRe, input.replace) : input.replace;\n lastIndex = matchIndex + m[0].length;\n }\n newBody += body.slice(lastIndex);\n\n const newContent = `${originalFmRegion}${newBody}`;\n await journalWrite(ctx, 'replace_in_note', input.path, raw, newContent);\n await atomicWrite(absPath, newContent);\n\n const written = await readFile(absPath, 'utf8');\n if (written.slice(0, originalFmRegion.length) !== originalFmRegion) {\n throw new Error('Write-safety violation: frontmatter region changed unexpectedly');\n }\n\n const cached = ctx.notes.get(input.path);\n if (cached) {\n cached.body = newBody;\n cached.raw = newContent;\n cached.sizeBytes = Buffer.byteLength(newContent, 'utf8');\n }\n\n return {\n path: input.path,\n replacements: toReplace.length,\n matches,\n bytesWritten: Buffer.byteLength(newContent, 'utf8'),\n frontmatterUnchanged: true,\n contentHash: contentHash(newContent),\n };\n}\n","import { mkdir, readFile, rm } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { z } from 'zod';\nimport { atomicWrite } from '../atomic-write.js';\nimport { contentHash } from '../content-hash.js';\nimport type { ServerContext } from '../context.js';\nimport { addNoteBacklinks, removeNoteBacklinks } from '../index/backlinks.js';\nimport { buildDoc, upsertDoc } from '../index/doc.js';\nimport type { JournalEntry } from '../journal.js';\nimport { assertWritable } from '../policy.js';\nimport { resolveVaultPath } from '../vault-path.js';\n\nexport const UndoWriteInput = z.object({\n seq: z\n .number()\n .int()\n .min(1)\n .optional()\n .describe(\n 'Journal entry to revert (from list_writes). Defaults to the most recent undoable write.',\n ),\n force: z\n .boolean()\n .default(false)\n .describe(\n 'Restore even if a file changed after the journaled write. The clobbered state is journaled first, so nothing is lost. Defaults to false — conflicts are refused.',\n ),\n});\nexport type UndoWriteInput = z.input<typeof UndoWriteInput>;\n\nexport interface UndoConflict {\n path: string;\n /** Hash the file had right after the journaled write (null = did not exist). */\n expectedHash: string | null;\n /** Hash the file has now (null = does not exist). */\n actualHash: string | null;\n expectedBytes: number | null;\n actualBytes: number | null;\n}\n\nexport interface UndoWriteResult {\n /** The entry that was reverted. */\n seq: number;\n /** The journal entry recording this undo — undo it to redo. */\n undoSeq: number;\n tool: string;\n restored: { path: string; restoredHash: string | null }[];\n /** Conflicts overridden with force: true (their clobbered state is journaled under undoSeq). */\n overrode?: UndoConflict[];\n}\n\n/**\n * Revert a journaled write by restoring every touched file's pre-image.\n * All-or-nothing: the current state of every file is checked against the\n * entry's postHash first (CAS against the journal), and any mismatch refuses\n * the whole undo with a structured `undo_conflict` unless `force` is set.\n * The undo is itself journaled, so undoing the undo redoes the write.\n */\nexport async function undoWrite(\n ctx: ServerContext,\n rawInput: UndoWriteInput,\n): Promise<UndoWriteResult> {\n const input = UndoWriteInput.parse(rawInput);\n const journal = ctx.journal;\n if (!journal) {\n throw new Error('Write journal is disabled (SEEKSTONE_HISTORY=0); nothing to undo.');\n }\n\n let entry: JournalEntry | undefined;\n if (input.seq === undefined) {\n entry = journal.latestUndoable();\n if (!entry) throw new Error('No undoable writes in the journal.');\n } else {\n entry = journal.get(input.seq);\n if (!entry) throw new Error(`Journal entry ${input.seq} not found.`);\n if (!journal.isUndoable(entry)) {\n throw new Error(\n JSON.stringify({\n error: 'entry_evicted',\n seq: entry.seq,\n hint: 'Its pre-image was evicted by the retention cap (SEEKSTONE_HISTORY_MAX_SIZE); it can no longer be undone.',\n }),\n );\n }\n }\n\n // Policy applies to every path the undo will write, before anything moves.\n for (const f of entry.files) assertWritable(ctx.policy, f.path);\n\n // Current state vs. what the journal says the write left behind.\n const current = new Map<string, string | null>();\n const conflicts: UndoConflict[] = [];\n for (const f of entry.files) {\n const abs = resolveVaultPath(ctx.vaultRoot, f.path);\n let cur: string | null = null;\n try {\n cur = await readFile(abs, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n }\n current.set(f.path, cur);\n const actualHash = cur === null ? null : contentHash(cur);\n if (actualHash !== f.postHash) {\n conflicts.push({\n path: f.path,\n expectedHash: f.postHash,\n actualHash,\n expectedBytes: f.postHash === null ? null : await postBytes(journal, f.postHash),\n actualBytes: cur === null ? null : Buffer.byteLength(cur, 'utf8'),\n });\n }\n }\n if (conflicts.length > 0 && !input.force) {\n throw new Error(\n JSON.stringify({\n error: 'undo_conflict',\n seq: entry.seq,\n conflicts,\n hint: 'A file changed after this write (by you or another tool). Re-check it, then pass force: true to restore anyway — the current state is journaled first.',\n }),\n );\n }\n\n // Load every pre-image before touching disk so a missing blob aborts cleanly.\n const preimages = new Map<string, string | null>();\n for (const f of entry.files) {\n preimages.set(f.path, f.preHash === null ? null : await journal.preimage(f.preHash));\n }\n\n // Journal the undo (current state → pre-image) — undoing it redoes the write.\n const txn = journal.begin('undo_write', entry.seq);\n for (const f of entry.files) {\n await txn.add(f.path, current.get(f.path) ?? null, preimages.get(f.path) ?? null);\n }\n const undoEntry = await txn.commit();\n\n const restored: UndoWriteResult['restored'] = [];\n for (const f of entry.files) {\n const abs = resolveVaultPath(ctx.vaultRoot, f.path);\n const pre = preimages.get(f.path) ?? null;\n if (pre === null) {\n await rm(abs, { force: true });\n removeNoteBacklinks(ctx, f.path);\n if (ctx.notes.has(f.path)) {\n ctx.index.discard(f.path);\n ctx.notes.delete(f.path);\n }\n restored.push({ path: f.path, restoredHash: null });\n } else {\n await mkdir(dirname(abs), { recursive: true });\n await atomicWrite(abs, pre);\n if (f.path.endsWith('.md')) {\n removeNoteBacklinks(ctx, f.path);\n upsertDoc(ctx, buildDoc(f.path, pre));\n addNoteBacklinks(ctx, f.path, pre);\n }\n restored.push({ path: f.path, restoredHash: contentHash(pre) });\n }\n }\n\n const result: UndoWriteResult = {\n seq: entry.seq,\n undoSeq: undoEntry.seq,\n tool: entry.tool,\n restored,\n };\n if (conflicts.length > 0) result.overrode = conflicts;\n return result;\n}\n\n/**\n * Byte count of the post-write state, if the journal still holds it (it does\n * whenever a later entry journaled that state as ITS pre-image); otherwise\n * null — the diff summary is best-effort metadata.\n */\nasync function postBytes(\n journal: NonNullable<ServerContext['journal']>,\n hash: string,\n): Promise<number | null> {\n try {\n return Buffer.byteLength(await journal.preimage(hash), 'utf8');\n } catch {\n return null;\n }\n}\n","import { type AuditFile, type AuditRecord, classifyError } from './audit.js';\nimport type { ServerContext } from './context.js';\nimport type { Logger } from './log.js';\nimport { AppendNoteInput, appendNote } from './tools/append_note.js';\nimport { ContextPackInput, contextPack } from './tools/context_pack.js';\nimport { CreateNoteInput, createNote } from './tools/create_note.js';\nimport { DeleteNoteInput, deleteNote } from './tools/delete_note.js';\nimport { GetBacklinksInput, getBacklinks } from './tools/get_backlinks.js';\nimport { GetLinksInput, getLinks } from './tools/get_links.js';\nimport { ListNotesInput, listNotes } from './tools/list_notes.js';\nimport { ListTagsInput, listTags } from './tools/list_tags.js';\nimport { ListWritesInput, listWrites } from './tools/list_writes.js';\nimport { MoveNoteInput, moveNote } from './tools/move_note.js';\nimport { OutlineNoteInput, outlineNote } from './tools/outline_note.js';\nimport { PatchFrontmatterInput, patchFrontmatter } from './tools/patch_frontmatter.js';\nimport { PatchNoteInput, patchNote } from './tools/patch_note.js';\nimport {\n AppendPeriodicNoteInput,\n appendPeriodicNote,\n GetPeriodicNoteInput,\n getPeriodicNote,\n} from './tools/periodic_note.js';\nimport { QueryNotesInput, queryNotes } from './tools/query_notes.js';\nimport { ReadNoteInput, readNote } from './tools/read_note.js';\nimport { RenameHeadingInput, renameHeading } from './tools/rename_heading.js';\nimport { ReplaceInNoteInput, replaceInNote } from './tools/replace_in_note.js';\nimport { SearchInput, search } from './tools/search.js';\nimport { UndoWriteInput, undoWrite } from './tools/undo_write.js';\n\nexport type ToolResult = {\n content: { type: 'text'; text: string }[];\n isError?: boolean;\n /**\n * Op-specific audit metadata set by write-tool cases (paths, counts,\n * flags — never content). Consumed and stripped by dispatch; absent means\n * \"nothing to audit\" (e.g. get_periodic_note that did not create).\n */\n audit?: Record<string, unknown>;\n};\n\n/** Tool names this dispatcher handles — kept in sync with the server's tool list. */\nexport const HANDLED_TOOLS = [\n 'search',\n 'query_notes',\n 'context_pack',\n 'read_note',\n 'list_notes',\n 'list_tags',\n 'create_note',\n 'delete_note',\n 'move_note',\n 'rename_heading',\n 'append_note',\n 'patch_frontmatter',\n 'outline_note',\n 'patch_note',\n 'get_backlinks',\n 'get_links',\n 'replace_in_note',\n 'get_periodic_note',\n 'append_periodic_note',\n 'list_writes',\n 'undo_write',\n] as const;\n\n/**\n * Tools that mutate the vault. Enforced here at dispatch (read-only mode\n * rejects them) and mirrored by tool-list.ts, which unregisters them from\n * tools/list — a new write tool must be added to this set to ship.\n */\nexport const WRITE_TOOLS: ReadonlySet<string> = new Set([\n 'create_note',\n 'delete_note',\n 'move_note',\n 'rename_heading',\n 'append_note',\n 'patch_frontmatter',\n 'patch_note',\n 'replace_in_note',\n 'append_periodic_note',\n 'undo_write',\n]);\n\n// Metadata-safe keys: logged at info. Note content (`content`, `frontmatter`,\n// `patch`) and the raw `query` string are intentionally excluded — they only\n// reach logs via the debug-level `args` dump.\nconst META_KEYS = [\n 'path',\n 'from',\n 'to',\n 'folder',\n 'tag',\n 'mode',\n 'limit',\n 'overwrite',\n 'pattern',\n 'minCount',\n 'sort',\n 'order',\n 'select',\n 'modifiedAfter',\n 'modifiedBefore',\n 'minSizeBytes',\n 'maxSizeBytes',\n 'period',\n 'date',\n 'permanent',\n 'prevHash',\n 'budgetBytes',\n 'seq',\n 'force',\n] as const;\n\nfunction safeMeta(args: unknown): Record<string, unknown> {\n if (typeof args !== 'object' || args === null) return {};\n const a = args as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const k of META_KEYS) {\n if (a[k] !== undefined) out[k] = a[k];\n }\n if (typeof a.query === 'string') out.queryLen = a.query.length; // not the query itself\n if (Array.isArray(a.where)) out.whereCount = a.where.length; // predicate values may be personal\n return out;\n}\n\nfunction resultBytes(r: ToolResult): number {\n let n = 0;\n for (const c of r.content) n += Buffer.byteLength(c.text);\n return n;\n}\n\n/**\n * Route a tool call to its handler, logging the outcome. Returns an MCP tool\n * result; failures are converted to `{ isError: true }` (never thrown) so the\n * transport stays alive, and are logged at `error` with a stack.\n */\nexport async function dispatch(\n ctx: ServerContext,\n name: string,\n args: unknown,\n log: Logger,\n): Promise<ToolResult> {\n const start = performance.now();\n const meta = safeMeta(args);\n log.debug('tool start', { tool: name, args }); // full args (may include content) — debug only\n if (ctx.policy.readOnly && WRITE_TOOLS.has(name)) {\n // Unregistered from tools/list, but a client can still send the call.\n log.info('tool rejected (read-only)', { tool: name, ...meta });\n const rejected: ToolResult = {\n content: [\n {\n type: 'text',\n text: 'Error: Server is read-only (SEEKSTONE_READ_ONLY=1); write tools are disabled.',\n },\n ],\n isError: true,\n };\n return audit(ctx, log, rejected, {\n v: 1,\n ts: new Date().toISOString(),\n tool: name,\n outcome: 'policy_denied',\n policy: 'read_only',\n error: 'read_only',\n durationMs: 0,\n ...pathMeta(meta),\n });\n }\n if (ctx.policy.readOnly && name === 'get_periodic_note') {\n // The one read tool with a write side-effect: force createIfMissing off.\n if (typeof args === 'object' && args !== null) {\n args = { ...(args as Record<string, unknown>), createIfMissing: false };\n }\n }\n const isWrite = WRITE_TOOLS.has(name) || name === 'get_periodic_note';\n const seqBefore = ctx.journal?.lastSeq ?? 0;\n const ts = new Date().toISOString();\n try {\n const { audit: detail, ...result } = await run(ctx, name, args);\n const durationMs = Math.round((performance.now() - start) * 100) / 100;\n log.info('tool ok', { tool: name, durationMs, resultBytes: resultBytes(result), ...meta });\n if (!isWrite || detail === undefined) return result;\n return audit(ctx, log, result, {\n v: 1,\n ts,\n tool: name,\n outcome: 'ok',\n durationMs,\n ...journalFiles(ctx, seqBefore, detail),\n ...detail,\n });\n } catch (err) {\n const durationMs = Math.round((performance.now() - start) * 100) / 100;\n const message = err instanceof Error ? err.message : String(err);\n log.error('tool error', {\n tool: name,\n durationMs,\n error: message,\n stack: err instanceof Error ? err.stack : undefined,\n ...meta,\n });\n const failed: ToolResult = {\n content: [{ type: 'text', text: `Error: ${message}` }],\n isError: true,\n };\n if (!isWrite) return failed;\n return audit(ctx, log, failed, {\n v: 1,\n ts,\n tool: name,\n ...classifyError(message),\n durationMs,\n ...pathMeta(meta),\n });\n }\n}\n\n/** Path-shaped metadata (path / from / to / seq) for records of calls that never reached a result. */\nfunction pathMeta(meta: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const k of ['path', 'from', 'to', 'seq'] as const)\n if (meta[k] !== undefined) out[k] = meta[k];\n return out;\n}\n\n/**\n * The hash-pair spine of an ok record: files + seq from the journal entry\n * this call committed; with the journal off, only the after-hash the tool\n * result carries.\n */\nfunction journalFiles(\n ctx: ServerContext,\n seqBefore: number,\n detail: Record<string, unknown>,\n): { seq?: number; files?: AuditFile[] } {\n const entry = ctx.journal?.since(seqBefore).at(-1);\n if (entry !== undefined) {\n return {\n seq: entry.seq,\n files: entry.files.map((f) => ({\n path: f.path,\n hashBefore: f.preHash,\n hashAfter: f.postHash,\n })),\n };\n }\n if (typeof detail.path === 'string' && typeof detail.contentHash === 'string') {\n return { files: [{ path: detail.path, hashAfter: detail.contentHash }] };\n }\n return {};\n}\n\n/**\n * Append the record when auditing is on. A failed append turns the (already\n * completed) call into a structured audit_failed error so an unauditable\n * write is never reported as a clean success.\n */\nfunction audit(ctx: ServerContext, log: Logger, result: ToolResult, rec: AuditRecord): ToolResult {\n if (!ctx.audit) return result;\n try {\n ctx.audit.record(rec);\n return result;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n log.error('audit write failed', { tool: rec.tool, error: message });\n return {\n content: [\n {\n type: 'text',\n text: `Error: ${JSON.stringify({\n error: 'audit_failed',\n tool: rec.tool,\n outcome: rec.outcome,\n hint: `The audit record could not be written (${message}). The vault operation itself ${\n rec.outcome === 'ok' ? 'DID complete' : 'did not run'\n }; fix SEEKSTONE_AUDIT_FILE before continuing.`,\n })}`,\n },\n ],\n isError: true,\n };\n }\n}\n\nasync function run(ctx: ServerContext, name: string, args: unknown): Promise<ToolResult> {\n switch (name) {\n case 'search': {\n const input = SearchInput.parse(args);\n const hits = search(ctx, input);\n // Minified: search is the headline context-tax metric — indentation is pure tax.\n return { content: [{ type: 'text', text: JSON.stringify(hits) }] };\n }\n case 'query_notes': {\n const input = QueryNotesInput.parse(args);\n const hits = queryNotes(ctx, input);\n // Minified like search — a second search mode, same context-tax discipline.\n return { content: [{ type: 'text', text: JSON.stringify(hits) }] };\n }\n case 'context_pack': {\n const input = ContextPackInput.parse(args);\n const pack = contextPack(ctx, input);\n // Minified: the assembler meters its byte budget against exactly this serialization.\n return { content: [{ type: 'text', text: JSON.stringify(pack) }] };\n }\n case 'read_note': {\n const input = ReadNoteInput.parse(args);\n const result = await readNote(ctx, input);\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };\n }\n case 'list_notes': {\n const input = ListNotesInput.parse(args);\n const entries = listNotes(ctx, input);\n return { content: [{ type: 'text', text: JSON.stringify(entries, null, 2) }] };\n }\n case 'list_tags': {\n const input = ListTagsInput.parse(args);\n const result = listTags(ctx, input);\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };\n }\n case 'create_note': {\n const input = CreateNoteInput.parse(args);\n const result = await createNote(ctx, input);\n return {\n content: [\n {\n type: 'text',\n text: `Created ${result.path} (${result.bytesWritten} bytes). contentHash: ${result.contentHash}`,\n },\n ],\n audit: {\n path: result.path,\n contentHash: result.contentHash,\n bytesWritten: result.bytesWritten,\n overwrite: input.overwrite,\n },\n };\n }\n case 'delete_note': {\n const input = DeleteNoteInput.parse(args);\n const result = await deleteNote(ctx, input);\n const text = result.trashedTo\n ? `Moved ${result.path} to ${result.trashedTo} (recoverable — restore by moving it back).`\n : `Permanently deleted ${result.path}.`;\n const audit: Record<string, unknown> = {\n path: result.path,\n contentHash: result.contentHash,\n permanent: result.permanent,\n };\n if (result.trashedTo !== undefined) audit.trashedTo = result.trashedTo;\n return { content: [{ type: 'text', text }], audit };\n }\n case 'move_note': {\n const input = MoveNoteInput.parse(args);\n const result = await moveNote(ctx, input);\n let text = `Moved ${result.from} → ${result.to}. Rewrote ${result.linksRewritten} link${\n result.linksRewritten === 1 ? '' : 's'\n } in ${result.notesRewritten} note${result.notesRewritten === 1 ? '' : 's'}.`;\n if (result.skipped?.length) {\n text += ` Skipped (outside SEEKSTONE_WRITE_PATHS): ${result.skipped.join(', ')}.`;\n }\n return {\n content: [{ type: 'text', text }],\n audit: {\n from: result.from,\n to: result.to,\n contentHash: result.contentHash,\n notesRewritten: result.notesRewritten,\n linksRewritten: result.linksRewritten,\n ...(result.skipped?.length ? { skipped: result.skipped } : {}),\n },\n };\n }\n case 'rename_heading': {\n const input = RenameHeadingInput.parse(args);\n const result = await renameHeading(ctx, input);\n let text = `Renamed heading \"${result.oldHeading}\" → \"${result.newHeading}\" in ${result.path} (line ${result.line}). Rewrote ${result.linksRewritten} link${\n result.linksRewritten === 1 ? '' : 's'\n } in ${result.notesRewritten} note${result.notesRewritten === 1 ? '' : 's'}. contentHash: ${result.contentHash}`;\n if (result.skipped?.length) {\n text += ` Skipped (outside SEEKSTONE_WRITE_PATHS): ${result.skipped.join(', ')}.`;\n }\n return {\n content: [{ type: 'text', text }],\n audit: {\n path: result.path,\n contentHash: result.contentHash,\n line: result.line,\n notesRewritten: result.notesRewritten,\n linksRewritten: result.linksRewritten,\n ...(result.skipped?.length ? { skipped: result.skipped } : {}),\n },\n };\n }\n case 'append_note': {\n const input = AppendNoteInput.parse(args);\n const result = await appendNote(ctx, input);\n return {\n content: [\n {\n type: 'text',\n text: `Appended ${result.bytesWritten} bytes to ${result.path}. contentHash: ${result.contentHash}`,\n },\n ],\n audit: {\n path: result.path,\n contentHash: result.contentHash,\n bytesWritten: result.bytesWritten,\n },\n };\n }\n case 'patch_frontmatter': {\n const input = PatchFrontmatterInput.parse(args);\n const result = await patchFrontmatter(ctx, input);\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n // Key NAMES only — values are note content and never leave the tool.\n audit: {\n path: result.path,\n contentHash: result.contentHash,\n keysChanged: result.keysChanged,\n keysAdded: result.keysAdded,\n keysRemoved: result.keysRemoved,\n },\n };\n }\n case 'outline_note': {\n const input = OutlineNoteInput.parse(args);\n const result = await outlineNote(ctx, input);\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };\n }\n case 'patch_note': {\n const input = PatchNoteInput.parse(args);\n const result = await patchNote(ctx, input);\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n audit: {\n path: result.path,\n contentHash: result.contentHash,\n bytesWritten: result.bytesWritten,\n operation: input.operation,\n targetLine: result.targetResolvedAt.line,\n },\n };\n }\n case 'get_backlinks': {\n const input = GetBacklinksInput.parse(args);\n const result = getBacklinks(ctx, input);\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };\n }\n case 'get_links': {\n const input = GetLinksInput.parse(args);\n const result = getLinks(ctx, input);\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };\n }\n case 'replace_in_note': {\n const input = ReplaceInNoteInput.parse(args);\n const result = await replaceInNote(ctx, input);\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n audit: {\n path: result.path,\n contentHash: result.contentHash,\n replacements: result.replacements,\n dryRun: input.dryRun,\n },\n };\n }\n case 'get_periodic_note': {\n const input = GetPeriodicNoteInput.parse(args);\n const result = await getPeriodicNote(ctx, input);\n const out: ToolResult = {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n };\n // Only the create side-effect is a write worth auditing.\n if (result.created) {\n out.audit = { path: result.path, contentHash: result.contentHash, created: true };\n }\n return out;\n }\n case 'append_periodic_note': {\n const input = AppendPeriodicNoteInput.parse(args);\n const result = await appendPeriodicNote(ctx, input);\n return {\n content: [\n {\n type: 'text',\n text: `Appended ${result.bytesWritten} bytes to ${result.path}. contentHash: ${result.contentHash}`,\n },\n ],\n audit: {\n path: result.path,\n contentHash: result.contentHash,\n bytesWritten: result.bytesWritten,\n },\n };\n }\n case 'list_writes': {\n const input = ListWritesInput.parse(args);\n const result = listWrites(ctx, input);\n return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };\n }\n case 'undo_write': {\n const input = UndoWriteInput.parse(args);\n const result = await undoWrite(ctx, input);\n return {\n content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],\n audit: {\n undoOf: result.seq,\n restored: result.restored.length,\n ...(result.overrode ? { forced: true, overrode: result.overrode.length } : {}),\n },\n };\n }\n default:\n throw new Error(`Unknown tool: ${name}`);\n }\n}\n","import { readFile } from 'node:fs/promises';\nimport { basename, extname } from 'node:path';\nimport { extractInlineTags, extractLinksWithLines, frontmatterTags } from '@seekstone/core/extract';\nimport { parseFrontmatter } from '@seekstone/core/frontmatter';\nimport { walkVault } from '@seekstone/core/walk';\nimport MiniSearch from 'minisearch';\nimport type { BacklinkRef } from '../context.js';\nimport { buildResolveMaps, resolveLink } from './resolve.js';\nimport type { IndexedNote } from './types.js';\n\nexport type VaultIndex = MiniSearch<IndexedNote>;\n\nexport interface BuildResult {\n index: VaultIndex;\n notes: Map<string, IndexedNote>;\n backlinks: Map<string, BacklinkRef[]>;\n buildMs: number;\n}\n\nexport async function buildIndex(vaultRoot: string): Promise<BuildResult> {\n const t0 = Date.now();\n\n const index = new MiniSearch<IndexedNote>({\n idField: 'id',\n fields: ['title', 'body', 'tags', 'fmKeys'],\n storeFields: ['id', 'title', 'tags', 'sizeBytes', 'mtimeMs'],\n searchOptions: {\n boost: { title: 3, tags: 2, body: 1 },\n fuzzy: 0.2,\n prefix: true,\n },\n });\n\n const entries = await walkVault(vaultRoot);\n const noteEntries = entries.filter((e) => e.kind === 'note');\n\n const docs: IndexedNote[] = [];\n const notes = new Map<string, IndexedNote>();\n\n await Promise.all(\n noteEntries.map(async (entry) => {\n try {\n const raw = await readFile(entry.absPath, 'utf8');\n const fm = parseFrontmatter(raw);\n const inlineTags = extractInlineTags(fm.body);\n const fmTags = frontmatterTags(fm.data);\n const allTags = [...new Set([...inlineTags, ...fmTags])];\n\n const title =\n typeof fm.data?.title === 'string' && fm.data.title\n ? fm.data.title\n : basename(entry.relPath, extname(entry.relPath));\n\n const doc: IndexedNote = {\n id: entry.relPath,\n title,\n body: fm.body,\n tags: allTags.join(' '),\n fmKeys: fm.keys.join(' '),\n fm: fm.data,\n raw,\n sizeBytes: entry.sizeBytes,\n mtimeMs: entry.mtimeMs,\n };\n docs.push(doc);\n notes.set(entry.relPath, doc);\n } catch {\n // Unreadable note — skip silently; index what we can.\n }\n }),\n );\n\n index.addAll(docs);\n\n const backlinks = buildBacklinks(notes);\n\n return { index, notes, backlinks, buildMs: Date.now() - t0 };\n}\n\nfunction buildBacklinks(notes: Map<string, IndexedNote>): Map<string, BacklinkRef[]> {\n const result = new Map<string, BacklinkRef[]>();\n const resolveMaps = buildResolveMaps(notes);\n for (const [srcPath, doc] of notes) {\n const seen = new Set<string>();\n for (const link of extractLinksWithLines(doc.raw)) {\n const resolved = resolveLink(link.target, notes, resolveMaps);\n if (resolved === undefined) continue;\n // De-duplicate: one entry per (source, resolved-target) pair\n const dedupeKey = `${srcPath}\\0${resolved}`;\n if (seen.has(dedupeKey)) continue;\n seen.add(dedupeKey);\n let arr = result.get(resolved);\n if (arr === undefined) {\n arr = [];\n result.set(resolved, arr);\n }\n arr.push({ path: srcPath, line: link.line, linkType: link.linkType });\n }\n }\n for (const arr of result.values()) {\n arr.sort((a, b) => a.path.localeCompare(b.path));\n }\n return result;\n}\n","import { stat } from 'node:fs/promises';\nimport { extname, join, relative, sep } from 'node:path';\nimport fg from 'fast-glob';\n\n/**\n * Categories we care about. Anything else falls into `other`.\n * Excalidraw saves as `.excalidraw` (sometimes `.excalidraw.md` — handled in classify()).\n */\nexport type FileKind =\n | 'note'\n | 'image'\n | 'pdf'\n | 'excalidraw'\n | 'canvas'\n | 'video'\n | 'audio'\n | 'other';\n\nexport interface FileEntry {\n absPath: string;\n relPath: string;\n topDir: string;\n ext: string;\n kind: FileKind;\n sizeBytes: number;\n mtimeMs: number;\n}\n\nconst IMAGE_EXTS = new Set(['.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg', '.bmp', '.heic']);\nconst VIDEO_EXTS = new Set(['.mp4', '.mov', '.webm', '.mkv', '.avi']);\nconst AUDIO_EXTS = new Set(['.mp3', '.m4a', '.wav', '.flac', '.ogg']);\n\n/**\n * Obsidian's own dot-directories plus VCS noise. We deliberately don't ignore\n * dotfiles at the *file* level — users sometimes commit `.gitkeep` etc. — but\n * any top-level dotted directory is treated as non-vault content.\n */\nconst IGNORE_GLOBS = [\n '**/.obsidian/**',\n '**/.trash/**',\n '**/.seekstone/**',\n '**/.git/**',\n '**/.DS_Store',\n '**/node_modules/**',\n];\n\nexport function classify(relPath: string): FileKind {\n // Excalidraw plugin sometimes writes `.excalidraw.md` — keep those as notes\n // (they still have YAML frontmatter and links), but pure `.excalidraw` is canvas-like.\n if (relPath.endsWith('.excalidraw.md')) return 'note';\n if (relPath.endsWith('.excalidraw')) return 'excalidraw';\n const ext = extname(relPath).toLowerCase();\n if (ext === '.md') return 'note';\n if (ext === '.canvas') return 'canvas';\n if (ext === '.pdf') return 'pdf';\n if (IMAGE_EXTS.has(ext)) return 'image';\n if (VIDEO_EXTS.has(ext)) return 'video';\n if (AUDIO_EXTS.has(ext)) return 'audio';\n return 'other';\n}\n\nexport async function walkVault(vaultRoot: string): Promise<FileEntry[]> {\n // We use fast-glob with `stats: true` so we can avoid an extra stat() round per file.\n const matches = await fg('**/*', {\n cwd: vaultRoot,\n absolute: true,\n onlyFiles: true,\n followSymbolicLinks: false,\n dot: true, // include dotfiles so the ignore globs are the only gate\n ignore: IGNORE_GLOBS,\n stats: true,\n suppressErrors: true,\n });\n\n const entries: FileEntry[] = [];\n for (const m of matches) {\n // fast-glob with stats: true returns objects; without, strings. Narrow here.\n const absPath = typeof m === 'string' ? m : m.path;\n const stats = typeof m === 'string' ? await stat(absPath) : m.stats;\n if (!stats) continue;\n // Index keys are forward-slash vault-relative paths on every platform —\n // the watcher, wikilink resolution, and MCP tool inputs all assume `/`.\n const relPath = relative(vaultRoot, absPath).split(sep).join('/');\n const topDir = relPath.split('/')[0] ?? '';\n entries.push({\n absPath,\n relPath,\n topDir,\n ext: extname(relPath).toLowerCase(),\n kind: classify(relPath),\n sizeBytes: stats.size,\n mtimeMs: stats.mtimeMs,\n });\n }\n return entries;\n}\n\nexport function _testJoin(...parts: string[]): string {\n return join(...parts);\n}\n","// execFileSync is used (not exec/execSync) because it bypasses the shell\n// entirely — it exec's the named binary directly. There is no shell injection\n// risk. Socket.dev flags the child_process import as \"shellAccess\" regardless\n// of which function is used; that score penalty is accepted. See SHA-139.\nimport { execFileSync } from 'node:child_process';\nimport type { Dirent } from 'node:fs';\nimport { access, copyFile, mkdir, readdir, readFile, stat, writeFile } from 'node:fs/promises';\nimport path, { dirname, join } from 'node:path';\n\n/**\n * `seekstone init` — a guided setup helper. Validates an Obsidian vault and\n * prints (or, with --write, patches) the MCP config for the chosen client\n * (Claude Desktop, Claude Code, Cursor) so a user doesn't have to hand-edit\n * JSON or guess paths.\n *\n * The pure helpers (arg parsing, config-path resolution, additive merge,\n * command string) are exported and unit-tested. `runInit` wires them to the\n * filesystem and console.\n */\n\nexport interface InitOptions {\n vault?: string;\n write: boolean;\n client: 'desktop' | 'code' | 'cursor' | 'vscode';\n /** Set when --client was given an unrecognized value; runInit errors on it. */\n invalidClient?: string;\n}\n\nexport function parseInitArgs(argv: readonly string[]): InitOptions {\n const opts: InitOptions = { write: false, client: 'desktop' };\n // argv is everything after the `init` subcommand.\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === '--write') opts.write = true;\n else if (a === '--vault') opts.vault = argv[++i];\n else if (a === '--client') {\n const v = argv[++i];\n if (v === 'desktop' || v === 'code' || v === 'cursor' || v === 'vscode') opts.client = v;\n // Record the bad value instead of silently falling back to desktop —\n // agents run init non-interactively and would otherwise configure the\n // wrong client without anyone noticing.\n else opts.invalidClient = v ?? '(missing)';\n }\n }\n return opts;\n}\n\n/** The server config object that goes under `mcpServers.seekstone`. */\nexport function seekstoneServerConfig(vaultPath: string): {\n command: string;\n args: string[];\n env: Record<string, string>;\n} {\n return {\n command: 'npx',\n args: ['-y', 'seekstone'],\n env: { SEEKSTONE_VAULT: vaultPath },\n };\n}\n\n/** The `claude mcp add` one-liner for Claude Code. */\nexport function mcpAddCommand(vaultPath: string): string {\n return `claude mcp add seekstone --env SEEKSTONE_VAULT=${vaultPath} -- npx -y seekstone`;\n}\n\n/**\n * Resolve the Claude Desktop config path for a platform. Pure — takes the\n * platform and a home/APPDATA lookup so it can be tested without touching the\n * real environment.\n */\nexport function claudeDesktopConfigPath(\n platform: NodeJS.Platform,\n env: { home?: string; appData?: string },\n): string {\n // Use the target platform's path semantics, not the host's, so the result is\n // correct in production AND deterministic in tests on any CI OS.\n if (platform === 'win32') {\n const j = path.win32.join;\n const base = env.appData ?? j(env.home ?? '', 'AppData', 'Roaming');\n return j(base, 'Claude', 'claude_desktop_config.json');\n }\n const j = path.posix.join;\n const home = env.home ?? '';\n if (platform === 'darwin') {\n return j(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');\n }\n // Linux / other\n return j(home, '.config', 'Claude', 'claude_desktop_config.json');\n}\n\n/**\n * Resolve Cursor's global MCP config path for a platform. Cursor reads\n * `~/.cursor/mcp.json` on every OS (home-relative, no APPDATA) and uses the\n * same `mcpServers` shape as Claude Desktop. Pure, like claudeDesktopConfigPath.\n */\nexport function cursorConfigPath(platform: NodeJS.Platform, env: { home?: string }): string {\n const j = platform === 'win32' ? path.win32.join : path.posix.join;\n return j(env.home ?? '', '.cursor', 'mcp.json');\n}\n\n/**\n * VS Code (GitHub Copilot) workspace MCP config: `.vscode/mcp.json` under the\n * given working directory. Workspace-level on purpose — the user-global config\n * has no stable documented path (VS Code's \"MCP: Open User Configuration\"\n * command owns it), and workspace config takes precedence anyway. Host path\n * semantics (unlike the other path helpers) because it resolves the *real*\n * cwd of the running process, not a target-platform location.\n */\nexport function vscodeMcpConfigPath(cwd: string): string {\n return join(cwd, '.vscode', 'mcp.json');\n}\n\n/**\n * Resolve the Obsidian vault registry path for a platform. Pure — mirrors the\n * claudeDesktopConfigPath pattern so it can be tested without real filesystem.\n */\nexport function obsidianRegistryPath(\n platform: NodeJS.Platform,\n env: { home?: string; appData?: string },\n): string {\n if (platform === 'win32') {\n const j = path.win32.join;\n const base = env.appData ?? j(env.home ?? '', 'AppData', 'Roaming');\n return j(base, 'obsidian', 'obsidian.json');\n }\n const j = path.posix.join;\n const home = env.home ?? '';\n if (platform === 'darwin') {\n return j(home, 'Library', 'Application Support', 'obsidian', 'obsidian.json');\n }\n return j(home, '.config', 'obsidian', 'obsidian.json');\n}\n\nexport type ObsidianVaultEntry = { path: string; open?: boolean };\n\n/**\n * Parse Obsidian's obsidian.json vault registry. Tolerant of missing/extra\n * keys and malformed JSON — always returns an array. Sorted: open vault first,\n * then lexically by path for determinism across runs.\n */\nexport function parseObsidianVaults(json: string): ObsidianVaultEntry[] {\n let data: unknown;\n try {\n data = JSON.parse(json);\n } catch {\n return [];\n }\n if (!data || typeof data !== 'object') return [];\n const raw = (data as Record<string, unknown>).vaults;\n if (!raw || typeof raw !== 'object') return [];\n const entries: ObsidianVaultEntry[] = [];\n for (const v of Object.values(raw as Record<string, unknown>)) {\n if (v && typeof v === 'object') {\n const entry = v as Record<string, unknown>;\n if (typeof entry.path === 'string') {\n entries.push({ path: entry.path, open: entry.open === true });\n }\n }\n }\n return entries.sort((a, b) => {\n if (a.open !== b.open) return a.open ? -1 : 1;\n return a.path.localeCompare(b.path);\n });\n}\n\ntype McpConfig = { mcpServers?: Record<string, unknown> } & Record<string, unknown>;\n\n/**\n * Additively merge the seekstone server into an existing Claude config object.\n * Never removes or alters other servers or top-level keys. Idempotent: running\n * it again with the same vault produces an identical object. Returns a new\n * object (does not mutate the input).\n */\nexport function mergeSeekstoneConfig(existing: McpConfig | null, vaultPath: string): McpConfig {\n const base: McpConfig = existing ? structuredClone(existing) : {};\n const servers = { ...(base.mcpServers ?? {}) };\n servers.seekstone = seekstoneServerConfig(vaultPath);\n return { ...base, mcpServers: servers };\n}\n\ntype VsCodeMcpConfig = { servers?: Record<string, unknown> } & Record<string, unknown>;\n\n/** The server entry for VS Code, which requires an explicit `\"type\": \"stdio\"`. */\nexport function vscodeServerConfig(vaultPath: string): {\n type: 'stdio';\n command: string;\n args: string[];\n env: Record<string, string>;\n} {\n return { type: 'stdio', ...seekstoneServerConfig(vaultPath) };\n}\n\n/**\n * VS Code variant of mergeSeekstoneConfig. Same additive/idempotent contract,\n * but VS Code's mcp.json is the one client config keyed `\"servers\"` (not\n * `\"mcpServers\"`) and requires `\"type\": \"stdio\"` on each entry.\n */\nexport function mergeSeekstoneConfigVsCode(\n existing: VsCodeMcpConfig | null,\n vaultPath: string,\n): VsCodeMcpConfig {\n const base: VsCodeMcpConfig = existing ? structuredClone(existing) : {};\n const servers = { ...(base.servers ?? {}) };\n servers.seekstone = vscodeServerConfig(vaultPath);\n return { ...base, servers };\n}\n\nexport interface VaultCheck {\n ok: boolean;\n noteCount?: number;\n error?: string;\n}\n\n/** Validate that `vaultPath` looks like an Obsidian vault and count .md notes. */\nexport async function validateVault(vaultPath: string): Promise<VaultCheck> {\n try {\n const st = await stat(vaultPath);\n if (!st.isDirectory()) return { ok: false, error: `Not a directory: ${vaultPath}` };\n } catch {\n return { ok: false, error: `Path does not exist: ${vaultPath}` };\n }\n // An Obsidian vault has a .obsidian/ config folder.\n try {\n await access(join(vaultPath, '.obsidian'));\n } catch {\n return {\n ok: false,\n error: `No \".obsidian\" folder found in ${vaultPath} — this doesn't look like an Obsidian vault. Open the folder in Obsidian once to initialize it, or pass the correct --vault path.`,\n };\n }\n return { ok: true, noteCount: await countMarkdown(vaultPath) };\n}\n\nasync function countMarkdown(root: string): Promise<number> {\n let count = 0;\n async function walk(dir: string): Promise<void> {\n let entries: Dirent[];\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n if (e.name.startsWith('.')) continue; // skip .obsidian, .git, .trash\n const full = join(dir, e.name);\n if (e.isDirectory()) await walk(full);\n else if (e.name.endsWith('.md')) count++;\n }\n }\n await walk(root);\n return count;\n}\n\nexport interface InitResult {\n ok: boolean;\n /** Lines to print to stdout. */\n output: string[];\n /** Process exit code. */\n exitCode: number;\n /** Set when --write patched Claude Desktop config. */\n wrotePath?: string;\n backupPath?: string;\n /** Set when --write --client code successfully ran `claude mcp add`. */\n ranClaudeMcpAdd?: boolean;\n}\n\n/**\n * Run the init flow. `deps` are injectable for testing (env, platform, clock).\n * Performs filesystem reads always; only writes when `opts.write` is true.\n */\nexport async function runInit(\n opts: InitOptions,\n deps: {\n env: Record<string, string | undefined>;\n platform: NodeJS.Platform;\n /** ISO timestamp for the backup filename (injected for determinism in tests). */\n timestamp: string;\n /** Working directory for workspace-level configs (vscode); defaults to process.cwd(). */\n cwd?: string;\n /** Injectable for testing; defaults to fs/promises readFile. */\n readFile?: (p: string, enc: 'utf8') => Promise<string>;\n /**\n * Injectable for testing; defaults to execFileSync('claude', args).\n * Returns ok:true on success, ok:false with an error string on failure.\n */\n spawnClaudeMcp?: (args: string[]) => { ok: boolean; error?: string };\n },\n): Promise<InitResult> {\n if (opts.invalidClient !== undefined) {\n return {\n ok: false,\n exitCode: 1,\n output: [\n `✗ Unknown --client: ${opts.invalidClient}. Known clients: desktop, code, cursor, vscode.`,\n ],\n };\n }\n\n const rf = deps.readFile ?? readFile;\n let vaultPath = opts.vault ?? deps.env.SEEKSTONE_VAULT;\n\n if (!vaultPath) {\n // Auto-detect from Obsidian's vault registry.\n const registryPath = obsidianRegistryPath(deps.platform, {\n home: deps.env.HOME,\n appData: deps.env.APPDATA,\n });\n let vaults: ObsidianVaultEntry[] = [];\n try {\n vaults = parseObsidianVaults(await rf(registryPath, 'utf8'));\n } catch {\n // Registry missing or unreadable — fall through to error.\n }\n\n if (vaults.length === 0) {\n return {\n ok: false,\n exitCode: 1,\n output: [\n 'No vault specified. Pass --vault <path> or set SEEKSTONE_VAULT.',\n 'Example: seekstone init --vault \"/Users/you/Obsidian/My Vault\"',\n ],\n };\n }\n\n if (vaults.length === 1) {\n const [first] = vaults;\n vaultPath = first?.path ?? '';\n } else {\n const list = vaults\n .map((v, i) => ` ${i + 1}. ${v.path}${v.open ? ' (currently open)' : ''}`)\n .join('\\n');\n return {\n ok: false,\n exitCode: 1,\n output: [\n 'Multiple Obsidian vaults found. Re-run with --vault to pick one:',\n '',\n list,\n '',\n 'Example: seekstone init --vault \"/path/to/vault\"',\n ],\n };\n }\n }\n\n // Resolve to absolute before validating or writing config: clients spawn the\n // server from their own working directory, so a relative SEEKSTONE_VAULT in\n // the written config would silently point at the wrong place.\n vaultPath = path.resolve(deps.cwd ?? process.cwd(), vaultPath);\n\n const check = await validateVault(vaultPath);\n if (!check.ok) {\n return { ok: false, exitCode: 1, output: [`✗ ${check.error}`] };\n }\n\n const out: string[] = [\n `✓ Vault looks good: ${vaultPath}`,\n ` ${check.noteCount} markdown note${check.noteCount === 1 ? '' : 's'} found.`,\n '',\n ];\n\n if (opts.client === 'code') {\n if (opts.write) {\n const spawn =\n deps.spawnClaudeMcp ??\n ((args: string[]) => {\n try {\n // Runs `claude mcp add …` — the canonical way to register an MCP\n // server with Claude Code. execFileSync (no shell) is intentional;\n // writing ~/.claude.json directly would couple us to an internal\n // format Anthropic can change without notice.\n execFileSync('claude', args, { stdio: 'inherit' });\n return { ok: true };\n } catch (err) {\n return { ok: false, error: err instanceof Error ? err.message : String(err) };\n }\n });\n\n const mcpArgs = [\n 'mcp',\n 'add',\n 'seekstone',\n '--env',\n `SEEKSTONE_VAULT=${vaultPath}`,\n '--',\n 'npx',\n '-y',\n 'seekstone',\n ];\n const result = spawn(mcpArgs);\n\n if (result.ok) {\n out.push('✓ seekstone added to Claude Code.', '', 'Restart Claude Code to load seekstone.');\n return { ok: true, exitCode: 0, output: out, ranClaudeMcpAdd: true };\n }\n\n // claude not on PATH or command failed — fall back to manual instructions.\n out.push(\n '⚠ Could not run `claude mcp add` automatically.',\n result.error ? ` ${result.error}` : '',\n '',\n 'Run this command manually instead:',\n '',\n ` ${mcpAddCommand(vaultPath)}`,\n '',\n );\n return { ok: false, exitCode: 1, output: out };\n }\n\n out.push('Add to Claude Code by running:', '', ` ${mcpAddCommand(vaultPath)}`, '');\n return { ok: true, exitCode: 0, output: out };\n }\n\n // File-config clients: Claude Desktop and Cursor share the same\n // `mcpServers` JSON shape; VS Code uses `servers` + explicit `type: stdio`.\n // Only the config path, JSON shape, and restart hint differ.\n const clientLabel =\n opts.client === 'cursor'\n ? 'Cursor'\n : opts.client === 'vscode'\n ? 'VS Code (GitHub Copilot)'\n : 'Claude Desktop';\n const configPath =\n opts.client === 'vscode'\n ? vscodeMcpConfigPath(deps.cwd ?? process.cwd())\n : opts.client === 'cursor'\n ? cursorConfigPath(deps.platform, { home: deps.env.HOME })\n : claudeDesktopConfigPath(deps.platform, {\n home: deps.env.HOME,\n appData: deps.env.APPDATA,\n });\n const block =\n opts.client === 'vscode'\n ? JSON.stringify({ servers: { seekstone: vscodeServerConfig(vaultPath) } }, null, 2)\n : JSON.stringify({ mcpServers: { seekstone: seekstoneServerConfig(vaultPath) } }, null, 2);\n const restartHint =\n opts.client === 'vscode'\n ? 'Reload VS Code, then open Copilot Chat in Agent mode — seekstone appears in the tools picker.'\n : `Restart ${clientLabel} to load seekstone.`;\n\n if (!opts.write) {\n out.push(\n `Add this to your ${clientLabel} config:`,\n ` ${configPath}`,\n ...(opts.client === 'vscode'\n ? [\n ' (workspace config — run from your project root, or use the Command Palette\\'s \"MCP: Open User Configuration\" for user-global)',\n ]\n : []),\n '',\n block,\n '',\n `${restartHint} Or re-run with --write to patch it automatically.`,\n );\n return { ok: true, exitCode: 0, output: out };\n }\n\n // --write: additive, backed-up patch.\n let existing: McpConfig | null = null;\n let existingRaw: string | null = null;\n try {\n existingRaw = await rf(configPath, 'utf8');\n existing = JSON.parse(existingRaw) as McpConfig;\n } catch (err) {\n if (existingRaw !== null) {\n // File exists but isn't valid JSON — refuse rather than clobber.\n return {\n ok: false,\n exitCode: 1,\n output: [\n `✗ ${configPath} exists but is not valid JSON; not modifying it.`,\n ` ${err instanceof Error ? err.message : String(err)}`,\n ],\n };\n }\n existing = null; // file simply doesn't exist yet\n }\n\n const merged =\n opts.client === 'vscode'\n ? mergeSeekstoneConfigVsCode(existing, vaultPath)\n : mergeSeekstoneConfig(existing, vaultPath);\n let backupPath: string | undefined;\n await mkdir(dirname(configPath), { recursive: true });\n if (existingRaw !== null) {\n backupPath = `${configPath}.backup-${deps.timestamp}`;\n await copyFile(configPath, backupPath);\n }\n await writeFile(configPath, `${JSON.stringify(merged, null, 2)}\\n`, 'utf8');\n\n out.push(\n `✓ Patched ${configPath}`,\n backupPath ? ` Backup saved to ${backupPath}` : ' (created a new config file)',\n '',\n restartHint,\n );\n return { ok: true, exitCode: 0, output: out, wrotePath: configPath, backupPath };\n}\n","import type { Logger } from './log.js';\n\n/**\n * Install a process-level safety net for the long-lived stdio server session.\n *\n * The server's known async paths (dispatch, watcher) already guard themselves,\n * so a stray `unhandledRejection` is unexpected — but crashing the whole MCP\n * session (and discarding the in-memory index, which is expensive to rebuild)\n * is a worse outcome than logging it and staying up. So we log via stderr and\n * keep running. `uncaughtException` is deliberately left to Node's default\n * crash behaviour: continuing after a truly uncaught throw risks corrupt state.\n *\n * Returns a disposer that removes the listener (used by tests to avoid leaking\n * handlers across cases).\n */\nexport function installProcessGuards(log: Logger): () => void {\n const onUnhandledRejection = (reason: unknown): void => {\n const error = reason instanceof Error ? reason.message : String(reason);\n log.error('unhandled promise rejection (server kept alive)', { error });\n };\n\n process.on('unhandledRejection', onUnhandledRejection);\n\n return () => {\n process.off('unhandledRejection', onUnhandledRejection);\n };\n}\n","import { createHash } from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { mkdir, readdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { Logger } from '../log.js';\nimport type { SemanticConfig } from './config.js';\nimport { findModel, type ModelManifest } from './model-manifest.js';\n\n/**\n * Materialize the embedding model shipped inside the semantic .mcpb variant.\n *\n * `seekstone-semantic.mcpb` carries the pinned default model as sub-cap byte\n * shards (`model/<name>.NNN.part` — Claude Desktop rejects any packed file\n * over ~108KB, SHA-169) plus a `manifest.json` naming the bundled model id.\n * Its extension manifest sets `SEEKSTONE_BUNDLED_MODEL_DIR`, and at boot this\n * reassembles the shards into the exact directory `seekstone fetch-model`\n * would have downloaded to, verifying every file against the SAME pinned\n * SHA-256 hashes (model-manifest.ts). Pure disk-to-disk I/O: the zero-network\n * guarantee (no-network.test.ts) holds bit-for-bit.\n *\n * Already-valid files are left untouched, so this is a fast hash check on\n * every boot after the first. A bundled id that doesn't match the requested\n * model (SEEKSTONE_SEMANTIC_MODEL override) is skipped — Semantic.start then\n * fails with its usual fetch-model hint.\n */\n\nexport interface MaterializeDeps {\n /** Test seam: pinned manifest lookup; defaults to model-manifest.ts. */\n manifestFor?: (id: string) => ModelManifest | undefined;\n log?: Logger;\n}\n\nexport async function materializeBundledModel(\n cfg: SemanticConfig,\n bundledDir: string | undefined,\n deps: MaterializeDeps = {},\n): Promise<void> {\n if (!bundledDir) return;\n if (!existsSync(bundledDir)) {\n // The env var is only ever set by the extension manifest, so a missing\n // dir means a broken install — but the model may still be on disk from a\n // prior boot; let Semantic.start decide whether anything is wrong.\n deps.log?.warn('bundled model dir missing — skipping materialization', { dir: bundledDir });\n return;\n }\n let bundledId: string;\n try {\n const raw = await readFile(join(bundledDir, 'manifest.json'), 'utf8');\n bundledId = String(JSON.parse(raw).id);\n } catch (err) {\n throw new Error(\n `bundled model: cannot read ${join(bundledDir, 'manifest.json')} — the extension bundle ` +\n `is corrupt; reinstall it (${err instanceof Error ? err.message : String(err)})`,\n );\n }\n if (bundledId !== cfg.modelId) {\n deps.log?.info('bundled model does not match the requested model — skipping', {\n bundled: bundledId,\n requested: cfg.modelId,\n });\n return;\n }\n const manifest = (deps.manifestFor ?? findModel)(cfg.modelId);\n if (!manifest) return; // cfg.modelId was already validated against the pinned list at boot\n await mkdir(cfg.modelDir, { recursive: true });\n let written = 0;\n for (const file of manifest.files) {\n const dest = join(cfg.modelDir, file.name);\n if (existsSync(dest) && sha256(await readFile(dest)) === file.sha256) continue;\n const buf = await concatParts(bundledDir, file.name);\n const got = sha256(buf);\n if (got !== file.sha256) {\n throw new Error(\n `bundled model: checksum mismatch for ${file.name} (expected ${file.sha256}, got ${got}) — ` +\n 'the extension bundle is corrupt; reinstall it',\n );\n }\n // Write-then-rename so a concurrently booting server never reads a torn\n // file (a torn file would also fail the hash check above and self-heal).\n const tmp = `${dest}.tmp-${process.pid}`;\n await writeFile(tmp, buf);\n await rename(tmp, dest);\n written++;\n }\n if (written > 0) {\n deps.log?.info('bundled model materialized', {\n model: manifest.id,\n dir: cfg.modelDir,\n files: written,\n });\n }\n}\n\n/** Concatenate `<name>.NNN.part` shards from the bundle dir, in order. */\nasync function concatParts(bundledDir: string, name: string): Promise<Buffer> {\n const prefix = `${name}.`;\n const partNum = (f: string) => Number(f.slice(prefix.length, -'.part'.length));\n const parts = (await readdir(bundledDir))\n .filter((f) => {\n if (!f.startsWith(prefix) || !f.endsWith('.part')) return false;\n const middle = f.slice(prefix.length, -'.part'.length);\n return /^\\d+$/.test(middle);\n })\n .sort((a, b) => partNum(a) - partNum(b));\n if (parts.length === 0) {\n throw new Error(\n `bundled model: no shards for ${name} in ${bundledDir} — the extension bundle is ` +\n 'corrupt; reinstall it',\n );\n }\n const buffers: Buffer[] = [];\n for (const part of parts) buffers.push(await readFile(join(bundledDir, part)));\n return Buffer.concat(buffers);\n}\n\nfunction sha256(buf: Buffer): string {\n return createHash('sha256').update(buf).digest('hex');\n}\n","/**\n * Paragraph-window chunking for note embedding.\n *\n * Notes are split on blank lines (single newlines are hard-wrap artifacts and\n * stay inside their paragraph), then adjacent paragraphs are merged greedily\n * into ~250–400-word windows. A single mean-pooled vector over a very large\n * note dilutes every topic in it — the fixture vault's tail runs to 832 KB —\n * so retrieval scores each chunk and max-pools per note.\n *\n * Each chunk also carries its `[start, end)` character span in the\n * CRLF-normalized body, so consumers (chunk-aware excerpts) can slice the\n * matching passage without re-chunking the note.\n */\n\nexport interface Chunk {\n /** Embedding input: note title, blank line, window text. */\n text: string;\n /** Word count of the window body (excludes the title). */\n words: number;\n /** Start offset of the window in the CRLF-normalized body. */\n start: number;\n /** End offset (exclusive) of the window in the CRLF-normalized body. */\n end: number;\n}\n\ninterface Paragraph {\n text: string;\n words: number;\n start: number;\n end: number;\n}\n\nconst MIN_WINDOW_WORDS = 250;\nconst MAX_WINDOW_WORDS = 400;\n\nexport function chunkNote(title: string, body: string): Chunk[] {\n const normalized = body.replace(/\\r\\n/g, '\\n');\n const paragraphs = splitParagraphs(normalized).flatMap(splitOversized);\n\n if (paragraphs.length === 0) return [{ text: title, words: 0, start: 0, end: 0 }];\n\n const chunks: Chunk[] = [];\n let window: Paragraph[] = [];\n let windowWords = 0;\n const flush = () => {\n const first = window[0];\n const last = window[window.length - 1];\n if (!first || !last) return;\n chunks.push({\n text: `${title}\\n\\n${window.map((p) => p.text).join('\\n\\n')}`,\n words: windowWords,\n start: first.start,\n end: last.end,\n });\n window = [];\n windowWords = 0;\n };\n for (const para of paragraphs) {\n if (windowWords >= MIN_WINDOW_WORDS || windowWords + para.words > MAX_WINDOW_WORDS) flush();\n window.push(para);\n windowWords += para.words;\n }\n flush();\n return chunks;\n}\n\n/** Blank-line-delimited paragraphs with trimmed text and exact spans. */\nfunction splitParagraphs(normalized: string): Paragraph[] {\n const out: Paragraph[] = [];\n const push = (rawStart: number, raw: string) => {\n const text = raw.trim();\n if (text.length === 0) return;\n const start = rawStart + (raw.length - raw.trimStart().length);\n out.push({ text, words: countWords(text), start, end: start + text.length });\n };\n const sep = /\\n[ \\t]*\\n+/g;\n let prev = 0;\n for (const m of normalized.matchAll(sep)) {\n push(prev, normalized.slice(prev, m.index));\n prev = m.index + m[0].length;\n }\n push(prev, normalized.slice(prev));\n return out;\n}\n\n/**\n * Hard-split a paragraph longer than the window cap on word boundaries.\n * Piece text joins words with single spaces (identical embedding input to\n * the pre-span implementation); spans stay exact via word offsets.\n */\nfunction splitOversized(para: Paragraph): Paragraph[] {\n if (para.words <= MAX_WINDOW_WORDS) return [para];\n const words = [...para.text.matchAll(/\\S+/g)];\n const pieces: Paragraph[] = [];\n for (let i = 0; i < words.length; i += MAX_WINDOW_WORDS) {\n const slice = words.slice(i, i + MAX_WINDOW_WORDS);\n const first = slice[0];\n const last = slice[slice.length - 1];\n if (!first || !last) continue;\n pieces.push({\n text: slice.map((w) => w[0]).join(' '),\n words: slice.length,\n start: para.start + first.index,\n end: para.start + last.index + last[0].length,\n });\n }\n return pieces;\n}\n\nfunction countWords(text: string): number {\n const m = text.match(/\\S+/g);\n return m ? m.length : 0;\n}\n","/**\n * Static late-interaction MaxSim scorer (SHA-314).\n *\n * ColBERT's late-interaction mechanism over static token vectors: for each\n * query token, take the max cosine similarity over the candidate chunk's\n * tokens, then aggregate across query tokens. Token vectors come from the\n * already-loaded Model2Vec embedding matrix (TokenEmbedder.tokenEmbed), so\n * this recovers term-level evidence (\"lead\", \"sulphate\") that mean-pooling\n * dilutes — with zero new dependencies and no storage change.\n *\n * Rows in both TokenEmbeddings are L2-normalized by contract (see types.ts),\n * so the inner loop is a plain dot product. A zero row (zero embedding) never\n * wins a max against any positive similarity and contributes 0 if the chunk\n * is all-zero — degrading gracefully rather than throwing.\n */\nimport type { TokenEmbedding } from './types.js';\n\n/**\n * How per-query-token maxima combine:\n * - `sum`: Σ wᵢ·maxᵢ — rewards queries with more matched tokens (ColBERT's choice).\n * - `mean`: Σ wᵢ·maxᵢ / Σ wᵢ — length-invariant, comparable across queries.\n */\nexport type MaxSimAggregate = 'sum' | 'mean';\n\nexport interface MaxSimOptions {\n aggregate?: MaxSimAggregate;\n /**\n * Per-query-token weights (e.g. IDF down-weighting of common tokens).\n * Length must equal the query token count. Defaults to all-ones.\n */\n weights?: ArrayLike<number>;\n}\n\n/**\n * MaxSim score of `doc` against `query`. Returns 0 when either side has no\n * tokens (empty text) or when `mean` aggregation has zero total weight.\n */\nexport function maxsimScore(\n query: TokenEmbedding,\n doc: TokenEmbedding,\n opts: MaxSimOptions = {},\n): number {\n if (query.dim !== doc.dim) {\n throw new Error(`maxsim: query dim ${query.dim} does not match doc dim ${doc.dim}`);\n }\n const n = query.ids.length;\n const weights = opts.weights;\n if (weights !== undefined && weights.length !== n) {\n throw new Error(`maxsim: ${weights.length} weights for ${n} query tokens`);\n }\n const m = doc.ids.length;\n if (n === 0 || m === 0) return 0;\n const { dim } = query;\n const q = query.vectors;\n const d = doc.vectors;\n let sum = 0;\n let weightSum = 0;\n for (let i = 0; i < n; i++) {\n const qBase = i * dim;\n let best = -Infinity;\n for (let c = 0; c < m; c++) {\n const dBase = c * dim;\n let dot = 0;\n for (let j = 0; j < dim; j++) {\n dot += (q[qBase + j] as number) * (d[dBase + j] as number);\n }\n if (dot > best) best = dot;\n }\n const w = weights === undefined ? 1 : (weights[i] as number);\n sum += w * best;\n weightSum += w;\n }\n if ((opts.aggregate ?? 'sum') === 'mean') {\n return weightSum > 0 ? sum / weightSum : 0;\n }\n return sum;\n}\n\n/**\n * MaxSim of MANY docs against one query — same math as calling\n * `maxsimScore` per doc, but each (query token × vocab token) similarity is\n * computed once and memoized by vocab id across all docs. Candidate chunks\n * share most of their vocabulary, so this collapses the O(q·d·dim) dot work\n * to O(q·unique(d)·dim) per query — the difference between ~115 ms and a\n * single-digit rerank at depth 50 (SHA-314 latency budget).\n *\n * Assumes equal token ids carry identical vectors in every doc — true for\n * any table-gather embedder (tokenEmbed reads the same matrix row).\n */\nexport function maxsimScoreAll(\n query: TokenEmbedding,\n docs: ReadonlyArray<TokenEmbedding>,\n opts: MaxSimOptions = {},\n): number[] {\n const n = query.ids.length;\n const weights = opts.weights;\n if (weights !== undefined && weights.length !== n) {\n throw new Error(`maxsim: ${weights.length} weights for ${n} query tokens`);\n }\n const mean = (opts.aggregate ?? 'sum') === 'mean';\n const out = new Array<number>(docs.length).fill(0);\n if (n === 0) return out;\n const { dim } = query;\n const q = query.vectors;\n /** vocab id → similarity against each query token, computed on first sight. */\n const simCache = new Map<number, Float64Array>();\n const best = new Float64Array(n);\n for (let d = 0; d < docs.length; d++) {\n const doc = docs[d] as TokenEmbedding;\n if (doc.dim !== dim) {\n throw new Error(`maxsim: query dim ${dim} does not match doc dim ${doc.dim}`);\n }\n const m = doc.ids.length;\n if (m === 0) continue;\n best.fill(Number.NEGATIVE_INFINITY);\n for (let t = 0; t < m; t++) {\n const id = doc.ids[t] as number;\n let sims = simCache.get(id);\n if (sims === undefined) {\n sims = new Float64Array(n);\n const dBase = t * dim;\n for (let i = 0; i < n; i++) {\n const qBase = i * dim;\n let dot = 0;\n for (let j = 0; j < dim; j++) {\n dot += (q[qBase + j] as number) * (doc.vectors[dBase + j] as number);\n }\n sims[i] = dot;\n }\n simCache.set(id, sims);\n }\n for (let i = 0; i < n; i++) {\n const s = sims[i] as number;\n if (s > (best[i] as number)) best[i] = s;\n }\n }\n let sum = 0;\n let weightSum = 0;\n for (let i = 0; i < n; i++) {\n const w = weights === undefined ? 1 : (weights[i] as number);\n sum += w * (best[i] as number);\n weightSum += w;\n }\n out[d] = mean ? (weightSum > 0 ? sum / weightSum : 0) : sum;\n }\n return out;\n}\n\n/**\n * MaxSim over token-ID docs with lazy vector gather: `tokenVector(id)` is\n * called once per unique id across ALL docs, and the (query token × vocab\n * token) similarities are memoized alongside. This skips materializing the\n * ~450 per-token vectors of every candidate chunk — the depth-50 rerank\n * gathers only the candidate set's few thousand unique tokens per query.\n * Scores are bit-identical to `maxsimScoreAll` over `tokenEmbed`ed docs.\n */\nexport function maxsimScoreTokens(\n query: TokenEmbedding,\n docs: ReadonlyArray<ArrayLike<number>>,\n tokenVector: (id: number) => Float32Array,\n opts: MaxSimOptions = {},\n): number[] {\n const n = query.ids.length;\n const weights = opts.weights;\n if (weights !== undefined && weights.length !== n) {\n throw new Error(`maxsim: ${weights.length} weights for ${n} query tokens`);\n }\n const mean = (opts.aggregate ?? 'sum') === 'mean';\n const out = new Array<number>(docs.length).fill(0);\n if (n === 0) return out;\n const { dim } = query;\n const q = query.vectors;\n const simCache = new Map<number, Float64Array>();\n const best = new Float64Array(n);\n for (let d = 0; d < docs.length; d++) {\n const ids = docs[d] as ArrayLike<number>;\n const m = ids.length;\n if (m === 0) continue;\n best.fill(Number.NEGATIVE_INFINITY);\n for (let t = 0; t < m; t++) {\n const id = ids[t] as number;\n let sims = simCache.get(id);\n if (sims === undefined) {\n sims = new Float64Array(n);\n const vec = tokenVector(id);\n if (vec.length !== dim) {\n throw new Error(`maxsim: token vector dim ${vec.length} does not match query dim ${dim}`);\n }\n for (let i = 0; i < n; i++) {\n const qBase = i * dim;\n let dot = 0;\n for (let j = 0; j < dim; j++) {\n dot += (q[qBase + j] as number) * (vec[j] as number);\n }\n sims[i] = dot;\n }\n simCache.set(id, sims);\n }\n for (let i = 0; i < n; i++) {\n const s = sims[i] as number;\n if (s > (best[i] as number)) best[i] = s;\n }\n }\n let sum = 0;\n let weightSum = 0;\n for (let i = 0; i < n; i++) {\n const w = weights === undefined ? 1 : (weights[i] as number);\n sum += w * (best[i] as number);\n weightSum += w;\n }\n out[d] = mean ? (weightSum > 0 ? sum / weightSum : 0) : sum;\n }\n return out;\n}\n\n/**\n * BM25-form IDF of each query token over the candidate docs' token-id sets:\n * `ln(1 + (N − df + 0.5) / (df + 0.5))`. Computed over the CANDIDATE SET at\n * query time — no corpus-wide statistics, no index/cache change. A token in\n * every candidate gets a near-zero weight; a token in one candidate\n * dominates (SHA-314 R3).\n */\nexport function candidateSetIdf(\n queryIds: ArrayLike<number>,\n docs: ReadonlyArray<ArrayLike<number>>,\n): number[] {\n const n = docs.length;\n const docSets: Array<Set<number>> = [];\n for (const doc of docs) {\n const set = new Set<number>();\n for (let t = 0; t < doc.length; t++) set.add(doc[t] as number);\n docSets.push(set);\n }\n const out = new Array<number>(queryIds.length);\n for (let i = 0; i < queryIds.length; i++) {\n const id = queryIds[i] as number;\n let df = 0;\n for (const set of docSets) {\n if (set.has(id)) df++;\n }\n out[i] = Math.log(1 + (n - df + 0.5) / (df + 0.5));\n }\n return out;\n}\n","/**\n * Model2Vec static-embedding inference: tokenize → gather rows from the\n * embedding matrix → mean-pool → L2-normalize. Zipf token weighting is baked\n * into the matrix at distillation time, so inference is exactly this simple —\n * no ONNX runtime, no native code, no network.\n *\n * Special tokens are excluded from the pool with one exception: [UNK] rows\n * carry real signal in Model2Vec models and are kept, matching the reference\n * implementation (which strips the [CLS]/[SEP] post-processor and pools\n * whatever the tokenizer emits).\n *\n * The loader also exposes `tokenEmbed()` (SHA-314 MaxSim rerank): the same\n * token filter, but returning each kept token's matrix row individually,\n * L2-normalized per row — no second copy of the matrix, rows are gathered\n * from the same in-memory table `embed()` pools from.\n */\nimport { readFile } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\nimport { readSafetensors } from './safetensors.js';\nimport { loadWordPieceTokenizer } from './tokenizer.js';\nimport type { TokenEmbedder, TokenEmbedding } from './types.js';\n\ninterface Model2VecConfig {\n hidden_dim?: number;\n normalize?: boolean;\n}\n\nconst TENSOR_NAME = 'embeddings';\n\nexport async function loadModel2Vec(modelDir: string): Promise<TokenEmbedder> {\n const [configRaw, tokenizerRaw, weights] = await Promise.all([\n readFile(join(modelDir, 'config.json'), 'utf8'),\n readFile(join(modelDir, 'tokenizer.json'), 'utf8'),\n readFile(join(modelDir, 'model.safetensors')),\n ]);\n const config = JSON.parse(configRaw) as Model2VecConfig;\n const tokenizer = loadWordPieceTokenizer(JSON.parse(tokenizerRaw));\n\n const tensors = readSafetensors(weights);\n const tensor =\n tensors.get(TENSOR_NAME) ?? (tensors.size === 1 ? [...tensors.values()][0] : undefined);\n if (!tensor) {\n throw new Error(\n `model2vec: no \"${TENSOR_NAME}\" tensor in ${modelDir}; found: ${[...tensors.keys()].join(', ')}`,\n );\n }\n if (tensor.shape.length !== 2) {\n throw new Error(`model2vec: expected a 2-D embedding matrix, got [${tensor.shape.join(', ')}]`);\n }\n const [rows, dim] = tensor.shape as [number, number];\n if (rows !== tokenizer.vocabSize) {\n throw new Error(\n `model2vec: embedding rows (${rows}) do not match tokenizer vocab size (${tokenizer.vocabSize})`,\n );\n }\n if (config.hidden_dim !== undefined && config.hidden_dim !== dim) {\n throw new Error(\n `model2vec: config hidden_dim ${config.hidden_dim} does not match tensor dim ${dim}`,\n );\n }\n\n const table = tensor.data;\n\n /** Token ids `embed()` would pool: specials skipped, [UNK] kept. */\n function pooledIds(text: string): number[] {\n const ids: number[] = [];\n for (const id of tokenizer.encode(text)) {\n if (tokenizer.specialIds.has(id) && id !== tokenizer.unkId) continue;\n ids.push(id);\n }\n return ids;\n }\n\n return {\n id: basename(modelDir),\n dim,\n embed(text: string): Float32Array {\n const out = new Float32Array(dim);\n const ids = pooledIds(text);\n for (const id of ids) {\n const base = id * dim;\n for (let j = 0; j < dim; j++) {\n out[j] = (out[j] as number) + (table[base + j] as number);\n }\n }\n const pooled = ids.length;\n if (pooled === 0) return out;\n let sumSquares = 0;\n for (let j = 0; j < dim; j++) {\n const mean = (out[j] as number) / pooled;\n out[j] = mean;\n sumSquares += mean * mean;\n }\n const norm = Math.sqrt(sumSquares);\n if (norm > 0) {\n for (let j = 0; j < dim; j++) out[j] = (out[j] as number) / norm;\n }\n return out;\n },\n tokenEmbed(text: string): TokenEmbedding {\n const ids = pooledIds(text);\n const vectors = new Float32Array(ids.length * dim);\n for (let t = 0; t < ids.length; t++) {\n writeNormalizedRow(ids[t] as number, vectors, t * dim);\n }\n return { ids, dim, vectors };\n },\n tokenIds: pooledIds,\n tokenVector(id: number): Float32Array {\n if (!Number.isInteger(id) || id < 0 || id >= tokenizer.vocabSize) {\n throw new Error(`model2vec: token id ${id} outside vocab [0, ${tokenizer.vocabSize})`);\n }\n const out = new Float32Array(dim);\n writeNormalizedRow(id, out, 0);\n return out;\n },\n };\n\n /** Copy row `id` of the table into `out` at `offset`, L2-normalized (zero rows stay zero). */\n function writeNormalizedRow(id: number, out: Float32Array, offset: number): void {\n const base = id * dim;\n let sumSquares = 0;\n for (let j = 0; j < dim; j++) {\n const x = table[base + j] as number;\n out[offset + j] = x;\n sumSquares += x * x;\n }\n const norm = Math.sqrt(sumSquares);\n if (norm > 0) {\n for (let j = 0; j < dim; j++) {\n out[offset + j] = (out[offset + j] as number) / norm;\n }\n }\n }\n}\n","/**\n * Minimal safetensors reader — just enough for Model2Vec model files, which\n * hold a single F32 embedding matrix. Format: 8-byte little-endian header\n * length, JSON header mapping tensor name → { dtype, shape, data_offsets },\n * then the raw tensor data (offsets relative to the end of the header).\n *\n * F32 only by design; quantized (I8) Model2Vec variants are a documented\n * future case and fail loudly here rather than decode garbage.\n */\n\nexport interface SafeTensor {\n dtype: string;\n shape: number[];\n data: Float32Array;\n}\n\ninterface TensorMeta {\n dtype: string;\n shape: number[];\n data_offsets: [number, number];\n}\n\nexport function readSafetensors(buf: Uint8Array): Map<string, SafeTensor> {\n if (buf.byteLength < 8) {\n throw new Error(`safetensors: buffer too small (${buf.byteLength} bytes) to hold a header`);\n }\n const view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);\n const headerLen = Number(view.getBigUint64(0, true));\n if (8 + headerLen > buf.byteLength) {\n throw new Error(\n `safetensors: header length ${headerLen} exceeds buffer (${buf.byteLength} bytes)`,\n );\n }\n const header = JSON.parse(new TextDecoder().decode(buf.subarray(8, 8 + headerLen))) as Record<\n string,\n TensorMeta\n >;\n const dataStart = 8 + headerLen;\n\n const out = new Map<string, SafeTensor>();\n const unsupported: string[] = [];\n for (const [name, meta] of Object.entries(header)) {\n if (name === '__metadata__') continue;\n if (meta.dtype !== 'F32') {\n unsupported.push(`${name} (${meta.dtype})`);\n continue;\n }\n const [begin, end] = meta.data_offsets;\n const byteLen = end - begin;\n const elems = meta.shape.reduce((a, b) => a * b, 1);\n if (byteLen !== elems * 4) {\n throw new Error(\n `safetensors: tensor \"${name}\" data span ${byteLen} B does not match shape [${meta.shape.join(', ')}]`,\n );\n }\n if (dataStart + end > buf.byteLength) {\n throw new Error(`safetensors: tensor \"${name}\" extends past the end of the buffer`);\n }\n // Float32Array views require 4-byte alignment, and 8 + headerLen (or the\n // source Uint8Array's own byteOffset) may not provide it. Copy explicitly\n // when misaligned — Buffer.slice() is a view, not a copy, so it can't help.\n const absStart = buf.byteOffset + dataStart + begin;\n let data: Float32Array;\n if (absStart % 4 === 0) {\n data = new Float32Array(buf.buffer, absStart, elems);\n } else {\n const copy = new Uint8Array(byteLen);\n copy.set(buf.subarray(dataStart + begin, dataStart + end));\n data = new Float32Array(copy.buffer);\n }\n out.set(name, { dtype: meta.dtype, shape: meta.shape, data });\n }\n if (unsupported.length > 0) {\n throw new Error(`safetensors: only F32 tensors are supported; found ${unsupported.join(', ')}`);\n }\n return out;\n}\n","/**\n * Minimal WordPiece tokenizer for Model2Vec models — implements the subset of\n * the HF `tokenizer.json` contract the potion models use: BertNormalizer →\n * BertPreTokenizer → WordPiece. The [CLS]/[SEP] post-processor is deliberately\n * NOT applied: Model2Vec pools raw word tokens only.\n */\n\ninterface BertNormalizerJson {\n type?: string;\n clean_text?: boolean;\n handle_chinese_chars?: boolean;\n strip_accents?: boolean | null;\n lowercase?: boolean;\n}\n\ninterface WordPieceModelJson {\n type?: string;\n unk_token?: string;\n continuing_subword_prefix?: string;\n max_input_chars_per_word?: number;\n vocab?: Record<string, number>;\n}\n\ninterface TokenizerJson {\n normalizer?: BertNormalizerJson | null;\n added_tokens?: Array<{ id: number; content: string; special?: boolean }>;\n model?: WordPieceModelJson;\n}\n\nexport interface WordPieceTokenizer {\n encode(text: string): number[];\n readonly vocabSize: number;\n readonly unkId: number;\n /** Ids of tokens flagged `special` in tokenizer.json ([PAD], [UNK], [CLS], …). */\n readonly specialIds: ReadonlySet<number>;\n}\n\nexport function loadWordPieceTokenizer(tokenizerJson: unknown): WordPieceTokenizer {\n const tj = tokenizerJson as TokenizerJson;\n const model = tj?.model;\n if (model?.type !== 'WordPiece' || !model.vocab) {\n throw new Error(\n `tokenizer: unsupported model type \"${model?.type ?? 'missing'}\" (only WordPiece is implemented)`,\n );\n }\n const vocab = new Map(Object.entries(model.vocab));\n const unkToken = model.unk_token ?? '[UNK]';\n const unkId = vocab.get(unkToken);\n if (unkId === undefined) {\n throw new Error(`tokenizer: unk_token \"${unkToken}\" is not in the vocab`);\n }\n const prefix = model.continuing_subword_prefix ?? '##';\n const maxChars = model.max_input_chars_per_word ?? 100;\n const norm: BertNormalizerJson = tj.normalizer ?? {};\n const cleanText = norm.clean_text ?? true;\n const handleCjk = norm.handle_chinese_chars ?? true;\n const lowercase = norm.lowercase ?? true;\n // HF BertNormalizer: when strip_accents is unset it follows `lowercase`.\n const stripAccents = norm.strip_accents ?? lowercase;\n const specialIds: ReadonlySet<number> = new Set(\n (tj.added_tokens ?? []).filter((t) => t.special).map((t) => t.id),\n );\n\n function normalize(text: string): string {\n let out = cleanText ? doCleanText(text) : text;\n if (handleCjk) out = padCjkChars(out);\n if (stripAccents) out = out.normalize('NFD').replace(/\\p{Mn}/gu, '');\n if (lowercase) out = out.toLowerCase();\n return out;\n }\n\n function wordPiece(word: string): number[] {\n const chars = [...word];\n if (chars.length > maxChars) return [unkId as number];\n const ids: number[] = [];\n let start = 0;\n while (start < chars.length) {\n let end = chars.length;\n let id: number | undefined;\n while (start < end) {\n const piece = (start > 0 ? prefix : '') + chars.slice(start, end).join('');\n const found = vocab.get(piece);\n if (found !== undefined) {\n id = found;\n break;\n }\n end--;\n }\n // BERT semantics: any unmatchable remainder makes the whole word [UNK].\n if (id === undefined) return [unkId as number];\n ids.push(id);\n start = end;\n }\n return ids;\n }\n\n return {\n vocabSize: vocab.size,\n unkId,\n specialIds,\n encode(text: string): number[] {\n const ids: number[] = [];\n for (const word of preTokenize(normalize(text))) {\n for (const id of wordPiece(word)) ids.push(id);\n }\n return ids;\n },\n };\n}\n\n/** BertPreTokenizer: split on whitespace; every punctuation char is its own token. */\nfunction preTokenize(text: string): string[] {\n const words: string[] = [];\n let cur = '';\n for (const ch of text) {\n const cp = ch.codePointAt(0) as number;\n if (isWhitespace(ch, cp)) {\n if (cur) {\n words.push(cur);\n cur = '';\n }\n } else if (isPunctuation(ch, cp)) {\n if (cur) {\n words.push(cur);\n cur = '';\n }\n words.push(ch);\n } else {\n cur += ch;\n }\n }\n if (cur) words.push(cur);\n return words;\n}\n\n/** Drop control chars and U+0000/U+FFFD; fold all whitespace to a plain space. */\nfunction doCleanText(text: string): string {\n let out = '';\n for (const ch of text) {\n const cp = ch.codePointAt(0) as number;\n if (cp === 0 || cp === 0xfffd || isControl(ch, cp)) continue;\n out += isWhitespace(ch, cp) ? ' ' : ch;\n }\n return out;\n}\n\n/** Surround CJK ideographs with spaces so each is tokenized in isolation. */\nfunction padCjkChars(text: string): string {\n let out = '';\n for (const ch of text) {\n out += isCjk(ch.codePointAt(0) as number) ? ` ${ch} ` : ch;\n }\n return out;\n}\n\nfunction isWhitespace(ch: string, cp: number): boolean {\n if (cp === 0x20 || cp === 0x09 || cp === 0x0a || cp === 0x0d) return true;\n return /\\p{Zs}/u.test(ch);\n}\n\nfunction isControl(ch: string, cp: number): boolean {\n if (cp === 0x09 || cp === 0x0a || cp === 0x0d) return false;\n return /\\p{Cc}|\\p{Cf}/u.test(ch);\n}\n\nfunction isPunctuation(ch: string, cp: number): boolean {\n // BERT treats all ASCII non-alphanumeric printables as punctuation, even\n // those Unicode classes as symbols ($, +, <, =, >, ^, `, |, ~).\n if (\n (cp >= 33 && cp <= 47) ||\n (cp >= 58 && cp <= 64) ||\n (cp >= 91 && cp <= 96) ||\n (cp >= 123 && cp <= 126)\n ) {\n return true;\n }\n return /\\p{P}/u.test(ch);\n}\n\nfunction isCjk(cp: number): boolean {\n return (\n (cp >= 0x4e00 && cp <= 0x9fff) ||\n (cp >= 0x3400 && cp <= 0x4dbf) ||\n (cp >= 0x20000 && cp <= 0x2a6df) ||\n (cp >= 0x2a700 && cp <= 0x2b73f) ||\n (cp >= 0x2b740 && cp <= 0x2b81f) ||\n (cp >= 0x2b820 && cp <= 0x2ceaf) ||\n (cp >= 0xf900 && cp <= 0xfaff) ||\n (cp >= 0x2f800 && cp <= 0x2fa1f)\n );\n}\n","/**\n * Chunk → note score pooling (SHA-313).\n *\n * A note is embedded as many chunk vectors; retrieval scores every chunk and\n * must reduce them to one note score. Every pooling here consumes the SAME\n * per-chunk dot products — the choice changes aggregation only, never the\n * multiply count, so query latency is identical across poolings.\n *\n * - `max`: the single best chunk. A hub note with hundreds of chunks holds\n * hundreds of lottery tickets, so giant articles crowd out precise ones.\n * - `top2mean`: mean of the two best chunks (a single-chunk note keeps its\n * full score) — demands sustained relevance from large notes.\n * - `logdiscount`: best chunk minus `lambda · ln(chunkCount)` — a direct\n * length penalty; risks burying long notes that ARE the answer.\n * - `softmax`: softmax-weighted mean of chunk scores at `temperature` —\n * approaches max as τ→0 and the plain mean as τ→∞; a lucky lone chunk\n * is diluted by the note's many weak ones, while a note whose best\n * chunks agree keeps its score.\n *\n * The winning chunk (for excerpts / spans) is always the max-scoring chunk,\n * whatever pooling ranks the note — the excerpt should show the passage\n * that matched best.\n */\n\nexport type ChunkPooling =\n | 'max'\n | 'top2mean'\n | { kind: 'logdiscount'; lambda: number }\n | { kind: 'softmax'; temperature: number };\n\n/** Human-readable id for reports and condition names, e.g. `softmax-t0.1`. */\nexport function poolingId(p: ChunkPooling): string {\n if (typeof p === 'string') return p;\n return p.kind === 'logdiscount' ? `logdiscount-l${p.lambda}` : `softmax-t${p.temperature}`;\n}\n\n/**\n * Streaming per-note accumulator: feed each chunk's score (with its index),\n * then `pool()` for the note score. Tracks only O(1) state per note so the\n * scan stays a single pass over the packed vectors.\n */\nexport class PoolAccumulator {\n top = Number.NEGATIVE_INFINITY;\n second = Number.NEGATIVE_INFINITY;\n bestChunk = 0;\n count = 0;\n /** Σ w_i and Σ s_i·w_i with w_i = exp((s_i − 1) / τ); shift keeps exp() ≤ 1. */\n private sumW = 0;\n private sumSW = 0;\n private readonly invTemp: number;\n\n constructor(pooling: ChunkPooling) {\n this.invTemp =\n typeof pooling === 'object' && pooling.kind === 'softmax' ? 1 / pooling.temperature : 0;\n }\n\n add(score: number, chunkIndex: number): void {\n this.count++;\n if (score > this.top) {\n this.second = this.top;\n this.top = score;\n this.bestChunk = chunkIndex;\n } else if (score > this.second) {\n this.second = score;\n }\n if (this.invTemp > 0) {\n const w = Math.exp((score - 1) * this.invTemp);\n this.sumW += w;\n this.sumSW += score * w;\n }\n }\n\n pool(pooling: ChunkPooling): number {\n if (this.count === 0) return Number.NEGATIVE_INFINITY;\n if (pooling === 'max') return this.top;\n if (pooling === 'top2mean') {\n return this.second === Number.NEGATIVE_INFINITY ? this.top : (this.top + this.second) / 2;\n }\n if (pooling.kind === 'logdiscount') return this.top - pooling.lambda * Math.log(this.count);\n // softmax: sumW > 0 whenever count > 0 (exp never underflows to 0 for cosines).\n return this.sumW > 0 ? this.sumSW / this.sumW : this.top;\n }\n}\n\nexport function assertValidPooling(p: ChunkPooling): void {\n // Captured before narrowing: in the unknown-kind branches `p` is `never`\n // for well-typed callers, but JS callers can still pass junk.\n const raw: unknown = p;\n if (typeof p === 'string') {\n if (p !== 'max' && p !== 'top2mean') throw new Error(`pooling: unknown kind \"${String(raw)}\"`);\n return;\n }\n if (p.kind === 'logdiscount') {\n if (!(p.lambda >= 0))\n throw new Error(`pooling: logdiscount lambda must be ≥ 0 (got ${p.lambda})`);\n } else if (p.kind === 'softmax') {\n if (!(p.temperature > 0)) {\n throw new Error(`pooling: softmax temperature must be > 0 (got ${p.temperature})`);\n }\n } else {\n const kind = typeof raw === 'object' && raw !== null ? (raw as { kind?: unknown }).kind : raw;\n throw new Error(`pooling: unknown kind \"${String(kind)}\"`);\n }\n}\n","/**\n * The embedding seam: everything downstream (chunk index, cosine scan,\n * retrieval eval) depends only on this interface, so alternative runtimes\n * (transformers.js, bring-your-own-model) can slot in behind it later.\n */\nexport interface Embedder {\n /** Stable identifier, e.g. \"potion-base-8M\". */\n readonly id: string;\n /** Output dimensionality. */\n readonly dim: number;\n /**\n * L2-normalized embedding of `text`. Returns the zero vector when the\n * input produces no poolable tokens (empty or whitespace-only text).\n * Pure CPU, synchronous.\n */\n embed(text: string): Float32Array;\n}\n\n/**\n * Packed per-token vectors for late-interaction scoring: `ids.length` rows\n * of `dim` floats in `vectors` (row t at `t * dim`). Each row is\n * L2-normalized so a dot product between rows is cosine similarity; an\n * all-zero embedding row stays zero.\n */\nexport interface TokenEmbedding {\n /** Vocab id per kept token, in input order. */\n readonly ids: number[];\n readonly dim: number;\n /** Packed row-major matrix, length `ids.length * dim`. */\n readonly vectors: Float32Array;\n}\n\n/**\n * An Embedder that can also expose per-token vectors from its (already\n * loaded) embedding matrix. Token filtering matches `embed()` exactly:\n * special tokens are skipped except [UNK], which carries real signal in\n * Model2Vec models.\n */\nexport interface TokenEmbedder extends Embedder {\n tokenEmbed(text: string): TokenEmbedding;\n /** The token ids `tokenEmbed` would embed — tokenization only, no gather. */\n tokenIds(text: string): number[];\n /**\n * One token's L2-normalized matrix row (a fresh array per call — callers\n * that loop should memoize by id; equal ids always yield equal rows).\n */\n tokenVector(id: number): Float32Array;\n}\n\n/** Narrow an Embedder to TokenEmbedder when the runtime provides token vectors. */\nexport function isTokenEmbedder(e: Embedder): e is TokenEmbedder {\n return typeof (e as TokenEmbedder).tokenEmbed === 'function';\n}\n","import { createHash } from 'node:crypto';\nimport { mkdir, readFile, rename, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { NoteVectors } from './store.js';\n\n/**\n * Persisted embedding cache so restarts don't re-embed the vault: one flat\n * binary (all packed Float32 chunk vectors, then all Uint32 chunk spans)\n * plus a JSON manifest keyed by (path, contentHash). Lives under the cache\n * dir, never inside the vault, in a per-vault subdirectory (sha of the vault\n * root) so multiple vaults never collide.\n *\n * Load is best-effort: any mismatch (version, model, dim, byte length,\n * binHash) silently invalidates the cache — the build just re-embeds. Writes\n * are temp-file + rename (binary first, then the manifest that describes it),\n * so a crash leaves either the old cache or the new one.\n */\n\n/** Bump when the on-disk layout OR the chunker semantics change. */\nconst CACHE_VERSION = 3;\n\nexport interface CachePaths {\n dir: string;\n bin: string;\n manifest: string;\n}\n\ninterface CacheManifest {\n version: number;\n modelId: string;\n dim: number;\n binHash: string;\n entries: Array<{ path: string; contentHash: string; chunks: number }>;\n}\n\nexport interface CacheData {\n vectors: Map<string, NoteVectors>;\n hashes: Map<string, string>;\n}\n\nexport function cachePathsFor(cacheDir: string, vaultRoot: string, modelId: string): CachePaths {\n const vaultKey = createHash('sha256').update(vaultRoot).digest('hex').slice(0, 16);\n const dir = join(cacheDir, 'embeddings', vaultKey);\n return { dir, bin: join(dir, `${modelId}.bin`), manifest: join(dir, `${modelId}.json`) };\n}\n\nexport async function loadCache(\n paths: CachePaths,\n modelId: string,\n dim: number,\n): Promise<CacheData | undefined> {\n try {\n const manifest = JSON.parse(await readFile(paths.manifest, 'utf8')) as CacheManifest;\n if (\n manifest.version !== CACHE_VERSION ||\n manifest.modelId !== modelId ||\n manifest.dim !== dim\n ) {\n return undefined;\n }\n const buf = await readFile(paths.bin);\n const totalChunks = manifest.entries.reduce((a, e) => a + e.chunks, 0);\n const vectorBytes = totalChunks * dim * 4;\n const spanBytes = totalChunks * 2 * 4;\n if (buf.byteLength !== vectorBytes + spanBytes) return undefined;\n if (binHashOf(buf) !== manifest.binHash) return undefined;\n // Buffers can be unaligned for typed-array views — copy to a fresh buffer.\n const aligned = new Uint8Array(buf.byteLength);\n aligned.set(buf);\n const floats = new Float32Array(aligned.buffer, 0, totalChunks * dim);\n const spans = new Uint32Array(aligned.buffer, vectorBytes, totalChunks * 2);\n const vectors = new Map<string, NoteVectors>();\n const hashes = new Map<string, string>();\n let chunkOffset = 0;\n for (const e of manifest.entries) {\n if (e.chunks <= 0) return undefined;\n vectors.set(e.path, {\n packed: floats.subarray(chunkOffset * dim, (chunkOffset + e.chunks) * dim),\n spans: spans.subarray(chunkOffset * 2, (chunkOffset + e.chunks) * 2),\n });\n hashes.set(e.path, e.contentHash);\n chunkOffset += e.chunks;\n }\n return { vectors, hashes };\n } catch {\n return undefined;\n }\n}\n\nexport async function saveCache(\n paths: CachePaths,\n modelId: string,\n dim: number,\n notes: Iterable<[string, NoteVectors]>,\n hashes: ReadonlyMap<string, string>,\n): Promise<void> {\n const rows: Array<{ path: string; contentHash: string; chunks: number; note: NoteVectors }> = [];\n let totalChunks = 0;\n for (const [path, note] of notes) {\n const contentHash = hashes.get(path);\n if (!contentHash) continue; // still being (re-)embedded — skip this round\n const chunks = note.packed.length / dim;\n rows.push({ path, contentHash, chunks, note });\n totalChunks += chunks;\n }\n rows.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));\n const entries: CacheManifest['entries'] = rows.map(({ path, contentHash, chunks }) => ({\n path,\n contentHash,\n chunks,\n }));\n const kept = rows.map((r) => r.note);\n const bin = new Uint8Array(totalChunks * dim * 4 + totalChunks * 2 * 4);\n const floats = new Float32Array(bin.buffer, 0, totalChunks * dim);\n const spans = new Uint32Array(bin.buffer, totalChunks * dim * 4, totalChunks * 2);\n let floatOffset = 0;\n let spanOffset = 0;\n for (const note of kept) {\n floats.set(note.packed, floatOffset);\n spans.set(note.spans, spanOffset);\n floatOffset += note.packed.length;\n spanOffset += note.spans.length;\n }\n const manifest: CacheManifest = {\n version: CACHE_VERSION,\n modelId,\n dim,\n binHash: binHashOf(bin),\n entries,\n };\n\n await mkdir(paths.dir, { recursive: true });\n // Binary first, manifest last: the manifest is the commit point, and load\n // validates the binary against the hash it records, so a torn state just\n // invalidates the cache.\n await atomicWriteBytes(paths.bin, bin);\n await atomicWriteBytes(paths.manifest, new TextEncoder().encode(JSON.stringify(manifest)));\n}\n\nfunction binHashOf(bin: Uint8Array): string {\n return createHash('sha256').update(bin).digest('hex');\n}\n\nlet tempSeq = 0;\n\nexport function tempPathFor(absPath: string): string {\n tempSeq += 1;\n return `${absPath}.${process.pid}.${tempSeq}.seekstone-cache-tmp`;\n}\n\nasync function atomicWriteBytes(absPath: string, bytes: Uint8Array): Promise<void> {\n const tmpPath = tempPathFor(absPath);\n await writeFile(tmpPath, bytes);\n await rename(tmpPath, absPath);\n}\n","import {\n chunkNote,\n type Embedder,\n isTokenEmbedder,\n loadModel2Vec,\n type TokenEmbedder,\n} from '@seekstone/core/embed';\nimport { contentHash } from '../content-hash.js';\nimport type { IndexedNote } from '../index/types.js';\nimport type { Logger } from '../log.js';\nimport { type CachePaths, cachePathsFor, loadCache, saveCache } from './cache.js';\nimport { fetchCommandFor, type SemanticConfig } from './config.js';\nimport { maxsimRerankHits } from './rerank.js';\nimport { type SemanticHit, SemanticStore } from './store.js';\n\nexport type SemanticProgress =\n | { state: 'building'; done: number; total: number }\n | { state: 'ready' };\n\n/** The slice of ServerContext the semantic index needs (avoids an import cycle). */\nexport interface SemanticCtx {\n vaultRoot: string;\n notes: Map<string, IndexedNote>;\n}\n\nexport interface SemanticDeps {\n log?: Logger;\n /** Per-note re-embed debounce (ms). */\n debounceMs?: number;\n /** Cache re-save debounce after watcher-driven changes (ms). */\n saveDebounceMs?: number;\n /** Yield to the event loop after this many freshly-embedded notes. */\n yieldEvery?: number;\n /** Test seam; defaults to loadModel2Vec. */\n loadModel?: (modelDir: string) => Promise<Embedder>;\n}\n\n/**\n * The live semantic index: embeds every note's chunks at boot (in the\n * background, off the hot path — queries during the build get a structured\n * progress error), keeps a per-vault (path, contentHash)-keyed cache so\n * restarts skip re-embedding, and re-embeds individual notes as the watcher\n * reports changes (debounced; the watcher's index update already refreshed\n * ctx.notes by then, so re-embeds read from memory, not disk).\n */\nexport class Semantic {\n readonly embedder: Embedder;\n readonly store: SemanticStore;\n progress: SemanticProgress;\n\n private readonly ctx: SemanticCtx;\n private readonly paths: CachePaths;\n private readonly log?: Logger;\n private readonly debounceMs: number;\n private readonly saveDebounceMs: number;\n private readonly yieldEvery: number;\n private readonly hashes = new Map<string, string>();\n /**\n * Lazy per-note chunk token ids for the MaxSim rerank (SHA-314): filled on\n * first rerank touch, dropped whenever the note changes or is removed.\n * Only queried candidates are ever tokenized, so the memo stays a small\n * fraction of the vault; it lives in memory only — the cache file format\n * is untouched.\n */\n private readonly tokenIdCache = new Map<string, Uint32Array[]>();\n private readonly tokenEmbedder: TokenEmbedder | undefined;\n private readonly pending = new Map<string, NodeJS.Timeout>();\n private saveTimer: NodeJS.Timeout | undefined;\n private stopped = false;\n\n private constructor(\n embedder: Embedder,\n ctx: SemanticCtx,\n cfg: SemanticConfig,\n deps: SemanticDeps,\n ) {\n this.embedder = embedder;\n this.tokenEmbedder = isTokenEmbedder(embedder) ? embedder : undefined;\n this.store = new SemanticStore(embedder.dim);\n this.ctx = ctx;\n this.paths = cachePathsFor(cfg.cacheDir, ctx.vaultRoot, embedder.id);\n this.log = deps.log;\n this.debounceMs = deps.debounceMs ?? 300;\n this.saveDebounceMs = deps.saveDebounceMs ?? 5000;\n this.yieldEvery = deps.yieldEvery ?? 8;\n this.progress = { state: 'building', done: 0, total: ctx.notes.size };\n }\n\n /**\n * Load the model and kick off the background index build. Rejects with an\n * actionable message when the model files are missing — the user enabled\n * the feature explicitly, so a broken setup should fail loudly at boot.\n */\n static async start(\n ctx: SemanticCtx,\n cfg: SemanticConfig,\n deps: SemanticDeps = {},\n ): Promise<Semantic> {\n let embedder: Embedder;\n try {\n embedder = await (deps.loadModel ?? loadModel2Vec)(cfg.modelDir);\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n throw new Error(\n `semantic search: could not load the embedding model ${cfg.modelId} from ${cfg.modelDir} — ` +\n `run \\`${fetchCommandFor(cfg.modelId)}\\` to download it, or point SEEKSTONE_MODEL_PATH at a Model2Vec model directory (${reason})`,\n );\n }\n const semantic = new Semantic(embedder, ctx, cfg, deps);\n void semantic.build();\n return semantic;\n }\n\n /** Resolves when the initial build has finished (tests and progress checks). */\n private buildDone: Promise<void> = Promise.resolve();\n\n ready(): Promise<void> {\n return this.buildDone;\n }\n\n private build(): Promise<void> {\n this.buildDone = this.buildInner().catch((err) => {\n this.log?.error('semantic build failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n });\n return this.buildDone;\n }\n\n private async buildInner(): Promise<void> {\n const t0 = performance.now();\n const cached = await loadCache(this.paths, this.embedder.id, this.embedder.dim);\n const ids = [...this.ctx.notes.keys()];\n this.progress = { state: 'building', done: 0, total: ids.length };\n let reused = 0;\n let sinceYield = 0;\n for (const id of ids) {\n if (this.stopped) return;\n // A watcher-driven re-embed may have processed this note already;\n // never overwrite fresh vectors with build-time ones.\n if (!this.hashes.has(id)) {\n const note = this.ctx.notes.get(id);\n if (note) {\n const current = contentHash(note.raw);\n const cachedVecs =\n cached?.hashes.get(id) === current ? cached.vectors.get(id) : undefined;\n if (cachedVecs !== undefined && cachedVecs.packed.length > 0) {\n this.store.setNote(id, cachedVecs.packed, cachedVecs.spans);\n reused++;\n } else {\n const { packed, spans } = this.embedNote(note);\n this.store.setNote(id, packed, spans);\n if (++sinceYield >= this.yieldEvery) {\n sinceYield = 0;\n await new Promise((r) => setImmediate(r));\n }\n }\n this.hashes.set(id, current);\n }\n }\n if (this.progress.state === 'building') this.progress.done++;\n }\n this.progress = { state: 'ready' };\n this.log?.info('semantic index ready', {\n notes: this.store.noteCount,\n chunks: this.store.chunkCount,\n reusedFromCache: reused,\n buildMs: Math.round(performance.now() - t0),\n });\n if (reused < this.store.noteCount) await this.save();\n }\n\n private embedNote(note: Pick<IndexedNote, 'title' | 'body'>): {\n packed: Float32Array;\n spans: Uint32Array;\n } {\n const chunks = chunkNote(note.title, note.body);\n const dim = this.embedder.dim;\n const packed = new Float32Array(chunks.length * dim);\n const spans = new Uint32Array(chunks.length * 2);\n for (let i = 0; i < chunks.length; i++) {\n const chunk = chunks[i] as { text: string; start: number; end: number };\n packed.set(this.embedder.embed(chunk.text), i * dim);\n spans[i * 2] = chunk.start;\n spans[i * 2 + 1] = chunk.end;\n }\n return { packed, spans };\n }\n\n embedQuery(query: string): Float32Array {\n return this.embedder.embed(query);\n }\n\n /**\n * MaxSim-rerank stage-1 candidates (SHA-314). Pass-through when the\n * embedder exposes no token vectors (alternative runtimes) — semantic\n * search then ships stage-1 order unchanged.\n */\n rerank(query: string, hits: ReadonlyArray<SemanticHit>): SemanticHit[] {\n const embedder = this.tokenEmbedder;\n if (!embedder) return [...hits];\n return maxsimRerankHits(embedder, query, hits, (hit) => {\n const ids = this.chunkTokenIds(hit.path);\n return ids?.[hit.chunkIndex];\n });\n }\n\n private chunkTokenIds(path: string): Uint32Array[] | undefined {\n const cached = this.tokenIdCache.get(path);\n if (cached) return cached;\n const embedder = this.tokenEmbedder;\n const note = this.ctx.notes.get(path);\n if (!embedder || !note) return undefined;\n const ids = chunkNote(note.title, note.body).map((chunk) =>\n Uint32Array.from(embedder.tokenIds(chunk.text)),\n );\n this.tokenIdCache.set(path, ids);\n return ids;\n }\n\n /** Watcher hook: a note was added or changed (ctx.notes is already fresh). */\n noteChanged(path: string): void {\n if (this.stopped) return;\n // ctx.notes already holds the new body — memoized token ids are stale now,\n // not just after the debounced re-embed.\n this.tokenIdCache.delete(path);\n const existing = this.pending.get(path);\n if (existing) clearTimeout(existing);\n const timer = setTimeout(() => {\n this.pending.delete(path);\n this.reembed(path);\n }, this.debounceMs);\n timer.unref?.();\n this.pending.set(path, timer);\n }\n\n /** Watcher hook: a note was deleted. */\n noteRemoved(path: string): void {\n const existing = this.pending.get(path);\n if (existing) {\n clearTimeout(existing);\n this.pending.delete(path);\n }\n this.tokenIdCache.delete(path);\n if (this.hashes.has(path) || this.store.getNote(path)) {\n this.store.removeNote(path);\n this.hashes.delete(path);\n this.scheduleSave();\n }\n }\n\n private reembed(path: string): void {\n const note = this.ctx.notes.get(path);\n if (!note) return;\n // Cache-staleness check, not a secret comparison — content hashes are\n // public fingerprints of vault bytes (Codacy's timing-attack rule\n // pattern-matches the identifier name, hence \"current\"/\"prior\").\n const current = contentHash(note.raw);\n const prior = this.hashes.get(path);\n if (prior === current) return;\n const { packed, spans } = this.embedNote(note);\n this.store.setNote(path, packed, spans);\n this.hashes.set(path, current);\n this.log?.debug('semantic re-embed', { path });\n this.scheduleSave();\n }\n\n private scheduleSave(): void {\n if (this.saveTimer) clearTimeout(this.saveTimer);\n this.saveTimer = setTimeout(() => {\n this.saveTimer = undefined;\n void this.save();\n }, this.saveDebounceMs);\n this.saveTimer.unref?.();\n }\n\n private async save(): Promise<void> {\n if (this.stopped) return;\n try {\n await saveCache(\n this.paths,\n this.embedder.id,\n this.embedder.dim,\n this.store.entries(),\n this.hashes,\n );\n this.log?.debug('semantic cache saved', { notes: this.store.noteCount });\n } catch (err) {\n // Cache persistence is an optimization — never let it break the server.\n this.log?.warn('semantic cache save failed', {\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n /** Tear down timers (tests; the process otherwise runs for the session). */\n stop(): void {\n this.stopped = true;\n for (const timer of this.pending.values()) clearTimeout(timer);\n this.pending.clear();\n if (this.saveTimer) clearTimeout(this.saveTimer);\n this.saveTimer = undefined;\n }\n}\n","/**\n * SHA-314: MaxSim late-interaction rerank of the semantic top-50.\n *\n * Stage 1 (pooled cosine over chunk vectors) picks candidates; this stage\n * re-scores each candidate's best chunk with token-level MaxSim — per query\n * token, max cosine over the chunk's token vectors — recovering\n * discriminating terms that mean pooling dilutes. Query tokens are\n * IDF-weighted over the candidate set and the MaxSim score is fused with\n * stage 1's by min-max weighted sum. Dev-split winner (idf-b50):\n * mean aggregation, candidate-set IDF, beta 0.5 — semantic hit@5\n * 70.4 → 85.2 with lexical routing untouched.\n *\n * The hit's chunkIndex/span are NOT changed: the excerpt keeps showing the\n * stage-1 best-matching passage; only the note ORDER (and score) moves.\n */\nimport { candidateSetIdf, maxsimScoreTokens, type TokenEmbedder } from '@seekstone/core/embed';\nimport type { SemanticHit } from './store.js';\n\n/** Fusion weight on the MaxSim score (0 = stage-1 only). Dev-split tuned. */\nexport const MAXSIM_BETA = 0.5;\n\nconst EMPTY: ArrayLike<number> = [];\n\n/**\n * Re-rank `hits` (stage-1 order). `tokenIdsFor` supplies each hit's best\n * chunk's token ids; `undefined` (note changed inside the re-embed debounce\n * window) contributes only its stage-1 score, like the harness fusion.\n * Returns a new array; input hits are not mutated.\n */\nexport function maxsimRerankHits(\n embedder: TokenEmbedder,\n query: string,\n hits: ReadonlyArray<SemanticHit>,\n tokenIdsFor: (hit: SemanticHit) => ArrayLike<number> | undefined,\n beta: number = MAXSIM_BETA,\n): SemanticHit[] {\n if (hits.length < 2 || beta <= 0) return [...hits];\n const qTok = embedder.tokenEmbed(query);\n if (qTok.ids.length === 0) return [...hits];\n const docs = hits.map((h) => tokenIdsFor(h) ?? EMPTY);\n const weights = candidateSetIdf(qTok.ids, docs);\n const maxsim = maxsimScoreTokens(qTok, docs, (id) => embedder.tokenVector(id), {\n aggregate: 'mean',\n weights,\n });\n const stage1 = normalize(hits.map((h) => h.score));\n const rerank = normalize(maxsim);\n return hits\n .map((h, i) => ({\n ...h,\n score: (1 - beta) * (stage1[i] as number) + beta * (rerank[i] as number),\n }))\n .sort((a, b) => b.score - a.score || (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));\n}\n\n/** Min-max normalize to [0, 1]; a constant list maps to all-1 (wsumFuse parity). */\nfunction normalize(scores: readonly number[]): number[] {\n let min = Number.POSITIVE_INFINITY;\n let max = Number.NEGATIVE_INFINITY;\n for (const s of scores) {\n if (s < min) min = s;\n if (s > max) max = s;\n }\n const span = max - min;\n return scores.map((s) => (span > 0 ? (s - min) / span : 1));\n}\n","/**\n * Mutable chunk-vector store for the live server: one packed Float32Array of\n * chunk embeddings per note (plus each chunk's [start, end) span in the\n * note's normalized body), so a watcher-driven re-embed replaces a single\n * map entry (the harness's append-only VectorSet can't mutate). Scanning\n * iterates note arrays with the same tight dot-product loop — ~10k map\n * entries of overhead on top of the identical multiply count.\n *\n * Vectors are L2-normalized, so dot product == cosine similarity. A note's\n * score is its pooled chunk score (see @seekstone/core pooling.ts — the\n * server's default is the recipe the SHA-313 dev-split eval chose), and the\n * best-scoring chunk's span is returned so the excerpt can be sliced from the\n * matching passage without re-chunking the note.\n */\n\nimport { assertValidPooling, type ChunkPooling, PoolAccumulator } from '@seekstone/core/embed';\n\n/** The shipped pooling; overridable per store for evals and tests. */\nexport const DEFAULT_POOLING: ChunkPooling = 'max';\n\nexport interface NoteVectors {\n /** chunkCount × dim floats, row-major. */\n packed: Float32Array;\n /** chunkCount × 2 uint32s: [start, end) body offsets per chunk. */\n spans: Uint32Array;\n}\n\nexport interface SemanticHit {\n path: string;\n score: number;\n /** Index of the note's best-scoring chunk (chunkNote() order). */\n chunkIndex: number;\n /** Body span of the best chunk (CRLF-normalized offsets). */\n start: number;\n end: number;\n}\n\nexport class SemanticStore {\n readonly dim: number;\n readonly pooling: ChunkPooling;\n private readonly notes = new Map<string, NoteVectors>();\n private chunks = 0;\n\n constructor(dim: number, pooling: ChunkPooling = DEFAULT_POOLING) {\n if (!Number.isInteger(dim) || dim <= 0) {\n throw new Error(`semantic store: invalid dim ${dim}`);\n }\n assertValidPooling(pooling);\n this.dim = dim;\n this.pooling = pooling;\n }\n\n /** Total chunk vectors across all notes. */\n get chunkCount(): number {\n return this.chunks;\n }\n\n get noteCount(): number {\n return this.notes.size;\n }\n\n /** Replace (or insert) a note's packed chunk vectors and spans. */\n setNote(path: string, packed: Float32Array, spans: Uint32Array): void {\n if (packed.length === 0 || packed.length % this.dim !== 0) {\n throw new Error(\n `semantic store: packed length ${packed.length} is not a positive multiple of dim ${this.dim} (${path})`,\n );\n }\n const n = packed.length / this.dim;\n if (spans.length !== n * 2) {\n throw new Error(\n `semantic store: spans length ${spans.length} does not match ${n} chunks (${path})`,\n );\n }\n const prev = this.notes.get(path);\n if (prev) this.chunks -= prev.packed.length / this.dim;\n this.notes.set(path, { packed, spans });\n this.chunks += n;\n }\n\n removeNote(path: string): void {\n const prev = this.notes.get(path);\n if (!prev) return;\n this.chunks -= prev.packed.length / this.dim;\n this.notes.delete(path);\n }\n\n getNote(path: string): NoteVectors | undefined {\n return this.notes.get(path);\n }\n\n /** Iterate (path, note vectors) — cache serialization uses this. */\n entries(): IterableIterator<[string, NoteVectors]> {\n return this.notes.entries();\n }\n\n /**\n * Top `k` notes by pooled chunk cosine, ties broken path-ascending. The\n * returned chunk/span is always the note's single best chunk, whatever\n * pooling ranked the note.\n */\n topNotes(query: Float32Array, k: number): SemanticHit[] {\n if (query.length !== this.dim) {\n throw new Error(`semantic store: query dim ${query.length} does not match ${this.dim}`);\n }\n const hits: SemanticHit[] = [];\n for (const [path, vectors] of this.notes) {\n hits.push(this.scoreVectors(path, vectors, query));\n }\n return hits\n .sort((a, b) => b.score - a.score || (a.path < b.path ? -1 : a.path > b.path ? 1 : 0))\n .slice(0, Math.max(0, k));\n }\n\n /**\n * Score a single note's cached chunk vectors against the query (SHA-315\n * graph expansion gates candidates on this). Same pooling and best-chunk\n * span as topNotes; undefined when the note has no vectors.\n */\n scoreNote(path: string, query: Float32Array): SemanticHit | undefined {\n if (query.length !== this.dim) {\n throw new Error(`semantic store: query dim ${query.length} does not match ${this.dim}`);\n }\n const vectors = this.notes.get(path);\n return vectors === undefined ? undefined : this.scoreVectors(path, vectors, query);\n }\n\n private scoreVectors(\n path: string,\n { packed, spans }: NoteVectors,\n query: Float32Array,\n ): SemanticHit {\n const dim = this.dim;\n const pooling = this.pooling;\n const acc = new PoolAccumulator(pooling);\n const n = packed.length / dim;\n for (let c = 0; c < n; c++) {\n const base = c * dim;\n let score = 0;\n for (let j = 0; j < dim; j++) {\n score += (packed[base + j] as number) * (query[j] as number);\n }\n acc.add(score, c);\n }\n const bestChunk = acc.bestChunk;\n return {\n path,\n score: acc.pool(pooling),\n chunkIndex: bestChunk,\n start: spans[bestChunk * 2] as number,\n end: spans[bestChunk * 2 + 1] as number,\n };\n }\n}\n","import type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';\nimport { WRITE_TOOLS } from './dispatch.js';\nimport type { WritePolicy } from './policy.js';\n\nconst READ_ONLY_ANNOTATIONS = {\n readOnlyHint: true,\n openWorldHint: false,\n} as const satisfies ToolAnnotations;\n\nconst ADDITIVE_WRITE_ANNOTATIONS = {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n} as const satisfies ToolAnnotations;\n\nconst DESTRUCTIVE_WRITE_ANNOTATIONS = {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: false,\n openWorldHint: false,\n} as const satisfies ToolAnnotations;\n\nconst IDEMPOTENT_DESTRUCTIVE_WRITE_ANNOTATIONS = {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: true,\n openWorldHint: false,\n} as const satisfies ToolAnnotations;\n\n/**\n * The full tool list served to MCP clients, extracted verbatim from the\n * ListTools handler so it can be filtered by policy and unit-tested.\n * Keep in sync with HANDLED_TOOLS in dispatch.ts.\n */\nexport const ALL_TOOLS = [\n {\n name: 'search',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n 'Full-text search across the vault. Returns ranked excerpts (~120 chars, tunable) — not full notes — to minimise context usage. Supports fuzzy matching and prefix search; with SEEKSTONE_SEMANTIC=1, mode \"semantic\"/\"hybrid\" searches by meaning via a local embedding model.',\n inputSchema: {\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Search query.' },\n mode: {\n type: 'string',\n enum: ['lexical', 'semantic', 'hybrid'],\n description:\n 'lexical = keyword search (default). semantic = meaning-based search (requires SEEKSTONE_SEMANTIC=1). hybrid = exact-title lookups go lexical, everything else semantic.',\n },\n limit: { type: 'number', description: 'Max results (1–50, default 10).' },\n folder: { type: 'string', description: 'Restrict to a vault-relative folder prefix.' },\n tag: { type: 'string', description: 'Restrict to notes with this tag.' },\n excerptLength: {\n type: 'number',\n description: 'Max characters of match context per hit (20–2000, default 120).',\n },\n },\n required: ['query'],\n },\n },\n {\n name: 'query_notes',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n 'Structured metadata query — filter notes by frontmatter key/value predicates, tag, folder, modified time, and size. Returns compact rows (path + title by default; opt into more via select), not note content. Use this instead of search when filtering by properties rather than text.',\n inputSchema: {\n type: 'object',\n properties: {\n where: {\n type: 'array',\n description: 'Frontmatter predicates — all must match (AND).',\n items: {\n type: 'object',\n properties: {\n key: { type: 'string', description: 'Frontmatter key to test.' },\n op: {\n type: 'string',\n enum: ['eq', 'ne', 'contains', 'exists', 'missing', 'gt', 'gte', 'lt', 'lte'],\n description:\n 'eq/ne compare scalars; contains matches array membership or substring; exists/missing test key presence; gt/gte/lt/lte compare numbers or strings (ISO dates sort correctly).',\n },\n value: {\n description: 'Comparison value. Required for every op except exists/missing.',\n },\n },\n required: ['key', 'op'],\n },\n },\n folder: { type: 'string', description: 'Restrict to a vault-relative folder prefix.' },\n tag: { type: 'string', description: 'Restrict to notes with this tag (# optional).' },\n modifiedAfter: {\n type: 'string',\n description: 'Only notes modified at or after this ISO 8601 date/time.',\n },\n modifiedBefore: {\n type: 'string',\n description: 'Only notes modified before this ISO 8601 date/time.',\n },\n minSizeBytes: { type: 'number', description: 'Only notes at least this many bytes.' },\n maxSizeBytes: { type: 'number', description: 'Only notes at most this many bytes.' },\n select: {\n type: 'array',\n items: { type: 'string' },\n description:\n 'Extra fields per hit: frontmatter keys, or \"mtime\", \"size\", \"tags\". Default returns only path + title.',\n },\n sort: {\n type: 'string',\n enum: ['path', 'title', 'mtime', 'size'],\n description: 'Sort field (default path).',\n },\n order: {\n type: 'string',\n enum: ['asc', 'desc'],\n description: 'Sort order (default asc).',\n },\n limit: { type: 'number', description: 'Max results (1–500, default 100).' },\n },\n required: [],\n },\n },\n {\n name: 'context_pack',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n 'Assemble everything needed to ANSWER a natural-language question in one call, under a strict byte budget (default 2048): ranked excerpts, linked neighbor notes (backlinks/outlinks) with one-line summaries, and follow-up source paths. Retrieval is lexical by default: for a question phrased in words the note itself may not use, pass mode \"hybrid\" or \"semantic\", and scope with folder/tag exactly as in search. Use search to locate notes and query_notes for metadata filters; use context_pack when you want answer-ready context without multiple round-trips. Empty excerpts with confidence \"none\" or \"low\" means the vault lacks coverage — do not infer content; with folder or tag set, \"none\" can also mean the filter excluded every match, which totalMatches distinguishes.',\n inputSchema: {\n type: 'object',\n properties: {\n query: { type: 'string', description: 'Natural-language question or topic.' },\n budgetBytes: {\n type: 'number',\n description: 'Hard cap on response JSON bytes (256–16384, default 2048).',\n },\n mode: {\n type: 'string',\n enum: ['lexical', 'semantic', 'hybrid'],\n description:\n 'lexical = keyword search (default). semantic = meaning-based over local embeddings (needs SEEKSTONE_SEMANTIC=1 and a fetched model). hybrid = exact-title lookups go lexical, everything else semantic.',\n },\n folder: { type: 'string', description: 'Restrict to a vault-relative folder prefix.' },\n tag: { type: 'string', description: 'Restrict to notes with this tag.' },\n },\n required: ['query'],\n },\n },\n {\n name: 'read_note',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n 'Read a note or a span of it — by heading section, block reference, or line range. Returns structured JSON with the content, bytes returned, total note size, and a contentHash to pass as prevHash to edit tools for compare-and-swap. Use search or outline_note first to find the right path and section names.',\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Vault-relative path, e.g. \"Daily Notes/2026-05-29.md\".',\n },\n section: {\n type: 'string',\n description:\n 'Return only this heading section (heading text, # prefix optional). First match wins.',\n },\n block: {\n type: 'string',\n description: 'Return only the line anchored by this block id (^ prefix optional).',\n },\n lines: {\n type: 'object',\n description: 'Return only this line range (1-indexed, inclusive).',\n properties: {\n from: { type: 'number', description: 'First line (1-indexed).' },\n to: {\n type: 'number',\n description: 'Last line (1-indexed, inclusive). Defaults to EOF.',\n },\n },\n required: ['from'],\n },\n includeFrontmatter: {\n type: 'boolean',\n description:\n 'Prepend frontmatter to section/block span results. Default false for spans.',\n },\n },\n required: ['path'],\n },\n },\n {\n name: 'list_notes',\n annotations: READ_ONLY_ANNOTATIONS,\n description: 'List notes, optionally filtered by folder prefix or tag.',\n inputSchema: {\n type: 'object',\n properties: {\n folder: { type: 'string', description: 'Vault-relative folder prefix.' },\n tag: { type: 'string', description: 'Filter by tag (# prefix optional).' },\n limit: { type: 'number', description: 'Max results (1–500, default 100).' },\n },\n required: [],\n },\n },\n {\n name: 'list_tags',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n 'List all tags in the vault with usage counts. Supports substring filtering, minimum count threshold, and sort order. Nested tags (e.g. area/work) include a parent field.',\n inputSchema: {\n type: 'object',\n properties: {\n pattern: {\n type: 'string',\n description:\n 'Substring filter on tag name. Example: \"work\" matches \"work\" and \"area/work\".',\n },\n minCount: {\n type: 'number',\n description: 'Only return tags used in at least this many notes.',\n },\n sort: {\n type: 'string',\n enum: ['count', 'name'],\n description: 'Sort by usage count descending (default) or alphabetically.',\n },\n },\n required: [],\n },\n },\n {\n name: 'create_note',\n annotations: DESTRUCTIVE_WRITE_ANNOTATIONS,\n description:\n 'Create a new note at a vault-relative path. Optionally sets frontmatter and body content. Parent directories are created automatically. Fails if the note already exists unless overwrite is true (prevHash may guard the overwrite).',\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Vault-relative path, e.g. \"Daily Notes/2026-06-01.md\".',\n },\n content: { type: 'string', description: 'Body content for the note.' },\n frontmatter: {\n type: 'object',\n description: 'Frontmatter key-value pairs.',\n additionalProperties: true,\n },\n overwrite: {\n type: 'boolean',\n description: 'Overwrite an existing note. Defaults to false.',\n },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n },\n },\n required: ['path'],\n },\n },\n {\n name: 'delete_note',\n annotations: DESTRUCTIVE_WRITE_ANNOTATIONS,\n description:\n 'Delete a note. By default it is moved to the vault .trash/ folder (recoverable by moving it back); pass permanent: true to remove it outright.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Vault-relative path of the note to delete.' },\n permanent: {\n type: 'boolean',\n description: 'Permanently remove instead of moving to .trash/. Defaults to false.',\n },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since — so you never delete content you have not seen.',\n },\n },\n required: ['path'],\n },\n },\n {\n name: 'move_note',\n annotations: DESTRUCTIVE_WRITE_ANNOTATIONS,\n description:\n 'Move or rename a note to a new vault-relative path, rewriting wikilinks and markdown links in other notes that point at it so nothing breaks (links inside fenced code blocks are left alone). Parent directories at the destination are created automatically. Fails if the destination already exists unless overwrite is true.',\n inputSchema: {\n type: 'object',\n properties: {\n from: { type: 'string', description: 'Vault-relative source path.' },\n to: { type: 'string', description: 'Vault-relative destination path.' },\n overwrite: {\n type: 'boolean',\n description: 'Overwrite destination if it exists. Defaults to false.',\n },\n rewriteLinks: {\n type: 'boolean',\n description:\n 'Rewrite references in other notes to follow the move. Defaults to true; pass false to move the file only.',\n },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard on the source note: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n },\n },\n required: ['from', 'to'],\n },\n },\n {\n name: 'rename_heading',\n annotations: DESTRUCTIVE_WRITE_ANNOTATIONS,\n description:\n 'Rename a heading in a note and rewrite every [[note#heading]] wikilink and embed across the vault so references keep working — aliases preserved, fenced code blocks left alone. Served from the warm backlink index, no vault scan. Heading matching is case-insensitive; with duplicate headings the first match wins, mirroring Obsidian link resolution.',\n inputSchema: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Vault-relative path of the note containing the heading.',\n },\n oldHeading: {\n type: 'string',\n description:\n 'Current heading text, without # markers. Case-insensitive; first match wins.',\n },\n newHeading: {\n type: 'string',\n description:\n 'New heading text, without # markers. Must not contain newlines, \"[\", \"]\", \"|\", or \"#\".',\n },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n },\n },\n required: ['path', 'oldHeading', 'newHeading'],\n },\n },\n {\n name: 'append_note',\n annotations: ADDITIVE_WRITE_ANNOTATIONS,\n description:\n 'Append text to a note body without touching the frontmatter. Safe for meeting notes, daily logs, and append-only workflows.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Vault-relative path to the note.' },\n content: { type: 'string', description: 'Text to append.' },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n },\n },\n required: ['path', 'content'],\n },\n },\n {\n name: 'patch_frontmatter',\n annotations: IDEMPOTENT_DESTRUCTIVE_WRITE_ANNOTATIONS,\n description:\n 'Set, update, or delete frontmatter keys without reordering existing keys or changing quote style. Pass null as a value to delete a key.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Vault-relative path to the note.' },\n patch: {\n type: 'object',\n description: 'Key-value pairs to set. Null value removes the key.',\n additionalProperties: true,\n },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n },\n },\n required: ['path', 'patch'],\n },\n },\n {\n name: 'outline_note',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n \"Return a note's structure — heading tree with offsets, block-reference anchors, and frontmatter key list — without returning any prose. Use this before section reads or patches to discover what sections exist at a fraction of the cost of reading the full note.\",\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Vault-relative path to the note.' },\n includeBlocks: {\n type: 'boolean',\n description: 'Include block-reference anchors (^id). Default true.',\n },\n includeSizes: {\n type: 'boolean',\n description: 'Include per-section character length in each heading entry. Default false.',\n },\n },\n required: ['path'],\n },\n },\n {\n name: 'patch_note',\n annotations: DESTRUCTIVE_WRITE_ANNOTATIONS,\n description:\n 'Surgically edit a section of a note — targeted by heading or block reference — without rewriting the whole file. Operations: append (add after section), prepend (add after heading line), replace (swap section content). Frontmatter is never touched.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Vault-relative path to the note.' },\n target: {\n type: 'object',\n description:\n 'Exactly one of: { heading: \"Section Title\" } or { block: \"block-id\" } (without the ^ prefix).',\n },\n operation: {\n type: 'string',\n enum: ['append', 'prepend', 'replace'],\n description:\n 'append: insert after section content. prepend: insert after heading line. replace: swap section content.',\n },\n content: { type: 'string', description: 'Content to insert or replace with.' },\n createIfMissing: {\n type: 'boolean',\n description:\n 'If the heading target is not found, append a new heading (level 2) + content. Only valid for heading targets. Default false.',\n },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n },\n },\n required: ['path', 'target', 'operation', 'content'],\n },\n },\n {\n name: 'get_backlinks',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n 'Return every note that links to the target note, with the source line and an optional excerpt. Results come from the pre-built reverse-link index so this is a fast, pure index lookup. Sort order: source path ascending.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Vault-relative path to the target note.' },\n includeContext: {\n type: 'boolean',\n description: 'Include a short excerpt (~200 chars) from the linking line. Default true.',\n },\n limit: {\n type: 'number',\n description: 'Max backlinks to return (1–500). Default 50.',\n },\n },\n required: ['path'],\n },\n },\n {\n name: 'get_links',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n 'Return all outgoing wikilinks and embeds from a note. Each link is marked resolved (with target path) or unresolved. Duplicate targets are de-duplicated; results sorted by line number.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Vault-relative path to the note.' },\n },\n required: ['path'],\n },\n },\n {\n name: 'replace_in_note',\n annotations: DESTRUCTIVE_WRITE_ANNOTATIONS,\n description:\n 'Find and replace text within a note body. Supports literal and regex search, case sensitivity, whole-word matching, and a replacement limit. Frontmatter is never touched. Use dryRun to preview matches before writing.',\n inputSchema: {\n type: 'object',\n properties: {\n path: { type: 'string', description: 'Vault-relative path to the note.' },\n find: { type: 'string', description: 'Text or pattern to find.' },\n replace: {\n type: 'string',\n description: 'Replacement text. Supports $1, $2, … backreferences in regex mode.',\n },\n regex: {\n type: 'boolean',\n description: 'Treat find as a regular expression. Default false.',\n },\n caseSensitive: {\n type: 'boolean',\n description: 'Case-sensitive matching. Default false.',\n },\n wholeWord: {\n type: 'boolean',\n description: 'Match whole words only (\\\\b boundary). Default false.',\n },\n limit: {\n type: 'number',\n description: 'Maximum number of replacements. Omit to replace all.',\n },\n dryRun: {\n type: 'boolean',\n description: 'If true, report matches without writing. Default false.',\n },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n },\n },\n required: ['path', 'find', 'replace'],\n },\n },\n {\n name: 'get_periodic_note',\n annotations: ADDITIVE_WRITE_ANNOTATIONS,\n description:\n 'Get the path and existence status of a periodic note (daily, weekly, monthly, quarterly, or yearly) for a given date. Reads folder/format config from .obsidian/daily-notes.json (daily) or the periodic-notes plugin data.json. Optionally creates the note from the configured template if it is missing.',\n inputSchema: {\n type: 'object',\n properties: {\n period: {\n type: 'string',\n enum: ['daily', 'weekly', 'monthly', 'quarterly', 'yearly'],\n description: 'Period type. Default: daily.',\n },\n date: {\n type: 'string',\n description: 'ISO date string (YYYY-MM-DD). Defaults to today when omitted.',\n },\n createIfMissing: {\n type: 'boolean',\n description:\n 'Create the note from the configured template if it does not exist. Default false.',\n },\n },\n required: [],\n },\n },\n {\n name: 'append_periodic_note',\n annotations: ADDITIVE_WRITE_ANNOTATIONS,\n description:\n 'Append text to a periodic note (daily, weekly, monthly, quarterly, or yearly). Preserves existing frontmatter exactly. Creates the note first (from template if configured) when createIfMissing is true (default).',\n inputSchema: {\n type: 'object',\n properties: {\n period: {\n type: 'string',\n enum: ['daily', 'weekly', 'monthly', 'quarterly', 'yearly'],\n description: 'Period type. Default: daily.',\n },\n date: {\n type: 'string',\n description: 'ISO date string (YYYY-MM-DD). Defaults to today when omitted.',\n },\n content: {\n type: 'string',\n description: 'Text to append to the note body.',\n },\n createIfMissing: {\n type: 'boolean',\n description: 'Create the note if it does not exist before appending. Default true.',\n },\n prevHash: {\n type: 'string',\n description:\n 'Optional compare-and-swap guard: the contentHash from a prior read. Fails with hash_conflict if the note changed since.',\n },\n },\n required: ['content'],\n },\n },\n {\n name: 'list_writes',\n annotations: READ_ONLY_ANNOTATIONS,\n description:\n 'List recent writes from the journal — every write tool records the pre-image of each file it touches, so any of them can be reverted with undo_write. Returns compact metadata rows (seq, timestamp, tool, paths, undoable), never note content.',\n inputSchema: {\n type: 'object',\n properties: {\n limit: {\n type: 'number',\n description: 'Max entries to return, newest first (1–200, default 20).',\n },\n path: {\n type: 'string',\n description: 'Only entries that touched this vault-relative path.',\n },\n },\n },\n },\n {\n name: 'undo_write',\n annotations: DESTRUCTIVE_WRITE_ANNOTATIONS,\n description:\n 'Revert a journaled write: restores every file it touched to its byte-identical pre-write state (a multi-file move or heading rename is restored whole; a delete is restored even if it was permanent). Defaults to the most recent undoable write. Refuses with undo_conflict if a file changed since that write, unless force: true. The undo is itself journaled — undo it to redo.',\n inputSchema: {\n type: 'object',\n properties: {\n seq: {\n type: 'number',\n description:\n 'Journal entry to revert (from list_writes). Defaults to the most recent undoable write.',\n },\n force: {\n type: 'boolean',\n description:\n 'Restore even if a file changed after the journaled write; the clobbered state is journaled first so nothing is lost. Defaults to false.',\n },\n },\n },\n },\n];\n\n/**\n * The tools visible to the client under a policy. In read-only mode write\n * tools are unregistered entirely (not just failing) — better for context\n * economy and honest about what the session can do. Dispatch still rejects\n * write calls independently; unregistering is presentation, not enforcement.\n */\nexport function visibleTools(policy: WritePolicy) {\n if (!policy.readOnly) return ALL_TOOLS;\n return ALL_TOOLS.filter((t) => !WRITE_TOOLS.has(t.name));\n}\n","import { realpathSync } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { join, relative, sep } from 'node:path';\nimport chokidar from 'chokidar';\nimport type { ServerContext } from './context.js';\nimport { addNoteBacklinks, removeNoteBacklinks } from './index/backlinks.js';\nimport { buildDoc, upsertDoc } from './index/doc.js';\nimport type { Logger } from './log.js';\n\n/**\n * Watch the vault for .md changes and keep the in-memory index in sync.\n *\n * Uses chokidar rather than `fs.watch(..., { recursive: true })`: recursive\n * native watching is unsupported on Linux, where fs.watch silently misses\n * nested changes. chokidar gives reliable, recursive, cross-platform events.\n *\n * Returns `stop()` to tear down the watcher and a `ready` promise that\n * resolves once chokidar has finished its initial scan and is live.\n */\nexport interface WatcherHandle {\n /**\n * Close the watcher. Returns chokidar's close promise so callers that need\n * deterministic teardown (tests, especially under usePolling where every\n * watched path holds a live stat-poll timer) can await full shutdown;\n * fire-and-forget callers may ignore the result.\n */\n stop: () => Promise<void>;\n ready: Promise<void>;\n}\n\nexport interface WatcherOptions {\n /**\n * Stat-poll instead of using native OS file events. Slower but reliable on\n * filesystems where native events are unreliable (network mounts, WSL, some\n * containers) and deterministic under load. Defaults to false, or true when\n * SEEKSTONE_WATCH_POLL=1.\n */\n usePolling?: boolean;\n /**\n * Stat-poll interval in ms; only meaningful with usePolling. Overrides\n * SEEKSTONE_WATCH_POLL_INTERVAL and the default. Tests pass a small value\n * here so the suite stays fast without dragging production polling down\n * with it.\n */\n pollInterval?: number;\n /**\n * Diagnostic hook fired for every raw chokidar event, before .md filtering\n * and before the index is updated. Receives the chokidar event name, the\n * absolute path as chokidar reported it, and the vault-relative key as\n * computed by toRel(). Use in tests only to capture what chokidar actually\n * emits when a failure needs investigation.\n */\n onRawEvent?: (event: 'add' | 'change' | 'unlink', absPath: string, relPath: string) => void;\n}\n\n/**\n * Default stat-poll interval (ms) under SEEKSTONE_WATCH_POLL=1. Deliberately\n * slow: poll cost scales with vault size ÷ interval, and on the network/9p\n * mounts where polling is needed at all, a 50ms sweep pinned ~25% of a CPU\n * core per instance (GH #280). Only pickup of *external* edits waits on this —\n * seekstone's own writes update the index in-process.\n */\nexport const DEFAULT_POLL_INTERVAL_MS = 10_000;\n\n/**\n * Resolve the stat-poll interval: explicit option → SEEKSTONE_WATCH_POLL_INTERVAL\n * (positive integer, ms) → default. A malformed env value warns and falls back\n * rather than throwing — a bad tuning knob shouldn't keep the server down.\n */\nexport function resolvePollInterval(\n optValue: number | undefined,\n envValue: string | undefined,\n log?: Logger,\n): number {\n if (optValue !== undefined) return optValue;\n if (envValue === undefined || envValue === '') return DEFAULT_POLL_INTERVAL_MS;\n const parsed = Number(envValue);\n if (!Number.isInteger(parsed) || parsed <= 0) {\n log?.warn('invalid SEEKSTONE_WATCH_POLL_INTERVAL, using default', {\n value: envValue,\n defaultMs: DEFAULT_POLL_INTERVAL_MS,\n });\n return DEFAULT_POLL_INTERVAL_MS;\n }\n return parsed;\n}\n\nexport function startWatcher(\n ctx: ServerContext,\n log?: Logger,\n opts?: WatcherOptions,\n): WatcherHandle {\n const usePolling = opts?.usePolling ?? process.env.SEEKSTONE_WATCH_POLL === '1';\n const pollInterval = resolvePollInterval(\n opts?.pollInterval,\n process.env.SEEKSTONE_WATCH_POLL_INTERVAL,\n log,\n );\n\n // chokidar's followSymlinks=true (the default) calls fs.realpath() on the\n // watched path, so events arrive with the real (resolved) path. On Windows,\n // os.tmpdir() can return 8.3 short paths (e.g. RUNNER~1) while realpath()\n // expands them to the long form. Without pre-resolving here, relative()\n // inside the ignored predicate and toRel() would produce \"..\" segments;\n // \"..\" starts with \".\" and trips the dot-directory filter, silencing every\n // event — the root cause of the flaky \"vault path containing spaces\" test.\n let vaultRoot = ctx.vaultRoot;\n try {\n vaultRoot = realpathSync(ctx.vaultRoot);\n } catch {\n // Vault doesn't exist yet or can't be resolved — keep original path.\n }\n\n // Index keys are forward-slash vault-relative paths on every platform.\n const toRel = (abs: string): string => relative(vaultRoot, abs).split(sep).join('/');\n\n async function upsert(relPath: string, op: 'add' | 'change'): Promise<void> {\n try {\n const raw = await readFile(join(vaultRoot, relPath), 'utf8');\n removeNoteBacklinks(ctx, relPath);\n upsertDoc(ctx, buildDoc(relPath, raw));\n addNoteBacklinks(ctx, relPath, raw);\n // Semantic re-embeds are debounced internally and read the fresh\n // ctx.notes entry — never the disk — so this stays off the hot path.\n ctx.semantic?.noteChanged(relPath);\n log?.debug('index updated', { path: relPath, op });\n } catch {\n // File vanished between event and read — ignore; an unlink will follow.\n }\n }\n\n function remove(relPath: string): void {\n if (ctx.notes.has(relPath)) {\n removeNoteBacklinks(ctx, relPath);\n ctx.index.discard(relPath);\n ctx.notes.delete(relPath);\n ctx.semantic?.noteRemoved(relPath);\n log?.debug('index removed', { path: relPath, op: 'delete' });\n }\n }\n\n const onUpsert = (op: 'add' | 'change') => (abs: string) => {\n const relPath = toRel(abs);\n opts?.onRawEvent?.(op, abs, relPath);\n if (relPath.endsWith('.md')) void upsert(relPath, op);\n };\n\n const watcher = chokidar.watch(vaultRoot, {\n // The startup index build already covers existing files.\n ignoreInitial: true,\n usePolling,\n interval: pollInterval,\n binaryInterval: pollInterval * 2,\n // Skip dot-dirs (.obsidian, .git, .trash, …) regardless of where the vault\n // lives — matched on the path relative to the vault root.\n ignored: (p: string) => {\n const rel = relative(vaultRoot, p);\n if (!rel || rel === '.') return false;\n // Exclude \"..\" — it means \"outside the vault root\" (a path normalisation\n // mismatch), not a dotfile. Treating \"..\" as a dot-segment would silence\n // all events if the ignored predicate ever receives an out-of-root path.\n return rel\n .split(sep)\n .filter(Boolean)\n .some((seg) => seg.startsWith('.') && seg !== '..');\n },\n });\n\n watcher\n .on('add', onUpsert('add'))\n .on('change', onUpsert('change'))\n .on('unlink', (abs: string) => {\n const relPath = toRel(abs);\n opts?.onRawEvent?.('unlink', abs, relPath);\n if (relPath.endsWith('.md')) remove(relPath);\n });\n\n const ready = new Promise<void>((resolve) => {\n watcher.once('ready', () => {\n resolve();\n });\n });\n\n return {\n stop: () => watcher.close(),\n ready,\n };\n}\n"],"mappings":"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","names":["join","homedir","createHash","existsSync","mkdir","readFile","writeFile","join","sha256","resolve","appendFileSync","renameSync","statSync","writeFile","DEFAULT_MAX_SIZE","path","statSync","appendFileSync","renameSync","readFile","path","rename","rename","vaultRoot","log","path","ctx","policy","vaultRoot","ctx","readFile","z","notes","path","z","path","z","path","ctx","z","ctx","path","mkdir","readFile","z","ctx","z","ctx","readFile","mkdir","access","mkdir","readFile","rename","rm","basename","extname","join","z","ctx","z","vaultRoot","extname","access","join","ctx","readFile","rm","mkdir","basename","rename","z","z","ctx","backlinks","z","z","ctx","z","ctx","path","z","ctx","z","ctx","mkdir","readFile","rename","dirname","join","z","matches","z","ctx","readFile","path","mkdir","dirname","rename","join","readFile","z","z","ctx","readFile","readFile","parseDocument","z","z","ctx","readFile","parseDocument","readFile","z","z","ctx","readFile","sep","newContent","path","access","mkdir","readFile","dirname","join","z","z","readFile","vaultRoot","cfg","join","ctx","path","access","mkdir","dirname","z","z","ctx","path","readFile","z","z","ctx","readFile","readFile","join","z","z","ctx","readFile","lineEnd","path","join","readFile","z","z","ctx","readFile","matches","mkdir","readFile","rm","dirname","z","z","ctx","readFile","rm","mkdir","dirname","ctx","log","audit","readFile","basename","extname","stat","extname","join","sep","vaultRoot","matches","vaultRoot","index","notes","readFile","basename","extname","backlinks","access","mkdir","readdir","readFile","stat","writeFile","dirname","join","j","log","createHash","mkdir","readdir","readFile","rename","writeFile","join","sep","readFile","basename","join","normalize","readFile","join","basename","createHash","mkdir","readFile","rename","writeFile","join","vaultRoot","notes","path","contentHash","path","ctx","path","policy","readFile","join","relative","sep","log","ctx","vaultRoot","relative","sep","readFile","join","watcher","resolve","runFetchModel","homedir","resolve"]}