@owrede/vault-memory 2.2.0 → 2.3.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/CHANGELOG.md +40 -0
- package/README.md +4 -2
- package/dist/cli.js +219 -25
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,46 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
14
14
|
|
|
15
15
|
_Nothing yet._
|
|
16
16
|
|
|
17
|
+
## [2.3.0] — 2026-07-01
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **Datacore/Dataview rendered indexing — foundation** (ADR-033). Phase 1 strips
|
|
22
|
+
Datacore/Dataview query source from indexed text so raw query blocks no longer
|
|
23
|
+
pollute search (`src/reader/datacore.ts`). Phase 2 adds migration 016
|
|
24
|
+
(`notes.rendered_source_hash`) as the schema foundation for indexing rendered
|
|
25
|
+
content supplied by the Obsidian plugin. _Note: later phases of ADR-033 are not
|
|
26
|
+
yet complete; this release ships the foundation only._
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- **Incremental full-vault indexer now re-indexes changed notes** (#14). `indexVault`
|
|
31
|
+
in `incremental` mode decided whether to re-index from chunk count alone, so a note
|
|
32
|
+
whose body changed but already had chunks kept stale chunks/embeddings/sections/edges
|
|
33
|
+
while its `hash`/`content` were updated in place. The reindex decision now mirrors the
|
|
34
|
+
single-note indexer's three-way logic (hash-unchanged / frontmatter-only / body-changed),
|
|
35
|
+
and a latent foreign-key ordering bug (sections must be deleted before chunks) is fixed.
|
|
36
|
+
- **MCP server version is derived from `package.json`** (#14). `server.ts` hardcoded
|
|
37
|
+
`VERSION = "1.0.0"`, so the server advertised the wrong version and sink provisioning
|
|
38
|
+
stamped a stale sentinel. A new `src/version.ts` is the single source of truth.
|
|
39
|
+
- **Frontmatter long-string serialization** (#14). Long string values are written
|
|
40
|
+
single-line instead of being folded into a `>-` YAML block scalar that Obsidian's
|
|
41
|
+
Properties editor mishandles.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- **`engines.node` narrowed to `>=22 <26`** (#14). Node 26+ has no `better-sqlite3`
|
|
46
|
+
prebuild for the new ABI and building from source currently fails. README prerequisites
|
|
47
|
+
updated accordingly.
|
|
48
|
+
- **Release versions reconciled to 2.3.0** across `package.json`, `plugin/package.json`,
|
|
49
|
+
`plugin/manifest.json`, and README (#14).
|
|
50
|
+
|
|
51
|
+
## [2.2.1] — 2026-06-29
|
|
52
|
+
|
|
53
|
+
### Fixed
|
|
54
|
+
|
|
55
|
+
- **Section identity is now content + context, not content alone (ADR-032, migration 015).** Two byte-identical sibling sections in *different* contexts (e.g. `# Q1 > ## Risks "TBD"` and `# Q2 > ## Risks "TBD"`) previously collapsed into one row under `UNIQUE(note_id, anchor)` — silently dropping the second — because the content-hash anchor excludes the ancestor chain. Section identity is now `(note_id, heading_path, anchor)`, so differently-placed identical sections persist as distinct rows. `anchor` stays a pure content hash (ADR-003 H-7 and the D-05 `source_hashes` contract are unchanged); `search-sections` dedup widened to match. Migration 015 swaps the unique index; a verbatim block repeated under the *same* parent still collapses (one citation). Existing DBs reconcile on the next `index --full`.
|
|
56
|
+
|
|
17
57
|
## [2.2.0] — 2026-06-29
|
|
18
58
|
|
|
19
59
|
### Added
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Local-first, source-agnostic-ready agentic knowledge layer over your Obsidian notes,
|
|
4
4
|
exposed to any MCP-aware agent.**
|
|
5
5
|
|
|
6
|
-
> See [CHANGELOG.md](./CHANGELOG.md) for release history. Latest: **v2.
|
|
6
|
+
> See [CHANGELOG.md](./CHANGELOG.md) for release history. Latest: **v2.3.0** — additive
|
|
7
7
|
> over v1.x; the 23 v1 tool names + input schemas are preserved byte-identical.
|
|
8
8
|
|
|
9
9
|
## 30-second example
|
|
@@ -198,7 +198,9 @@ vault-memory supports two engines, selectable **per vault**:
|
|
|
198
198
|
|
|
199
199
|
### Prerequisites
|
|
200
200
|
|
|
201
|
-
- **Node.js
|
|
201
|
+
- **Node.js 22–25** (`>=22 <26`) — runtime for the MCP server (`brew install node@22`).
|
|
202
|
+
Node 26+ is not yet supported: the native `better-sqlite3` dependency has no
|
|
203
|
+
prebuild for the new ABI and building from source currently fails.
|
|
202
204
|
- One or more Obsidian vaults; an MCP-aware client.
|
|
203
205
|
- **Ollama engine only:** [Ollama](https://ollama.com) on `localhost:11434`
|
|
204
206
|
(`brew install ollama && brew services start ollama`) + the `bge-m3` model
|
package/dist/cli.js
CHANGED
|
@@ -1320,7 +1320,7 @@ function backfillSectionsFromChunks(db) {
|
|
|
1320
1320
|
@parent_id, @ord, @chunk_id_first, @chunk_id_last, @created_at)
|
|
1321
1321
|
`);
|
|
1322
1322
|
const lookupExistingSection = db.prepare(
|
|
1323
|
-
"SELECT id FROM sections WHERE note_id = ? AND anchor = ?"
|
|
1323
|
+
"SELECT id FROM sections WHERE note_id = ? AND heading_path = ? AND anchor = ?"
|
|
1324
1324
|
);
|
|
1325
1325
|
let backfilled = 0;
|
|
1326
1326
|
const now = Date.now();
|
|
@@ -1356,7 +1356,11 @@ function backfillSectionsFromChunks(db) {
|
|
|
1356
1356
|
if (info.changes > 0) {
|
|
1357
1357
|
insertedIds.push(Number(info.lastInsertRowid));
|
|
1358
1358
|
} else {
|
|
1359
|
-
const existing2 = lookupExistingSection.get(
|
|
1359
|
+
const existing2 = lookupExistingSection.get(
|
|
1360
|
+
note.id,
|
|
1361
|
+
JSON.stringify(s.heading_path),
|
|
1362
|
+
s.anchor
|
|
1363
|
+
);
|
|
1360
1364
|
insertedIds.push(existing2 ? Number(existing2.id) : null);
|
|
1361
1365
|
}
|
|
1362
1366
|
}
|
|
@@ -1688,6 +1692,17 @@ function runMigration014(db, _ctx) {
|
|
|
1688
1692
|
ON contract_audit(verb);
|
|
1689
1693
|
`);
|
|
1690
1694
|
}
|
|
1695
|
+
function runMigration015(db, _ctx) {
|
|
1696
|
+
db.exec(
|
|
1697
|
+
"DROP INDEX IF EXISTS sections_note_anchor; CREATE UNIQUE INDEX IF NOT EXISTS sections_note_headingpath_anchor ON sections(note_id, heading_path, anchor);"
|
|
1698
|
+
);
|
|
1699
|
+
}
|
|
1700
|
+
function runMigration016(db, _ctx) {
|
|
1701
|
+
const cols = db.prepare("PRAGMA table_info(notes)").all();
|
|
1702
|
+
if (!cols.some((c) => c.name === "rendered_source_hash")) {
|
|
1703
|
+
db.exec("ALTER TABLE notes ADD COLUMN rendered_source_hash TEXT");
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1691
1706
|
var INITIAL_SCHEMA, MIGRATION_002_ALIASES, MIGRATION_003_FIX_DELETE_FKS, MIGRATION_004_VARIABLE_DIMS, MIGRATION_006_BODY_HASH, MIGRATION_007_DOC_URI_ADD, MIGRATIONS;
|
|
1692
1707
|
var init_schema = __esm({
|
|
1693
1708
|
"src/db/schema.ts"() {
|
|
@@ -1963,6 +1978,16 @@ CREATE INDEX IF NOT EXISTS idx_notes_doc_uri ON notes(doc_uri);
|
|
|
1963
1978
|
version: 14,
|
|
1964
1979
|
description: "contract_audit table \u2014 Phase 6 / CON-* / Q-AUD",
|
|
1965
1980
|
run: runMigration014
|
|
1981
|
+
},
|
|
1982
|
+
{
|
|
1983
|
+
version: 15,
|
|
1984
|
+
description: "section identity = (note_id, heading_path, anchor) \u2014 context-aware, no longer collapse byte-identical siblings in different contexts (ADR-032 revised)",
|
|
1985
|
+
run: runMigration015
|
|
1986
|
+
},
|
|
1987
|
+
{
|
|
1988
|
+
version: 16,
|
|
1989
|
+
description: "notes.rendered_source_hash \u2014 overlay marker for plugin-rendered Datacore content (ADR-033)",
|
|
1990
|
+
run: runMigration016
|
|
1966
1991
|
}
|
|
1967
1992
|
];
|
|
1968
1993
|
}
|
|
@@ -3067,6 +3092,9 @@ var init_sections = __esm({
|
|
|
3067
3092
|
this._getByAnchor = db.prepare(
|
|
3068
3093
|
"SELECT * FROM sections WHERE note_id = ? AND anchor = ?"
|
|
3069
3094
|
);
|
|
3095
|
+
this._getByIdentity = db.prepare(
|
|
3096
|
+
"SELECT * FROM sections WHERE note_id = ? AND heading_path = ? AND anchor = ?"
|
|
3097
|
+
);
|
|
3070
3098
|
this._findContainingChunk = db.prepare(
|
|
3071
3099
|
// `chunk_id` is monotonically increasing per note; chunk_id_first
|
|
3072
3100
|
// and chunk_id_last carve disjoint ranges (or both NULL for a
|
|
@@ -3090,6 +3118,7 @@ var init_sections = __esm({
|
|
|
3090
3118
|
_deleteByNote;
|
|
3091
3119
|
_getByNote;
|
|
3092
3120
|
_getByAnchor;
|
|
3121
|
+
_getByIdentity;
|
|
3093
3122
|
_findContainingChunk;
|
|
3094
3123
|
_countByNote;
|
|
3095
3124
|
/**
|
|
@@ -3122,14 +3151,15 @@ var init_sections = __esm({
|
|
|
3122
3151
|
return ids;
|
|
3123
3152
|
}
|
|
3124
3153
|
/**
|
|
3125
|
-
* Insert one section, collision-safe. Returns the id of the row that
|
|
3126
|
-
*
|
|
3127
|
-
* same-
|
|
3128
|
-
* row's id (so callers can resolve parent_id
|
|
3129
|
-
*
|
|
3130
|
-
*
|
|
3131
|
-
*
|
|
3132
|
-
*
|
|
3154
|
+
* Insert one section, collision-safe. Returns the id of the row that now
|
|
3155
|
+
* owns the identity (note_id, heading_path, anchor): the freshly inserted
|
|
3156
|
+
* row, or — when a same-context byte-identical sibling already won the
|
|
3157
|
+
* unique slot — that surviving row's id (so callers can resolve parent_id
|
|
3158
|
+
* linkage). Per ADR-032 (revised), a collision now requires BOTH same anchor
|
|
3159
|
+
* AND same heading_path, so differently-placed identical sections persist as
|
|
3160
|
+
* distinct rows. Mirrors src/sections/backfill.ts. The live indexer uses
|
|
3161
|
+
* this instead of `insertMany` so duplicate sibling headings can't abort the
|
|
3162
|
+
* whole index run (see ISSUE-indexer-duplicate-anchor.md).
|
|
3133
3163
|
*/
|
|
3134
3164
|
insertOneResolving(r) {
|
|
3135
3165
|
const info = this._insert.run({
|
|
@@ -3145,7 +3175,7 @@ var init_sections = __esm({
|
|
|
3145
3175
|
created_at: Date.now()
|
|
3146
3176
|
});
|
|
3147
3177
|
if (info.changes > 0) return Number(info.lastInsertRowid);
|
|
3148
|
-
const existing = this.
|
|
3178
|
+
const existing = this._getByIdentity.get(r.note_id, r.heading_path, r.anchor);
|
|
3149
3179
|
return existing ? Number(existing.id) : null;
|
|
3150
3180
|
}
|
|
3151
3181
|
deleteByNote(noteId) {
|
|
@@ -5873,6 +5903,73 @@ var init_wikilinks2 = __esm({
|
|
|
5873
5903
|
}
|
|
5874
5904
|
});
|
|
5875
5905
|
|
|
5906
|
+
// src/reader/datacore.ts
|
|
5907
|
+
function stripDynamicViewBlocks(body) {
|
|
5908
|
+
if (!body.includes("```") && !body.includes("~~~")) {
|
|
5909
|
+
return { content: body, replaced: 0 };
|
|
5910
|
+
}
|
|
5911
|
+
const lines = body.split("\n");
|
|
5912
|
+
const out = [];
|
|
5913
|
+
let replaced = 0;
|
|
5914
|
+
let i = 0;
|
|
5915
|
+
while (i < lines.length) {
|
|
5916
|
+
const line = lines[i];
|
|
5917
|
+
const open2 = FENCE_OPEN_RE.exec(line);
|
|
5918
|
+
if (open2) {
|
|
5919
|
+
const indent = open2[1] ?? "";
|
|
5920
|
+
const marker = open2[2] ?? "";
|
|
5921
|
+
const lang = (open2[3] ?? "").toLowerCase();
|
|
5922
|
+
const markerChar = marker[0];
|
|
5923
|
+
const isDynamic = DYNAMIC_VIEW_LANGS.has(lang);
|
|
5924
|
+
let j = i + 1;
|
|
5925
|
+
let closed = false;
|
|
5926
|
+
while (j < lines.length) {
|
|
5927
|
+
const close = FENCE_OPEN_RE.exec(lines[j]);
|
|
5928
|
+
if (close && (close[2] ?? "")[0] === markerChar && (close[2] ?? "").length >= marker.length && (close[3] ?? "") === "") {
|
|
5929
|
+
closed = true;
|
|
5930
|
+
break;
|
|
5931
|
+
}
|
|
5932
|
+
j++;
|
|
5933
|
+
}
|
|
5934
|
+
if (isDynamic) {
|
|
5935
|
+
out.push(`${indent}${DATACORE_PLACEHOLDER}`);
|
|
5936
|
+
replaced++;
|
|
5937
|
+
i = closed ? j + 1 : lines.length;
|
|
5938
|
+
} else {
|
|
5939
|
+
out.push(line);
|
|
5940
|
+
if (closed) {
|
|
5941
|
+
for (let k = i + 1; k <= j; k++) out.push(lines[k]);
|
|
5942
|
+
i = j + 1;
|
|
5943
|
+
} else {
|
|
5944
|
+
for (let k = i + 1; k < lines.length; k++) out.push(lines[k]);
|
|
5945
|
+
i = lines.length;
|
|
5946
|
+
}
|
|
5947
|
+
}
|
|
5948
|
+
} else {
|
|
5949
|
+
out.push(line);
|
|
5950
|
+
i++;
|
|
5951
|
+
}
|
|
5952
|
+
}
|
|
5953
|
+
if (replaced === 0) return { content: body, replaced: 0 };
|
|
5954
|
+
return { content: out.join("\n"), replaced };
|
|
5955
|
+
}
|
|
5956
|
+
var DYNAMIC_VIEW_LANGS, DATACORE_PLACEHOLDER, FENCE_OPEN_RE;
|
|
5957
|
+
var init_datacore = __esm({
|
|
5958
|
+
"src/reader/datacore.ts"() {
|
|
5959
|
+
"use strict";
|
|
5960
|
+
init_esm_shims();
|
|
5961
|
+
DYNAMIC_VIEW_LANGS = /* @__PURE__ */ new Set([
|
|
5962
|
+
"datacore",
|
|
5963
|
+
"datacorejsx",
|
|
5964
|
+
"datacorejs",
|
|
5965
|
+
"dataview",
|
|
5966
|
+
"dataviewjs"
|
|
5967
|
+
]);
|
|
5968
|
+
DATACORE_PLACEHOLDER = "[Datacore view]";
|
|
5969
|
+
FENCE_OPEN_RE = /^(\s*)(`{3,}|~{3,})\s*([A-Za-z0-9_-]*)\s*$/;
|
|
5970
|
+
}
|
|
5971
|
+
});
|
|
5972
|
+
|
|
5876
5973
|
// src/adapters/source/obsidian-fs/hash.ts
|
|
5877
5974
|
import { createHash as createHash3 } from "crypto";
|
|
5878
5975
|
function sha256(input) {
|
|
@@ -5925,9 +6022,11 @@ async function parseNote(absolutePath, vaultRoot) {
|
|
|
5925
6022
|
const wikilinks = frontmatterLinks.length === 0 ? bodyLinks : mergeFrontmatterIntoBody(bodyLinks, frontmatterLinks);
|
|
5926
6023
|
const wordCount = countWords2(content);
|
|
5927
6024
|
const relativePath = toPosix2(path3.relative(path3.resolve(vaultRoot), path3.resolve(absolutePath)));
|
|
6025
|
+
const indexedContent = stripDynamicViewBlocks(content).content;
|
|
5928
6026
|
return {
|
|
5929
6027
|
relativePath,
|
|
5930
6028
|
content,
|
|
6029
|
+
indexedContent,
|
|
5931
6030
|
frontmatter,
|
|
5932
6031
|
title,
|
|
5933
6032
|
hash,
|
|
@@ -5971,6 +6070,7 @@ var init_parser = __esm({
|
|
|
5971
6070
|
"use strict";
|
|
5972
6071
|
init_esm_shims();
|
|
5973
6072
|
init_wikilinks2();
|
|
6073
|
+
init_datacore();
|
|
5974
6074
|
init_hash();
|
|
5975
6075
|
}
|
|
5976
6076
|
});
|
|
@@ -6814,6 +6914,9 @@ async function indexVault(vault, options) {
|
|
|
6814
6914
|
log(` skipped (parse error): ${rel} \u2014 ${msg}`);
|
|
6815
6915
|
continue;
|
|
6816
6916
|
}
|
|
6917
|
+
const previous = vault.db.notes.getByPath(parsed.relativePath);
|
|
6918
|
+
const hashUnchanged = previous != null && previous.hash === parsed.hash;
|
|
6919
|
+
const bodyUnchanged = previous != null && previous.body_hash != null && previous.body_hash === parsed.bodyHash;
|
|
6817
6920
|
const upsert = vault.db.notes.upsertByPath({
|
|
6818
6921
|
path: parsed.relativePath,
|
|
6819
6922
|
content: parsed.content,
|
|
@@ -6826,24 +6929,28 @@ async function indexVault(vault, options) {
|
|
|
6826
6929
|
});
|
|
6827
6930
|
vault.db.notes.setStatus(upsert.id, extractStatus(parsed.frontmatter));
|
|
6828
6931
|
vault.db.aliases.setForNote(upsert.id, extractAliases(parsed.frontmatter));
|
|
6829
|
-
const noteExisted = !upsert.isNew;
|
|
6830
|
-
const existing = noteExisted ? vault.db.notes.getById(upsert.id) : null;
|
|
6831
6932
|
const chunkCount = vault.db.chunks.getByNote(upsert.id).length;
|
|
6832
|
-
const
|
|
6933
|
+
const bodyChanged = !hashUnchanged && !bodyUnchanged;
|
|
6934
|
+
const needsReindex = mode === "full" || upsert.isNew || chunkCount === 0 || bodyChanged;
|
|
6935
|
+
const frontmatterOnly = !upsert.isNew && !needsReindex && !hashUnchanged;
|
|
6833
6936
|
if (upsert.isNew) notesIndexed++;
|
|
6834
|
-
else if (needsReindex) notesUpdated++;
|
|
6937
|
+
else if (needsReindex || frontmatterOnly) notesUpdated++;
|
|
6835
6938
|
if (needsReindex) {
|
|
6836
6939
|
parsedNotes.push({ parsed, noteId: upsert.id, needsReindex: true });
|
|
6940
|
+
} else if (frontmatterOnly) {
|
|
6941
|
+
vault.db.wikilinks.deleteByNote(upsert.id);
|
|
6942
|
+
vault.db.edges.deleteByNote(upsert.id);
|
|
6943
|
+
insertWikilinks(vault, upsert.id, parsed.wikilinks, firstPassResolver);
|
|
6944
|
+
writeAllEdges(vault, upsert.id, parsed, firstPassResolver);
|
|
6837
6945
|
}
|
|
6838
|
-
void existing;
|
|
6839
6946
|
}
|
|
6840
6947
|
log(`${parsedNotes.length} notes need (re-)indexing`);
|
|
6841
6948
|
for (const { parsed, noteId } of parsedNotes) {
|
|
6949
|
+
vault.db.sections.deleteByNote(noteId);
|
|
6842
6950
|
vault.db.chunks.deleteByNote(noteId);
|
|
6843
6951
|
vault.db.wikilinks.deleteByNote(noteId);
|
|
6844
6952
|
vault.db.edges.deleteByNote(noteId);
|
|
6845
|
-
|
|
6846
|
-
const chunks = chunkNote(parsed.content);
|
|
6953
|
+
const chunks = chunkNote(parsed.indexedContent);
|
|
6847
6954
|
if (chunks.length === 0) {
|
|
6848
6955
|
insertWikilinks(vault, noteId, parsed.wikilinks, firstPassResolver);
|
|
6849
6956
|
writeAllEdges(vault, noteId, parsed, firstPassResolver);
|
|
@@ -6860,7 +6967,7 @@ async function indexVault(vault, options) {
|
|
|
6860
6967
|
}));
|
|
6861
6968
|
const chunkIds = vault.db.chunks.insertBatch(noteId, chunkInputs);
|
|
6862
6969
|
try {
|
|
6863
|
-
buildSectionsForNote(vault, noteId, parsed.
|
|
6970
|
+
buildSectionsForNote(vault, noteId, parsed.indexedContent, chunkIds);
|
|
6864
6971
|
} catch (err) {
|
|
6865
6972
|
const message = err instanceof Error ? err.message : String(err);
|
|
6866
6973
|
console.error(
|
|
@@ -7197,7 +7304,7 @@ async function indexNote(options) {
|
|
|
7197
7304
|
vault.db.chunks.deleteByNote(upsert.id);
|
|
7198
7305
|
vault.db.wikilinks.deleteByNote(upsert.id);
|
|
7199
7306
|
vault.db.edges.deleteByNote(upsert.id);
|
|
7200
|
-
const chunks = chunkNote(parsed.
|
|
7307
|
+
const chunks = chunkNote(parsed.indexedContent);
|
|
7201
7308
|
if (chunks.length === 0) {
|
|
7202
7309
|
insertWikilinks2(vault, upsert.id, parsed.wikilinks);
|
|
7203
7310
|
writeAllEdges2(vault, upsert.id, parsed);
|
|
@@ -7224,7 +7331,7 @@ async function indexNote(options) {
|
|
|
7224
7331
|
}))
|
|
7225
7332
|
);
|
|
7226
7333
|
try {
|
|
7227
|
-
buildSectionsForNote(vault, upsert.id, parsed.
|
|
7334
|
+
buildSectionsForNote(vault, upsert.id, parsed.indexedContent, chunkIds);
|
|
7228
7335
|
} catch (err) {
|
|
7229
7336
|
const message = err instanceof Error ? err.message : String(err);
|
|
7230
7337
|
process.stderr.write(
|
|
@@ -7829,7 +7936,8 @@ async function writeNote(input) {
|
|
|
7829
7936
|
};
|
|
7830
7937
|
}
|
|
7831
7938
|
}
|
|
7832
|
-
const
|
|
7939
|
+
const yamlDumpOptions = { lineWidth: -1 };
|
|
7940
|
+
const fileText = frontmatter !== null && Object.keys(frontmatter).length > 0 ? matter2.stringify(content, frontmatter, yamlDumpOptions) : content;
|
|
7833
7941
|
input.onBeforeFsWrite?.();
|
|
7834
7942
|
await atomicWriteFile(absPath, fileText);
|
|
7835
7943
|
const written = await readExistingFile(absPath);
|
|
@@ -10756,7 +10864,7 @@ async function searchSections(deps, args2) {
|
|
|
10756
10864
|
const resolution = deps.sectionForHit(hit.vault, hit.notePath, hit.chunkIdx);
|
|
10757
10865
|
if (!resolution) continue;
|
|
10758
10866
|
if (resolution.headingPath.length === 0) continue;
|
|
10759
|
-
const key = `${resolution.noteId}#${resolution.anchor}`;
|
|
10867
|
+
const key = `${resolution.noteId}#${resolution.headingPath.join("\0")}#${resolution.anchor}`;
|
|
10760
10868
|
const existing = sectionMap.get(key);
|
|
10761
10869
|
if (!existing) {
|
|
10762
10870
|
sectionMap.set(key, {
|
|
@@ -16119,6 +16227,92 @@ var init_contracts2 = __esm({
|
|
|
16119
16227
|
}
|
|
16120
16228
|
});
|
|
16121
16229
|
|
|
16230
|
+
// package.json
|
|
16231
|
+
var package_default;
|
|
16232
|
+
var init_package = __esm({
|
|
16233
|
+
"package.json"() {
|
|
16234
|
+
package_default = {
|
|
16235
|
+
name: "@owrede/vault-memory",
|
|
16236
|
+
version: "2.3.0",
|
|
16237
|
+
description: "Local-first semantic memory MCP server for Obsidian vaults",
|
|
16238
|
+
type: "module",
|
|
16239
|
+
license: "MIT",
|
|
16240
|
+
workspaces: [
|
|
16241
|
+
"plugin"
|
|
16242
|
+
],
|
|
16243
|
+
repository: {
|
|
16244
|
+
type: "git",
|
|
16245
|
+
url: "git+https://github.com/owrede/vault-memory.git"
|
|
16246
|
+
},
|
|
16247
|
+
bin: {
|
|
16248
|
+
"vault-memory": "dist/cli.js"
|
|
16249
|
+
},
|
|
16250
|
+
files: [
|
|
16251
|
+
"dist",
|
|
16252
|
+
"README.md",
|
|
16253
|
+
"LICENSE",
|
|
16254
|
+
"CHANGELOG.md"
|
|
16255
|
+
],
|
|
16256
|
+
engines: {
|
|
16257
|
+
node: ">=22 <26"
|
|
16258
|
+
},
|
|
16259
|
+
scripts: {
|
|
16260
|
+
build: "tsup",
|
|
16261
|
+
dev: "tsx watch src/cli.ts",
|
|
16262
|
+
start: "node dist/cli.js",
|
|
16263
|
+
test: "vitest run",
|
|
16264
|
+
"test:watch": "vitest",
|
|
16265
|
+
lint: "tsc --noEmit",
|
|
16266
|
+
"lint:adapters": "sh scripts/lint-adapters.sh",
|
|
16267
|
+
"lint:check": 'sh scripts/check-fixture-privacy.sh && sh scripts/lint-no-telemetry.sh && sh scripts/lint-adapters.sh && tsc --noEmit && prettier --check "src/**/*.ts"',
|
|
16268
|
+
format: 'prettier --write "src/**/*.ts"',
|
|
16269
|
+
"eval:baseline": "vitest run evals/v1-baseline/baseline.test.ts",
|
|
16270
|
+
"eval:snapshot": "node evals/v1-baseline/dump-tools.mjs > evals/v1-baseline/tools-list.snapshot.json && node evals/v1-baseline/dump-resources.mjs > evals/v1-baseline/resources-list.snapshot.json",
|
|
16271
|
+
"eval:smoketest": "npm run build && node scripts/smoketest-non-claude.mjs",
|
|
16272
|
+
release: "node scripts/release.mjs",
|
|
16273
|
+
"sync-marketplace": "node scripts/sync-marketplace.mjs"
|
|
16274
|
+
},
|
|
16275
|
+
dependencies: {
|
|
16276
|
+
"@huggingface/tokenizers": "^0.1.3",
|
|
16277
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
16278
|
+
"better-sqlite3": "^11.7.0",
|
|
16279
|
+
chokidar: "^4.0.1",
|
|
16280
|
+
"cross-spawn": "^7.0.6",
|
|
16281
|
+
graphology: "^0.26.0",
|
|
16282
|
+
"graphology-communities-louvain": "^2.0.2",
|
|
16283
|
+
"gray-matter": "^4.0.3",
|
|
16284
|
+
"onnxruntime-node": "^1.26.0",
|
|
16285
|
+
seedrandom: "^3.0.5",
|
|
16286
|
+
"smol-toml": "^1.3.1",
|
|
16287
|
+
"sqlite-vec": "^0.1.6",
|
|
16288
|
+
yaml: "^2.9.0",
|
|
16289
|
+
zod: "^4.4.3"
|
|
16290
|
+
},
|
|
16291
|
+
devDependencies: {
|
|
16292
|
+
"@types/better-sqlite3": "^7.6.12",
|
|
16293
|
+
"@types/node": "^22.10.0",
|
|
16294
|
+
"@types/seedrandom": "^3.0.8",
|
|
16295
|
+
prettier: "^3.4.0",
|
|
16296
|
+
tsup: "^8.3.5",
|
|
16297
|
+
tsx: "^4.19.2",
|
|
16298
|
+
typescript: "^5.7.0",
|
|
16299
|
+
vitest: "^2.1.8"
|
|
16300
|
+
}
|
|
16301
|
+
};
|
|
16302
|
+
}
|
|
16303
|
+
});
|
|
16304
|
+
|
|
16305
|
+
// src/version.ts
|
|
16306
|
+
var VERSION;
|
|
16307
|
+
var init_version = __esm({
|
|
16308
|
+
"src/version.ts"() {
|
|
16309
|
+
"use strict";
|
|
16310
|
+
init_esm_shims();
|
|
16311
|
+
init_package();
|
|
16312
|
+
VERSION = package_default.version;
|
|
16313
|
+
}
|
|
16314
|
+
});
|
|
16315
|
+
|
|
16122
16316
|
// src/server.ts
|
|
16123
16317
|
var server_exports = {};
|
|
16124
16318
|
__export(server_exports, {
|
|
@@ -17200,7 +17394,7 @@ async function serve(options = {}) {
|
|
|
17200
17394
|
`);
|
|
17201
17395
|
});
|
|
17202
17396
|
}
|
|
17203
|
-
var
|
|
17397
|
+
var MEMORY_AUTO_DISCOVERY_FOLDER;
|
|
17204
17398
|
var init_server = __esm({
|
|
17205
17399
|
"src/server.ts"() {
|
|
17206
17400
|
"use strict";
|
|
@@ -17239,7 +17433,7 @@ var init_server = __esm({
|
|
|
17239
17433
|
init_brief2();
|
|
17240
17434
|
init_assembly2();
|
|
17241
17435
|
init_contracts2();
|
|
17242
|
-
|
|
17436
|
+
init_version();
|
|
17243
17437
|
MEMORY_AUTO_DISCOVERY_FOLDER = "_memory";
|
|
17244
17438
|
}
|
|
17245
17439
|
});
|