daftari 1.6.0 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/README.md +63 -7
- package/dist/hooks/loader.d.ts +3 -1
- package/dist/hooks/loader.d.ts.map +1 -1
- package/dist/hooks/loader.js +37 -6
- package/dist/hooks/loader.js.map +1 -1
- package/dist/hooks/runner.d.ts +6 -1
- package/dist/hooks/runner.d.ts.map +1 -1
- package/dist/hooks/runner.js +48 -0
- package/dist/hooks/runner.js.map +1 -1
- package/dist/hooks/types.d.ts +7 -1
- package/dist/hooks/types.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +97 -32
- package/dist/index.js.map +1 -1
- package/dist/search/index-state.d.ts +17 -0
- package/dist/search/index-state.d.ts.map +1 -0
- package/dist/search/index-state.js +68 -0
- package/dist/search/index-state.js.map +1 -0
- package/dist/search/reindex.d.ts +1 -0
- package/dist/search/reindex.d.ts.map +1 -1
- package/dist/search/reindex.js +105 -1
- package/dist/search/reindex.js.map +1 -1
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +37 -8
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js +67 -9
- package/dist/tools/write.js.map +1 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +49 -26
- package/dist/utils/config.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Process-wide indexing state.
|
|
2
|
+
//
|
|
3
|
+
// The MCP server opens the stdio transport before running a cold-start reindex
|
|
4
|
+
// so `initialize` / `tools/list` answer immediately. While that background pass
|
|
5
|
+
// runs the server is alive but search and write tools cannot trust the index;
|
|
6
|
+
// they consult this module to decide whether to serve or to reply "still
|
|
7
|
+
// indexing — N/M chunks". A single in-process snapshot is enough because the
|
|
8
|
+
// server is one Node process per vault.
|
|
9
|
+
function freshState() {
|
|
10
|
+
return {
|
|
11
|
+
status: "ready",
|
|
12
|
+
done: 0,
|
|
13
|
+
total: 0,
|
|
14
|
+
error: null,
|
|
15
|
+
startedAt: null,
|
|
16
|
+
finishedAt: null,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
let state = freshState();
|
|
20
|
+
export function getIndexStatus() {
|
|
21
|
+
return { ...state };
|
|
22
|
+
}
|
|
23
|
+
export function markIndexing() {
|
|
24
|
+
state = {
|
|
25
|
+
status: "indexing",
|
|
26
|
+
done: 0,
|
|
27
|
+
total: 0,
|
|
28
|
+
error: null,
|
|
29
|
+
startedAt: new Date().toISOString(),
|
|
30
|
+
finishedAt: null,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function setIndexProgress(done, total) {
|
|
34
|
+
if (state.status !== "indexing")
|
|
35
|
+
return;
|
|
36
|
+
state = { ...state, done, total };
|
|
37
|
+
}
|
|
38
|
+
export function markIndexReady() {
|
|
39
|
+
state = {
|
|
40
|
+
...state,
|
|
41
|
+
status: "ready",
|
|
42
|
+
error: null,
|
|
43
|
+
finishedAt: new Date().toISOString(),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export function markIndexError(message) {
|
|
47
|
+
state = {
|
|
48
|
+
...state,
|
|
49
|
+
status: "error",
|
|
50
|
+
error: message,
|
|
51
|
+
finishedAt: new Date().toISOString(),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
// Tests load tools without running main(); resetting the singleton between
|
|
55
|
+
// suites keeps cross-test pollution out of the state machine.
|
|
56
|
+
export function resetIndexState() {
|
|
57
|
+
state = freshState();
|
|
58
|
+
}
|
|
59
|
+
// Formatted message tools return to clients while indexing is in progress.
|
|
60
|
+
// One place so the phrasing is consistent across vault_search, vault_write,
|
|
61
|
+
// vault_reindex, etc.
|
|
62
|
+
export function indexingBusyMessage(snapshot) {
|
|
63
|
+
if (snapshot.total > 0) {
|
|
64
|
+
return `vault is still indexing (${snapshot.done}/${snapshot.total} chunks) — try again shortly`;
|
|
65
|
+
}
|
|
66
|
+
return `vault is still indexing — try again shortly`;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=index-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-state.js","sourceRoot":"","sources":["../../src/search/index-state.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,EAAE;AACF,+EAA+E;AAC/E,gFAAgF;AAChF,8EAA8E;AAC9E,yEAAyE;AACzE,6EAA6E;AAC7E,wCAAwC;AAaxC,SAAS,UAAU;IACjB,OAAO;QACL,MAAM,EAAE,OAAO;QACf,IAAI,EAAE,CAAC;QACP,KAAK,EAAE,CAAC;QACR,KAAK,EAAE,IAAI;QACX,SAAS,EAAE,IAAI;QACf,UAAU,EAAE,IAAI;KACjB,CAAC;AACJ,CAAC;AAED,IAAI,KAAK,GAAkB,UAAU,EAAE,CAAC;AAExC,MAAM,UAAU,cAAc;IAC5B,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,KAAK,GAAG;QACN,MAAM,EAAE,UAAU;QAClB,IAAI,EAAE,CAAC;QACP,KAAK,EAAE,CAAC;QACR,KAAK,EAAE,IAAI;QACX,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,UAAU,EAAE,IAAI;KACjB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY,EAAE,KAAa;IAC1D,IAAI,KAAK,CAAC,MAAM,KAAK,UAAU;QAAE,OAAO;IACxC,KAAK,GAAG,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,KAAK,GAAG;QACN,GAAG,KAAK;QACR,MAAM,EAAE,OAAO;QACf,KAAK,EAAE,IAAI;QACX,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,KAAK,GAAG;QACN,GAAG,KAAK;QACR,MAAM,EAAE,OAAO;QACf,KAAK,EAAE,OAAO;QACd,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACrC,CAAC;AACJ,CAAC;AAED,2EAA2E;AAC3E,8DAA8D;AAC9D,MAAM,UAAU,eAAe;IAC7B,KAAK,GAAG,UAAU,EAAE,CAAC;AACvB,CAAC;AAED,2EAA2E;AAC3E,4EAA4E;AAC5E,sBAAsB;AACtB,MAAM,UAAU,mBAAmB,CAAC,QAAuB;IACzD,IAAI,QAAQ,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,4BAA4B,QAAQ,CAAC,IAAI,IAAI,QAAQ,CAAC,KAAK,8BAA8B,CAAC;IACnG,CAAC;IACD,OAAO,6CAA6C,CAAC;AACvD,CAAC"}
|
package/dist/search/reindex.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reindex.d.ts","sourceRoot":"","sources":["../../src/search/reindex.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reindex.d.ts","sourceRoot":"","sources":["../../src/search/reindex.ts"],"names":[],"mappings":"AAaA,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAyE/D,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CActE;AAED,MAAM,WAAW,aAAa;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAI7B,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACpD;AA4FD,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC,CA0CvC;AAED,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;CACxB;AAQD,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC,CAqE7C"}
|
package/dist/search/reindex.js
CHANGED
|
@@ -8,12 +8,92 @@
|
|
|
8
8
|
// in fixed-size sub-batches so peak memory stays flat as the vault grows. If
|
|
9
9
|
// the model is unavailable the documents (and their BM25 tokens) still index;
|
|
10
10
|
// only the vector column is left NULL and vectorEnabled is false.
|
|
11
|
+
import { stat } from "node:fs/promises";
|
|
11
12
|
import { parseDocument } from "../frontmatter/parser.js";
|
|
12
13
|
import { err, ok } from "../frontmatter/types.js";
|
|
13
|
-
import { clearIndex, deleteDocument, documentCount, insertChunk, insertDocument, openIndexDb, setMeta, } from "../storage/index-db.js";
|
|
14
|
+
import { clearIndex, deleteDocument, documentCount, getMeta, insertChunk, insertDocument, openIndexDb, setMeta, } from "../storage/index-db.js";
|
|
14
15
|
import { listFiles, readFile, resolveVaultPath } from "../storage/local.js";
|
|
15
16
|
import { tokenize } from "./bm25.js";
|
|
16
17
|
import { chunkText, EMBEDDING_DIM, embed } from "./vector.js";
|
|
18
|
+
// Manifest key in the meta table: JSON object mapping vault-relative path to
|
|
19
|
+
// mtime in ms. Written at the end of a successful reindex and updated by
|
|
20
|
+
// indexDocument after each incremental write, so a startup freshness check
|
|
21
|
+
// can decide whether the persisted index already reflects the files on disk.
|
|
22
|
+
const MANIFEST_META_KEY = "vault_manifest";
|
|
23
|
+
// Walks the vault and produces a fresh path→mtimeMs map. Returns null if any
|
|
24
|
+
// file cannot be stat'd or the file listing fails — caller treats null as
|
|
25
|
+
// "can't prove freshness, fall back to a full reindex."
|
|
26
|
+
async function buildManifest(vaultRoot) {
|
|
27
|
+
const list = await listFiles(vaultRoot);
|
|
28
|
+
if (!list.ok)
|
|
29
|
+
return null;
|
|
30
|
+
const manifest = {};
|
|
31
|
+
for (const relPath of list.value) {
|
|
32
|
+
const resolved = resolveVaultPath(vaultRoot, relPath);
|
|
33
|
+
if (!resolved.ok)
|
|
34
|
+
return null;
|
|
35
|
+
try {
|
|
36
|
+
const st = await stat(resolved.value);
|
|
37
|
+
manifest[relPath] = st.mtimeMs;
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return manifest;
|
|
44
|
+
}
|
|
45
|
+
function readManifest(db) {
|
|
46
|
+
const raw = getMeta(db, MANIFEST_META_KEY);
|
|
47
|
+
if (!raw)
|
|
48
|
+
return null;
|
|
49
|
+
try {
|
|
50
|
+
const parsed = JSON.parse(raw);
|
|
51
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
52
|
+
return null;
|
|
53
|
+
return parsed;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function writeManifest(db, manifest) {
|
|
60
|
+
setMeta(db, MANIFEST_META_KEY, JSON.stringify(manifest));
|
|
61
|
+
}
|
|
62
|
+
function manifestsMatch(a, b) {
|
|
63
|
+
const aKeys = Object.keys(a);
|
|
64
|
+
const bKeys = Object.keys(b);
|
|
65
|
+
if (aKeys.length !== bKeys.length)
|
|
66
|
+
return false;
|
|
67
|
+
for (const key of aKeys) {
|
|
68
|
+
if (a[key] !== b[key])
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
// Returns true when the persisted index already reflects every markdown file
|
|
74
|
+
// on disk: doc count is non-zero, a manifest exists, and every file's mtime
|
|
75
|
+
// matches the stored value. Used by `main()` to skip a 20+ minute re-embed
|
|
76
|
+
// pass on every restart of a vault that hasn't changed.
|
|
77
|
+
export async function isIndexFresh(vaultRoot) {
|
|
78
|
+
const dbResult = openIndexDb(vaultRoot);
|
|
79
|
+
if (!dbResult.ok)
|
|
80
|
+
return false;
|
|
81
|
+
const db = dbResult.value;
|
|
82
|
+
try {
|
|
83
|
+
if (documentCount(db) === 0)
|
|
84
|
+
return false;
|
|
85
|
+
const stored = readManifest(db);
|
|
86
|
+
if (!stored)
|
|
87
|
+
return false;
|
|
88
|
+
const current = await buildManifest(vaultRoot);
|
|
89
|
+
if (!current)
|
|
90
|
+
return false;
|
|
91
|
+
return manifestsMatch(stored, current);
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
db.close();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
17
97
|
// Reads and parses a single markdown file into the shape the index needs.
|
|
18
98
|
// Returns null when the file should be skipped (unreadable, or malformed YAML
|
|
19
99
|
// frontmatter) so a reindex never aborts on one bad file.
|
|
@@ -115,6 +195,11 @@ export async function reindexVault(vaultRoot, opts = {}) {
|
|
|
115
195
|
setMeta(db, "indexed_at", indexedAt);
|
|
116
196
|
setMeta(db, "vector_enabled", String(vectorEnabled));
|
|
117
197
|
setMeta(db, "embedding_dim", String(EMBEDDING_DIM));
|
|
198
|
+
// Persist a freshness manifest so the next startup can skip this whole
|
|
199
|
+
// pass when nothing on disk has changed.
|
|
200
|
+
const manifest = await buildManifest(vaultRoot);
|
|
201
|
+
if (manifest)
|
|
202
|
+
writeManifest(db, manifest);
|
|
118
203
|
return ok({
|
|
119
204
|
documentCount: staged.length,
|
|
120
205
|
chunkCount,
|
|
@@ -180,6 +265,25 @@ export async function indexDocument(vaultRoot, relPath) {
|
|
|
180
265
|
});
|
|
181
266
|
});
|
|
182
267
|
write();
|
|
268
|
+
// Keep the freshness manifest in sync with this single write so the next
|
|
269
|
+
// startup still sees a current index. Stat the file we just indexed and
|
|
270
|
+
// patch only its entry — re-statting the whole vault would defeat the
|
|
271
|
+
// point of the incremental path.
|
|
272
|
+
const stored = readManifest(db);
|
|
273
|
+
if (stored) {
|
|
274
|
+
const resolved = resolveVaultPath(vaultRoot, relPath);
|
|
275
|
+
if (resolved.ok) {
|
|
276
|
+
try {
|
|
277
|
+
const st = await stat(resolved.value);
|
|
278
|
+
stored[relPath] = st.mtimeMs;
|
|
279
|
+
writeManifest(db, stored);
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
// ignore — manifest just stays stale for this entry; worst case is
|
|
283
|
+
// one extra reindex on next startup.
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
183
287
|
return ok({ chunkCount: chunks.length, vectorEnabled });
|
|
184
288
|
}
|
|
185
289
|
catch (e) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reindex.js","sourceRoot":"","sources":["../../src/search/reindex.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,EAAE;AACF,2EAA2E;AAC3E,2EAA2E;AAC3E,6EAA6E;AAC7E,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,8EAA8E;AAC9E,kEAAkE;AAElE,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,GAAG,EAAE,EAAE,EAAe,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EACL,UAAU,EACV,cAAc,EACd,aAAa,
|
|
1
|
+
{"version":3,"file":"reindex.js","sourceRoot":"","sources":["../../src/search/reindex.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,aAAa,EAAW,MAAM,mBAAmB,CAAC;AAChE,OAAO,
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,aAAa,EAAW,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAW,KAAK,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAEL,KAAK,kBAAkB,EAGvB,KAAK,mBAAmB,EAEzB,MAAM,qBAAqB,CAAC;AAQ7B,OAAO,EAAE,KAAK,aAAa,EAAgB,MAAM,sBAAsB,CAAC;AAExE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAkEhD,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC,CA2B5C;AAMD,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC,CA2B7C;AAMD,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD,KAAK,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,KAAK,CAAC,CAAC,CAahG;AAgBD,eAAO,MAAM,WAAW,EAAE,cAAc,EA2DvC,CAAC"}
|
package/dist/tools/search.js
CHANGED
|
@@ -6,22 +6,43 @@
|
|
|
6
6
|
// it. If the index is empty (first run after a fresh clone) they trigger a
|
|
7
7
|
// reindex first, so search works without an explicit setup step.
|
|
8
8
|
import { canRead } from "../access/rbac.js";
|
|
9
|
-
import { ok } from "../frontmatter/types.js";
|
|
9
|
+
import { err, ok } from "../frontmatter/types.js";
|
|
10
10
|
import { DEFAULT_WEIGHTS, hybridSearch, relatedSearch, } from "../search/hybrid.js";
|
|
11
|
+
import { getIndexStatus, indexingBusyMessage, markIndexError, markIndexing, markIndexReady, } from "../search/index-state.js";
|
|
11
12
|
import { reindexVault } from "../search/reindex.js";
|
|
12
13
|
import { documentCount, openIndexDb } from "../storage/index-db.js";
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
|
|
14
|
+
// Gate every index-backed tool on the current indexing state.
|
|
15
|
+
//
|
|
16
|
+
// - "indexing": refuse with a progress-bearing message. The server is still
|
|
17
|
+
// embedding the vault from cold; the client should retry shortly.
|
|
18
|
+
// - "error": refuse with the prior failure so the client sees a real
|
|
19
|
+
// diagnostic instead of an empty / partial result set.
|
|
20
|
+
// - "ready": fall through to the per-tool logic, with one fallback: if
|
|
21
|
+
// the SQLite index is empty (a direct test invocation that never went
|
|
22
|
+
// through main(), or a vault whose .daftari directory was wiped) trigger
|
|
23
|
+
// a synchronous reindex so search still works without an explicit
|
|
24
|
+
// --reindex step.
|
|
25
|
+
async function ensureIndexReady(vaultRoot) {
|
|
26
|
+
const status = getIndexStatus();
|
|
27
|
+
if (status.status === "indexing") {
|
|
28
|
+
return err(new Error(indexingBusyMessage(status)));
|
|
29
|
+
}
|
|
30
|
+
if (status.status === "error") {
|
|
31
|
+
return err(new Error(`vault index is in error state: ${status.error ?? "unknown"}`));
|
|
32
|
+
}
|
|
16
33
|
const dbResult = openIndexDb(vaultRoot);
|
|
17
34
|
if (!dbResult.ok)
|
|
18
35
|
return dbResult;
|
|
19
36
|
const empty = documentCount(dbResult.value) === 0;
|
|
20
37
|
dbResult.value.close();
|
|
21
38
|
if (empty) {
|
|
39
|
+
markIndexing();
|
|
22
40
|
const reindexed = await reindexVault(vaultRoot);
|
|
23
|
-
if (!reindexed.ok)
|
|
41
|
+
if (!reindexed.ok) {
|
|
42
|
+
markIndexError(reindexed.error.message);
|
|
24
43
|
return reindexed;
|
|
44
|
+
}
|
|
45
|
+
markIndexReady();
|
|
25
46
|
}
|
|
26
47
|
return ok(undefined);
|
|
27
48
|
}
|
|
@@ -57,7 +78,7 @@ export async function vaultSearch(vaultRoot, args, access) {
|
|
|
57
78
|
error: new Error("vault_search requires a non-empty 'query' argument"),
|
|
58
79
|
};
|
|
59
80
|
}
|
|
60
|
-
const ready = await
|
|
81
|
+
const ready = await ensureIndexReady(vaultRoot);
|
|
61
82
|
if (!ready.ok)
|
|
62
83
|
return ready;
|
|
63
84
|
const dbResult = openIndexDb(vaultRoot);
|
|
@@ -90,7 +111,7 @@ export async function vaultSearchRelated(vaultRoot, args, access) {
|
|
|
90
111
|
error: new Error("vault_search_related requires a non-empty 'path' argument"),
|
|
91
112
|
};
|
|
92
113
|
}
|
|
93
|
-
const ready = await
|
|
114
|
+
const ready = await ensureIndexReady(vaultRoot);
|
|
94
115
|
if (!ready.ok)
|
|
95
116
|
return ready;
|
|
96
117
|
const dbResult = openIndexDb(vaultRoot);
|
|
@@ -113,9 +134,17 @@ export async function vaultSearchRelated(vaultRoot, args, access) {
|
|
|
113
134
|
}
|
|
114
135
|
}
|
|
115
136
|
export async function vaultReindex(vaultRoot) {
|
|
137
|
+
const status = getIndexStatus();
|
|
138
|
+
if (status.status === "indexing") {
|
|
139
|
+
return err(new Error(indexingBusyMessage(status)));
|
|
140
|
+
}
|
|
141
|
+
markIndexing();
|
|
116
142
|
const result = await reindexVault(vaultRoot);
|
|
117
|
-
if (!result.ok)
|
|
143
|
+
if (!result.ok) {
|
|
144
|
+
markIndexError(result.error.message);
|
|
118
145
|
return result;
|
|
146
|
+
}
|
|
147
|
+
markIndexReady();
|
|
119
148
|
return ok({ ...result.value, vault: vaultRoot });
|
|
120
149
|
}
|
|
121
150
|
// ---------------------------------------------------------------------------
|
package/dist/tools/search.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,EAAE;AACF,wEAAwE;AACxE,4EAA4E;AAC5E,+EAA+E;AAC/E,2EAA2E;AAC3E,iEAAiE;AAEjE,OAAO,EAAsB,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,EAAE,EAAe,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,KAAK,aAAa,EAAwB,MAAM,mBAAmB,CAAC;AAI7E,OAAO,EAIL,KAAK,WAAW,EAEhB,KAAK,MAAM,EAEX,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/tools/write.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,KAAK,aAAa,EAAwB,MAAM,mBAAmB,CAAC;AAI7E,OAAO,EAIL,KAAK,WAAW,EAEhB,KAAK,MAAM,EAEX,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AAOjC,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAqDhD,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,UAAU,EAAE,eAAe,EAAE,GAC5B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASzB;AAMD,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,WAAW,EACf,IAAI,EAAE,MAAM,EACZ,UAAU,GAAE,eAAe,EAAO,EAClC,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAChC,MAAM,CAuBR;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC;IAGjE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,YAAY,EAAE,OAAO,CAAC;CACvB;AAsJD,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAgIrC;AAQD,wBAAsB,WAAW,CAC/B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CA4FrC;AASD,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CA2ErC;AASD,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,CAAC,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAuErC;AAuBD,eAAO,MAAM,UAAU,EAAE,cAAc,EAuGtC,CAAC"}
|
package/dist/tools/write.js
CHANGED
|
@@ -16,8 +16,9 @@ import { frontmatterDiff, recordProvenance } from "../curation/provenance.js";
|
|
|
16
16
|
import { parseDocument } from "../frontmatter/parser.js";
|
|
17
17
|
import { validateFrontmatter } from "../frontmatter/schema.js";
|
|
18
18
|
import { CONFIDENCES, err, ok, } from "../frontmatter/types.js";
|
|
19
|
-
import { loadHooks } from "../hooks/loader.js";
|
|
20
|
-
import { runPreWriteHooks } from "../hooks/runner.js";
|
|
19
|
+
import { loadHooks, loadPreWriteTransformHooks } from "../hooks/loader.js";
|
|
20
|
+
import { runPreWriteHooks, runPreWriteTransformHooks } from "../hooks/runner.js";
|
|
21
|
+
import { getIndexStatus, indexingBusyMessage } from "../search/index-state.js";
|
|
21
22
|
import { indexDocument } from "../search/reindex.js";
|
|
22
23
|
import { readFile, resolveVaultPath } from "../storage/local.js";
|
|
23
24
|
import { loadConfig } from "../utils/config.js";
|
|
@@ -29,6 +30,21 @@ import { sha256Hex } from "../utils/hash.js";
|
|
|
29
30
|
function todayISO() {
|
|
30
31
|
return new Date().toISOString().slice(0, 10);
|
|
31
32
|
}
|
|
33
|
+
// Refuses writes while the index is being (re)built. The write path ends in
|
|
34
|
+
// indexDocument(), which races with a concurrent reindexVault() — the reindex
|
|
35
|
+
// clears the index and re-inserts every document, so a write that lands in
|
|
36
|
+
// between can be wiped or land against a half-built index. Failing fast keeps
|
|
37
|
+
// hooks, locks, and git commits from running for a write we can't index yet.
|
|
38
|
+
function requireIndexReady() {
|
|
39
|
+
const status = getIndexStatus();
|
|
40
|
+
if (status.status === "indexing") {
|
|
41
|
+
return err(new Error(indexingBusyMessage(status)));
|
|
42
|
+
}
|
|
43
|
+
if (status.status === "error") {
|
|
44
|
+
return err(new Error(`vault index is in error state: ${status.error ?? "unknown"}`));
|
|
45
|
+
}
|
|
46
|
+
return ok(undefined);
|
|
47
|
+
}
|
|
32
48
|
// A document's RBAC collection: its frontmatter `collection`, falling back to
|
|
33
49
|
// the top-level directory of its vault-relative path.
|
|
34
50
|
function collectionOf(relPath, fm) {
|
|
@@ -208,6 +224,9 @@ function readBaseVersion(args, tool) {
|
|
|
208
224
|
// the full frontmatter; `updated` and `updated_by` are always stamped by the
|
|
209
225
|
// server, and `created` is preserved from the existing document on an update.
|
|
210
226
|
export async function vaultWrite(vaultRoot, args, access) {
|
|
227
|
+
const ready = requireIndexReady();
|
|
228
|
+
if (!ready.ok)
|
|
229
|
+
return ready;
|
|
211
230
|
const path = requireString(args, "path", "vault_write");
|
|
212
231
|
if (!path.ok)
|
|
213
232
|
return path;
|
|
@@ -248,6 +267,7 @@ export async function vaultWrite(vaultRoot, args, access) {
|
|
|
248
267
|
oldFrontmatter = parsed.value.frontmatter;
|
|
249
268
|
}
|
|
250
269
|
const isUpdate = oldFrontmatter !== null;
|
|
270
|
+
const hookOperation = isUpdate ? "update" : "create";
|
|
251
271
|
// Config-declared schema extensions participate in validation and
|
|
252
272
|
// serialization. A malformed config fails the write loudly, matching the
|
|
253
273
|
// server's loud-config contract.
|
|
@@ -255,6 +275,22 @@ export async function vaultWrite(vaultRoot, args, access) {
|
|
|
255
275
|
if (!config.ok)
|
|
256
276
|
return config;
|
|
257
277
|
const extensions = config.value.schemaExtensions;
|
|
278
|
+
// Pre-write transform hooks run BEFORE schema validation, so they can
|
|
279
|
+
// derive or override built-in frontmatter fields the validator would
|
|
280
|
+
// otherwise reject. Each returns a Partial<Frontmatter>; the runner merges
|
|
281
|
+
// them Object.assign-style (shallow, last-writer-wins) and the result is
|
|
282
|
+
// merged back into rawFrontmatter so validation, hooks, and serialization
|
|
283
|
+
// all see the transformed values. A transform throw or non-object return
|
|
284
|
+
// becomes a synthetic blocking issue. The loader fails loud, same as the
|
|
285
|
+
// pre_write loader.
|
|
286
|
+
const loadedTransformHooks = await loadPreWriteTransformHooks(vaultRoot, config.value.hooks.preWriteTransform);
|
|
287
|
+
if (!loadedTransformHooks.ok)
|
|
288
|
+
return loadedTransformHooks;
|
|
289
|
+
const transformResult = runPreWriteTransformHooks(loadedTransformHooks.value, rawFrontmatter, {
|
|
290
|
+
path: path.value,
|
|
291
|
+
operation: hookOperation,
|
|
292
|
+
});
|
|
293
|
+
Object.assign(rawFrontmatter, transformResult.merged);
|
|
258
294
|
const { frontmatter, report } = validateFrontmatter(rawFrontmatter, extensions);
|
|
259
295
|
// Pre-write hooks run after built-in schema validation has filled
|
|
260
296
|
// defaults. Their issues merge into the report and are treated the same
|
|
@@ -263,12 +299,15 @@ export async function vaultWrite(vaultRoot, args, access) {
|
|
|
263
299
|
const loadedHooks = await loadHooks(vaultRoot, config.value.hooks.preWrite);
|
|
264
300
|
if (!loadedHooks.ok)
|
|
265
301
|
return loadedHooks;
|
|
266
|
-
const hookOperation = isUpdate ? "update" : "create";
|
|
267
302
|
const hookIssues = runPreWriteHooks(loadedHooks.value, rawFrontmatter, {
|
|
268
303
|
path: path.value,
|
|
269
304
|
operation: hookOperation,
|
|
270
305
|
});
|
|
271
|
-
const mergedIssues = [
|
|
306
|
+
const mergedIssues = [
|
|
307
|
+
...transformResult.issues,
|
|
308
|
+
...report.issues,
|
|
309
|
+
...hookIssues,
|
|
310
|
+
];
|
|
272
311
|
const mergedReport = {
|
|
273
312
|
valid: mergedIssues.length === 0,
|
|
274
313
|
issues: mergedIssues,
|
|
@@ -305,6 +344,9 @@ export async function vaultWrite(vaultRoot, args, access) {
|
|
|
305
344
|
// Appends a markdown section to an existing document's body, leaving the
|
|
306
345
|
// frontmatter intact apart from the stamped `updated` / `updated_by` fields.
|
|
307
346
|
export async function vaultAppend(vaultRoot, args, access) {
|
|
347
|
+
const ready = requireIndexReady();
|
|
348
|
+
if (!ready.ok)
|
|
349
|
+
return ready;
|
|
308
350
|
const path = requireString(args, "path", "vault_append");
|
|
309
351
|
if (!path.ok)
|
|
310
352
|
return path;
|
|
@@ -345,15 +387,25 @@ export async function vaultAppend(vaultRoot, args, access) {
|
|
|
345
387
|
updated_by: agent.value,
|
|
346
388
|
};
|
|
347
389
|
const newBody = `${parsed.value.content.replace(/\s+$/, "")}\n\n${section.value.trim()}\n`;
|
|
348
|
-
// Pre-write hooks
|
|
349
|
-
//
|
|
350
|
-
//
|
|
390
|
+
// Pre-write transform hooks run before the pre_write validators; their
|
|
391
|
+
// Partial<Frontmatter> patch is merged Object.assign-style into the
|
|
392
|
+
// post-stamp frontmatter so the validators below see the transformed
|
|
393
|
+
// values. A transform throw or non-object return blocks the append.
|
|
394
|
+
const loadedTransformHooks = await loadPreWriteTransformHooks(vaultRoot, config.value.hooks.preWriteTransform);
|
|
395
|
+
if (!loadedTransformHooks.ok)
|
|
396
|
+
return loadedTransformHooks;
|
|
397
|
+
const transformResult = runPreWriteTransformHooks(loadedTransformHooks.value, newFrontmatter, { path: path.value, operation: "append" });
|
|
398
|
+
Object.assign(newFrontmatter, transformResult.merged);
|
|
399
|
+
// Pre-write hooks see the post-stamp, post-transform frontmatter (the same
|
|
400
|
+
// shape a subsequent vault_read would return). Issues block the append,
|
|
401
|
+
// same as for vault_write.
|
|
351
402
|
const loadedHooks = await loadHooks(vaultRoot, config.value.hooks.preWrite);
|
|
352
403
|
if (!loadedHooks.ok)
|
|
353
404
|
return loadedHooks;
|
|
354
405
|
const hookIssues = runPreWriteHooks(loadedHooks.value, newFrontmatter, { path: path.value, operation: "append" });
|
|
355
|
-
|
|
356
|
-
|
|
406
|
+
const appendIssues = [...transformResult.issues, ...hookIssues];
|
|
407
|
+
if (appendIssues.length > 0) {
|
|
408
|
+
const summary = appendIssues.map((i) => `${i.field}: ${i.message}`).join("; ");
|
|
357
409
|
return err(new Error(`invalid frontmatter: ${summary}`));
|
|
358
410
|
}
|
|
359
411
|
return performWrite({
|
|
@@ -379,6 +431,9 @@ export async function vaultAppend(vaultRoot, args, access) {
|
|
|
379
431
|
// reachable through this tool, and it refuses unless the document's
|
|
380
432
|
// frontmatter is complete and a confidence level has been explicitly set.
|
|
381
433
|
export async function vaultPromote(vaultRoot, args, access) {
|
|
434
|
+
const ready = requireIndexReady();
|
|
435
|
+
if (!ready.ok)
|
|
436
|
+
return ready;
|
|
382
437
|
const path = requireString(args, "path", "vault_promote");
|
|
383
438
|
if (!path.ok)
|
|
384
439
|
return path;
|
|
@@ -452,6 +507,9 @@ export async function vaultPromote(vaultRoot, args, access) {
|
|
|
452
507
|
// commit message; an optional `superseded_by` points at the document that
|
|
453
508
|
// replaces this one.
|
|
454
509
|
export async function vaultDeprecate(vaultRoot, args, access) {
|
|
510
|
+
const ready = requireIndexReady();
|
|
511
|
+
if (!ready.ok)
|
|
512
|
+
return ready;
|
|
455
513
|
const path = requireString(args, "path", "vault_deprecate");
|
|
456
514
|
if (!path.ok)
|
|
457
515
|
return path;
|