@theglitchking/semantic-memory 1.0.1 → 1.1.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/.claude-plugin/marketplace.json +4 -4
- package/CHANGELOG.md +66 -0
- package/commands/contract.md +14 -0
- package/commands/healthcheck.md +21 -3
- package/dist/chunk-CCSX3BHF.js +273 -0
- package/dist/chunk-CCSX3BHF.js.map +1 -0
- package/dist/{chunk-CXTRTCIK.js → chunk-XBAN7GRT.js} +380 -6
- package/dist/chunk-XBAN7GRT.js.map +1 -0
- package/dist/cli/index.js +299 -22
- package/dist/cli/index.js.map +1 -1
- package/dist/core/index.d.ts +276 -3
- package/dist/core/index.js +22 -2
- package/dist/healthcheck-DCFGPI7M.js +14 -0
- package/dist/healthcheck-DCFGPI7M.js.map +1 -0
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +1008 -568
- package/dist/mcp/server.js.map +1 -1
- package/hooks/vault-context.js +130 -1
- package/package.json +1 -1
- package/dist/chunk-CXTRTCIK.js.map +0 -1
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { program } from \"commander\";\nimport { resolve, join, dirname, relative } from \"node:path\";\nimport { existsSync, readFileSync, writeFileSync, rmSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { spawnSync } from \"node:child_process\";\nimport { registerUpdateCommands } from \"@theglitchking/claude-plugin-runtime\";\n\nconst require_ = createRequire(import.meta.url);\nconst { version } = require_(\"../../package.json\") as { version: string };\n\nconst PKG_NAME = \"@theglitchking/semantic-sidekick\";\n\nfunction runRelink(cwd: string) {\n const linker = join(cwd, \"node_modules\", \"@theglitchking\", \"semantic-sidekick\", \"scripts\", \"link-skills.js\");\n const script = existsSync(linker) ? linker : resolve(process.cwd(), \"scripts\", \"link-skills.js\");\n if (!existsSync(script)) {\n console.error(\"link-skills.js not found — is the package installed?\");\n return;\n }\n spawnSync(process.execPath, [script], {\n cwd,\n env: { ...process.env, INIT_CWD: cwd },\n stdio: \"inherit\",\n });\n}\n\nfunction findLocalBin(cwd: string): string | null {\n const p = join(cwd, \"node_modules\", \"@theglitchking\", \"semantic-sidekick\", \"bin\", \"semantic-sidekick\");\n return existsSync(p) ? p : null;\n}\n\nfunction localBinArg(cwd: string): string | null {\n const abs = findLocalBin(cwd);\n if (!abs) return null;\n const rel = relative(cwd, abs);\n return rel.startsWith(\"..\") ? abs : `./${rel}`;\n}\n\nfunction readJsonSafe(path: string): any {\n try {\n const raw = readFileSync(path, \"utf8\");\n return raw.trim() ? JSON.parse(raw) : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Returns the fragile npx-form pattern we used to write in pre-0.10.0\n * SessionStart hooks, so normalize-config can detect and rewrite it.\n */\nfunction isNpxForm(entry: any): boolean {\n if (!entry || typeof entry !== \"object\") return false;\n const cmd = entry.command;\n const args = Array.isArray(entry.args) ? entry.args : [];\n return cmd === \"npx\" && args.some((a: unknown) => typeof a === \"string\" && a.includes(PKG_NAME));\n}\n\nfunction isLocalForm(entry: any): boolean {\n if (!entry || typeof entry !== \"object\") return false;\n const cmd = entry.command;\n const args = Array.isArray(entry.args) ? entry.args : [];\n return (\n cmd === \"node\" &&\n args.some((a: unknown) => typeof a === \"string\" && a.includes(\"node_modules/@theglitchking/semantic-sidekick\"))\n );\n}\n\nfunction extractNotesPath(entry: any): string | null {\n const args = Array.isArray(entry?.args) ? entry.args : [];\n const i = args.indexOf(\"--notes\");\n if (i === -1 || i + 1 >= args.length) return null;\n return String(args[i + 1]);\n}\n\nfunction extractExtraFlags(entry: any): string[] {\n const args = Array.isArray(entry?.args) ? entry.args : [];\n return args.filter((a: unknown): a is string => typeof a === \"string\" && a.startsWith(\"--\") && a !== \"--notes\");\n}\n\nconst TOOL_HELP: Record<string, { description: string; args: string; examples: string[] }> = {\n // Search\n search_semantic: {\n description: \"Vector similarity search — find notes by meaning, not just keywords\",\n args: '{ \"query\": \"string\", \"limit?\": 10 }',\n examples: [\n '{ \"query\": \"microservices architecture\", \"limit\": 5 }',\n '{ \"query\": \"how to deploy to production\" }',\n ],\n },\n search_text: {\n description: \"Full-text keyword or regex search with optional filters\",\n args: '{ \"pattern\": \"string\", \"regex?\": false, \"caseSensitive?\": false, \"pathGlob?\": \"string\", \"tagFilter?\": [\"string\"], \"limit?\": 20 }',\n examples: [\n '{ \"pattern\": \"RabbitMQ\" }',\n '{ \"pattern\": \"OAuth\\\\\\\\d\", \"regex\": true }',\n '{ \"pattern\": \"deploy\", \"pathGlob\": \"devops/**\", \"tagFilter\": [\"kubernetes\"] }',\n ],\n },\n search_graph: {\n description: \"Graph traversal — find notes connected to a concept via wikilinks and tags\",\n args: '{ \"concept\": \"string\", \"maxDepth?\": 2 }',\n examples: [\n '{ \"concept\": \"microservices\" }',\n '{ \"concept\": \"auth\", \"maxDepth\": 3 }',\n ],\n },\n search_hybrid: {\n description: \"Combined semantic + graph search — vector results re-ranked by graph proximity\",\n args: '{ \"query\": \"string\", \"limit?\": 10 }',\n examples: [\n '{ \"query\": \"event driven architecture\", \"limit\": 5 }',\n ],\n },\n\n // Read\n read_note: {\n description: \"Read the full content of a specific note by path\",\n args: '{ \"path\": \"string\" }',\n examples: [\n '{ \"path\": \"project-overview.md\" }',\n '{ \"path\": \"notes/meeting-2024-01-15.md\" }',\n ],\n },\n read_multiple_notes: {\n description: \"Batch read multiple notes in one call\",\n args: '{ \"paths\": [\"string\"] }',\n examples: [\n '{ \"paths\": [\"overview.md\", \"architecture.md\", \"deployment.md\"] }',\n ],\n },\n list_notes: {\n description: \"List all indexed notes with metadata (title, tags, link count)\",\n args: \"{}\",\n examples: [\"{}\"],\n },\n\n // Write\n create_note: {\n description: \"Create a new markdown note with optional YAML frontmatter\",\n args: '{ \"path\": \"string\", \"content\": \"string\", \"frontmatter?\": {} }',\n examples: [\n '{ \"path\": \"new-guide.md\", \"content\": \"# Guide\\\\n\\\\nContent here.\" }',\n '{ \"path\": \"tagged.md\", \"content\": \"Content.\", \"frontmatter\": { \"title\": \"Tagged Note\", \"tags\": [\"test\"] } }',\n ],\n },\n update_note: {\n description: \"Edit note content — overwrite, append, prepend, or patch by heading\",\n args: '{ \"path\": \"string\", \"content\": \"string\", \"mode\": \"overwrite|append|prepend|patch-by-heading\", \"heading?\": \"string\" }',\n examples: [\n '{ \"path\": \"guide.md\", \"content\": \"New content.\", \"mode\": \"overwrite\" }',\n '{ \"path\": \"guide.md\", \"content\": \"\\\\n## Appendix\\\\nExtra info.\", \"mode\": \"append\" }',\n '{ \"path\": \"guide.md\", \"content\": \"Updated architecture section.\", \"mode\": \"patch-by-heading\", \"heading\": \"Architecture\" }',\n ],\n },\n delete_note: {\n description: \"Delete a note permanently (requires confirm=true)\",\n args: '{ \"path\": \"string\", \"confirm\": true }',\n examples: [\n '{ \"path\": \"old-note.md\", \"confirm\": true }',\n '{ \"path\": \"old-note.md\", \"confirm\": false } // returns warning, does not delete',\n ],\n },\n move_note: {\n description: \"Move or rename a note — automatically updates wikilinks across the vault\",\n args: '{ \"from\": \"string\", \"to\": \"string\" }',\n examples: [\n '{ \"from\": \"user-service.md\", \"to\": \"auth-service.md\" }',\n '{ \"from\": \"old/note.md\", \"to\": \"new/location/note.md\" }',\n ],\n },\n\n // Metadata\n get_frontmatter: {\n description: \"Read parsed YAML frontmatter from a note as JSON\",\n args: '{ \"path\": \"string\" }',\n examples: ['{ \"path\": \"project-overview.md\" }'],\n },\n update_frontmatter: {\n description: \"Set or delete YAML frontmatter keys — pass null to delete a key\",\n args: '{ \"path\": \"string\", \"fields\": {} }',\n examples: [\n '{ \"path\": \"note.md\", \"fields\": { \"status\": \"active\", \"priority\": 1 } }',\n '{ \"path\": \"note.md\", \"fields\": { \"deprecated_field\": null } } // deletes the key',\n ],\n },\n manage_tags: {\n description: \"Add, remove, or list tags on a note (frontmatter and inline)\",\n args: '{ \"path\": \"string\", \"action\": \"add|remove|list\", \"tags?\": [\"string\"] }',\n examples: [\n '{ \"path\": \"note.md\", \"action\": \"list\" }',\n '{ \"path\": \"note.md\", \"action\": \"add\", \"tags\": [\"important\", \"reviewed\"] }',\n '{ \"path\": \"note.md\", \"action\": \"remove\", \"tags\": [\"draft\"] }',\n ],\n },\n rename_tag: {\n description: \"Rename a tag across all notes in the vault (frontmatter + inline)\",\n args: '{ \"oldTag\": \"string\", \"newTag\": \"string\" }',\n examples: ['{ \"oldTag\": \"architecture\", \"newTag\": \"arch\" }'],\n },\n\n // Graph\n backlinks: {\n description: \"Find all notes that link TO a given note via [[wikilinks]]\",\n args: '{ \"path\": \"string\" }',\n examples: ['{ \"path\": \"microservices.md\" }'],\n },\n forwardlinks: {\n description: \"Find all notes linked FROM a given note\",\n args: '{ \"path\": \"string\" }',\n examples: ['{ \"path\": \"project-overview.md\" }'],\n },\n graph_path: {\n description: \"Find the shortest path between two notes in the knowledge graph\",\n args: '{ \"from\": \"string\", \"to\": \"string\" }',\n examples: ['{ \"from\": \"project-overview.md\", \"to\": \"user-service.md\" }'],\n },\n graph_statistics: {\n description: \"Knowledge graph stats — most connected nodes, orphans, density\",\n args: \"{}\",\n examples: [\"{}\"],\n },\n\n // System\n get_stats: {\n description: \"Vault and index statistics — note count, chunks, embeddings, graph density\",\n args: \"{}\",\n examples: [\"{}\"],\n },\n reindex: {\n description: \"Force a full reindex of the vault\",\n args: \"{}\",\n examples: [\"{}\"],\n },\n};\n\nconst TOOL_CATEGORIES: Record<string, string[]> = {\n Search: [\"search_semantic\", \"search_text\", \"search_graph\", \"search_hybrid\"],\n Read: [\"read_note\", \"read_multiple_notes\", \"list_notes\"],\n Write: [\"create_note\", \"update_note\", \"delete_note\", \"move_note\"],\n Metadata: [\"get_frontmatter\", \"update_frontmatter\", \"manage_tags\", \"rename_tag\"],\n Graph: [\"backlinks\", \"forwardlinks\", \"graph_path\", \"graph_statistics\"],\n System: [\"get_stats\", \"reindex\"],\n};\n\nfunction printToolList() {\n console.log(\"\\nSemantic Pages — 21 MCP Tools\\n\");\n console.log(\"Usage: These tools are available via MCP when the server is running.\");\n console.log(\" Run `semantic-sidekick tools <name>` for details on a specific tool.\\n\");\n\n for (const [category, tools] of Object.entries(TOOL_CATEGORIES)) {\n console.log(` ${category}:`);\n for (const name of tools) {\n const tool = TOOL_HELP[name];\n console.log(` ${name.padEnd(24)} ${tool.description}`);\n }\n console.log();\n }\n\n console.log(\"Run `semantic-sidekick tools <tool-name>` for arguments and examples.\");\n}\n\nfunction printToolDetail(name: string) {\n const tool = TOOL_HELP[name];\n if (!tool) {\n console.error(`Unknown tool: ${name}`);\n console.error(`Run \\`semantic-sidekick tools\\` to see all available tools.`);\n process.exit(1);\n }\n\n console.log(`\\n ${name}`);\n console.log(` ${\"─\".repeat(name.length)}`);\n console.log(` ${tool.description}\\n`);\n console.log(` Arguments:`);\n console.log(` ${tool.args}\\n`);\n console.log(` Examples:`);\n for (const ex of tool.examples) {\n console.log(` ${ex}`);\n }\n console.log();\n}\n\nprogram\n .name(\"semantic-memory\")\n .description(\n \"Unified memory-layer MCP server for Claude Code (rebrand of semantic-sidekick at v1.0.0).\\n\" +\n \"The `semantic-sidekick` command is preserved as an alias.\\n\\n\" +\n \" Start MCP server: semantic-memory --notes ./vault\\n\" +\n \" Show vault stats: semantic-memory --notes ./vault --stats\\n\" +\n \" Force reindex: semantic-memory --notes ./vault --reindex\\n\" +\n \" List MCP tools: semantic-memory tools\\n\" +\n \" Tool details: semantic-memory tools search_semantic\"\n )\n .version(version);\n\nprogram\n .command(\"search <query>\")\n .description(\"Run a vault search and print top hits as JSON (used by activation hooks)\")\n .requiredOption(\"--notes <path>\", \"Path to markdown notes directory\")\n .option(\"--limit <n>\", \"Max results\", (v) => parseInt(v, 10), 8)\n .option(\"--text-only\", \"Skip embedder — keyword-only search (fast path, no model init)\")\n .option(\"--json\", \"Emit raw JSON (default)\", true)\n .action(async (query: string, opts) => {\n const { runSearch } = await import(\"./search.js\");\n try {\n const hits = await runSearch({\n notes: opts.notes,\n query,\n limit: opts.limit,\n textOnly: opts.textOnly,\n });\n process.stdout.write(JSON.stringify(hits, null, 2) + \"\\n\");\n process.exit(0);\n } catch (err: any) {\n console.error(`search failed: ${err.message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"lint\")\n .description(\"Lint the vault against vault.schema.yml (schema violations + missing provenance + stale)\")\n .requiredOption(\"--notes <path>\", \"Path to markdown notes directory\")\n .option(\"--rule <name>\", \"Limit output to one rule: schema_violations | missing_provenance | stale\")\n .option(\"--json\", \"Emit JSON instead of the human-readable report\")\n .option(\"--strict\", \"Exit non-zero on warnings too (default: exit non-zero only on errors)\")\n .action(async (opts) => {\n const { lintVault, formatLintReport } = await import(\"../core/lint.js\");\n const report = await lintVault(resolve(opts.notes));\n // Use console.log + process.exitCode (not process.exit) so Node flushes\n // stdout fully before the process ends. Early process.exit with a large\n // buffered JSON payload can truncate output.\n if (opts.json) {\n const out = opts.rule ? report.byRule[opts.rule as keyof typeof report.byRule] : report;\n console.log(JSON.stringify(out, null, 2));\n } else {\n console.log(formatLintReport(report, { rule: opts.rule }));\n }\n const bad = opts.strict ? report.counts.errors + report.counts.warnings : report.counts.errors;\n process.exitCode = bad > 0 ? 1 : 0;\n });\n\nprogram\n .command(\"log-event\")\n .description(\"Append a structured event to the vault's log.md (used by hooks and CI scripts — same shape as mcp__semantic-vault__log_event)\")\n .requiredOption(\"--notes <path>\", \"Path to markdown notes directory\")\n .requiredOption(\"--kind <name>\", \"Event category: ingest, synthesis, error, mode_change, etc.\")\n .requiredOption(\"--summary <text>\", \"One-line human summary\")\n .option(\"--payload <json>\", \"Structured payload as JSON string\")\n .action(async (opts) => {\n const { logEvent } = await import(\"../core/log.js\");\n let payload: Record<string, unknown> | undefined;\n if (opts.payload) {\n try {\n payload = JSON.parse(opts.payload);\n } catch (e: any) {\n console.error(`invalid --payload JSON: ${e.message}`);\n process.exitCode = 1;\n return;\n }\n }\n try {\n const entry = await logEvent(resolve(opts.notes), {\n kind: opts.kind,\n summary: opts.summary,\n payload,\n });\n console.log(JSON.stringify(entry));\n } catch (e: any) {\n console.error(`log-event failed: ${e.message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command(\"log-query\")\n .description(\"Read structured log entries from log.md — filters by kind, date range, limit\")\n .requiredOption(\"--notes <path>\", \"Path to markdown notes directory\")\n .option(\"--kind <name>\", \"Filter by kind (ingest, synthesis, error, mode_change, etc.)\")\n .option(\"--after <iso>\", \"ISO timestamp — only entries on or after\")\n .option(\"--before <iso>\", \"ISO timestamp — only entries on or before\")\n .option(\"--limit <n>\", \"Max entries (most recent)\", (v) => parseInt(v, 10))\n .action(async (opts) => {\n const { logQuery } = await import(\"../core/log.js\");\n try {\n const entries = await logQuery(resolve(opts.notes), {\n kind: opts.kind,\n after: opts.after,\n before: opts.before,\n limit: opts.limit,\n });\n console.log(JSON.stringify(entries));\n } catch (e: any) {\n console.error(`log-query failed: ${e.message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command(\"install-schema\")\n .description(\"Bootstrap vault.schema.yml in the vault root with the default schema\")\n .requiredOption(\"--notes <path>\", \"Path to markdown notes directory\")\n .option(\"--force\", \"Overwrite existing schema file\")\n .action(async (opts) => {\n const { installDefaultSchema } = await import(\"../core/schema.js\");\n const r = await installDefaultSchema(resolve(opts.notes), opts.force);\n console.log(r.written ? `Installed default schema: ${r.path}` : `Schema already exists: ${r.path} (use --force to overwrite)`);\n process.exit(0);\n });\n\nprogram\n .command(\"tools [name]\")\n .description(\"List all MCP tools, or show details for a specific tool\")\n .action((name?: string) => {\n if (name) {\n printToolDetail(name);\n } else {\n printToolList();\n }\n process.exit(0);\n });\n\nprogram\n .command(\"serve\", { isDefault: true })\n .description(\"Start the MCP server (default command)\")\n .requiredOption(\"--notes <path>\", \"Path to markdown notes directory\")\n .option(\"--reindex\", \"Force full reindex and exit\")\n .option(\"--stats\", \"Show vault statistics and exit\")\n .option(\"--wait-for-ready\", \"Block startup until index is fully built before serving (default: index in background; tools return 'Indexing in progress' until ready)\")\n .option(\"--read-only\", \"Suppress write tools (create_note, update_note, delete_note, move_note, update_frontmatter, manage_tags, rename_tag) — use for shared docs vaults owned by another tool\")\n .option(\"--model <name>\", \"Embedding model to use (default: all-MiniLM-L6-v2, fast; use nomic-ai/nomic-embed-text-v1.5 for higher quality)\")\n .option(\"--workers <n>\", \"Number of worker threads for parallel embedding\", parseInt)\n .option(\"--batch-size <n>\", \"Texts per ONNX forward pass (default: 8)\", parseInt)\n .option(\"--no-quantized\", \"Use full-precision model instead of quantized (slower, slightly higher quality)\")\n .option(\"--no-watch\", \"Disable file watcher\")\n .action(async (opts) => {\n const notesPath = resolve(opts.notes);\n\n if (!existsSync(notesPath)) {\n console.error(`Error: notes directory not found: ${notesPath}`);\n process.exit(1);\n }\n\n if (opts.stats) {\n const { Indexer } = await import(\"../core/indexer.js\");\n const indexer = new Indexer(notesPath);\n const docs = await indexer.indexAll();\n console.log(`Notes: ${docs.length}`);\n console.log(`Chunks: ${docs.reduce((n: number, d: any) => n + d.chunks.length, 0)}`);\n console.log(`Wikilinks: ${docs.reduce((n: number, d: any) => n + d.wikilinks.length, 0)}`);\n console.log(`Tags: ${new Set(docs.flatMap((d: any) => d.tags)).size} unique`);\n process.exit(0);\n }\n\n if (opts.reindex) {\n const { createServer } = await import(\"../mcp/server.js\");\n await createServer(notesPath, {\n watch: false,\n waitForReady: true,\n model: opts.model,\n workers: opts.workers,\n batchSize: opts.batchSize,\n quantized: opts.quantized,\n onProgress: (embedded, total) => {\n process.stderr.write(`\\rEmbedding ${embedded}/${total} chunks...`);\n },\n });\n process.stderr.write(\"\\n\");\n console.log(\"Reindex complete.\");\n process.exit(0);\n }\n\n // Default: start MCP server on stdio\n const { startServer } = await import(\"../mcp/server.js\");\n await startServer(notesPath, {\n watch: opts.watch,\n waitForReady: opts.waitForReady,\n model: opts.model,\n workers: opts.workers,\n batchSize: opts.batchSize,\n quantized: opts.quantized,\n readOnly: opts.readOnly,\n });\n });\n\nregisterUpdateCommands(program, {\n packageName: PKG_NAME,\n pluginName: \"semantic-sidekick\",\n configFile: \"semantic-sidekick.json\",\n onAfterUpdate: (cwd) => runRelink(cwd),\n});\n\nprogram\n .command(\"normalize-config\")\n .description(\n \"Rewrite fragile `npx @latest` entries in .mcp.json to the stable node-against-node_modules form (with backup and validation)\",\n )\n .option(\"--dry-run\", \"print the proposed changes but don't write\")\n .action((opts: { dryRun?: boolean }) => {\n const cwd = process.cwd();\n const mcpPath = join(cwd, \".mcp.json\");\n if (!existsSync(mcpPath)) {\n console.log(\"no .mcp.json in current directory — nothing to do\");\n process.exit(0);\n }\n const data = readJsonSafe(mcpPath);\n if (!data || typeof data !== \"object\" || !data.mcpServers || typeof data.mcpServers !== \"object\") {\n console.error(`could not parse ${mcpPath}`);\n process.exit(1);\n }\n const bin = localBinArg(cwd);\n if (!bin) {\n console.error(\n `no local install found at ./node_modules/@theglitchking/semantic-sidekick/bin/semantic-sidekick.\\n` +\n `run 'npm install --save @theglitchking/semantic-sidekick' first, then re-run this command.`,\n );\n process.exit(1);\n }\n const rewritten: string[] = [];\n for (const [key, entry] of Object.entries<any>(data.mcpServers)) {\n if (!isNpxForm(entry)) continue;\n const notes = extractNotesPath(entry) ?? \"./.claude/.vault\";\n const extra = extractExtraFlags(entry);\n data.mcpServers[key] = {\n type: \"stdio\",\n command: \"node\",\n args: [bin, \"--notes\", notes, ...extra],\n };\n rewritten.push(key);\n }\n if (rewritten.length === 0) {\n console.log(\"no npx-form entries found — .mcp.json is already in the stable form.\");\n process.exit(0);\n }\n console.log(`Rewriting ${rewritten.length} entr${rewritten.length === 1 ? \"y\" : \"ies\"}: ${rewritten.join(\", \")}`);\n if (opts.dryRun) {\n console.log(\"--- proposed .mcp.json:\");\n console.log(JSON.stringify(data, null, 2));\n console.log(\"--- (dry-run; no changes written)\");\n process.exit(0);\n }\n // Back up\n const bakPath = join(dirname(mcpPath), \".mcp.json.bak\");\n try {\n writeFileSync(bakPath, readFileSync(mcpPath, \"utf8\"));\n console.log(`backup written: ${bakPath}`);\n } catch (err: any) {\n console.error(`could not write backup: ${err.message}`);\n process.exit(1);\n }\n writeFileSync(mcpPath, JSON.stringify(data, null, 2) + \"\\n\");\n\n // Verify the local bin starts cleanly. We just run --version — fast and\n // enough to catch ERR_MODULE_NOT_FOUND type failures.\n const verify = spawnSync(\"node\", [bin, \"--version\"], { cwd, stdio: \"pipe\", timeout: 15_000 });\n if (verify.status !== 0) {\n console.error(`verification failed (exit ${verify.status}):\\n${verify.stderr?.toString() || \"\"}`);\n console.error(`rolling back from ${bakPath}`);\n writeFileSync(mcpPath, readFileSync(bakPath, \"utf8\"));\n process.exit(1);\n }\n console.log(`✓ .mcp.json normalized and verified. Toggle the MCPs in /mcp to reconnect.`);\n process.exit(0);\n });\n\nprogram\n .command(\"healthcheck\")\n .description(\n \"Verify the local install starts cleanly; self-heal common npx-cache corruption (ERR_MODULE_NOT_FOUND)\",\n )\n .action(() => {\n const cwd = process.cwd();\n const bin = findLocalBin(cwd);\n if (!bin) {\n console.error(`no local install at ./node_modules/@theglitchking/semantic-sidekick/bin/semantic-sidekick`);\n console.error(`run 'npm install --save @theglitchking/semantic-sidekick' to install.`);\n process.exit(1);\n }\n\n // 1. Warn if .mcp.json uses the fragile form.\n const mcpPath = join(cwd, \".mcp.json\");\n if (existsSync(mcpPath)) {\n const data = readJsonSafe(mcpPath);\n const entries = data?.mcpServers && typeof data.mcpServers === \"object\" ? Object.entries<any>(data.mcpServers) : [];\n const fragile = entries.filter(([, e]) => isNpxForm(e)).map(([k]) => k);\n if (fragile.length > 0) {\n console.warn(\n `⚠️ .mcp.json uses the fragile npx-@latest form for: ${fragile.join(\", \")}`,\n );\n console.warn(` Rewrite to the stable form:`);\n console.warn(` npx --no @theglitchking/semantic-sidekick normalize-config`);\n }\n }\n\n // 2. Smoke-test the local bin.\n const r = spawnSync(\"node\", [bin, \"--version\"], { cwd, stdio: \"pipe\", timeout: 15_000 });\n if (r.status === 0) {\n console.log(`✓ local install starts cleanly (v${r.stdout?.toString().trim()})`);\n process.exit(0);\n }\n\n const stderr = r.stderr?.toString() ?? \"\";\n\n // 3. Self-heal ERR_MODULE_NOT_FOUND in npx cache (rare but the classic\n // failure mode that triggered 0.10.0). Extract the offending npx cache\n // dir from the error message, rm -rf it, retry once.\n if (stderr.includes(\"ERR_MODULE_NOT_FOUND\")) {\n const match = stderr.match(/([\\/~][^'\"\\s]*\\/_npx\\/[^\\/'\"\\s]+)/);\n if (match) {\n const bad = match[1];\n console.warn(`detected broken npx cache at ${bad} — clearing and retrying...`);\n try { rmSync(bad, { recursive: true, force: true }); } catch {}\n const r2 = spawnSync(\"node\", [bin, \"--version\"], { cwd, stdio: \"pipe\", timeout: 15_000 });\n if (r2.status === 0) {\n console.log(`✓ cleared npx cache and verified (v${r2.stdout?.toString().trim()})`);\n process.exit(0);\n }\n console.error(`retry still failed:\\n${r2.stderr?.toString() || \"\"}`);\n } else {\n console.error(`ERR_MODULE_NOT_FOUND but could not locate offending cache path in the error.`);\n }\n }\n\n console.error(stderr || `local install failed (exit ${r.status})`);\n process.exit(1);\n });\n\nprogram.parse();\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/index.ts","../../src/cli/skills.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { program } from \"commander\";\nimport { resolve, join, dirname, relative } from \"node:path\";\nimport { existsSync, readFileSync, writeFileSync, rmSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { spawnSync } from \"node:child_process\";\nimport { registerUpdateCommands } from \"@theglitchking/claude-plugin-runtime\";\nimport {\n resolveTarget,\n installSkills,\n uninstallSkills,\n listShippedSkills,\n SKILL_BUNDLER_AGENTS,\n type AgentName,\n type Scope,\n} from \"./skills.js\";\n\nconst require_ = createRequire(import.meta.url);\nconst { version } = require_(\"../../package.json\") as { version: string };\n\nconst PKG_NAME = \"@theglitchking/semantic-sidekick\";\n\nfunction runRelink(cwd: string) {\n const linker = join(cwd, \"node_modules\", \"@theglitchking\", \"semantic-sidekick\", \"scripts\", \"link-skills.js\");\n const script = existsSync(linker) ? linker : resolve(process.cwd(), \"scripts\", \"link-skills.js\");\n if (!existsSync(script)) {\n console.error(\"link-skills.js not found — is the package installed?\");\n return;\n }\n spawnSync(process.execPath, [script], {\n cwd,\n env: { ...process.env, INIT_CWD: cwd },\n stdio: \"inherit\",\n });\n}\n\nfunction findLocalBin(cwd: string): string | null {\n const p = join(cwd, \"node_modules\", \"@theglitchking\", \"semantic-sidekick\", \"bin\", \"semantic-sidekick\");\n return existsSync(p) ? p : null;\n}\n\nfunction localBinArg(cwd: string): string | null {\n const abs = findLocalBin(cwd);\n if (!abs) return null;\n const rel = relative(cwd, abs);\n return rel.startsWith(\"..\") ? abs : `./${rel}`;\n}\n\nfunction readJsonSafe(path: string): any {\n try {\n const raw = readFileSync(path, \"utf8\");\n return raw.trim() ? JSON.parse(raw) : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Returns the fragile npx-form pattern we used to write in pre-0.10.0\n * SessionStart hooks, so normalize-config can detect and rewrite it.\n */\nfunction isNpxForm(entry: any): boolean {\n if (!entry || typeof entry !== \"object\") return false;\n const cmd = entry.command;\n const args = Array.isArray(entry.args) ? entry.args : [];\n return cmd === \"npx\" && args.some((a: unknown) => typeof a === \"string\" && a.includes(PKG_NAME));\n}\n\nfunction isLocalForm(entry: any): boolean {\n if (!entry || typeof entry !== \"object\") return false;\n const cmd = entry.command;\n const args = Array.isArray(entry.args) ? entry.args : [];\n return (\n cmd === \"node\" &&\n args.some((a: unknown) => typeof a === \"string\" && a.includes(\"node_modules/@theglitchking/semantic-sidekick\"))\n );\n}\n\nfunction extractNotesPath(entry: any): string | null {\n const args = Array.isArray(entry?.args) ? entry.args : [];\n const i = args.indexOf(\"--notes\");\n if (i === -1 || i + 1 >= args.length) return null;\n return String(args[i + 1]);\n}\n\nfunction extractExtraFlags(entry: any): string[] {\n const args = Array.isArray(entry?.args) ? entry.args : [];\n return args.filter((a: unknown): a is string => typeof a === \"string\" && a.startsWith(\"--\") && a !== \"--notes\");\n}\n\nconst TOOL_HELP: Record<string, { description: string; args: string; examples: string[] }> = {\n // Search\n search_semantic: {\n description: \"Vector similarity search — find notes by meaning, not just keywords\",\n args: '{ \"query\": \"string\", \"limit?\": 10 }',\n examples: [\n '{ \"query\": \"microservices architecture\", \"limit\": 5 }',\n '{ \"query\": \"how to deploy to production\" }',\n ],\n },\n search_text: {\n description: \"Full-text keyword or regex search with optional filters\",\n args: '{ \"pattern\": \"string\", \"regex?\": false, \"caseSensitive?\": false, \"pathGlob?\": \"string\", \"tagFilter?\": [\"string\"], \"limit?\": 20 }',\n examples: [\n '{ \"pattern\": \"RabbitMQ\" }',\n '{ \"pattern\": \"OAuth\\\\\\\\d\", \"regex\": true }',\n '{ \"pattern\": \"deploy\", \"pathGlob\": \"devops/**\", \"tagFilter\": [\"kubernetes\"] }',\n ],\n },\n search_graph: {\n description: \"Graph traversal — find notes connected to a concept via wikilinks and tags\",\n args: '{ \"concept\": \"string\", \"maxDepth?\": 2 }',\n examples: [\n '{ \"concept\": \"microservices\" }',\n '{ \"concept\": \"auth\", \"maxDepth\": 3 }',\n ],\n },\n search_hybrid: {\n description: \"Combined semantic + graph search — vector results re-ranked by graph proximity\",\n args: '{ \"query\": \"string\", \"limit?\": 10 }',\n examples: [\n '{ \"query\": \"event driven architecture\", \"limit\": 5 }',\n ],\n },\n\n // Read\n read_note: {\n description: \"Read the full content of a specific note by path\",\n args: '{ \"path\": \"string\" }',\n examples: [\n '{ \"path\": \"project-overview.md\" }',\n '{ \"path\": \"notes/meeting-2024-01-15.md\" }',\n ],\n },\n read_multiple_notes: {\n description: \"Batch read multiple notes in one call\",\n args: '{ \"paths\": [\"string\"] }',\n examples: [\n '{ \"paths\": [\"overview.md\", \"architecture.md\", \"deployment.md\"] }',\n ],\n },\n list_notes: {\n description: \"List all indexed notes with metadata (title, tags, link count)\",\n args: \"{}\",\n examples: [\"{}\"],\n },\n\n // Write\n create_note: {\n description: \"Create a new markdown note with optional YAML frontmatter\",\n args: '{ \"path\": \"string\", \"content\": \"string\", \"frontmatter?\": {} }',\n examples: [\n '{ \"path\": \"new-guide.md\", \"content\": \"# Guide\\\\n\\\\nContent here.\" }',\n '{ \"path\": \"tagged.md\", \"content\": \"Content.\", \"frontmatter\": { \"title\": \"Tagged Note\", \"tags\": [\"test\"] } }',\n ],\n },\n update_note: {\n description: \"Edit note content — overwrite, append, prepend, or patch by heading\",\n args: '{ \"path\": \"string\", \"content\": \"string\", \"mode\": \"overwrite|append|prepend|patch-by-heading\", \"heading?\": \"string\" }',\n examples: [\n '{ \"path\": \"guide.md\", \"content\": \"New content.\", \"mode\": \"overwrite\" }',\n '{ \"path\": \"guide.md\", \"content\": \"\\\\n## Appendix\\\\nExtra info.\", \"mode\": \"append\" }',\n '{ \"path\": \"guide.md\", \"content\": \"Updated architecture section.\", \"mode\": \"patch-by-heading\", \"heading\": \"Architecture\" }',\n ],\n },\n delete_note: {\n description: \"Delete a note permanently (requires confirm=true)\",\n args: '{ \"path\": \"string\", \"confirm\": true }',\n examples: [\n '{ \"path\": \"old-note.md\", \"confirm\": true }',\n '{ \"path\": \"old-note.md\", \"confirm\": false } // returns warning, does not delete',\n ],\n },\n move_note: {\n description: \"Move or rename a note — automatically updates wikilinks across the vault\",\n args: '{ \"from\": \"string\", \"to\": \"string\" }',\n examples: [\n '{ \"from\": \"user-service.md\", \"to\": \"auth-service.md\" }',\n '{ \"from\": \"old/note.md\", \"to\": \"new/location/note.md\" }',\n ],\n },\n\n // Metadata\n get_frontmatter: {\n description: \"Read parsed YAML frontmatter from a note as JSON\",\n args: '{ \"path\": \"string\" }',\n examples: ['{ \"path\": \"project-overview.md\" }'],\n },\n update_frontmatter: {\n description: \"Set or delete YAML frontmatter keys — pass null to delete a key\",\n args: '{ \"path\": \"string\", \"fields\": {} }',\n examples: [\n '{ \"path\": \"note.md\", \"fields\": { \"status\": \"active\", \"priority\": 1 } }',\n '{ \"path\": \"note.md\", \"fields\": { \"deprecated_field\": null } } // deletes the key',\n ],\n },\n manage_tags: {\n description: \"Add, remove, or list tags on a note (frontmatter and inline)\",\n args: '{ \"path\": \"string\", \"action\": \"add|remove|list\", \"tags?\": [\"string\"] }',\n examples: [\n '{ \"path\": \"note.md\", \"action\": \"list\" }',\n '{ \"path\": \"note.md\", \"action\": \"add\", \"tags\": [\"important\", \"reviewed\"] }',\n '{ \"path\": \"note.md\", \"action\": \"remove\", \"tags\": [\"draft\"] }',\n ],\n },\n rename_tag: {\n description: \"Rename a tag across all notes in the vault (frontmatter + inline)\",\n args: '{ \"oldTag\": \"string\", \"newTag\": \"string\" }',\n examples: ['{ \"oldTag\": \"architecture\", \"newTag\": \"arch\" }'],\n },\n\n // Graph\n backlinks: {\n description: \"Find all notes that link TO a given note via [[wikilinks]]\",\n args: '{ \"path\": \"string\" }',\n examples: ['{ \"path\": \"microservices.md\" }'],\n },\n forwardlinks: {\n description: \"Find all notes linked FROM a given note\",\n args: '{ \"path\": \"string\" }',\n examples: ['{ \"path\": \"project-overview.md\" }'],\n },\n graph_path: {\n description: \"Find the shortest path between two notes in the knowledge graph\",\n args: '{ \"from\": \"string\", \"to\": \"string\" }',\n examples: ['{ \"from\": \"project-overview.md\", \"to\": \"user-service.md\" }'],\n },\n graph_statistics: {\n description: \"Knowledge graph stats — most connected nodes, orphans, density\",\n args: \"{}\",\n examples: [\"{}\"],\n },\n\n // System\n get_stats: {\n description: \"Vault and index statistics — note count, chunks, embeddings, graph density\",\n args: \"{}\",\n examples: [\"{}\"],\n },\n reindex: {\n description: \"Force a full reindex of the vault\",\n args: \"{}\",\n examples: [\"{}\"],\n },\n};\n\nconst TOOL_CATEGORIES: Record<string, string[]> = {\n Search: [\"search_semantic\", \"search_text\", \"search_graph\", \"search_hybrid\"],\n Read: [\"read_note\", \"read_multiple_notes\", \"list_notes\"],\n Write: [\"create_note\", \"update_note\", \"delete_note\", \"move_note\"],\n Metadata: [\"get_frontmatter\", \"update_frontmatter\", \"manage_tags\", \"rename_tag\"],\n Graph: [\"backlinks\", \"forwardlinks\", \"graph_path\", \"graph_statistics\"],\n System: [\"get_stats\", \"reindex\"],\n};\n\nfunction printToolList() {\n console.log(\"\\nSemantic Pages — 21 MCP Tools\\n\");\n console.log(\"Usage: These tools are available via MCP when the server is running.\");\n console.log(\" Run `semantic-sidekick tools <name>` for details on a specific tool.\\n\");\n\n for (const [category, tools] of Object.entries(TOOL_CATEGORIES)) {\n console.log(` ${category}:`);\n for (const name of tools) {\n const tool = TOOL_HELP[name];\n console.log(` ${name.padEnd(24)} ${tool.description}`);\n }\n console.log();\n }\n\n console.log(\"Run `semantic-sidekick tools <tool-name>` for arguments and examples.\");\n}\n\nfunction printToolDetail(name: string) {\n const tool = TOOL_HELP[name];\n if (!tool) {\n console.error(`Unknown tool: ${name}`);\n console.error(`Run \\`semantic-sidekick tools\\` to see all available tools.`);\n process.exit(1);\n }\n\n console.log(`\\n ${name}`);\n console.log(` ${\"─\".repeat(name.length)}`);\n console.log(` ${tool.description}\\n`);\n console.log(` Arguments:`);\n console.log(` ${tool.args}\\n`);\n console.log(` Examples:`);\n for (const ex of tool.examples) {\n console.log(` ${ex}`);\n }\n console.log();\n}\n\nprogram\n .name(\"semantic-memory\")\n .description(\n \"Unified memory-layer MCP server for Claude Code (rebrand of semantic-sidekick at v1.0.0).\\n\" +\n \"The `semantic-sidekick` command is preserved as an alias.\\n\\n\" +\n \" Start MCP server: semantic-memory --notes ./vault\\n\" +\n \" Show vault stats: semantic-memory --notes ./vault --stats\\n\" +\n \" Force reindex: semantic-memory --notes ./vault --reindex\\n\" +\n \" List MCP tools: semantic-memory tools\\n\" +\n \" Tool details: semantic-memory tools search_semantic\"\n )\n .version(version);\n\nprogram\n .command(\"search <query>\")\n .description(\"Run a vault search and print top hits as JSON (used by activation hooks)\")\n .requiredOption(\"--notes <path>\", \"Path to markdown notes directory\")\n .option(\"--limit <n>\", \"Max results\", (v) => parseInt(v, 10), 8)\n .option(\"--text-only\", \"Skip embedder — keyword-only search (fast path, no model init)\")\n .option(\"--json\", \"Emit raw JSON (default)\", true)\n .action(async (query: string, opts) => {\n const { runSearch } = await import(\"./search.js\");\n try {\n const hits = await runSearch({\n notes: opts.notes,\n query,\n limit: opts.limit,\n textOnly: opts.textOnly,\n });\n process.stdout.write(JSON.stringify(hits, null, 2) + \"\\n\");\n process.exit(0);\n } catch (err: any) {\n console.error(`search failed: ${err.message}`);\n process.exit(1);\n }\n });\n\nprogram\n .command(\"lint\")\n .description(\"Lint the vault against vault.schema.yml (schema violations + missing provenance + stale)\")\n .requiredOption(\"--notes <path>\", \"Path to markdown notes directory\")\n .option(\"--rule <name>\", \"Limit output to one rule: schema_violations | missing_provenance | stale\")\n .option(\"--json\", \"Emit JSON instead of the human-readable report\")\n .option(\"--strict\", \"Exit non-zero on warnings too (default: exit non-zero only on errors)\")\n .action(async (opts) => {\n const { lintVault, formatLintReport } = await import(\"../core/lint.js\");\n const report = await lintVault(resolve(opts.notes));\n // Use console.log + process.exitCode (not process.exit) so Node flushes\n // stdout fully before the process ends. Early process.exit with a large\n // buffered JSON payload can truncate output.\n if (opts.json) {\n const out = opts.rule ? report.byRule[opts.rule as keyof typeof report.byRule] : report;\n console.log(JSON.stringify(out, null, 2));\n } else {\n console.log(formatLintReport(report, { rule: opts.rule }));\n }\n const bad = opts.strict ? report.counts.errors + report.counts.warnings : report.counts.errors;\n process.exitCode = bad > 0 ? 1 : 0;\n });\n\nprogram\n .command(\"log-event\")\n .description(\"Append a structured event to the vault's log.md (used by hooks and CI scripts — same shape as mcp__semantic-vault__log_event)\")\n .requiredOption(\"--notes <path>\", \"Path to markdown notes directory\")\n .requiredOption(\"--kind <name>\", \"Event category: ingest, synthesis, error, mode_change, etc.\")\n .requiredOption(\"--summary <text>\", \"One-line human summary\")\n .option(\"--payload <json>\", \"Structured payload as JSON string\")\n .action(async (opts) => {\n const { logEvent } = await import(\"../core/log.js\");\n let payload: Record<string, unknown> | undefined;\n if (opts.payload) {\n try {\n payload = JSON.parse(opts.payload);\n } catch (e: any) {\n console.error(`invalid --payload JSON: ${e.message}`);\n process.exitCode = 1;\n return;\n }\n }\n try {\n const entry = await logEvent(resolve(opts.notes), {\n kind: opts.kind,\n summary: opts.summary,\n payload,\n });\n console.log(JSON.stringify(entry));\n } catch (e: any) {\n console.error(`log-event failed: ${e.message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command(\"log-query\")\n .description(\"Read structured log entries from log.md — filters by kind, date range, limit\")\n .requiredOption(\"--notes <path>\", \"Path to markdown notes directory\")\n .option(\"--kind <name>\", \"Filter by kind (ingest, synthesis, error, mode_change, etc.)\")\n .option(\"--after <iso>\", \"ISO timestamp — only entries on or after\")\n .option(\"--before <iso>\", \"ISO timestamp — only entries on or before\")\n .option(\"--limit <n>\", \"Max entries (most recent)\", (v) => parseInt(v, 10))\n .action(async (opts) => {\n const { logQuery } = await import(\"../core/log.js\");\n try {\n const entries = await logQuery(resolve(opts.notes), {\n kind: opts.kind,\n after: opts.after,\n before: opts.before,\n limit: opts.limit,\n });\n console.log(JSON.stringify(entries));\n } catch (e: any) {\n console.error(`log-query failed: ${e.message}`);\n process.exitCode = 1;\n }\n });\n\nprogram\n .command(\"install-schema\")\n .description(\"Bootstrap vault.schema.yml in the vault root with the default schema\")\n .requiredOption(\"--notes <path>\", \"Path to markdown notes directory\")\n .option(\"--force\", \"Overwrite existing schema file\")\n .action(async (opts) => {\n const { installDefaultSchema } = await import(\"../core/schema.js\");\n const r = await installDefaultSchema(resolve(opts.notes), opts.force);\n console.log(r.written ? `Installed default schema: ${r.path}` : `Schema already exists: ${r.path} (use --force to overwrite)`);\n process.exit(0);\n });\n\nprogram\n .command(\"tools [name]\")\n .description(\"List all MCP tools, or show details for a specific tool\")\n .action((name?: string) => {\n if (name) {\n printToolDetail(name);\n } else {\n printToolList();\n }\n process.exit(0);\n });\n\nprogram\n .command(\"serve\", { isDefault: true })\n .description(\"Start the MCP server (default command)\")\n .requiredOption(\"--notes <path>\", \"Path to markdown notes directory\")\n .option(\"--reindex\", \"Force full reindex and exit\")\n .option(\"--stats\", \"Show vault statistics and exit\")\n .option(\"--wait-for-ready\", \"Block startup until index is fully built before serving (default: index in background; tools return 'Indexing in progress' until ready)\")\n .option(\"--read-only\", \"Suppress write tools (create_note, update_note, delete_note, move_note, update_frontmatter, manage_tags, rename_tag) — use for shared docs vaults owned by another tool\")\n .option(\"--model <name>\", \"Embedding model to use (default: all-MiniLM-L6-v2, fast; use nomic-ai/nomic-embed-text-v1.5 for higher quality)\")\n .option(\"--workers <n>\", \"Number of worker threads for parallel embedding\", parseInt)\n .option(\"--batch-size <n>\", \"Texts per ONNX forward pass (default: 8)\", parseInt)\n .option(\"--no-quantized\", \"Use full-precision model instead of quantized (slower, slightly higher quality)\")\n .option(\"--no-watch\", \"Disable file watcher\")\n .action(async (opts) => {\n const notesPath = resolve(opts.notes);\n\n if (!existsSync(notesPath)) {\n console.error(`Error: notes directory not found: ${notesPath}`);\n process.exit(1);\n }\n\n if (opts.stats) {\n const { Indexer } = await import(\"../core/indexer.js\");\n const indexer = new Indexer(notesPath);\n const docs = await indexer.indexAll();\n console.log(`Notes: ${docs.length}`);\n console.log(`Chunks: ${docs.reduce((n: number, d: any) => n + d.chunks.length, 0)}`);\n console.log(`Wikilinks: ${docs.reduce((n: number, d: any) => n + d.wikilinks.length, 0)}`);\n console.log(`Tags: ${new Set(docs.flatMap((d: any) => d.tags)).size} unique`);\n process.exit(0);\n }\n\n if (opts.reindex) {\n const { createServer } = await import(\"../mcp/server.js\");\n await createServer(notesPath, {\n watch: false,\n waitForReady: true,\n model: opts.model,\n workers: opts.workers,\n batchSize: opts.batchSize,\n quantized: opts.quantized,\n onProgress: (embedded, total) => {\n process.stderr.write(`\\rEmbedding ${embedded}/${total} chunks...`);\n },\n });\n process.stderr.write(\"\\n\");\n console.log(\"Reindex complete.\");\n process.exit(0);\n }\n\n // Default: start MCP server on stdio\n const { startServer } = await import(\"../mcp/server.js\");\n await startServer(notesPath, {\n watch: opts.watch,\n waitForReady: opts.waitForReady,\n model: opts.model,\n workers: opts.workers,\n batchSize: opts.batchSize,\n quantized: opts.quantized,\n readOnly: opts.readOnly,\n });\n });\n\nregisterUpdateCommands(program, {\n packageName: PKG_NAME,\n pluginName: \"semantic-sidekick\",\n configFile: \"semantic-sidekick.json\",\n onAfterUpdate: (cwd) => runRelink(cwd),\n});\n\nprogram\n .command(\"normalize-config\")\n .description(\n \"Rewrite fragile `npx @latest` entries in .mcp.json to the stable node-against-node_modules form (with backup and validation)\",\n )\n .option(\"--dry-run\", \"print the proposed changes but don't write\")\n .action((opts: { dryRun?: boolean }) => {\n const cwd = process.cwd();\n const mcpPath = join(cwd, \".mcp.json\");\n if (!existsSync(mcpPath)) {\n console.log(\"no .mcp.json in current directory — nothing to do\");\n process.exit(0);\n }\n const data = readJsonSafe(mcpPath);\n if (!data || typeof data !== \"object\" || !data.mcpServers || typeof data.mcpServers !== \"object\") {\n console.error(`could not parse ${mcpPath}`);\n process.exit(1);\n }\n const bin = localBinArg(cwd);\n if (!bin) {\n console.error(\n `no local install found at ./node_modules/@theglitchking/semantic-sidekick/bin/semantic-sidekick.\\n` +\n `run 'npm install --save @theglitchking/semantic-sidekick' first, then re-run this command.`,\n );\n process.exit(1);\n }\n const rewritten: string[] = [];\n for (const [key, entry] of Object.entries<any>(data.mcpServers)) {\n if (!isNpxForm(entry)) continue;\n const notes = extractNotesPath(entry) ?? \"./.claude/.vault\";\n const extra = extractExtraFlags(entry);\n data.mcpServers[key] = {\n type: \"stdio\",\n command: \"node\",\n args: [bin, \"--notes\", notes, ...extra],\n };\n rewritten.push(key);\n }\n if (rewritten.length === 0) {\n console.log(\"no npx-form entries found — .mcp.json is already in the stable form.\");\n process.exit(0);\n }\n console.log(`Rewriting ${rewritten.length} entr${rewritten.length === 1 ? \"y\" : \"ies\"}: ${rewritten.join(\", \")}`);\n if (opts.dryRun) {\n console.log(\"--- proposed .mcp.json:\");\n console.log(JSON.stringify(data, null, 2));\n console.log(\"--- (dry-run; no changes written)\");\n process.exit(0);\n }\n // Back up\n const bakPath = join(dirname(mcpPath), \".mcp.json.bak\");\n try {\n writeFileSync(bakPath, readFileSync(mcpPath, \"utf8\"));\n console.log(`backup written: ${bakPath}`);\n } catch (err: any) {\n console.error(`could not write backup: ${err.message}`);\n process.exit(1);\n }\n writeFileSync(mcpPath, JSON.stringify(data, null, 2) + \"\\n\");\n\n // Verify the local bin starts cleanly. We just run --version — fast and\n // enough to catch ERR_MODULE_NOT_FOUND type failures.\n const verify = spawnSync(\"node\", [bin, \"--version\"], { cwd, stdio: \"pipe\", timeout: 15_000 });\n if (verify.status !== 0) {\n console.error(`verification failed (exit ${verify.status}):\\n${verify.stderr?.toString() || \"\"}`);\n console.error(`rolling back from ${bakPath}`);\n writeFileSync(mcpPath, readFileSync(bakPath, \"utf8\"));\n process.exit(1);\n }\n console.log(`✓ .mcp.json normalized and verified. Toggle the MCPs in /mcp to reconnect.`);\n process.exit(0);\n });\n\nprogram\n .command(\"healthcheck\")\n .description(\n \"Verify the local install starts cleanly + run drift detection. Self-heals common npx-cache corruption (ERR_MODULE_NOT_FOUND). With --fast, skips the slow tier (full vault lint).\",\n )\n .option(\"--fast\", \"Run only the fast-tier drift checks (file-system probes). Skips the slow tier (full vault lint).\", false)\n .option(\"--json\", \"Emit structured JSON output instead of human-readable text.\", false)\n .action(async (opts) => {\n const cwd = process.cwd();\n const bin = findLocalBin(cwd);\n if (!bin) {\n console.error(`no local install at ./node_modules/@theglitchking/semantic-sidekick/bin/semantic-sidekick`);\n console.error(`run 'npm install --save @theglitchking/semantic-sidekick' to install.`);\n process.exit(1);\n }\n\n // 1. Warn if .mcp.json uses the fragile form.\n const mcpPath = join(cwd, \".mcp.json\");\n if (existsSync(mcpPath)) {\n const data = readJsonSafe(mcpPath);\n const entries = data?.mcpServers && typeof data.mcpServers === \"object\" ? Object.entries<any>(data.mcpServers) : [];\n const fragile = entries.filter(([, e]) => isNpxForm(e)).map(([k]) => k);\n if (fragile.length > 0) {\n console.warn(\n `⚠️ .mcp.json uses the fragile npx-@latest form for: ${fragile.join(\", \")}`,\n );\n console.warn(` Rewrite to the stable form:`);\n console.warn(` npx --no @theglitchking/semantic-sidekick normalize-config`);\n }\n }\n\n // 2. Smoke-test the local bin.\n const r = spawnSync(\"node\", [bin, \"--version\"], { cwd, stdio: \"pipe\", timeout: 15_000 });\n if (r.status === 0) {\n console.log(`✓ local install starts cleanly (v${r.stdout?.toString().trim()})`);\n process.exit(0);\n }\n\n const stderr = r.stderr?.toString() ?? \"\";\n\n // 3. Self-heal ERR_MODULE_NOT_FOUND in npx cache (rare but the classic\n // failure mode that triggered 0.10.0). Extract the offending npx cache\n // dir from the error message, rm -rf it, retry once.\n if (stderr.includes(\"ERR_MODULE_NOT_FOUND\")) {\n const match = stderr.match(/([\\/~][^'\"\\s]*\\/_npx\\/[^\\/'\"\\s]+)/);\n if (match) {\n const bad = match[1];\n console.warn(`detected broken npx cache at ${bad} — clearing and retrying...`);\n try { rmSync(bad, { recursive: true, force: true }); } catch {}\n const r2 = spawnSync(\"node\", [bin, \"--version\"], { cwd, stdio: \"pipe\", timeout: 15_000 });\n if (r2.status === 0) {\n console.log(`✓ cleared npx cache and verified (v${r2.stdout?.toString().trim()})`);\n process.exit(0);\n }\n console.error(`retry still failed:\\n${r2.stderr?.toString() || \"\"}`);\n } else {\n console.error(`ERR_MODULE_NOT_FOUND but could not locate offending cache path in the error.`);\n }\n }\n\n if (stderr) console.error(stderr);\n if (r.status !== 0) {\n console.error(`local install failed (exit ${r.status})`);\n process.exit(1);\n }\n });\n\n// Append drift detection to the healthcheck handler (Phase 8). Wraps the original\n// handler — the function above runs first (npx-cache self-heal), then drift detection\n// runs and prints additional findings. --fast skips the slow tier (full vault lint).\nconst driftHealthcheckActionPostprocess = async (opts: { fast?: boolean; json?: boolean }) => {\n try {\n const { runHealthcheck, formatDriftBanner } = await import(\"../core/healthcheck.js\");\n const projectRoot = process.cwd();\n // For the auto-derived vault path, prefer .claude/.vault if present\n const vaultCandidate = join(projectRoot, \".claude\", \".vault\");\n const vaultPath = existsSync(vaultCandidate) ? vaultCandidate : undefined;\n const result = await runHealthcheck({\n projectRoot,\n vaultPath,\n tier: opts.fast ? \"fast\" : \"all\",\n force: true,\n });\n if (opts.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n const banner = formatDriftBanner(result);\n if (banner) {\n console.log(\"\");\n console.log(banner);\n } else {\n console.log(\"\");\n console.log(`✓ no drift detected (${result.findings.length} checks ran in ${result.duration_ms}ms)`);\n }\n } catch (err: any) {\n console.error(`drift check threw: ${err?.message ?? err}`);\n }\n};\n\n// Wire the drift-detection postprocess. We do this by attaching to the existing\n// healthcheck command's postAction hook so the original handler still runs first.\nconst healthcheckCmd = program.commands.find((c) => c.name() === \"healthcheck\");\nif (healthcheckCmd) {\n healthcheckCmd.hook(\"postAction\", async (thisCmd) => {\n const opts = thisCmd.opts();\n await driftHealthcheckActionPostprocess({ fast: !!opts.fast, json: !!opts.json });\n });\n}\n\n// --- Skill bundler (Phase 6) ---\n\nfunction parseAgent(input: string): AgentName {\n const a = input.toLowerCase();\n if (!SKILL_BUNDLER_AGENTS.includes(a as AgentName)) {\n console.error(`Unknown agent: ${input}. Supported: ${SKILL_BUNDLER_AGENTS.join(\", \")}.`);\n process.exit(2);\n }\n return a as AgentName;\n}\n\nfunction parseScope(input: string): Scope {\n if (input !== \"global\" && input !== \"local\") {\n console.error(`Unknown scope: ${input}. Use 'global' or 'local'.`);\n process.exit(2);\n }\n return input;\n}\n\nfunction findSourceRoot(): string {\n // 1. Installed: <cwd>/node_modules/@theglitchking/semantic-sidekick or semantic-memory\n for (const pkg of [\"semantic-memory\", \"semantic-sidekick\"]) {\n const installed = join(process.cwd(), \"node_modules\", \"@theglitchking\", pkg);\n if (existsSync(installed)) return installed;\n }\n // 2. Dev: derive from the bin location (this file lives at <root>/dist/cli/index.js)\n const dev = resolve(new URL(\"../../\", import.meta.url).pathname);\n return dev;\n}\n\nconst skillsCmd = program.command(\"skills\").description(\"Install, target, or uninstall skill bundles for non-Claude agents (codex, copilot, pi). Claude installs continue to use the npm postinstall flow.\");\n\nskillsCmd\n .command(\"targets\")\n .description(\"Preview where skill bundles would be installed for one or more agents.\")\n .option(\"--agent <name...>\", \"One or more agents (default: all). Repeatable.\", undefined as any)\n .option(\"--scope <scope>\", \"global or local (default: local)\", \"local\")\n .option(\"--project <path>\", \"Project root for local-scope paths (default: cwd)\", process.cwd())\n .action((opts) => {\n const scope = parseScope(opts.scope);\n const agents: AgentName[] = (opts.agent && opts.agent.length > 0 ? opts.agent : SKILL_BUNDLER_AGENTS).map(parseAgent);\n const out = agents.map((a) => resolveTarget(a, scope, opts.project));\n console.log(JSON.stringify(out, null, 2));\n });\n\nskillsCmd\n .command(\"install\")\n .description(\"Install skill bundles into an agent's skill directory. Non-destructive by default; --force to overwrite.\")\n .requiredOption(\"--agent <name>\", \"Agent runtime (claude, codex, copilot, pi)\")\n .option(\"--scope <scope>\", \"global or local (default: local)\", \"local\")\n .option(\"--project <path>\", \"Project root for local-scope paths (default: cwd)\", process.cwd())\n .option(\"--only <names...>\", \"Restrict to specific skill names (default: all shipped)\")\n .option(\"--force\", \"Overwrite even if drift is detected against an existing manifest\", false)\n .action(async (opts) => {\n const agent = parseAgent(opts.agent);\n const scope = parseScope(opts.scope);\n if (agent === \"claude\") {\n console.error(\n \"Claude skill installs are handled by the npm postinstall (claude-plugin-runtime). \" +\n \"Run `npm install @theglitchking/semantic-memory` instead — that flow symlinks \" +\n \"skills into ~/.claude/skills/ or .claude/skills/ automatically. The skills CLI \" +\n \"is intended for non-Claude agents (codex, copilot, pi) which do not have that \" +\n \"postinstall integration.\"\n );\n process.exit(2);\n }\n const sourceRoot = findSourceRoot();\n const result = await installSkills({\n agent,\n scope,\n sourceRoot,\n projectRoot: opts.project,\n version,\n only: opts.only,\n force: opts.force === true,\n });\n console.log(JSON.stringify(result, null, 2));\n if (result.installed.length === 0 && result.reason) process.exit(1);\n });\n\nskillsCmd\n .command(\"uninstall\")\n .description(\"Remove skill bundles tracked by the semantic-memory manifest. User-written skills outside the manifest are left untouched.\")\n .requiredOption(\"--agent <name>\", \"Agent runtime (claude, codex, copilot, pi)\")\n .option(\"--scope <scope>\", \"global or local (default: local)\", \"local\")\n .option(\"--project <path>\", \"Project root for local-scope paths (default: cwd)\", process.cwd())\n .action(async (opts) => {\n const agent = parseAgent(opts.agent);\n const scope = parseScope(opts.scope);\n if (agent === \"claude\") {\n console.error(\"Claude skill uninstalls go through the npm uninstall flow. The skills CLI is for non-Claude agents.\");\n process.exit(2);\n }\n const result = await uninstallSkills({ agent, scope, projectRoot: opts.project });\n console.log(JSON.stringify(result, null, 2));\n });\n\nskillsCmd\n .command(\"list\")\n .description(\"List the skill bundles shipped with this plugin version.\")\n .action(async () => {\n const sourceRoot = findSourceRoot();\n const shipped = await listShippedSkills(sourceRoot);\n console.log(JSON.stringify(shipped.map((s) => s.name), null, 2));\n });\n\nprogram.parse();\n","import { mkdir, readFile, writeFile, copyFile, readdir, rm } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { join, basename, resolve } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { createHash } from \"node:crypto\";\n\nexport type AgentName = \"claude\" | \"codex\" | \"copilot\" | \"pi\";\nexport type Scope = \"global\" | \"local\";\n\nexport interface AgentTargetSpec {\n agent: AgentName;\n scope: Scope;\n /** Absolute resolved path where the skill bundles will land. */\n path: string;\n}\n\nexport interface SkillManifest {\n package: string;\n version: string;\n agent: AgentName;\n scope: Scope;\n installed_at: string;\n skills: { name: string; sha256: string }[];\n}\n\nexport interface InstallResult {\n agent: AgentName;\n scope: Scope;\n target_path: string;\n installed: string[];\n skipped: string[];\n reason?: string;\n manifest_path?: string;\n}\n\nconst MANIFEST_FILE = \".semantic-memory-skill-manifest.json\";\n\n/**\n * Resolve where a given (agent, scope) tuple should land. Project root is required for local\n * scope (to anchor relative paths); for global scope it's not used.\n */\nexport function resolveTarget(agent: AgentName, scope: Scope, projectRoot: string): AgentTargetSpec {\n const root = resolve(projectRoot);\n const home = homedir();\n const map: Record<AgentName, { global: string; local: string }> = {\n claude: { global: join(home, \".claude\", \"skills\"), local: join(root, \".claude\", \"skills\") },\n codex: { global: join(home, \".codex\", \"skills\"), local: join(root, \".codex\", \"skills\") },\n copilot: { global: join(home, \".copilot\", \"skills\"), local: join(root, \".github\", \"skills\") },\n pi: { global: join(home, \".pi\", \"agent\", \"skills\"), local: join(root, \".pi\", \"skills\") },\n };\n return { agent, scope, path: map[agent][scope] };\n}\n\n/**\n * Enumerate the canonical skill bundles shipped by this plugin. Each bundle is a directory\n * under `<sourceRoot>/skills/` containing at least a SKILL.md file. Entries without\n * SKILL.md are silently skipped (allows future non-skill files like `/skills/.gitkeep`).\n */\nexport async function listShippedSkills(sourceRoot: string): Promise<{ name: string; dir: string }[]> {\n const skillsDir = join(sourceRoot, \"skills\");\n if (!existsSync(skillsDir)) return [];\n const entries = await readdir(skillsDir, { withFileTypes: true });\n const out: { name: string; dir: string }[] = [];\n for (const e of entries) {\n if (!e.isDirectory()) continue;\n const dir = join(skillsDir, e.name);\n const skillFile = join(dir, \"SKILL.md\");\n if (!existsSync(skillFile)) continue;\n out.push({ name: e.name, dir });\n }\n return out;\n}\n\nasync function sha256OfFile(path: string): Promise<string> {\n const buf = await readFile(path);\n return createHash(\"sha256\").update(buf).digest(\"hex\");\n}\n\n/**\n * Copy a single skill bundle (SKILL.md plus any sibling files in the same directory) into\n * the target directory, overlaying it with the agent name. Returns the list of files written.\n *\n * The target layout is `<targetPath>/<skillName>/SKILL.md` plus mirrored siblings, so each\n * bundle is namespaced and easy to remove later.\n */\nasync function copyBundle(srcDir: string, destDir: string): Promise<string[]> {\n await mkdir(destDir, { recursive: true });\n const entries = await readdir(srcDir, { withFileTypes: true });\n const written: string[] = [];\n for (const e of entries) {\n const src = join(srcDir, e.name);\n const dest = join(destDir, e.name);\n if (e.isDirectory()) {\n const childWritten = await copyBundle(src, dest);\n written.push(...childWritten);\n continue;\n }\n if (!e.isFile()) continue;\n await copyFile(src, dest);\n written.push(dest);\n }\n return written;\n}\n\nexport interface InstallOptions {\n agent: AgentName;\n scope: Scope;\n /** Path to the package's source root (usually the repo root, where `skills/` lives). */\n sourceRoot: string;\n /** Used to anchor local-scope target paths. */\n projectRoot: string;\n /** Plugin version, recorded in the manifest. */\n version: string;\n /** Specific skills to install. When omitted, all shipped skills are installed. */\n only?: string[];\n /**\n * When false, refuse to overwrite an existing install (manifest present + sha mismatch\n * indicates upstream drift). When true, overwrite. Default false.\n */\n force?: boolean;\n}\n\n/**\n * Install all (or selected) skill bundles into an agent's skill directory.\n *\n * Behavior:\n * - Resolves the destination via resolveTarget.\n * - Reads any existing manifest. If a manifest exists, version differs from `version`,\n * AND any skill sha256 differs from the source: this is a drift event. Without\n * `force: true`, returns a refusal with reason \"drift detected\". With force, proceeds\n * and overwrites.\n * - For each shipped skill (or each in `only`), copies the bundle into\n * <target>/<skillName>/, overwriting any existing files in that subdirectory.\n * - Writes a fresh manifest at <target>/<MANIFEST_FILE> recording sha256 of each\n * SKILL.md installed, the plugin version, agent, and scope.\n */\nexport async function installSkills(opts: InstallOptions): Promise<InstallResult> {\n const target = resolveTarget(opts.agent, opts.scope, opts.projectRoot);\n const shipped = await listShippedSkills(opts.sourceRoot);\n const filter = opts.only && opts.only.length > 0 ? new Set(opts.only) : null;\n const toInstall = filter ? shipped.filter((s) => filter.has(s.name)) : shipped;\n\n if (toInstall.length === 0) {\n return {\n agent: opts.agent,\n scope: opts.scope,\n target_path: target.path,\n installed: [],\n skipped: [],\n reason: filter ? `No matching skills found (only=${[...filter].join(\",\")}).` : \"No shipped skills found at sourceRoot/skills/.\",\n };\n }\n\n const manifestPath = join(target.path, MANIFEST_FILE);\n const existing = await readManifest(manifestPath);\n\n if (existing && !opts.force) {\n const drift = await detectDrift(existing, toInstall);\n if (drift.length > 0) {\n return {\n agent: opts.agent,\n scope: opts.scope,\n target_path: target.path,\n installed: [],\n skipped: toInstall.map((s) => s.name),\n reason: `Drift detected on ${drift.length} skill(s): ${drift.join(\", \")}. Pass --force to overwrite.`,\n manifest_path: manifestPath,\n };\n }\n }\n\n await mkdir(target.path, { recursive: true });\n const installed: string[] = [];\n const skillEntries: { name: string; sha256: string }[] = [];\n for (const skill of toInstall) {\n const destDir = join(target.path, skill.name);\n await copyBundle(skill.dir, destDir);\n const skillFile = join(skill.dir, \"SKILL.md\");\n skillEntries.push({ name: skill.name, sha256: await sha256OfFile(skillFile) });\n installed.push(skill.name);\n }\n\n const manifest: SkillManifest = {\n package: \"@theglitchking/semantic-memory\",\n version: opts.version,\n agent: opts.agent,\n scope: opts.scope,\n installed_at: new Date().toISOString(),\n skills: skillEntries,\n };\n await writeFile(manifestPath, JSON.stringify(manifest, null, 2), \"utf-8\");\n\n return {\n agent: opts.agent,\n scope: opts.scope,\n target_path: target.path,\n installed,\n skipped: [],\n manifest_path: manifestPath,\n };\n}\n\nexport interface UninstallOptions {\n agent: AgentName;\n scope: Scope;\n projectRoot: string;\n}\n\nexport interface UninstallResult {\n agent: AgentName;\n scope: Scope;\n target_path: string;\n removed: string[];\n manifest_present: boolean;\n reason?: string;\n}\n\n/**\n * Remove only the skill bundles tracked in the manifest. User-written skills outside\n * the manifest are left untouched.\n */\nexport async function uninstallSkills(opts: UninstallOptions): Promise<UninstallResult> {\n const target = resolveTarget(opts.agent, opts.scope, opts.projectRoot);\n const manifestPath = join(target.path, MANIFEST_FILE);\n const manifest = await readManifest(manifestPath);\n if (!manifest) {\n return {\n agent: opts.agent,\n scope: opts.scope,\n target_path: target.path,\n removed: [],\n manifest_present: false,\n reason: \"No semantic-memory manifest found — nothing to uninstall.\",\n };\n }\n const removed: string[] = [];\n for (const skill of manifest.skills) {\n const dir = join(target.path, skill.name);\n if (existsSync(dir)) {\n await rm(dir, { recursive: true, force: true });\n removed.push(skill.name);\n }\n }\n await rm(manifestPath, { force: true });\n return {\n agent: opts.agent,\n scope: opts.scope,\n target_path: target.path,\n removed,\n manifest_present: true,\n };\n}\n\nasync function readManifest(path: string): Promise<SkillManifest | null> {\n if (!existsSync(path)) return null;\n try {\n const raw = await readFile(path, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (typeof parsed?.package !== \"string\") return null;\n return parsed as SkillManifest;\n } catch {\n return null;\n }\n}\n\nasync function detectDrift(\n existing: SkillManifest,\n toInstall: { name: string; dir: string }[]\n): Promise<string[]> {\n const driftNames: string[] = [];\n const existingByName = new Map(existing.skills.map((s) => [s.name, s.sha256]));\n for (const skill of toInstall) {\n const sourceSha = await sha256OfFile(join(skill.dir, \"SKILL.md\"));\n const existingSha = existingByName.get(skill.name);\n if (existingSha !== undefined && existingSha !== sourceSha) {\n driftNames.push(skill.name);\n }\n }\n return driftNames;\n}\n\nexport const SKILL_BUNDLER_AGENTS: AgentName[] = [\"claude\", \"codex\", \"copilot\", \"pi\"];\n"],"mappings":";;;;AAEA,SAAS,eAAe;AACxB,SAAS,WAAAA,UAAS,QAAAC,OAAM,SAAS,gBAAgB;AACjD,SAAS,cAAAC,aAAY,cAAc,eAAe,cAAc;AAChE,SAAS,qBAAqB;AAC9B,SAAS,iBAAiB;AAC1B,SAAS,8BAA8B;;;ACPvC,SAAS,OAAO,UAAU,WAAW,UAAU,SAAS,UAAU;AAClE,SAAS,kBAAkB;AAC3B,SAAS,MAAgB,eAAe;AACxC,SAAS,eAAe;AACxB,SAAS,kBAAkB;AA+B3B,IAAM,gBAAgB;AAMf,SAAS,cAAc,OAAkB,OAAc,aAAsC;AAClG,QAAM,OAAO,QAAQ,WAAW;AAChC,QAAM,OAAO,QAAQ;AACrB,QAAM,MAA4D;AAAA,IAChE,QAAQ,EAAE,QAAQ,KAAK,MAAM,WAAW,QAAQ,GAAG,OAAO,KAAK,MAAM,WAAW,QAAQ,EAAE;AAAA,IAC1F,OAAO,EAAE,QAAQ,KAAK,MAAM,UAAU,QAAQ,GAAG,OAAO,KAAK,MAAM,UAAU,QAAQ,EAAE;AAAA,IACvF,SAAS,EAAE,QAAQ,KAAK,MAAM,YAAY,QAAQ,GAAG,OAAO,KAAK,MAAM,WAAW,QAAQ,EAAE;AAAA,IAC5F,IAAI,EAAE,QAAQ,KAAK,MAAM,OAAO,SAAS,QAAQ,GAAG,OAAO,KAAK,MAAM,OAAO,QAAQ,EAAE;AAAA,EACzF;AACA,SAAO,EAAE,OAAO,OAAO,MAAM,IAAI,KAAK,EAAE,KAAK,EAAE;AACjD;AAOA,eAAsB,kBAAkB,YAA8D;AACpG,QAAM,YAAY,KAAK,YAAY,QAAQ;AAC3C,MAAI,CAAC,WAAW,SAAS,EAAG,QAAO,CAAC;AACpC,QAAM,UAAU,MAAM,QAAQ,WAAW,EAAE,eAAe,KAAK,CAAC;AAChE,QAAM,MAAuC,CAAC;AAC9C,aAAW,KAAK,SAAS;AACvB,QAAI,CAAC,EAAE,YAAY,EAAG;AACtB,UAAM,MAAM,KAAK,WAAW,EAAE,IAAI;AAClC,UAAM,YAAY,KAAK,KAAK,UAAU;AACtC,QAAI,CAAC,WAAW,SAAS,EAAG;AAC5B,QAAI,KAAK,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAAA,EAChC;AACA,SAAO;AACT;AAEA,eAAe,aAAa,MAA+B;AACzD,QAAM,MAAM,MAAM,SAAS,IAAI;AAC/B,SAAO,WAAW,QAAQ,EAAE,OAAO,GAAG,EAAE,OAAO,KAAK;AACtD;AASA,eAAe,WAAW,QAAgB,SAAoC;AAC5E,QAAM,MAAM,SAAS,EAAE,WAAW,KAAK,CAAC;AACxC,QAAM,UAAU,MAAM,QAAQ,QAAQ,EAAE,eAAe,KAAK,CAAC;AAC7D,QAAM,UAAoB,CAAC;AAC3B,aAAW,KAAK,SAAS;AACvB,UAAM,MAAM,KAAK,QAAQ,EAAE,IAAI;AAC/B,UAAM,OAAO,KAAK,SAAS,EAAE,IAAI;AACjC,QAAI,EAAE,YAAY,GAAG;AACnB,YAAM,eAAe,MAAM,WAAW,KAAK,IAAI;AAC/C,cAAQ,KAAK,GAAG,YAAY;AAC5B;AAAA,IACF;AACA,QAAI,CAAC,EAAE,OAAO,EAAG;AACjB,UAAM,SAAS,KAAK,IAAI;AACxB,YAAQ,KAAK,IAAI;AAAA,EACnB;AACA,SAAO;AACT;AAkCA,eAAsB,cAAc,MAA8C;AAChF,QAAM,SAAS,cAAc,KAAK,OAAO,KAAK,OAAO,KAAK,WAAW;AACrE,QAAM,UAAU,MAAM,kBAAkB,KAAK,UAAU;AACvD,QAAM,SAAS,KAAK,QAAQ,KAAK,KAAK,SAAS,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI;AACxE,QAAM,YAAY,SAAS,QAAQ,OAAO,CAAC,MAAM,OAAO,IAAI,EAAE,IAAI,CAAC,IAAI;AAEvE,MAAI,UAAU,WAAW,GAAG;AAC1B,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,MACZ,aAAa,OAAO;AAAA,MACpB,WAAW,CAAC;AAAA,MACZ,SAAS,CAAC;AAAA,MACV,QAAQ,SAAS,kCAAkC,CAAC,GAAG,MAAM,EAAE,KAAK,GAAG,CAAC,OAAO;AAAA,IACjF;AAAA,EACF;AAEA,QAAM,eAAe,KAAK,OAAO,MAAM,aAAa;AACpD,QAAM,WAAW,MAAM,aAAa,YAAY;AAEhD,MAAI,YAAY,CAAC,KAAK,OAAO;AAC3B,UAAM,QAAQ,MAAM,YAAY,UAAU,SAAS;AACnD,QAAI,MAAM,SAAS,GAAG;AACpB,aAAO;AAAA,QACL,OAAO,KAAK;AAAA,QACZ,OAAO,KAAK;AAAA,QACZ,aAAa,OAAO;AAAA,QACpB,WAAW,CAAC;AAAA,QACZ,SAAS,UAAU,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,QACpC,QAAQ,qBAAqB,MAAM,MAAM,cAAc,MAAM,KAAK,IAAI,CAAC;AAAA,QACvE,eAAe;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,MAAM,OAAO,MAAM,EAAE,WAAW,KAAK,CAAC;AAC5C,QAAM,YAAsB,CAAC;AAC7B,QAAM,eAAmD,CAAC;AAC1D,aAAW,SAAS,WAAW;AAC7B,UAAM,UAAU,KAAK,OAAO,MAAM,MAAM,IAAI;AAC5C,UAAM,WAAW,MAAM,KAAK,OAAO;AACnC,UAAM,YAAY,KAAK,MAAM,KAAK,UAAU;AAC5C,iBAAa,KAAK,EAAE,MAAM,MAAM,MAAM,QAAQ,MAAM,aAAa,SAAS,EAAE,CAAC;AAC7E,cAAU,KAAK,MAAM,IAAI;AAAA,EAC3B;AAEA,QAAM,WAA0B;AAAA,IAC9B,SAAS;AAAA,IACT,SAAS,KAAK;AAAA,IACd,OAAO,KAAK;AAAA,IACZ,OAAO,KAAK;AAAA,IACZ,eAAc,oBAAI,KAAK,GAAE,YAAY;AAAA,IACrC,QAAQ;AAAA,EACV;AACA,QAAM,UAAU,cAAc,KAAK,UAAU,UAAU,MAAM,CAAC,GAAG,OAAO;AAExE,SAAO;AAAA,IACL,OAAO,KAAK;AAAA,IACZ,OAAO,KAAK;AAAA,IACZ,aAAa,OAAO;AAAA,IACpB;AAAA,IACA,SAAS,CAAC;AAAA,IACV,eAAe;AAAA,EACjB;AACF;AAqBA,eAAsB,gBAAgB,MAAkD;AACtF,QAAM,SAAS,cAAc,KAAK,OAAO,KAAK,OAAO,KAAK,WAAW;AACrE,QAAM,eAAe,KAAK,OAAO,MAAM,aAAa;AACpD,QAAM,WAAW,MAAM,aAAa,YAAY;AAChD,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,MACZ,aAAa,OAAO;AAAA,MACpB,SAAS,CAAC;AAAA,MACV,kBAAkB;AAAA,MAClB,QAAQ;AAAA,IACV;AAAA,EACF;AACA,QAAM,UAAoB,CAAC;AAC3B,aAAW,SAAS,SAAS,QAAQ;AACnC,UAAM,MAAM,KAAK,OAAO,MAAM,MAAM,IAAI;AACxC,QAAI,WAAW,GAAG,GAAG;AACnB,YAAM,GAAG,KAAK,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAC9C,cAAQ,KAAK,MAAM,IAAI;AAAA,IACzB;AAAA,EACF;AACA,QAAM,GAAG,cAAc,EAAE,OAAO,KAAK,CAAC;AACtC,SAAO;AAAA,IACL,OAAO,KAAK;AAAA,IACZ,OAAO,KAAK;AAAA,IACZ,aAAa,OAAO;AAAA,IACpB;AAAA,IACA,kBAAkB;AAAA,EACpB;AACF;AAEA,eAAe,aAAa,MAA6C;AACvE,MAAI,CAAC,WAAW,IAAI,EAAG,QAAO;AAC9B,MAAI;AACF,UAAM,MAAM,MAAM,SAAS,MAAM,OAAO;AACxC,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,OAAO,QAAQ,YAAY,SAAU,QAAO;AAChD,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,YACb,UACA,WACmB;AACnB,QAAM,aAAuB,CAAC;AAC9B,QAAM,iBAAiB,IAAI,IAAI,SAAS,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAC7E,aAAW,SAAS,WAAW;AAC7B,UAAM,YAAY,MAAM,aAAa,KAAK,MAAM,KAAK,UAAU,CAAC;AAChE,UAAM,cAAc,eAAe,IAAI,MAAM,IAAI;AACjD,QAAI,gBAAgB,UAAa,gBAAgB,WAAW;AAC1D,iBAAW,KAAK,MAAM,IAAI;AAAA,IAC5B;AAAA,EACF;AACA,SAAO;AACT;AAEO,IAAM,uBAAoC,CAAC,UAAU,SAAS,WAAW,IAAI;;;ADvQpF,IAAM,WAAW,cAAc,YAAY,GAAG;AAC9C,IAAM,EAAE,QAAQ,IAAI,SAAS,oBAAoB;AAEjD,IAAM,WAAW;AAEjB,SAAS,UAAU,KAAa;AAC9B,QAAM,SAASC,MAAK,KAAK,gBAAgB,kBAAkB,qBAAqB,WAAW,gBAAgB;AAC3G,QAAM,SAASC,YAAW,MAAM,IAAI,SAASC,SAAQ,QAAQ,IAAI,GAAG,WAAW,gBAAgB;AAC/F,MAAI,CAACD,YAAW,MAAM,GAAG;AACvB,YAAQ,MAAM,2DAAsD;AACpE;AAAA,EACF;AACA,YAAU,QAAQ,UAAU,CAAC,MAAM,GAAG;AAAA,IACpC;AAAA,IACA,KAAK,EAAE,GAAG,QAAQ,KAAK,UAAU,IAAI;AAAA,IACrC,OAAO;AAAA,EACT,CAAC;AACH;AAEA,SAAS,aAAa,KAA4B;AAChD,QAAM,IAAID,MAAK,KAAK,gBAAgB,kBAAkB,qBAAqB,OAAO,mBAAmB;AACrG,SAAOC,YAAW,CAAC,IAAI,IAAI;AAC7B;AAEA,SAAS,YAAY,KAA4B;AAC/C,QAAM,MAAM,aAAa,GAAG;AAC5B,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,MAAM,SAAS,KAAK,GAAG;AAC7B,SAAO,IAAI,WAAW,IAAI,IAAI,MAAM,KAAK,GAAG;AAC9C;AAEA,SAAS,aAAa,MAAmB;AACvC,MAAI;AACF,UAAM,MAAM,aAAa,MAAM,MAAM;AACrC,WAAO,IAAI,KAAK,IAAI,KAAK,MAAM,GAAG,IAAI;AAAA,EACxC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMA,SAAS,UAAU,OAAqB;AACtC,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,MAAM,MAAM;AAClB,QAAM,OAAO,MAAM,QAAQ,MAAM,IAAI,IAAI,MAAM,OAAO,CAAC;AACvD,SAAO,QAAQ,SAAS,KAAK,KAAK,CAAC,MAAe,OAAO,MAAM,YAAY,EAAE,SAAS,QAAQ,CAAC;AACjG;AAYA,SAAS,iBAAiB,OAA2B;AACnD,QAAM,OAAO,MAAM,QAAQ,OAAO,IAAI,IAAI,MAAM,OAAO,CAAC;AACxD,QAAM,IAAI,KAAK,QAAQ,SAAS;AAChC,MAAI,MAAM,MAAM,IAAI,KAAK,KAAK,OAAQ,QAAO;AAC7C,SAAO,OAAO,KAAK,IAAI,CAAC,CAAC;AAC3B;AAEA,SAAS,kBAAkB,OAAsB;AAC/C,QAAM,OAAO,MAAM,QAAQ,OAAO,IAAI,IAAI,MAAM,OAAO,CAAC;AACxD,SAAO,KAAK,OAAO,CAAC,MAA4B,OAAO,MAAM,YAAY,EAAE,WAAW,IAAI,KAAK,MAAM,SAAS;AAChH;AAEA,IAAM,YAAuF;AAAA;AAAA,EAE3F,iBAAiB;AAAA,IACf,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,eAAe;AAAA,IACb,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,WAAW;AAAA,IACT,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,qBAAqB;AAAA,IACnB,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU,CAAC,IAAI;AAAA,EACjB;AAAA;AAAA,EAGA,aAAa;AAAA,IACX,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,WAAW;AAAA,IACT,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,iBAAiB;AAAA,IACf,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU,CAAC,mCAAmC;AAAA,EAChD;AAAA,EACA,oBAAoB;AAAA,IAClB,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,aAAa;AAAA,IACX,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EACA,YAAY;AAAA,IACV,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU,CAAC,gDAAgD;AAAA,EAC7D;AAAA;AAAA,EAGA,WAAW;AAAA,IACT,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU,CAAC,gCAAgC;AAAA,EAC7C;AAAA,EACA,cAAc;AAAA,IACZ,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU,CAAC,mCAAmC;AAAA,EAChD;AAAA,EACA,YAAY;AAAA,IACV,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU,CAAC,4DAA4D;AAAA,EACzE;AAAA,EACA,kBAAkB;AAAA,IAChB,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU,CAAC,IAAI;AAAA,EACjB;AAAA;AAAA,EAGA,WAAW;AAAA,IACT,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU,CAAC,IAAI;AAAA,EACjB;AAAA,EACA,SAAS;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,IACN,UAAU,CAAC,IAAI;AAAA,EACjB;AACF;AAEA,IAAM,kBAA4C;AAAA,EAChD,QAAQ,CAAC,mBAAmB,eAAe,gBAAgB,eAAe;AAAA,EAC1E,MAAM,CAAC,aAAa,uBAAuB,YAAY;AAAA,EACvD,OAAO,CAAC,eAAe,eAAe,eAAe,WAAW;AAAA,EAChE,UAAU,CAAC,mBAAmB,sBAAsB,eAAe,YAAY;AAAA,EAC/E,OAAO,CAAC,aAAa,gBAAgB,cAAc,kBAAkB;AAAA,EACrE,QAAQ,CAAC,aAAa,SAAS;AACjC;AAEA,SAAS,gBAAgB;AACvB,UAAQ,IAAI,wCAAmC;AAC/C,UAAQ,IAAI,sEAAsE;AAClF,UAAQ,IAAI,+EAA+E;AAE3F,aAAW,CAAC,UAAU,KAAK,KAAK,OAAO,QAAQ,eAAe,GAAG;AAC/D,YAAQ,IAAI,KAAK,QAAQ,GAAG;AAC5B,eAAW,QAAQ,OAAO;AACxB,YAAM,OAAO,UAAU,IAAI;AAC3B,cAAQ,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC,IAAI,KAAK,WAAW,EAAE;AAAA,IAC1D;AACA,YAAQ,IAAI;AAAA,EACd;AAEA,UAAQ,IAAI,uEAAuE;AACrF;AAEA,SAAS,gBAAgB,MAAc;AACrC,QAAM,OAAO,UAAU,IAAI;AAC3B,MAAI,CAAC,MAAM;AACT,YAAQ,MAAM,iBAAiB,IAAI,EAAE;AACrC,YAAQ,MAAM,6DAA6D;AAC3E,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,UAAQ,IAAI;AAAA,IAAO,IAAI,EAAE;AACzB,UAAQ,IAAI,KAAK,SAAI,OAAO,KAAK,MAAM,CAAC,EAAE;AAC1C,UAAQ,IAAI,KAAK,KAAK,WAAW;AAAA,CAAI;AACrC,UAAQ,IAAI,cAAc;AAC1B,UAAQ,IAAI,OAAO,KAAK,IAAI;AAAA,CAAI;AAChC,UAAQ,IAAI,aAAa;AACzB,aAAW,MAAM,KAAK,UAAU;AAC9B,YAAQ,IAAI,OAAO,EAAE,EAAE;AAAA,EACzB;AACA,UAAQ,IAAI;AACd;AAEA,QACG,KAAK,iBAAiB,EACtB;AAAA,EACC;AAOF,EACC,QAAQ,OAAO;AAElB,QACG,QAAQ,gBAAgB,EACxB,YAAY,0EAA0E,EACtF,eAAe,kBAAkB,kCAAkC,EACnE,OAAO,eAAe,eAAe,CAAC,MAAM,SAAS,GAAG,EAAE,GAAG,CAAC,EAC9D,OAAO,eAAe,qEAAgE,EACtF,OAAO,UAAU,2BAA2B,IAAI,EAChD,OAAO,OAAO,OAAe,SAAS;AACrC,QAAM,EAAE,UAAU,IAAI,MAAM,OAAO,uBAAa;AAChD,MAAI;AACF,UAAM,OAAO,MAAM,UAAU;AAAA,MAC3B,OAAO,KAAK;AAAA,MACZ;AAAA,MACA,OAAO,KAAK;AAAA,MACZ,UAAU,KAAK;AAAA,IACjB,CAAC;AACD,YAAQ,OAAO,MAAM,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,IAAI;AACzD,YAAQ,KAAK,CAAC;AAAA,EAChB,SAAS,KAAU;AACjB,YAAQ,MAAM,kBAAkB,IAAI,OAAO,EAAE;AAC7C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAEH,QACG,QAAQ,MAAM,EACd,YAAY,0FAA0F,EACtG,eAAe,kBAAkB,kCAAkC,EACnE,OAAO,iBAAiB,0EAA0E,EAClG,OAAO,UAAU,gDAAgD,EACjE,OAAO,YAAY,uEAAuE,EAC1F,OAAO,OAAO,SAAS;AACtB,QAAM,EAAE,WAAW,iBAAiB,IAAI,MAAM,OAAO,qBAAiB;AACtE,QAAM,SAAS,MAAM,UAAUE,SAAQ,KAAK,KAAK,CAAC;AAIlD,MAAI,KAAK,MAAM;AACb,UAAM,MAAM,KAAK,OAAO,OAAO,OAAO,KAAK,IAAkC,IAAI;AACjF,YAAQ,IAAI,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AAAA,EAC1C,OAAO;AACL,YAAQ,IAAI,iBAAiB,QAAQ,EAAE,MAAM,KAAK,KAAK,CAAC,CAAC;AAAA,EAC3D;AACA,QAAM,MAAM,KAAK,SAAS,OAAO,OAAO,SAAS,OAAO,OAAO,WAAW,OAAO,OAAO;AACxF,UAAQ,WAAW,MAAM,IAAI,IAAI;AACnC,CAAC;AAEH,QACG,QAAQ,WAAW,EACnB,YAAY,oIAA+H,EAC3I,eAAe,kBAAkB,kCAAkC,EACnE,eAAe,iBAAiB,6DAA6D,EAC7F,eAAe,oBAAoB,wBAAwB,EAC3D,OAAO,oBAAoB,mCAAmC,EAC9D,OAAO,OAAO,SAAS;AACtB,QAAM,EAAE,SAAS,IAAI,MAAM,OAAO,oBAAgB;AAClD,MAAI;AACJ,MAAI,KAAK,SAAS;AAChB,QAAI;AACF,gBAAU,KAAK,MAAM,KAAK,OAAO;AAAA,IACnC,SAAS,GAAQ;AACf,cAAQ,MAAM,2BAA2B,EAAE,OAAO,EAAE;AACpD,cAAQ,WAAW;AACnB;AAAA,IACF;AAAA,EACF;AACA,MAAI;AACF,UAAM,QAAQ,MAAM,SAASA,SAAQ,KAAK,KAAK,GAAG;AAAA,MAChD,MAAM,KAAK;AAAA,MACX,SAAS,KAAK;AAAA,MACd;AAAA,IACF,CAAC;AACD,YAAQ,IAAI,KAAK,UAAU,KAAK,CAAC;AAAA,EACnC,SAAS,GAAQ;AACf,YAAQ,MAAM,qBAAqB,EAAE,OAAO,EAAE;AAC9C,YAAQ,WAAW;AAAA,EACrB;AACF,CAAC;AAEH,QACG,QAAQ,WAAW,EACnB,YAAY,mFAA8E,EAC1F,eAAe,kBAAkB,kCAAkC,EACnE,OAAO,iBAAiB,8DAA8D,EACtF,OAAO,iBAAiB,+CAA0C,EAClE,OAAO,kBAAkB,gDAA2C,EACpE,OAAO,eAAe,6BAA6B,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC,EACzE,OAAO,OAAO,SAAS;AACtB,QAAM,EAAE,SAAS,IAAI,MAAM,OAAO,oBAAgB;AAClD,MAAI;AACF,UAAM,UAAU,MAAM,SAASA,SAAQ,KAAK,KAAK,GAAG;AAAA,MAClD,MAAM,KAAK;AAAA,MACX,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,OAAO,KAAK;AAAA,IACd,CAAC;AACD,YAAQ,IAAI,KAAK,UAAU,OAAO,CAAC;AAAA,EACrC,SAAS,GAAQ;AACf,YAAQ,MAAM,qBAAqB,EAAE,OAAO,EAAE;AAC9C,YAAQ,WAAW;AAAA,EACrB;AACF,CAAC;AAEH,QACG,QAAQ,gBAAgB,EACxB,YAAY,sEAAsE,EAClF,eAAe,kBAAkB,kCAAkC,EACnE,OAAO,WAAW,gCAAgC,EAClD,OAAO,OAAO,SAAS;AACtB,QAAM,EAAE,qBAAqB,IAAI,MAAM,OAAO,uBAAmB;AACjE,QAAM,IAAI,MAAM,qBAAqBA,SAAQ,KAAK,KAAK,GAAG,KAAK,KAAK;AACpE,UAAQ,IAAI,EAAE,UAAU,6BAA6B,EAAE,IAAI,KAAK,0BAA0B,EAAE,IAAI,6BAA6B;AAC7H,UAAQ,KAAK,CAAC;AAChB,CAAC;AAEH,QACG,QAAQ,cAAc,EACtB,YAAY,yDAAyD,EACrE,OAAO,CAAC,SAAkB;AACzB,MAAI,MAAM;AACR,oBAAgB,IAAI;AAAA,EACtB,OAAO;AACL,kBAAc;AAAA,EAChB;AACA,UAAQ,KAAK,CAAC;AAChB,CAAC;AAEH,QACG,QAAQ,SAAS,EAAE,WAAW,KAAK,CAAC,EACpC,YAAY,wCAAwC,EACpD,eAAe,kBAAkB,kCAAkC,EACnE,OAAO,aAAa,6BAA6B,EACjD,OAAO,WAAW,gCAAgC,EAClD,OAAO,oBAAoB,yIAAyI,EACpK,OAAO,eAAe,8KAAyK,EAC/L,OAAO,kBAAkB,iHAAiH,EAC1I,OAAO,iBAAiB,mDAAmD,QAAQ,EACnF,OAAO,oBAAoB,4CAA4C,QAAQ,EAC/E,OAAO,kBAAkB,iFAAiF,EAC1G,OAAO,cAAc,sBAAsB,EAC3C,OAAO,OAAO,SAAS;AACtB,QAAM,YAAYA,SAAQ,KAAK,KAAK;AAEpC,MAAI,CAACC,YAAW,SAAS,GAAG;AAC1B,YAAQ,MAAM,qCAAqC,SAAS,EAAE;AAC9D,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,KAAK,OAAO;AACd,UAAM,EAAE,QAAQ,IAAI,MAAM,OAAO,wBAAoB;AACrD,UAAM,UAAU,IAAI,QAAQ,SAAS;AACrC,UAAM,OAAO,MAAM,QAAQ,SAAS;AACpC,YAAQ,IAAI,UAAU,KAAK,MAAM,EAAE;AACnC,YAAQ,IAAI,WAAW,KAAK,OAAO,CAAC,GAAW,MAAW,IAAI,EAAE,OAAO,QAAQ,CAAC,CAAC,EAAE;AACnF,YAAQ,IAAI,cAAc,KAAK,OAAO,CAAC,GAAW,MAAW,IAAI,EAAE,UAAU,QAAQ,CAAC,CAAC,EAAE;AACzF,YAAQ,IAAI,SAAS,IAAI,IAAI,KAAK,QAAQ,CAAC,MAAW,EAAE,IAAI,CAAC,EAAE,IAAI,SAAS;AAC5E,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,MAAI,KAAK,SAAS;AAChB,UAAM,EAAE,aAAa,IAAI,MAAM,OAAO,kBAAkB;AACxD,UAAM,aAAa,WAAW;AAAA,MAC5B,OAAO;AAAA,MACP,cAAc;AAAA,MACd,OAAO,KAAK;AAAA,MACZ,SAAS,KAAK;AAAA,MACd,WAAW,KAAK;AAAA,MAChB,WAAW,KAAK;AAAA,MAChB,YAAY,CAAC,UAAU,UAAU;AAC/B,gBAAQ,OAAO,MAAM,eAAe,QAAQ,IAAI,KAAK,YAAY;AAAA,MACnE;AAAA,IACF,CAAC;AACD,YAAQ,OAAO,MAAM,IAAI;AACzB,YAAQ,IAAI,mBAAmB;AAC/B,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,EAAE,YAAY,IAAI,MAAM,OAAO,kBAAkB;AACvD,QAAM,YAAY,WAAW;AAAA,IAC3B,OAAO,KAAK;AAAA,IACZ,cAAc,KAAK;AAAA,IACnB,OAAO,KAAK;AAAA,IACZ,SAAS,KAAK;AAAA,IACd,WAAW,KAAK;AAAA,IAChB,WAAW,KAAK;AAAA,IAChB,UAAU,KAAK;AAAA,EACjB,CAAC;AACH,CAAC;AAEH,uBAAuB,SAAS;AAAA,EAC9B,aAAa;AAAA,EACb,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,eAAe,CAAC,QAAQ,UAAU,GAAG;AACvC,CAAC;AAED,QACG,QAAQ,kBAAkB,EAC1B;AAAA,EACC;AACF,EACC,OAAO,aAAa,4CAA4C,EAChE,OAAO,CAAC,SAA+B;AACtC,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,UAAUC,MAAK,KAAK,WAAW;AACrC,MAAI,CAACD,YAAW,OAAO,GAAG;AACxB,YAAQ,IAAI,wDAAmD;AAC/D,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,OAAO,aAAa,OAAO;AACjC,MAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,CAAC,KAAK,cAAc,OAAO,KAAK,eAAe,UAAU;AAChG,YAAQ,MAAM,mBAAmB,OAAO,EAAE;AAC1C,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,MAAM,YAAY,GAAG;AAC3B,MAAI,CAAC,KAAK;AACR,YAAQ;AAAA,MACN;AAAA;AAAA,IAEF;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,YAAsB,CAAC;AAC7B,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAa,KAAK,UAAU,GAAG;AAC/D,QAAI,CAAC,UAAU,KAAK,EAAG;AACvB,UAAM,QAAQ,iBAAiB,KAAK,KAAK;AACzC,UAAM,QAAQ,kBAAkB,KAAK;AACrC,SAAK,WAAW,GAAG,IAAI;AAAA,MACrB,MAAM;AAAA,MACN,SAAS;AAAA,MACT,MAAM,CAAC,KAAK,WAAW,OAAO,GAAG,KAAK;AAAA,IACxC;AACA,cAAU,KAAK,GAAG;AAAA,EACpB;AACA,MAAI,UAAU,WAAW,GAAG;AAC1B,YAAQ,IAAI,2EAAsE;AAClF,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,UAAQ,IAAI,aAAa,UAAU,MAAM,QAAQ,UAAU,WAAW,IAAI,MAAM,KAAK,KAAK,UAAU,KAAK,IAAI,CAAC,EAAE;AAChH,MAAI,KAAK,QAAQ;AACf,YAAQ,IAAI,yBAAyB;AACrC,YAAQ,IAAI,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AACzC,YAAQ,IAAI,mCAAmC;AAC/C,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,UAAUC,MAAK,QAAQ,OAAO,GAAG,eAAe;AACtD,MAAI;AACF,kBAAc,SAAS,aAAa,SAAS,MAAM,CAAC;AACpD,YAAQ,IAAI,mBAAmB,OAAO,EAAE;AAAA,EAC1C,SAAS,KAAU;AACjB,YAAQ,MAAM,2BAA2B,IAAI,OAAO,EAAE;AACtD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,gBAAc,SAAS,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,IAAI;AAI3D,QAAM,SAAS,UAAU,QAAQ,CAAC,KAAK,WAAW,GAAG,EAAE,KAAK,OAAO,QAAQ,SAAS,KAAO,CAAC;AAC5F,MAAI,OAAO,WAAW,GAAG;AACvB,YAAQ,MAAM,6BAA6B,OAAO,MAAM;AAAA,EAAO,OAAO,QAAQ,SAAS,KAAK,EAAE,EAAE;AAChG,YAAQ,MAAM,qBAAqB,OAAO,EAAE;AAC5C,kBAAc,SAAS,aAAa,SAAS,MAAM,CAAC;AACpD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,UAAQ,IAAI,iFAA4E;AACxF,UAAQ,KAAK,CAAC;AAChB,CAAC;AAEH,QACG,QAAQ,aAAa,EACrB;AAAA,EACC;AACF,EACC,OAAO,UAAU,oGAAoG,KAAK,EAC1H,OAAO,UAAU,+DAA+D,KAAK,EACrF,OAAO,OAAO,SAAS;AACtB,QAAM,MAAM,QAAQ,IAAI;AACxB,QAAM,MAAM,aAAa,GAAG;AAC5B,MAAI,CAAC,KAAK;AACR,YAAQ,MAAM,2FAA2F;AACzG,YAAQ,MAAM,uEAAuE;AACrF,YAAQ,KAAK,CAAC;AAAA,EAChB;AAGA,QAAM,UAAUA,MAAK,KAAK,WAAW;AACrC,MAAID,YAAW,OAAO,GAAG;AACvB,UAAM,OAAO,aAAa,OAAO;AACjC,UAAM,UAAU,MAAM,cAAc,OAAO,KAAK,eAAe,WAAW,OAAO,QAAa,KAAK,UAAU,IAAI,CAAC;AAClH,UAAM,UAAU,QAAQ,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AACtE,QAAI,QAAQ,SAAS,GAAG;AACtB,cAAQ;AAAA,QACN,kEAAwD,QAAQ,KAAK,IAAI,CAAC;AAAA,MAC5E;AACA,cAAQ,KAAK,gCAAgC;AAC7C,cAAQ,KAAK,iEAAiE;AAAA,IAChF;AAAA,EACF;AAGA,QAAM,IAAI,UAAU,QAAQ,CAAC,KAAK,WAAW,GAAG,EAAE,KAAK,OAAO,QAAQ,SAAS,KAAO,CAAC;AACvF,MAAI,EAAE,WAAW,GAAG;AAClB,YAAQ,IAAI,yCAAoC,EAAE,QAAQ,SAAS,EAAE,KAAK,CAAC,GAAG;AAC9E,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,QAAM,SAAS,EAAE,QAAQ,SAAS,KAAK;AAKvC,MAAI,OAAO,SAAS,sBAAsB,GAAG;AAC3C,UAAM,QAAQ,OAAO,MAAM,mCAAmC;AAC9D,QAAI,OAAO;AACT,YAAM,MAAM,MAAM,CAAC;AACnB,cAAQ,KAAK,gCAAgC,GAAG,kCAA6B;AAC7E,UAAI;AAAE,eAAO,KAAK,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,MAAG,QAAQ;AAAA,MAAC;AAC9D,YAAM,KAAK,UAAU,QAAQ,CAAC,KAAK,WAAW,GAAG,EAAE,KAAK,OAAO,QAAQ,SAAS,KAAO,CAAC;AACxF,UAAI,GAAG,WAAW,GAAG;AACnB,gBAAQ,IAAI,2CAAsC,GAAG,QAAQ,SAAS,EAAE,KAAK,CAAC,GAAG;AACjF,gBAAQ,KAAK,CAAC;AAAA,MAChB;AACA,cAAQ,MAAM;AAAA,EAAwB,GAAG,QAAQ,SAAS,KAAK,EAAE,EAAE;AAAA,IACrE,OAAO;AACL,cAAQ,MAAM,8EAA8E;AAAA,IAC9F;AAAA,EACF;AAEA,MAAI,OAAQ,SAAQ,MAAM,MAAM;AAChC,MAAI,EAAE,WAAW,GAAG;AAClB,YAAQ,MAAM,8BAA8B,EAAE,MAAM,GAAG;AACvD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACF,CAAC;AAKH,IAAM,oCAAoC,OAAO,SAA6C;AAC5F,MAAI;AACF,UAAM,EAAE,gBAAgB,kBAAkB,IAAI,MAAM,OAAO,4BAAwB;AACnF,UAAM,cAAc,QAAQ,IAAI;AAEhC,UAAM,iBAAiBC,MAAK,aAAa,WAAW,QAAQ;AAC5D,UAAM,YAAYD,YAAW,cAAc,IAAI,iBAAiB;AAChE,UAAM,SAAS,MAAM,eAAe;AAAA,MAClC;AAAA,MACA;AAAA,MACA,MAAM,KAAK,OAAO,SAAS;AAAA,MAC3B,OAAO;AAAA,IACT,CAAC;AACD,QAAI,KAAK,MAAM;AACb,cAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAC3C;AAAA,IACF;AACA,UAAM,SAAS,kBAAkB,MAAM;AACvC,QAAI,QAAQ;AACV,cAAQ,IAAI,EAAE;AACd,cAAQ,IAAI,MAAM;AAAA,IACpB,OAAO;AACL,cAAQ,IAAI,EAAE;AACd,cAAQ,IAAI,6BAAwB,OAAO,SAAS,MAAM,kBAAkB,OAAO,WAAW,KAAK;AAAA,IACrG;AAAA,EACF,SAAS,KAAU;AACjB,YAAQ,MAAM,sBAAsB,KAAK,WAAW,GAAG,EAAE;AAAA,EAC3D;AACF;AAIA,IAAM,iBAAiB,QAAQ,SAAS,KAAK,CAAC,MAAM,EAAE,KAAK,MAAM,aAAa;AAC9E,IAAI,gBAAgB;AAClB,iBAAe,KAAK,cAAc,OAAO,YAAY;AACnD,UAAM,OAAO,QAAQ,KAAK;AAC1B,UAAM,kCAAkC,EAAE,MAAM,CAAC,CAAC,KAAK,MAAM,MAAM,CAAC,CAAC,KAAK,KAAK,CAAC;AAAA,EAClF,CAAC;AACH;AAIA,SAAS,WAAW,OAA0B;AAC5C,QAAM,IAAI,MAAM,YAAY;AAC5B,MAAI,CAAC,qBAAqB,SAAS,CAAc,GAAG;AAClD,YAAQ,MAAM,kBAAkB,KAAK,gBAAgB,qBAAqB,KAAK,IAAI,CAAC,GAAG;AACvF,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO;AACT;AAEA,SAAS,WAAW,OAAsB;AACxC,MAAI,UAAU,YAAY,UAAU,SAAS;AAC3C,YAAQ,MAAM,kBAAkB,KAAK,4BAA4B;AACjE,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO;AACT;AAEA,SAAS,iBAAyB;AAEhC,aAAW,OAAO,CAAC,mBAAmB,mBAAmB,GAAG;AAC1D,UAAM,YAAYC,MAAK,QAAQ,IAAI,GAAG,gBAAgB,kBAAkB,GAAG;AAC3E,QAAID,YAAW,SAAS,EAAG,QAAO;AAAA,EACpC;AAEA,QAAM,MAAMD,SAAQ,IAAI,IAAI,UAAU,YAAY,GAAG,EAAE,QAAQ;AAC/D,SAAO;AACT;AAEA,IAAM,YAAY,QAAQ,QAAQ,QAAQ,EAAE,YAAY,mJAAmJ;AAE3M,UACG,QAAQ,SAAS,EACjB,YAAY,wEAAwE,EACpF,OAAO,qBAAqB,kDAAkD,MAAgB,EAC9F,OAAO,mBAAmB,oCAAoC,OAAO,EACrE,OAAO,oBAAoB,qDAAqD,QAAQ,IAAI,CAAC,EAC7F,OAAO,CAAC,SAAS;AAChB,QAAM,QAAQ,WAAW,KAAK,KAAK;AACnC,QAAM,UAAuB,KAAK,SAAS,KAAK,MAAM,SAAS,IAAI,KAAK,QAAQ,sBAAsB,IAAI,UAAU;AACpH,QAAM,MAAM,OAAO,IAAI,CAAC,MAAM,cAAc,GAAG,OAAO,KAAK,OAAO,CAAC;AACnE,UAAQ,IAAI,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AAC1C,CAAC;AAEH,UACG,QAAQ,SAAS,EACjB,YAAY,0GAA0G,EACtH,eAAe,kBAAkB,4CAA4C,EAC7E,OAAO,mBAAmB,oCAAoC,OAAO,EACrE,OAAO,oBAAoB,qDAAqD,QAAQ,IAAI,CAAC,EAC7F,OAAO,qBAAqB,yDAAyD,EACrF,OAAO,WAAW,oEAAoE,KAAK,EAC3F,OAAO,OAAO,SAAS;AACtB,QAAM,QAAQ,WAAW,KAAK,KAAK;AACnC,QAAM,QAAQ,WAAW,KAAK,KAAK;AACnC,MAAI,UAAU,UAAU;AACtB,YAAQ;AAAA,MACN;AAAA,IAKF;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,aAAa,eAAe;AAClC,QAAM,SAAS,MAAM,cAAc;AAAA,IACjC;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa,KAAK;AAAA,IAClB;AAAA,IACA,MAAM,KAAK;AAAA,IACX,OAAO,KAAK,UAAU;AAAA,EACxB,CAAC;AACD,UAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAC3C,MAAI,OAAO,UAAU,WAAW,KAAK,OAAO,OAAQ,SAAQ,KAAK,CAAC;AACpE,CAAC;AAEH,UACG,QAAQ,WAAW,EACnB,YAAY,4HAA4H,EACxI,eAAe,kBAAkB,4CAA4C,EAC7E,OAAO,mBAAmB,oCAAoC,OAAO,EACrE,OAAO,oBAAoB,qDAAqD,QAAQ,IAAI,CAAC,EAC7F,OAAO,OAAO,SAAS;AACtB,QAAM,QAAQ,WAAW,KAAK,KAAK;AACnC,QAAM,QAAQ,WAAW,KAAK,KAAK;AACnC,MAAI,UAAU,UAAU;AACtB,YAAQ,MAAM,qGAAqG;AACnH,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,SAAS,MAAM,gBAAgB,EAAE,OAAO,OAAO,aAAa,KAAK,QAAQ,CAAC;AAChF,UAAQ,IAAI,KAAK,UAAU,QAAQ,MAAM,CAAC,CAAC;AAC7C,CAAC;AAEH,UACG,QAAQ,MAAM,EACd,YAAY,0DAA0D,EACtE,OAAO,YAAY;AAClB,QAAM,aAAa,eAAe;AAClC,QAAM,UAAU,MAAM,kBAAkB,UAAU;AAClD,UAAQ,IAAI,KAAK,UAAU,QAAQ,IAAI,CAAC,MAAM,EAAE,IAAI,GAAG,MAAM,CAAC,CAAC;AACjE,CAAC;AAEH,QAAQ,MAAM;","names":["resolve","join","existsSync","join","existsSync","resolve","resolve","existsSync","join"]}
|
package/dist/core/index.d.ts
CHANGED
|
@@ -249,11 +249,11 @@ interface VaultSchema {
|
|
|
249
249
|
};
|
|
250
250
|
};
|
|
251
251
|
}
|
|
252
|
-
type Severity = "warn" | "error";
|
|
252
|
+
type Severity$1 = "warn" | "error";
|
|
253
253
|
interface LintFinding {
|
|
254
254
|
path: string;
|
|
255
255
|
rule: "missing_provenance" | "stale" | "schema_violations" | "broken_links";
|
|
256
|
-
severity: Severity;
|
|
256
|
+
severity: Severity$1;
|
|
257
257
|
message: string;
|
|
258
258
|
}
|
|
259
259
|
declare function loadSchema(vaultPath: string): Promise<VaultSchema>;
|
|
@@ -444,11 +444,28 @@ interface SynthesizeNoteInput {
|
|
|
444
444
|
decided_on?: string;
|
|
445
445
|
severity?: string;
|
|
446
446
|
extra_frontmatter?: Record<string, unknown>;
|
|
447
|
+
/**
|
|
448
|
+
* When true, the resulting note is filed under `proposals/<date>-<slug>.md` with
|
|
449
|
+
* `status: proposal` frontmatter, regardless of `suggested_path`. The original path
|
|
450
|
+
* is preserved as `proposed_target` in frontmatter so `synthesize_promote` knows
|
|
451
|
+
* where to move it on acceptance.
|
|
452
|
+
*/
|
|
453
|
+
proposal?: boolean;
|
|
454
|
+
/**
|
|
455
|
+
* When provided alongside `proposal: true`, used as the proposal subdirectory name.
|
|
456
|
+
* Defaults to "proposals". Useful for callers that want to segregate by source
|
|
457
|
+
* (e.g. "proposals/research", "proposals/outage").
|
|
458
|
+
*/
|
|
459
|
+
proposal_subdir?: string;
|
|
447
460
|
}
|
|
448
461
|
interface SynthesizePreview {
|
|
449
462
|
changeset: ChangeSet;
|
|
450
463
|
path: string;
|
|
451
464
|
title: string;
|
|
465
|
+
/** True when the preview is a proposal — caller (or `synthesize_promote`) must move it later. */
|
|
466
|
+
is_proposal?: boolean;
|
|
467
|
+
/** When `is_proposal` is true, the canonical path that `synthesize_promote` should move it to. */
|
|
468
|
+
proposed_target?: string;
|
|
452
469
|
}
|
|
453
470
|
/**
|
|
454
471
|
* Convert a query answer + provenance into a ChangeSet that can be fed to applyPatch.
|
|
@@ -456,8 +473,48 @@ interface SynthesizePreview {
|
|
|
456
473
|
* any related_notes that appear as bare titles in the body.
|
|
457
474
|
*
|
|
458
475
|
* Does NOT write to disk — always returns a ChangeSet. Callers pass it to applyPatch.
|
|
476
|
+
*
|
|
477
|
+
* Proposal mode: when `proposal: true`, the path is rewritten to
|
|
478
|
+
* `<proposal_subdir>/<YYYY-MM-DD>-<slug>.md`, the `status` is forced to `proposal`,
|
|
479
|
+
* and `proposed_target` records the original suggested path. `synthesize_promote`
|
|
480
|
+
* later moves the file to that target and clears the proposal frontmatter.
|
|
459
481
|
*/
|
|
460
482
|
declare function buildSynthesizeChangeSet(input: SynthesizeNoteInput): SynthesizePreview;
|
|
483
|
+
interface PromoteInput {
|
|
484
|
+
/**
|
|
485
|
+
* Path to the proposal note (relative to vault root). Must have `status: proposal` frontmatter
|
|
486
|
+
* AND `proposed_target` frontmatter, both written by `buildSynthesizeChangeSet` in proposal mode.
|
|
487
|
+
*/
|
|
488
|
+
proposal_path: string;
|
|
489
|
+
/**
|
|
490
|
+
* Optional override for the destination path. When omitted, the proposal's own
|
|
491
|
+
* `proposed_target` frontmatter is used.
|
|
492
|
+
*/
|
|
493
|
+
target_path?: string;
|
|
494
|
+
}
|
|
495
|
+
interface PromotePreview {
|
|
496
|
+
changeset: ChangeSet;
|
|
497
|
+
from: string;
|
|
498
|
+
to: string;
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Promote a reviewed proposal to its canonical destination.
|
|
502
|
+
*
|
|
503
|
+
* Reads the proposal's existing content + frontmatter, strips `status: proposal` and
|
|
504
|
+
* `proposed_target` keys, restores the original status (default "active"), and returns
|
|
505
|
+
* a ChangeSet that:
|
|
506
|
+
* - creates the canonical path with the cleaned frontmatter + body
|
|
507
|
+
* - deletes the proposal path
|
|
508
|
+
*
|
|
509
|
+
* The caller (the MCP tool) reads the proposal file, runs this builder, and applies the
|
|
510
|
+
* resulting changeset via applyPatch — preserving atomicity and rollback semantics.
|
|
511
|
+
*/
|
|
512
|
+
declare function buildPromoteChangeSet(input: {
|
|
513
|
+
proposal_path: string;
|
|
514
|
+
target_path?: string;
|
|
515
|
+
body: string;
|
|
516
|
+
frontmatter: Record<string, unknown>;
|
|
517
|
+
}): PromotePreview;
|
|
461
518
|
|
|
462
519
|
interface LintReport {
|
|
463
520
|
schemaPath: string;
|
|
@@ -483,4 +540,220 @@ declare function formatLintReport(report: LintReport, opts?: {
|
|
|
483
540
|
rule?: keyof LintReport["byRule"];
|
|
484
541
|
}): string;
|
|
485
542
|
|
|
486
|
-
|
|
543
|
+
interface ToolSummary {
|
|
544
|
+
name: string;
|
|
545
|
+
description: string;
|
|
546
|
+
deprecated?: boolean;
|
|
547
|
+
}
|
|
548
|
+
interface ModeSummary {
|
|
549
|
+
name: string;
|
|
550
|
+
description: string;
|
|
551
|
+
isDefault?: boolean;
|
|
552
|
+
}
|
|
553
|
+
interface RegenerateContractOptions {
|
|
554
|
+
projectRoot: string;
|
|
555
|
+
pluginVersion: string;
|
|
556
|
+
tools: ToolSummary[];
|
|
557
|
+
modes?: ModeSummary[];
|
|
558
|
+
/** When true, overwrite hand-edited managed blocks. Default false → fails loudly on detected hand-edits. */
|
|
559
|
+
force?: boolean;
|
|
560
|
+
/** Override "now" — used by tests for deterministic timestamps. */
|
|
561
|
+
nowIso?: string;
|
|
562
|
+
}
|
|
563
|
+
interface RegenerateContractResult {
|
|
564
|
+
path: string;
|
|
565
|
+
written: boolean;
|
|
566
|
+
reason?: string;
|
|
567
|
+
hand_edit_detected?: boolean;
|
|
568
|
+
preserved_local_notes_chars?: number;
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Generate or refresh AGENTS.md at the project root.
|
|
572
|
+
*
|
|
573
|
+
* Behavior:
|
|
574
|
+
* - If AGENTS.md is absent, write the full contract + an empty Local Notes section.
|
|
575
|
+
* - If AGENTS.md exists and contains the managed block markers:
|
|
576
|
+
* * Regenerate the content INSIDE the markers from the current tool/mode inventory.
|
|
577
|
+
* * Preserve everything OUTSIDE the markers (Local Notes tail, custom sections, frontmatter the
|
|
578
|
+
* user added).
|
|
579
|
+
* * If `force` is false and the inside-block content differs from a freshly-generated block AND
|
|
580
|
+
* the difference is not just a regenerable timestamp/version, fail with hand_edit_detected.
|
|
581
|
+
* - If AGENTS.md exists without managed-block markers, refuse and report — the user has a custom
|
|
582
|
+
* AGENTS.md and we should not silently take it over.
|
|
583
|
+
*/
|
|
584
|
+
declare function regenerateAgentsContract(opts: RegenerateContractOptions): Promise<RegenerateContractResult>;
|
|
585
|
+
/**
|
|
586
|
+
* Inspect AGENTS.md without modifying it. Returns whether the file exists, whether it has managed
|
|
587
|
+
* markers, and how many characters of Local Notes tail are preserved.
|
|
588
|
+
*/
|
|
589
|
+
declare function inspectAgentsContract(projectRoot: string): Promise<{
|
|
590
|
+
path: string;
|
|
591
|
+
exists: boolean;
|
|
592
|
+
has_managed_block: boolean;
|
|
593
|
+
local_notes_chars: number;
|
|
594
|
+
}>;
|
|
595
|
+
|
|
596
|
+
interface VerificationRecord {
|
|
597
|
+
cmd: string;
|
|
598
|
+
exit: number | null;
|
|
599
|
+
signal: string | null;
|
|
600
|
+
duration_ms: number;
|
|
601
|
+
tail: string;
|
|
602
|
+
at: string;
|
|
603
|
+
}
|
|
604
|
+
interface SessionState {
|
|
605
|
+
id: string;
|
|
606
|
+
task: string;
|
|
607
|
+
started_at: string;
|
|
608
|
+
last_activity_at: string;
|
|
609
|
+
verifications: VerificationRecord[];
|
|
610
|
+
notes_touched: string[];
|
|
611
|
+
closed_at?: string;
|
|
612
|
+
closed_summary?: string;
|
|
613
|
+
closed_verified_waived?: boolean;
|
|
614
|
+
closed_waiver_reason?: string;
|
|
615
|
+
}
|
|
616
|
+
type SessionStatus = {
|
|
617
|
+
state: "no_session";
|
|
618
|
+
} | (SessionState & {
|
|
619
|
+
state: "active" | "stale";
|
|
620
|
+
});
|
|
621
|
+
interface SessionStartOptions {
|
|
622
|
+
/** When true and a session for the same task is already open, return the existing id rather than failing. Defaults to true. */
|
|
623
|
+
reuseSameTask?: boolean;
|
|
624
|
+
}
|
|
625
|
+
interface SessionFinishInput {
|
|
626
|
+
summary: string;
|
|
627
|
+
/**
|
|
628
|
+
* When false, the caller is explicitly waiving verification (e.g. for doc-only edits).
|
|
629
|
+
* Requires a non-empty `reason`. When true (default) and no verifications have been
|
|
630
|
+
* recorded, the call is refused.
|
|
631
|
+
*/
|
|
632
|
+
verified?: boolean;
|
|
633
|
+
reason?: string;
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* SessionManager owns a single session.json file at `<sessionDir>/session.json`.
|
|
637
|
+
*
|
|
638
|
+
* State is durable across MCP server restarts (the file persists). At most one session
|
|
639
|
+
* is active per project at a time — concurrent sessions are explicitly out of scope
|
|
640
|
+
* for v1.1; brain has the same constraint.
|
|
641
|
+
*
|
|
642
|
+
* Hard gates:
|
|
643
|
+
* - session_finish refuses without verifications unless verified=false + reason
|
|
644
|
+
* - session_run refuses without an open session
|
|
645
|
+
* - session_start refuses if another session is open with a different task
|
|
646
|
+
*
|
|
647
|
+
* Stale detection: a session whose last_activity_at is >24h old is reported as
|
|
648
|
+
* state:"stale" by status(). Stale sessions can still be finished or extended; the
|
|
649
|
+
* label is informational so callers can decide whether to abandon (rm + start new) or
|
|
650
|
+
* resume.
|
|
651
|
+
*/
|
|
652
|
+
declare class SessionManager {
|
|
653
|
+
private sessionDir;
|
|
654
|
+
constructor(sessionDir: string);
|
|
655
|
+
get sessionPath(): string;
|
|
656
|
+
start(task: string, opts?: SessionStartOptions): Promise<{
|
|
657
|
+
ok: true;
|
|
658
|
+
id: string;
|
|
659
|
+
reused?: boolean;
|
|
660
|
+
} | {
|
|
661
|
+
ok: false;
|
|
662
|
+
error: string;
|
|
663
|
+
}>;
|
|
664
|
+
status(): Promise<SessionStatus>;
|
|
665
|
+
run(cmd: string, timeoutMs?: number): Promise<{
|
|
666
|
+
ok: true;
|
|
667
|
+
record: VerificationRecord;
|
|
668
|
+
} | {
|
|
669
|
+
ok: false;
|
|
670
|
+
error: string;
|
|
671
|
+
}>;
|
|
672
|
+
finish(input: SessionFinishInput): Promise<{
|
|
673
|
+
ok: true;
|
|
674
|
+
closed: SessionState;
|
|
675
|
+
} | {
|
|
676
|
+
ok: false;
|
|
677
|
+
error: string;
|
|
678
|
+
}>;
|
|
679
|
+
/**
|
|
680
|
+
* Append paths to notes_touched on the active session, deduplicating. No-op when no
|
|
681
|
+
* session is active. Used by patch tools to record what the session edited.
|
|
682
|
+
*/
|
|
683
|
+
recordNotesTouched(paths: string[]): Promise<void>;
|
|
684
|
+
/**
|
|
685
|
+
* Read the active session WITHOUT computing the stale label. Returns null when no
|
|
686
|
+
* session is active or when the file is unparseable.
|
|
687
|
+
*/
|
|
688
|
+
readActive(): Promise<SessionState | null>;
|
|
689
|
+
private read;
|
|
690
|
+
private spawnAndCapture;
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Heuristic: derive the project root from the vault path. If the vault path ends in
|
|
694
|
+
* `.claude/.vault`, the project root is two levels up. Otherwise the vault path is
|
|
695
|
+
* treated as the project root.
|
|
696
|
+
*/
|
|
697
|
+
declare function deriveProjectRoot(notesPath: string): string;
|
|
698
|
+
declare function deriveSessionDir(notesPath: string): string;
|
|
699
|
+
|
|
700
|
+
type Tier = "fast" | "slow" | "all";
|
|
701
|
+
type Severity = "ok" | "warn" | "error";
|
|
702
|
+
interface DriftFinding {
|
|
703
|
+
check: string;
|
|
704
|
+
severity: Severity;
|
|
705
|
+
summary: string;
|
|
706
|
+
detail?: string;
|
|
707
|
+
fixable_via?: "skill-link" | "mcp-reconcile" | "regenerate-contract" | "reindex" | "none";
|
|
708
|
+
}
|
|
709
|
+
interface HealthcheckResult {
|
|
710
|
+
tier_run: Tier;
|
|
711
|
+
ran_at: string;
|
|
712
|
+
duration_ms: number;
|
|
713
|
+
findings: DriftFinding[];
|
|
714
|
+
counts: {
|
|
715
|
+
ok: number;
|
|
716
|
+
warn: number;
|
|
717
|
+
error: number;
|
|
718
|
+
};
|
|
719
|
+
cached?: boolean;
|
|
720
|
+
}
|
|
721
|
+
interface HealthcheckOptions {
|
|
722
|
+
projectRoot: string;
|
|
723
|
+
/** Vault path. When omitted, derived from projectRoot's .claude/.vault. */
|
|
724
|
+
vaultPath?: string;
|
|
725
|
+
tier?: Tier;
|
|
726
|
+
/** Cache file path. Default: <projectRoot>/.claude/.semantic-memory/healthcheck-cache.json */
|
|
727
|
+
cachePath?: string;
|
|
728
|
+
/** Force re-run even if cache is <5 minutes old. */
|
|
729
|
+
force?: boolean;
|
|
730
|
+
/** Override "now" — used by tests. */
|
|
731
|
+
nowMs?: number;
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Run the drift-detection healthcheck.
|
|
735
|
+
*
|
|
736
|
+
* - Fast tier: cheap file-system probes (~ms each). Plugin version, skill manifests,
|
|
737
|
+
* .mcp.json registration, hook registration, index freshness, session staleness,
|
|
738
|
+
* AGENTS.md managed-block sha. All independent, run in parallel. Total budget: <100ms
|
|
739
|
+
* on a representative install.
|
|
740
|
+
* - Slow tier: full vault lint. Adds tens of seconds on large vaults — invoked by
|
|
741
|
+
* explicit /healthcheck, never by the SessionStart auto path.
|
|
742
|
+
* - Cache: when force=false and the cache file is <5min old, return the cached result.
|
|
743
|
+
*
|
|
744
|
+
* Fail-open: any individual check that throws produces a `severity: "warn"` finding
|
|
745
|
+
* with the error message; never propagates.
|
|
746
|
+
*/
|
|
747
|
+
declare function runHealthcheck(opts: HealthcheckOptions): Promise<HealthcheckResult>;
|
|
748
|
+
/**
|
|
749
|
+
* Surface filter — return findings with severity >= warn. Used by the SessionStart hook
|
|
750
|
+
* to decide whether to emit anything at all.
|
|
751
|
+
*/
|
|
752
|
+
declare function filterToDrift(result: HealthcheckResult): DriftFinding[];
|
|
753
|
+
/**
|
|
754
|
+
* Format a drift summary for the SessionStart hook. Returns the text to inject as
|
|
755
|
+
* additionalContext, or an empty string when there's nothing to surface.
|
|
756
|
+
*/
|
|
757
|
+
declare function formatDriftBanner(result: HealthcheckResult): string;
|
|
758
|
+
|
|
759
|
+
export { type ApplyPatchOptions, type ApplyPatchResult, type ChangeSet, type DriftFinding, Embedder, FrontmatterManager, GraphBuilder, type GraphEdge, type GraphNode, type HealthcheckOptions, type HealthcheckResult, type Severity as HealthcheckSeverity, type Tier as HealthcheckTier, INDEX_FILE, INDEX_OVERFLOW_THRESHOLD, type IndexEntry, type IndexedDocument, Indexer, type IngestInput, type IngestPreview, type IngestSource, type IngestUnit, type LintFinding, type LintReport, type LogEntry, type LogEventInput, type LogQueryOptions, type ModeSummary, NoteCrud, type PromoteInput, type PromotePreview, type RegenResult, type RegenerateContractOptions, type RegenerateContractResult, type SearchResult, type SessionFinishInput, SessionManager, type SessionStartOptions, type SessionState, type SessionStatus, type Severity$1 as Severity, type SynthesizeNoteInput, type SynthesizePreview, TagManager, TextSearch, type ToolSummary, type VaultSchema, type VaultStats, VectorIndex, type VerificationRecord, Watcher, applyPatch, buildIngestChangeSet, buildPromoteChangeSet, buildSynthesizeChangeSet, deriveProjectRoot, deriveSessionDir, filterToDrift, formatDriftBanner, formatLintReport, inspectAgentsContract, installDefaultSchema, lintVault, loadSchema, logEvent, logQuery, regenDirectoryIndex, regenIndexesForPaths, regenerateAgentsContract, runHealthcheck, validateNote };
|
package/dist/core/index.js
CHANGED
|
@@ -1,16 +1,27 @@
|
|
|
1
|
+
import {
|
|
2
|
+
filterToDrift,
|
|
3
|
+
formatDriftBanner,
|
|
4
|
+
runHealthcheck
|
|
5
|
+
} from "../chunk-CCSX3BHF.js";
|
|
1
6
|
import {
|
|
2
7
|
FrontmatterManager,
|
|
3
8
|
INDEX_FILE,
|
|
4
9
|
INDEX_OVERFLOW_THRESHOLD,
|
|
5
10
|
NoteCrud,
|
|
11
|
+
SessionManager,
|
|
6
12
|
TagManager,
|
|
7
13
|
Watcher,
|
|
8
14
|
applyPatch,
|
|
9
15
|
buildIngestChangeSet,
|
|
16
|
+
buildPromoteChangeSet,
|
|
10
17
|
buildSynthesizeChangeSet,
|
|
18
|
+
deriveProjectRoot,
|
|
19
|
+
deriveSessionDir,
|
|
20
|
+
inspectAgentsContract,
|
|
11
21
|
regenDirectoryIndex,
|
|
12
|
-
regenIndexesForPaths
|
|
13
|
-
|
|
22
|
+
regenIndexesForPaths,
|
|
23
|
+
regenerateAgentsContract
|
|
24
|
+
} from "../chunk-XBAN7GRT.js";
|
|
14
25
|
import {
|
|
15
26
|
Embedder,
|
|
16
27
|
GraphBuilder,
|
|
@@ -42,14 +53,21 @@ export {
|
|
|
42
53
|
INDEX_OVERFLOW_THRESHOLD,
|
|
43
54
|
Indexer,
|
|
44
55
|
NoteCrud,
|
|
56
|
+
SessionManager,
|
|
45
57
|
TagManager,
|
|
46
58
|
TextSearch,
|
|
47
59
|
VectorIndex,
|
|
48
60
|
Watcher,
|
|
49
61
|
applyPatch,
|
|
50
62
|
buildIngestChangeSet,
|
|
63
|
+
buildPromoteChangeSet,
|
|
51
64
|
buildSynthesizeChangeSet,
|
|
65
|
+
deriveProjectRoot,
|
|
66
|
+
deriveSessionDir,
|
|
67
|
+
filterToDrift,
|
|
68
|
+
formatDriftBanner,
|
|
52
69
|
formatLintReport,
|
|
70
|
+
inspectAgentsContract,
|
|
53
71
|
installDefaultSchema,
|
|
54
72
|
lintVault,
|
|
55
73
|
loadSchema,
|
|
@@ -57,6 +75,8 @@ export {
|
|
|
57
75
|
logQuery,
|
|
58
76
|
regenDirectoryIndex,
|
|
59
77
|
regenIndexesForPaths,
|
|
78
|
+
regenerateAgentsContract,
|
|
79
|
+
runHealthcheck,
|
|
60
80
|
validateNote
|
|
61
81
|
};
|
|
62
82
|
//# sourceMappingURL=index.js.map
|