obsidian-anchor 0.2.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/LICENSE +21 -0
- package/README.md +209 -0
- package/dist/chunk/chunker.js +169 -0
- package/dist/chunk/chunker.js.map +1 -0
- package/dist/chunk/markdown.js +49 -0
- package/dist/chunk/markdown.js.map +1 -0
- package/dist/chunk/types.js +5 -0
- package/dist/chunk/types.js.map +1 -0
- package/dist/config.js +17 -0
- package/dist/config.js.map +1 -0
- package/dist/container.js +84 -0
- package/dist/container.js.map +1 -0
- package/dist/edit/safeEdit.js +130 -0
- package/dist/edit/safeEdit.js.map +1 -0
- package/dist/edit/snapshots.js +31 -0
- package/dist/edit/snapshots.js.map +1 -0
- package/dist/embeddings/local.js +61 -0
- package/dist/embeddings/local.js.map +1 -0
- package/dist/embeddings/openai.js +63 -0
- package/dist/embeddings/openai.js.map +1 -0
- package/dist/embeddings/provider.js +5 -0
- package/dist/embeddings/provider.js.map +1 -0
- package/dist/index/indexer.js +108 -0
- package/dist/index/indexer.js.map +1 -0
- package/dist/index/walk.js +28 -0
- package/dist/index/walk.js.map +1 -0
- package/dist/index/watcher.js +115 -0
- package/dist/index/watcher.js.map +1 -0
- package/dist/index.js +192 -0
- package/dist/index.js.map +1 -0
- package/dist/server.js +61 -0
- package/dist/server.js.map +1 -0
- package/dist/store/chunkStore.js +82 -0
- package/dist/store/chunkStore.js.map +1 -0
- package/dist/store/db.js +59 -0
- package/dist/store/db.js.map +1 -0
- package/dist/store/schema.js +67 -0
- package/dist/store/schema.js.map +1 -0
- package/dist/store/search.js +33 -0
- package/dist/store/search.js.map +1 -0
- package/dist/store/types.js +3 -0
- package/dist/store/types.js.map +1 -0
- package/dist/store/vectorStore.js +77 -0
- package/dist/store/vectorStore.js.map +1 -0
- package/dist/tools/cite.js +51 -0
- package/dist/tools/cite.js.map +1 -0
- package/dist/tools/restoreNote.js +49 -0
- package/dist/tools/restoreNote.js.map +1 -0
- package/dist/tools/safeEdit.js +65 -0
- package/dist/tools/safeEdit.js.map +1 -0
- package/dist/tools/searchNotes.js +47 -0
- package/dist/tools/searchNotes.js.map +1 -0
- package/dist/tools/verifyGrounding.js +66 -0
- package/dist/tools/verifyGrounding.js.map +1 -0
- package/dist/util/hash.js +6 -0
- package/dist/util/hash.js.map +1 -0
- package/dist/util/logger.js +41 -0
- package/dist/util/logger.js.map +1 -0
- package/dist/util/timeout.js +19 -0
- package/dist/util/timeout.js.map +1 -0
- package/dist/verify/anthropic.js +126 -0
- package/dist/verify/anthropic.js.map +1 -0
- package/dist/verify/decompose.js +100 -0
- package/dist/verify/decompose.js.map +1 -0
- package/dist/verify/localVerifier.js +89 -0
- package/dist/verify/localVerifier.js.map +1 -0
- package/dist/verify/pipeline.js +165 -0
- package/dist/verify/pipeline.js.map +1 -0
- package/dist/verify/score.js +64 -0
- package/dist/verify/score.js.map +1 -0
- package/dist/verify/types.js +3 -0
- package/dist/verify/types.js.map +1 -0
- package/dist/verify/verifier.js +2 -0
- package/dist/verify/verifier.js.map +1 -0
- package/package.json +71 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { createContext } from "./container.js";
|
|
5
|
+
import { VaultWatcher } from "./index/watcher.js";
|
|
6
|
+
import { buildServer, SERVER_NAME, SERVER_VERSION } from "./server.js";
|
|
7
|
+
import { logger } from "./util/logger.js";
|
|
8
|
+
let watcher;
|
|
9
|
+
let shuttingDown = false;
|
|
10
|
+
function parseArgs(argv) {
|
|
11
|
+
const args = argv.slice(2);
|
|
12
|
+
const positionals = [];
|
|
13
|
+
const config = {};
|
|
14
|
+
let reindex = false;
|
|
15
|
+
const num = (raw) => {
|
|
16
|
+
if (raw === undefined)
|
|
17
|
+
return undefined;
|
|
18
|
+
const value = Number(raw);
|
|
19
|
+
return Number.isFinite(value) ? value : undefined;
|
|
20
|
+
};
|
|
21
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
22
|
+
const arg = args[i];
|
|
23
|
+
if (arg === undefined)
|
|
24
|
+
continue;
|
|
25
|
+
switch (arg) {
|
|
26
|
+
case "--reindex":
|
|
27
|
+
reindex = true;
|
|
28
|
+
break;
|
|
29
|
+
case "--watch-polling":
|
|
30
|
+
process.env.ANCHOR_WATCH_POLLING = "1";
|
|
31
|
+
break;
|
|
32
|
+
case "--verifier": {
|
|
33
|
+
const value = args[(i += 1)];
|
|
34
|
+
if (value)
|
|
35
|
+
process.env.ANCHOR_VERIFIER = value;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
case "--embedding": {
|
|
39
|
+
const value = args[(i += 1)];
|
|
40
|
+
if (value)
|
|
41
|
+
process.env.ANCHOR_EMBEDDING = value;
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
case "--knn": {
|
|
45
|
+
const value = num(args[(i += 1)]);
|
|
46
|
+
if (value !== undefined)
|
|
47
|
+
config.knn = value;
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
case "--grounded-threshold": {
|
|
51
|
+
const value = num(args[(i += 1)]);
|
|
52
|
+
if (value !== undefined)
|
|
53
|
+
config.grounded = value;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
case "--refuse-threshold": {
|
|
57
|
+
const value = num(args[(i += 1)]);
|
|
58
|
+
if (value !== undefined)
|
|
59
|
+
config.refuse = value;
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
case "--evidence-min-score": {
|
|
63
|
+
const value = num(args[(i += 1)]);
|
|
64
|
+
if (value !== undefined)
|
|
65
|
+
config.evidenceMinScore = value;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
case "--verify-timeout-ms": {
|
|
69
|
+
const value = num(args[(i += 1)]);
|
|
70
|
+
if (value !== undefined)
|
|
71
|
+
config.verifyTimeoutMs = value;
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
default:
|
|
75
|
+
if (!arg.startsWith("-"))
|
|
76
|
+
positionals.push(arg);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return { vaultPath: positionals[0], reindex, config };
|
|
81
|
+
}
|
|
82
|
+
function installGlobalErrorHandlers() {
|
|
83
|
+
process.on("unhandledRejection", (reason) => {
|
|
84
|
+
logger.error("Unhandled promise rejection", {
|
|
85
|
+
reason: reason instanceof Error ? reason.message : String(reason),
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
process.on("uncaughtException", (error) => {
|
|
89
|
+
logger.error("Uncaught exception", { error: error.message });
|
|
90
|
+
process.exit(1);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
function installShutdownHandlers(context) {
|
|
94
|
+
let closing = false;
|
|
95
|
+
const closeDb = () => {
|
|
96
|
+
try {
|
|
97
|
+
context?.db.close();
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
logger.error("Error closing the index database", {
|
|
101
|
+
error: error instanceof Error ? error.message : String(error),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
const shutdown = (reason, forceExit) => {
|
|
106
|
+
if (closing)
|
|
107
|
+
return;
|
|
108
|
+
closing = true;
|
|
109
|
+
shuttingDown = true;
|
|
110
|
+
logger.info(`Shutting down (${reason})`);
|
|
111
|
+
if (forceExit) {
|
|
112
|
+
void watcher?.stop();
|
|
113
|
+
closeDb();
|
|
114
|
+
process.exit(0);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
// stdin-close: stop the watcher, wait for any in-flight initial index to
|
|
118
|
+
// settle, then close the DB and let the event loop drain so final responses
|
|
119
|
+
// still flush. `shuttingDown` prevents the index pass from starting a new
|
|
120
|
+
// watcher afterwards.
|
|
121
|
+
void (async () => {
|
|
122
|
+
await watcher?.stop();
|
|
123
|
+
const indexing = context?.indexing;
|
|
124
|
+
if (indexing) {
|
|
125
|
+
try {
|
|
126
|
+
await indexing;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// already logged during indexing
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
closeDb();
|
|
133
|
+
})();
|
|
134
|
+
};
|
|
135
|
+
process.on("SIGINT", () => { shutdown("SIGINT", true); });
|
|
136
|
+
process.on("SIGTERM", () => { shutdown("SIGTERM", true); });
|
|
137
|
+
// The MCP client closing stdin (EOF) is also a shutdown signal — otherwise the
|
|
138
|
+
// persistent file watcher keeps the process alive after the client exits.
|
|
139
|
+
process.stdin.on("end", () => { shutdown("stdin closed", false); });
|
|
140
|
+
process.stdin.on("close", () => { shutdown("stdin closed", false); });
|
|
141
|
+
}
|
|
142
|
+
async function main() {
|
|
143
|
+
installGlobalErrorHandlers();
|
|
144
|
+
const { vaultPath, reindex, config } = parseArgs(process.argv);
|
|
145
|
+
let context;
|
|
146
|
+
if (vaultPath) {
|
|
147
|
+
const absVault = resolve(vaultPath);
|
|
148
|
+
logger.info("Starting Anchor", { vaultPath: absVault });
|
|
149
|
+
const ctx = createContext(absVault, { config, reindex });
|
|
150
|
+
context = ctx;
|
|
151
|
+
installShutdownHandlers(ctx);
|
|
152
|
+
// Index in the BACKGROUND so a large vault never blocks the MCP initialize
|
|
153
|
+
// handshake. Vault-backed tools await `context.indexing` before serving, so
|
|
154
|
+
// an early call simply waits for the first index pass to finish. Once the
|
|
155
|
+
// initial pass is done, watch the vault to keep the index live.
|
|
156
|
+
ctx.indexing = ctx.indexer
|
|
157
|
+
.indexAll()
|
|
158
|
+
.then((stats) => {
|
|
159
|
+
logger.info("Vault indexed", stats);
|
|
160
|
+
if (shuttingDown)
|
|
161
|
+
return;
|
|
162
|
+
watcher = new VaultWatcher(absVault, ctx.indexer, {
|
|
163
|
+
// Set ANCHOR_WATCH_POLLING=1 on filesystems without native fs events
|
|
164
|
+
// (network drives, WSL, Docker volumes).
|
|
165
|
+
usePolling: process.env.ANCHOR_WATCH_POLLING === "1",
|
|
166
|
+
});
|
|
167
|
+
watcher.start();
|
|
168
|
+
logger.info("Watching vault for changes");
|
|
169
|
+
})
|
|
170
|
+
.catch((error) => {
|
|
171
|
+
logger.error("Initial indexing failed", {
|
|
172
|
+
error: error instanceof Error ? error.message : String(error),
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
installShutdownHandlers(undefined);
|
|
178
|
+
logger.warn("No vault path provided; starting in no-vault mode (only the ping tool is available). " +
|
|
179
|
+
"Usage: obsidian-anchor <path-to-vault>");
|
|
180
|
+
}
|
|
181
|
+
const server = buildServer(context);
|
|
182
|
+
const transport = new StdioServerTransport();
|
|
183
|
+
await server.connect(transport);
|
|
184
|
+
logger.info(`Anchor MCP server ready (${SERVER_NAME} v${SERVER_VERSION})`);
|
|
185
|
+
}
|
|
186
|
+
main().catch((error) => {
|
|
187
|
+
logger.error("Fatal error during startup", {
|
|
188
|
+
error: error instanceof Error ? error.message : String(error),
|
|
189
|
+
});
|
|
190
|
+
process.exitCode = 1;
|
|
191
|
+
});
|
|
192
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { registerCite } from "./tools/cite.js";
|
|
4
|
+
import { registerRestoreNote } from "./tools/restoreNote.js";
|
|
5
|
+
import { registerSafeEdit } from "./tools/safeEdit.js";
|
|
6
|
+
import { registerSearchNotes } from "./tools/searchNotes.js";
|
|
7
|
+
import { registerVerifyGrounding } from "./tools/verifyGrounding.js";
|
|
8
|
+
import { logger } from "./util/logger.js";
|
|
9
|
+
export const SERVER_NAME = "anchor";
|
|
10
|
+
export const SERVER_VERSION = "0.2.0";
|
|
11
|
+
/**
|
|
12
|
+
* Builds the Anchor MCP server with its tools registered.
|
|
13
|
+
*
|
|
14
|
+
* The server is transport-agnostic: callers attach a transport (stdio in
|
|
15
|
+
* production, in-memory in tests) via `server.connect(...)`. Vault-backed tools
|
|
16
|
+
* are registered only when an {@link AppContext} is supplied.
|
|
17
|
+
*/
|
|
18
|
+
export function buildServer(context) {
|
|
19
|
+
const server = new McpServer({
|
|
20
|
+
name: SERVER_NAME,
|
|
21
|
+
version: SERVER_VERSION,
|
|
22
|
+
});
|
|
23
|
+
registerPingTool(server);
|
|
24
|
+
if (context) {
|
|
25
|
+
registerSearchNotes(server, context);
|
|
26
|
+
registerVerifyGrounding(server, context);
|
|
27
|
+
registerCite(server, context);
|
|
28
|
+
registerSafeEdit(server, context);
|
|
29
|
+
registerRestoreNote(server, context);
|
|
30
|
+
}
|
|
31
|
+
return server;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A trivial health-check tool. It exists so the server boot, tool registration,
|
|
35
|
+
* and transport handshake can be validated end-to-end before any real tooling
|
|
36
|
+
* (search / grounding) lands.
|
|
37
|
+
*/
|
|
38
|
+
function registerPingTool(server) {
|
|
39
|
+
server.registerTool("ping", {
|
|
40
|
+
title: "Ping",
|
|
41
|
+
description: "Health check. Returns pong plus the server name and version.",
|
|
42
|
+
inputSchema: {},
|
|
43
|
+
outputSchema: {
|
|
44
|
+
pong: z.literal(true),
|
|
45
|
+
server: z.string(),
|
|
46
|
+
version: z.string(),
|
|
47
|
+
},
|
|
48
|
+
}, () => {
|
|
49
|
+
logger.debug("ping invoked");
|
|
50
|
+
const payload = {
|
|
51
|
+
pong: true,
|
|
52
|
+
server: SERVER_NAME,
|
|
53
|
+
version: SERVER_VERSION,
|
|
54
|
+
};
|
|
55
|
+
return {
|
|
56
|
+
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
57
|
+
structuredContent: payload,
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC;AACpC,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAEtC;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,OAAoB;IAC9C,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,cAAc;KACxB,CAAC,CAAC;IAEH,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzB,IAAI,OAAO,EAAE,CAAC;QACZ,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACrC,uBAAuB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACzC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC9B,gBAAgB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAClC,mBAAmB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,SAAS,gBAAgB,CAAC,MAAiB;IACzC,MAAM,CAAC,YAAY,CACjB,MAAM,EACN;QACE,KAAK,EAAE,MAAM;QACb,WAAW,EAAE,8DAA8D;QAC3E,WAAW,EAAE,EAAE;QACf,YAAY,EAAE;YACZ,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;YACrB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;YAClB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;SACpB;KACF,EACD,GAAG,EAAE;QACH,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC7B,MAAM,OAAO,GAAG;YACd,IAAI,EAAE,IAAa;YACnB,MAAM,EAAE,WAAW;YACnB,OAAO,EAAE,cAAc;SACxB,CAAC;QACF,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1D,iBAAiB,EAAE,OAAO;SAC3B,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Column aliasing so rows hydrate directly into StoredChunk (camelCase) fields.
|
|
2
|
+
const HYDRATE_COLUMNS = "chunk_id AS chunkId, path AS notePath, heading_path AS headingPath, " +
|
|
3
|
+
"block_id AS blockId, anchor, ordinal, char_start AS charStart, char_end AS charEnd, text";
|
|
4
|
+
/**
|
|
5
|
+
* Owns the relational side of the index: notes, chunks, and their wikilinks.
|
|
6
|
+
* Vector rows live in {@link VectorStore} and are keyed by the same chunk id.
|
|
7
|
+
*/
|
|
8
|
+
export class ChunkStore {
|
|
9
|
+
db;
|
|
10
|
+
constructor(db) {
|
|
11
|
+
this.db = db;
|
|
12
|
+
}
|
|
13
|
+
/** Inserts a note row and returns its id. Caller ensures the path is new. */
|
|
14
|
+
insertNote(note, indexedAt) {
|
|
15
|
+
const result = this.db
|
|
16
|
+
.prepare("INSERT INTO notes (path, mtime_ms, content_hash, indexed_at) VALUES (?, ?, ?, ?)")
|
|
17
|
+
.run(note.path, note.mtimeMs, note.contentHash, indexedAt);
|
|
18
|
+
return Number(result.lastInsertRowid);
|
|
19
|
+
}
|
|
20
|
+
/** Inserts one chunk (and its wikilinks); returns the new chunk id. */
|
|
21
|
+
insertChunk(noteId, chunk) {
|
|
22
|
+
const result = this.db
|
|
23
|
+
.prepare("INSERT INTO chunks " +
|
|
24
|
+
"(note_id, path, heading_path, block_id, anchor, ordinal, char_start, char_end, text, token_est) " +
|
|
25
|
+
"VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
|
26
|
+
.run(noteId, chunk.meta.path, chunk.meta.headingPath, chunk.meta.blockId, chunk.meta.anchor, chunk.ordinal, chunk.charStart, chunk.charEnd, chunk.text, chunk.tokenEst);
|
|
27
|
+
const chunkId = Number(result.lastInsertRowid);
|
|
28
|
+
this.insertWikilinks(chunkId, chunk);
|
|
29
|
+
return chunkId;
|
|
30
|
+
}
|
|
31
|
+
insertWikilinks(chunkId, chunk) {
|
|
32
|
+
if (chunk.meta.wikilinks.length === 0)
|
|
33
|
+
return;
|
|
34
|
+
const stmt = this.db.prepare("INSERT INTO wikilinks (chunk_id, target_note, target_anchor, alias) VALUES (?, ?, ?, ?)");
|
|
35
|
+
for (const link of chunk.meta.wikilinks) {
|
|
36
|
+
stmt.run(chunkId, link.targetNote, link.targetAnchor, link.alias);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Looks up a note id by path, or undefined if not indexed. */
|
|
40
|
+
getNoteId(path) {
|
|
41
|
+
const row = this.db.prepare("SELECT note_id AS id FROM notes WHERE path = ?").get(path);
|
|
42
|
+
return row?.id;
|
|
43
|
+
}
|
|
44
|
+
/** Returns every indexed note (id + path), e.g. to prune ones deleted on disk. */
|
|
45
|
+
getAllNotes() {
|
|
46
|
+
return this.db.prepare("SELECT note_id AS noteId, path FROM notes").all();
|
|
47
|
+
}
|
|
48
|
+
/** Looks up a note's id and content hash by path (for incremental indexing). */
|
|
49
|
+
getNote(path) {
|
|
50
|
+
return this.db
|
|
51
|
+
.prepare("SELECT note_id AS noteId, content_hash AS contentHash FROM notes WHERE path = ?")
|
|
52
|
+
.get(path);
|
|
53
|
+
}
|
|
54
|
+
/** Returns the chunk ids belonging to a note. */
|
|
55
|
+
getChunkIdsForNote(noteId) {
|
|
56
|
+
const rows = this.db
|
|
57
|
+
.prepare("SELECT chunk_id AS id FROM chunks WHERE note_id = ?")
|
|
58
|
+
.all(noteId);
|
|
59
|
+
return rows.map((r) => r.id);
|
|
60
|
+
}
|
|
61
|
+
getChunk(chunkId) {
|
|
62
|
+
return this.db.prepare(`SELECT ${HYDRATE_COLUMNS} FROM chunks WHERE chunk_id = ?`).get(chunkId);
|
|
63
|
+
}
|
|
64
|
+
/** Hydrates chunks by id, preserving the given id order and dropping misses. */
|
|
65
|
+
hydrate(chunkIds) {
|
|
66
|
+
if (chunkIds.length === 0)
|
|
67
|
+
return [];
|
|
68
|
+
const placeholders = chunkIds.map(() => "?").join(", ");
|
|
69
|
+
const rows = this.db
|
|
70
|
+
.prepare(`SELECT ${HYDRATE_COLUMNS} FROM chunks WHERE chunk_id IN (${placeholders})`)
|
|
71
|
+
.all(...chunkIds);
|
|
72
|
+
const byId = new Map(rows.map((r) => [r.chunkId, r]));
|
|
73
|
+
return chunkIds
|
|
74
|
+
.map((id) => byId.get(id))
|
|
75
|
+
.filter((c) => c !== undefined);
|
|
76
|
+
}
|
|
77
|
+
/** Deletes a note row by id (cascades chunks + wikilinks via foreign keys). */
|
|
78
|
+
deleteNoteRow(noteId) {
|
|
79
|
+
this.db.prepare("DELETE FROM notes WHERE note_id = ?").run(noteId);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=chunkStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunkStore.js","sourceRoot":"","sources":["../../src/store/chunkStore.ts"],"names":[],"mappings":"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"}
|
package/dist/store/db.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import Database from "better-sqlite3";
|
|
2
|
+
import * as sqliteVec from "sqlite-vec";
|
|
3
|
+
import { logger } from "../util/logger.js";
|
|
4
|
+
import { FALLBACK_VEC_SCHEMA_SQL, RELATIONAL_SCHEMA_SQL, SCHEMA_VERSION, vecSchemaSql } from "./schema.js";
|
|
5
|
+
const IN_MEMORY = ":memory:";
|
|
6
|
+
/**
|
|
7
|
+
* Opens and migrates the Anchor index database. It tries to load the sqlite-vec
|
|
8
|
+
* native extension; if that fails on this platform, it falls back to a pure-JS
|
|
9
|
+
* brute-force vector store so Anchor still works (just slower on large vaults).
|
|
10
|
+
*/
|
|
11
|
+
export function openDb(options) {
|
|
12
|
+
const db = new Database(options.path);
|
|
13
|
+
let vectorBackend = "native";
|
|
14
|
+
try {
|
|
15
|
+
sqliteVec.load(db);
|
|
16
|
+
const probe = db.prepare("SELECT vec_version() AS v").get();
|
|
17
|
+
if (!probe?.v)
|
|
18
|
+
throw new Error("vec_version() returned no value after load");
|
|
19
|
+
logger.debug("Vector extension ready", { vecVersion: probe.v });
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
vectorBackend = "fallback";
|
|
23
|
+
logger.warn("sqlite-vec native extension unavailable; using the pure-JS vector fallback (slower on large vaults)", { detail: error instanceof Error ? error.message : String(error) });
|
|
24
|
+
}
|
|
25
|
+
if (options.path !== IN_MEMORY) {
|
|
26
|
+
db.pragma("journal_mode = WAL");
|
|
27
|
+
}
|
|
28
|
+
db.pragma("synchronous = NORMAL");
|
|
29
|
+
db.pragma("foreign_keys = ON");
|
|
30
|
+
migrate(db, options, vectorBackend);
|
|
31
|
+
return { db, vectorBackend };
|
|
32
|
+
}
|
|
33
|
+
function readMeta(db, key) {
|
|
34
|
+
const row = db.prepare("SELECT value FROM meta WHERE key = ?").get(key);
|
|
35
|
+
return row?.value;
|
|
36
|
+
}
|
|
37
|
+
function writeMeta(db, key, value) {
|
|
38
|
+
db.prepare("INSERT INTO meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(key, value);
|
|
39
|
+
}
|
|
40
|
+
function migrate(db, options, backend) {
|
|
41
|
+
db.exec(RELATIONAL_SCHEMA_SQL);
|
|
42
|
+
const prevDim = readMeta(db, "embedding_dim");
|
|
43
|
+
const prevModel = readMeta(db, "embedding_model");
|
|
44
|
+
const dimChanged = prevDim !== undefined && Number(prevDim) !== options.dim;
|
|
45
|
+
const modelChanged = prevModel !== undefined && prevModel !== options.embeddingModel;
|
|
46
|
+
if (dimChanged || modelChanged) {
|
|
47
|
+
logger.warn("Embedding configuration changed; rebuilding the vector index and clearing the stored index (a re-index is required).", { prevModel, prevDim, model: options.embeddingModel, dim: options.dim });
|
|
48
|
+
db.exec("DROP TABLE IF EXISTS vec_chunks;");
|
|
49
|
+
db.exec("DROP TABLE IF EXISTS vec_chunks_js;");
|
|
50
|
+
// Stored chunks reference embeddings that no longer match the active model;
|
|
51
|
+
// clear them so the next indexing pass rebuilds everything consistently.
|
|
52
|
+
db.exec("DELETE FROM chunks; DELETE FROM notes;");
|
|
53
|
+
}
|
|
54
|
+
db.exec(backend === "native" ? vecSchemaSql(options.dim) : FALLBACK_VEC_SCHEMA_SQL);
|
|
55
|
+
writeMeta(db, "schema_version", String(SCHEMA_VERSION));
|
|
56
|
+
writeMeta(db, "embedding_model", options.embeddingModel);
|
|
57
|
+
writeMeta(db, "embedding_dim", String(options.dim));
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/store/db.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
// Index database schema. Kept as inlined SQL (rather than a .sql asset) so it
|
|
2
|
+
// ships cleanly in the compiled dist/ output for `npx` distribution.
|
|
3
|
+
export const SCHEMA_VERSION = 1;
|
|
4
|
+
/**
|
|
5
|
+
* Relational tables + indexes. Dimension-independent and idempotent
|
|
6
|
+
* (`IF NOT EXISTS`), so it is safe to run on every open.
|
|
7
|
+
*/
|
|
8
|
+
export const RELATIONAL_SCHEMA_SQL = `
|
|
9
|
+
CREATE TABLE IF NOT EXISTS meta (
|
|
10
|
+
key TEXT PRIMARY KEY,
|
|
11
|
+
value TEXT NOT NULL
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
CREATE TABLE IF NOT EXISTS notes (
|
|
15
|
+
note_id INTEGER PRIMARY KEY,
|
|
16
|
+
path TEXT NOT NULL UNIQUE,
|
|
17
|
+
mtime_ms INTEGER NOT NULL,
|
|
18
|
+
content_hash TEXT NOT NULL,
|
|
19
|
+
indexed_at INTEGER NOT NULL
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
-- One row per chunk == the citation / evidence unit.
|
|
23
|
+
CREATE TABLE IF NOT EXISTS chunks (
|
|
24
|
+
chunk_id INTEGER PRIMARY KEY,
|
|
25
|
+
note_id INTEGER NOT NULL REFERENCES notes(note_id) ON DELETE CASCADE,
|
|
26
|
+
path TEXT NOT NULL,
|
|
27
|
+
heading_path TEXT,
|
|
28
|
+
block_id TEXT,
|
|
29
|
+
anchor TEXT NOT NULL,
|
|
30
|
+
ordinal INTEGER NOT NULL,
|
|
31
|
+
char_start INTEGER NOT NULL,
|
|
32
|
+
char_end INTEGER NOT NULL,
|
|
33
|
+
text TEXT NOT NULL,
|
|
34
|
+
token_est INTEGER NOT NULL
|
|
35
|
+
);
|
|
36
|
+
CREATE INDEX IF NOT EXISTS idx_chunks_note ON chunks(note_id);
|
|
37
|
+
CREATE INDEX IF NOT EXISTS idx_chunks_block ON chunks(path, block_id);
|
|
38
|
+
|
|
39
|
+
CREATE TABLE IF NOT EXISTS wikilinks (
|
|
40
|
+
chunk_id INTEGER NOT NULL REFERENCES chunks(chunk_id) ON DELETE CASCADE,
|
|
41
|
+
target_note TEXT NOT NULL,
|
|
42
|
+
target_anchor TEXT,
|
|
43
|
+
alias TEXT
|
|
44
|
+
);
|
|
45
|
+
CREATE INDEX IF NOT EXISTS idx_wikilinks_chunk ON wikilinks(chunk_id);
|
|
46
|
+
CREATE INDEX IF NOT EXISTS idx_wikilinks_target ON wikilinks(target_note);
|
|
47
|
+
`;
|
|
48
|
+
/**
|
|
49
|
+
* The vec0 virtual table holding chunk embeddings. Its column width is fixed at
|
|
50
|
+
* creation time, so it is templated by the active embedding dimension and
|
|
51
|
+
* rebuilt whenever the embedding provider (and thus the dimension) changes.
|
|
52
|
+
*/
|
|
53
|
+
export function vecSchemaSql(dim) {
|
|
54
|
+
return `CREATE VIRTUAL TABLE IF NOT EXISTS vec_chunks USING vec0(
|
|
55
|
+
chunk_id INTEGER PRIMARY KEY,
|
|
56
|
+
embedding float[${dim}]
|
|
57
|
+
);`;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Fallback embedding table used when the sqlite-vec native extension can't be
|
|
61
|
+
* loaded. KNN is brute-forced in JS over these blobs (slower, but it works).
|
|
62
|
+
*/
|
|
63
|
+
export const FALLBACK_VEC_SCHEMA_SQL = `CREATE TABLE IF NOT EXISTS vec_chunks_js (
|
|
64
|
+
chunk_id INTEGER PRIMARY KEY,
|
|
65
|
+
embedding BLOB NOT NULL
|
|
66
|
+
);`;
|
|
67
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/store/schema.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,qEAAqE;AAErE,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC;AAEhC;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuCpC,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,OAAO;;oBAEW,GAAG;GACpB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;GAGpC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Semantic search: embed the query, find nearest chunks, and hydrate them with
|
|
3
|
+
* their Obsidian citation metadata. This is the retrieval primitive reused by
|
|
4
|
+
* the grounding pipeline ("reuse, don't reinvent" search).
|
|
5
|
+
*/
|
|
6
|
+
export class SearchService {
|
|
7
|
+
embeddings;
|
|
8
|
+
vectorStore;
|
|
9
|
+
chunkStore;
|
|
10
|
+
constructor(embeddings, vectorStore, chunkStore) {
|
|
11
|
+
this.embeddings = embeddings;
|
|
12
|
+
this.vectorStore = vectorStore;
|
|
13
|
+
this.chunkStore = chunkStore;
|
|
14
|
+
}
|
|
15
|
+
async search(query, limit) {
|
|
16
|
+
const queryVector = await this.embeddings.embedOne(query);
|
|
17
|
+
const hits = this.vectorStore.knn(queryVector, limit);
|
|
18
|
+
if (hits.length === 0)
|
|
19
|
+
return [];
|
|
20
|
+
const distanceById = new Map(hits.map((hit) => [hit.chunkId, hit.distance]));
|
|
21
|
+
const stored = this.chunkStore.hydrate(hits.map((hit) => hit.chunkId));
|
|
22
|
+
return stored.map((chunk) => {
|
|
23
|
+
const distance = distanceById.get(chunk.chunkId) ?? 0;
|
|
24
|
+
return { ...chunk, distance, score: distanceToScore(distance) };
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** Maps L2 distance between normalized vectors to a cosine similarity in 0..1. */
|
|
29
|
+
function distanceToScore(distance) {
|
|
30
|
+
const cosine = 1 - (distance * distance) / 2;
|
|
31
|
+
return Math.max(0, Math.min(1, cosine));
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/store/search.ts"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,MAAM,OAAO,aAAa;IAEL;IACA;IACA;IAHnB,YACmB,UAA6B,EAC7B,WAAwB,EACxB,UAAsB;QAFtB,eAAU,GAAV,UAAU,CAAmB;QAC7B,gBAAW,GAAX,WAAW,CAAa;QACxB,eAAU,GAAV,UAAU,CAAY;IACtC,CAAC;IAEJ,KAAK,CAAC,MAAM,CAAC,KAAa,EAAE,KAAa;QACvC,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC1D,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QACtD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAEjC,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,QAAQ,CAAU,CAAC,CAAC,CAAC;QACtF,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QAEvE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;YAC1B,MAAM,QAAQ,GAAG,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACtD,OAAO,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClE,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAED,kFAAkF;AAClF,SAAS,eAAe,CAAC,QAAgB;IACvC,MAAM,MAAM,GAAG,CAAC,GAAG,CAAC,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC7C,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/store/types.ts"],"names":[],"mappings":"AAAA,+DAA+D"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Owns the embedding store. With the native sqlite-vec extension it uses a vec0
|
|
3
|
+
* virtual table; without it (fallback) it stores blobs in a plain table and
|
|
4
|
+
* brute-forces cosine KNN in JS. Vector rows are keyed by the same chunk id as
|
|
5
|
+
* the relational `chunks` table but are not foreign-key linked, so the indexer
|
|
6
|
+
* must delete vector rows explicitly when a note is re-indexed.
|
|
7
|
+
*/
|
|
8
|
+
export class VectorStore {
|
|
9
|
+
db;
|
|
10
|
+
backend;
|
|
11
|
+
constructor(db, backend = "native") {
|
|
12
|
+
this.db = db;
|
|
13
|
+
this.backend = backend;
|
|
14
|
+
}
|
|
15
|
+
/** Stores the embedding for a chunk. */
|
|
16
|
+
insert(chunkId, embedding) {
|
|
17
|
+
if (this.backend === "native") {
|
|
18
|
+
// vec0 requires the primary key as a SQLite INTEGER (BigInt) and the vector
|
|
19
|
+
// as a packed float32 blob.
|
|
20
|
+
this.db
|
|
21
|
+
.prepare("INSERT INTO vec_chunks (chunk_id, embedding) VALUES (?, ?)")
|
|
22
|
+
.run(BigInt(chunkId), toBlob(embedding));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
this.db
|
|
26
|
+
.prepare("INSERT OR REPLACE INTO vec_chunks_js (chunk_id, embedding) VALUES (?, ?)")
|
|
27
|
+
.run(chunkId, toBlob(embedding));
|
|
28
|
+
}
|
|
29
|
+
/** Approximate-nearest-neighbour search; up to k hits, closest first. */
|
|
30
|
+
knn(query, k) {
|
|
31
|
+
if (this.backend === "native") {
|
|
32
|
+
return this.db
|
|
33
|
+
.prepare("SELECT chunk_id AS chunkId, distance FROM vec_chunks " +
|
|
34
|
+
"WHERE embedding MATCH ? AND k = ? ORDER BY distance")
|
|
35
|
+
.all(toBlob(query), k);
|
|
36
|
+
}
|
|
37
|
+
// Fallback: brute-force. Embeddings are unit-normalized, so cosine == dot
|
|
38
|
+
// product, and L2 distance == sqrt(2 - 2*dot).
|
|
39
|
+
const rows = this.db.prepare("SELECT chunk_id AS chunkId, embedding FROM vec_chunks_js").all();
|
|
40
|
+
const scored = rows.map((row) => {
|
|
41
|
+
const vector = bufferToFloat32(row.embedding);
|
|
42
|
+
const length = Math.min(vector.length, query.length);
|
|
43
|
+
let dot = 0;
|
|
44
|
+
for (let i = 0; i < length; i += 1)
|
|
45
|
+
dot += (query[i] ?? 0) * (vector[i] ?? 0);
|
|
46
|
+
return { chunkId: row.chunkId, distance: Math.sqrt(Math.max(0, 2 - 2 * dot)) };
|
|
47
|
+
});
|
|
48
|
+
scored.sort((a, b) => a.distance - b.distance);
|
|
49
|
+
return scored.slice(0, k);
|
|
50
|
+
}
|
|
51
|
+
deleteByChunkIds(chunkIds) {
|
|
52
|
+
if (chunkIds.length === 0)
|
|
53
|
+
return;
|
|
54
|
+
if (this.backend === "native") {
|
|
55
|
+
const stmt = this.db.prepare("DELETE FROM vec_chunks WHERE chunk_id = ?");
|
|
56
|
+
for (const id of chunkIds)
|
|
57
|
+
stmt.run(BigInt(id));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const stmt = this.db.prepare("DELETE FROM vec_chunks_js WHERE chunk_id = ?");
|
|
61
|
+
for (const id of chunkIds)
|
|
62
|
+
stmt.run(id);
|
|
63
|
+
}
|
|
64
|
+
count() {
|
|
65
|
+
const table = this.backend === "native" ? "vec_chunks" : "vec_chunks_js";
|
|
66
|
+
const row = this.db.prepare(`SELECT count(*) AS n FROM ${table}`).get();
|
|
67
|
+
return row.n;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** Packs a Float32Array into a Buffer view for binding as a blob. */
|
|
71
|
+
function toBlob(vector) {
|
|
72
|
+
return Buffer.from(vector.buffer, vector.byteOffset, vector.byteLength);
|
|
73
|
+
}
|
|
74
|
+
function bufferToFloat32(buffer) {
|
|
75
|
+
return new Float32Array(buffer.buffer, buffer.byteOffset, Math.floor(buffer.byteLength / 4));
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=vectorStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vectorStore.js","sourceRoot":"","sources":["../../src/store/vectorStore.ts"],"names":[],"mappings":"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"}
|