@oomkapwn/enquire-mcp 0.7.4
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 +334 -0
- package/LICENSE +21 -0
- package/README.md +358 -0
- package/SECURITY.md +49 -0
- package/assets/social-preview.png +0 -0
- package/dist/dql.d.ts +37 -0
- package/dist/dql.d.ts.map +1 -0
- package/dist/dql.js +342 -0
- package/dist/dql.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +470 -0
- package/dist/index.js.map +1 -0
- package/dist/parser.d.ts +21 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +107 -0
- package/dist/parser.js.map +1 -0
- package/dist/tools.d.ts +143 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +445 -0
- package/dist/tools.js.map +1 -0
- package/dist/vault.d.ts +72 -0
- package/dist/vault.d.ts.map +1 -0
- package/dist/vault.js +424 -0
- package/dist/vault.js.map +1 -0
- package/docs/api.md +262 -0
- package/package.json +82 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
4
|
+
|
|
5
|
+
## [0.7.4] — 2026-05-03
|
|
6
|
+
|
|
7
|
+
Repeat-audit pass — five public-facing inconsistencies closed.
|
|
8
|
+
|
|
9
|
+
### Packaging
|
|
10
|
+
- Regenerated `package-lock.json`. The lockfile root still claimed `@oomkapwn/obsidian-mcp@0.4.0` with `node>=18` and bin `obsidian-mcp` — pre-rename identity. Now correctly reflects `@oomkapwn/enquire-mcp@0.7.4`, `node>=20`, bin `enquire-mcp`. No dependency-tree changes.
|
|
11
|
+
|
|
12
|
+
### Docs
|
|
13
|
+
- README "Support the project" links now use absolute GitHub URLs (`https://github.com/oomkapwn/enquire-mcp/issues/new?template=...`) instead of relative `./.github/...` paths that would 404 when the README is rendered on npmjs.com.
|
|
14
|
+
- `docs/api.md` "Phase 3 (planned)" section renamed to "Roadmap" and rewritten — it claimed persistent cache and write tools were future work, but both shipped in v0.6.0 / v0.3.0 respectively. Now lists actual remaining items (cross-vault index, full DQL, rename/move tools, graph queries).
|
|
15
|
+
- `.github/ISSUE_TEMPLATE/bug_report.yml` version placeholder bumped from `0.7.1` to neutral `0.7.x` so it doesn't drift again next release.
|
|
16
|
+
- Social preview banner updated: `137 tests` → `140 tests`. Both SVG and rendered PNG refreshed.
|
|
17
|
+
|
|
18
|
+
### Security
|
|
19
|
+
- **P1 — Symlink-overwrite via `obsidian_create_note` with `overwrite=true`**: if a path inside the vault was a symlink whose target lived outside the vault, `fs.writeFile(abs, ...)` followed the link and overwrote the outside file. The existing `assertParentInsideVault` only protected parent directories; the leaf target was unchecked. Fix: `writeNote` now `lstat`s the target before writing and refuses if it's a symlink. The `overwrite=false` path was unaffected (a dangling symlink-to-missing-target presents as `not exists` to `fs.stat`, but `lstat` catches it explicitly). Regression test added.
|
|
20
|
+
|
|
21
|
+
### Packaging
|
|
22
|
+
- Added `assets/social-preview.png` to the `files` list in `package.json`. Without it, the README hero image rendered broken on npmjs.com — the file was referenced but not shipped. Tarball grew from ~58 kB → ~214 kB (the PNG is 159 kB).
|
|
23
|
+
|
|
24
|
+
### Repo hygiene
|
|
25
|
+
- Added `.claude/` to `.gitignore`.
|
|
26
|
+
|
|
27
|
+
### Tests
|
|
28
|
+
- 140 unit tests (was 139).
|
|
29
|
+
|
|
30
|
+
## [0.7.2] — 2026-05-03
|
|
31
|
+
|
|
32
|
+
### Security
|
|
33
|
+
- **P1 — Cache pollution via path traversal**: a crafted persistent-cache file with a `relPath` like `../../../etc/hosts` could pollute the in-memory cache with content keyed by paths outside the vault root. The orphaned entry was never *served* via tools (`resolveSafePath` blocks reads to out-of-vault paths), but it would persist back to the on-disk cache file on the next save, perpetuating the pollution. Fix: `loadDiskCache` now validates the resolved abs path stays inside the vault (relative-path check + `realpath` belt-and-braces). Two regression tests added (relative `../` traversal and absolute paths).
|
|
34
|
+
|
|
35
|
+
### MCP-spec correctness
|
|
36
|
+
- **Write tool annotations**: `obsidian_create_note` (which can overwrite irreversibly with `overwrite=true`) and `obsidian_append_to_note` (which mutates persistent state) were both annotated `destructiveHint: false`. Per MCP spec, `destructiveHint: true` is the right hint for tools that may make non-undoable changes. Updated. Read tools remain `destructiveHint` unset / `readOnlyHint: true`.
|
|
37
|
+
|
|
38
|
+
### Cleanup
|
|
39
|
+
- Dead conditional in `likeToRegex`: simplified `next === "*" || next === "\\" ? \`\\${next}\` : \`\\${next}\`` to its always-equal RHS. No behavior change.
|
|
40
|
+
- README coverage badge drifted from 83% → actual 82% lines (slight churn after persistent-cache code added). Refreshed badge and the per-percent breakdown.
|
|
41
|
+
|
|
42
|
+
### Docs
|
|
43
|
+
- README gains a "Support the project" section (star CTA + bug-report / feature-request / PR / Discussions pointers) and the ENQUIRE/Berners-Lee origin moved into the credits as a one-paragraph close.
|
|
44
|
+
|
|
45
|
+
### Tests
|
|
46
|
+
- 139 unit tests (was 137). 2 new regression tests for cache path-traversal (relative `..` escape and absolute path).
|
|
47
|
+
|
|
48
|
+
## [0.7.1] — 2026-05-03
|
|
49
|
+
|
|
50
|
+
**Second rename: `memex` → `enquire-mcp`.**
|
|
51
|
+
|
|
52
|
+
### Why a second rename
|
|
53
|
+
After v0.7.0 shipped under «memex», a deeper landscape audit revealed the `memex` namespace is even more contested than `obsidian-mcp`:
|
|
54
|
+
- **[WorldBrain Memex](https://github.com/WorldBrain/Memex)** — established browser extension with an explicit **memex-obsidian** plugin. Direct user-confusion risk.
|
|
55
|
+
- **[iamtouchskyer/memex](https://github.com/iamtouchskyer/memex)** (npm `@touchskyer/memex`) — Zettelkasten persistent memory for AI coding agents. Same client list (Claude Code / Cursor / Codex / Windsurf), same MCP positioning. Functionally near-identical.
|
|
56
|
+
- **[memex.tech](https://memex.tech/)** — commercial product with active MCP launch.
|
|
57
|
+
- **[memex.ai](https://memex.ai/)** — commercial brand.
|
|
58
|
+
- **[`memex-ai`](https://www.npmjs.com/package/memex-ai)** npm package: «Install the Memex AI MCP server for Claude Code and Claude Desktop». Tight collision.
|
|
59
|
+
- Plus `memex-md`, `@ai2070/memex`, `memex-cc`, `memex-vault` (Obsidian template), `memex-life/memex`, `memex-lab/memex`, etc.
|
|
60
|
+
|
|
61
|
+
We traded one crowded namespace for an even more crowded one. Time to commit to a name with a unique historical referent and minimal commercial collision.
|
|
62
|
+
|
|
63
|
+
### Why ENQUIRE
|
|
64
|
+
[**ENQUIRE**](https://en.wikipedia.org/wiki/ENQUIRE) is the program Tim Berners-Lee wrote at CERN in 1980 to track «the complex web of relationships between people, programs, machines and ideas». It was the **direct prototype of the World Wide Web** — cards with hyperlinked relationships, exactly the data model we expose to AI agents over MCP. Bush's memex was theoretical; ENQUIRE was real, working hypertext software. No commercial trademark holder. Available on npm with `-mcp` suffix and across all relevant places.
|
|
65
|
+
|
|
66
|
+
### Renamed
|
|
67
|
+
- npm package: `@oomkapwn/memex` → `@oomkapwn/enquire-mcp`
|
|
68
|
+
- CLI binary: `memex-mcp` → `enquire-mcp`
|
|
69
|
+
- GitHub repo: `oomkapwn/memex` → `oomkapwn/enquire-mcp`
|
|
70
|
+
- MCP server `name` reported in handshake: `memex` → `enquire`
|
|
71
|
+
- Boot stderr message: `memex <v> ready` → `enquire <v> ready`
|
|
72
|
+
- Default cache dir: `~/Library/Caches/memex/` → `~/Library/Caches/enquire/`
|
|
73
|
+
- Banner redesigned: «enquire» as brand, «MCP server for Obsidian vaults» subtitle in cyan, Berners-Lee tagline.
|
|
74
|
+
- README hero rewritten with the ENQUIRE narrative + Wikipedia link to ENQUIRE.
|
|
75
|
+
|
|
76
|
+
### Tool names: still unchanged
|
|
77
|
+
`obsidian_*` tool names (`obsidian_list_notes`, etc.) **remain `obsidian_`-prefixed** by design. The prefix tells the LLM what domain it's operating in.
|
|
78
|
+
|
|
79
|
+
### Disclaimer reaffirmed
|
|
80
|
+
README and SECURITY.md still carry the «Not affiliated with Obsidian.md» notice. Added clarification that the «enquire» name is a tribute to Berners-Lee's 1980 system, not a trademark claim.
|
|
81
|
+
|
|
82
|
+
### Tests
|
|
83
|
+
Still 137 unit tests, all green. No code changes — pure rename + docs.
|
|
84
|
+
|
|
85
|
+
## [0.7.0] — 2026-05-03
|
|
86
|
+
|
|
87
|
+
**First rename: `obsidian-mcp` → `memex`.**
|
|
88
|
+
|
|
89
|
+
### Why the rename
|
|
90
|
+
- The npm/GitHub `obsidian-mcp` namespace turned out to be crowded — at least 12 GitHub projects and 4 npm packages with overlapping names. We're indistinguishable in search.
|
|
91
|
+
- Trademark risk: `bitbonsai/mcpvault` was forced-renamed by Obsidian.md in March 2026, even though it didn't contain "obsidian" in the name. Anything with "obsidian" in the package name is exposed.
|
|
92
|
+
- The new name (`memex`) is a nod to Vannevar Bush's 1945 essay [As We May Think](https://en.wikipedia.org/wiki/Memex) — the original vision of a personal knowledge system. Resonates with the PKM / second-brain audience without leaning on Obsidian's brand.
|
|
93
|
+
- Obsidian-MCP discoverability is preserved via npm description, GitHub topics, README hero subtitle ("MCP server for Obsidian vaults"), and SVG banner — not via the package name.
|
|
94
|
+
|
|
95
|
+
### Renamed
|
|
96
|
+
- npm package: `@oomkapwn/obsidian-mcp` → `@oomkapwn/memex`
|
|
97
|
+
- CLI binary: `obsidian-mcp` → `memex-mcp`
|
|
98
|
+
- GitHub repo: `oomkapwn/obsidian-mcp` → `oomkapwn/memex`
|
|
99
|
+
- MCP server `name` reported in handshake: `obsidian-mcp` → `memex`
|
|
100
|
+
- Boot stderr message: `obsidian-mcp <v> ready` → `memex <v> ready`
|
|
101
|
+
- Default cache dir: `~/Library/Caches/obsidian-mcp/` → `~/Library/Caches/memex/`
|
|
102
|
+
|
|
103
|
+
### Tool names: unchanged
|
|
104
|
+
All `obsidian_*` tool names (`obsidian_list_notes`, `obsidian_read_note`, etc.) **remain `obsidian_`-prefixed** by design. The prefix tells the LLM what domain it's operating in. We are an MCP server that operates on Obsidian vaults; the tools should advertise that.
|
|
105
|
+
|
|
106
|
+
### Disclaimer added
|
|
107
|
+
Explicit "Not affiliated with Obsidian.md" notice in README and SECURITY.md. Obsidian and the Obsidian logo are trademarks of Dynalist Inc.
|
|
108
|
+
|
|
109
|
+
### Bundled fixes
|
|
110
|
+
|
|
111
|
+
**Cleanups carried into this release:**
|
|
112
|
+
- **DQL `LIKE` regex bug**: `\*` (escaped literal asterisk) used to compile to `^\\*$` — a regex matching "any number of literal backslashes" — instead of matching a literal `*`. Rewrote `likeToRegex` as a single-pass walker so escaping is unambiguous.
|
|
113
|
+
- **Disk cache load: parallelized stats**: `loadDiskCache` now does `Promise.all` over all entry-stat checks instead of awaiting them one at a time.
|
|
114
|
+
- **Disk cache size guard**: refuses to load or save cache files exceeding 50 MB by default (configurable via `maxDiskCacheBytes`).
|
|
115
|
+
- **Disk cache per-entry validation**: rejects entries whose `content` exceeds `maxFileBytes`, whose `relPath` isn't a string, or whose `mtimeMs` isn't a number.
|
|
116
|
+
- **`beforeExit` flush race**: guarded by a `saved` flag so flush completion doesn't trigger recursive `beforeExit`. Signal handlers use `process.once`.
|
|
117
|
+
|
|
118
|
+
**Audit findings closed:**
|
|
119
|
+
- **Persistent cache size-limit bypass**: `loadDiskCache` filters oversized entries from the in-memory cache load.
|
|
120
|
+
- **Persistent cache privacy**: cache file is now written with mode `0600` and parent directory `0700`. Documented explicitly in [README "Cache & privacy"](./README.md#cache--privacy) and [SECURITY.md](./SECURITY.md). Added test for file mode.
|
|
121
|
+
- **Deleted-note content lingers in cache**: when `loadDiskCache` skips entries because the source file was deleted (or is mtime-stale, or oversized), the cache is now marked dirty. Next save writes a clean file without those entries. Added test for deleted-note purge.
|
|
122
|
+
- **`clear-cache` CLI subcommand**: `enquire-mcp clear-cache --vault <path>` deletes the persistent-cache file. Returns 0 even if no file exists.
|
|
123
|
+
- **Node 18 incompatibility**: `commander` 14 and `vitest` 4 (shipped in v0.3.3) require Node ≥ 20. Bumped `engines.node` to `>=20`, dropped Node 18 from CI matrix (now `[20, 22, 24]`), updated README badge.
|
|
124
|
+
- **DQL malformed `OR` / `FROM #` accepted as match-all**: `parseWhere` now rejects empty `OR` / `AND` groups (trailing-OR, duplicated-OR-OR, trailing-AND, etc.) with `DqlParseError`. `parseSource` rejects `FROM ""` and `FROM #` with no tag name. 5 regression tests added.
|
|
125
|
+
- **Stale `obsidian_dataview_query` description**: tool description still claimed "no OR" — updated to reflect `AND`/`OR`, `=`/`!=`/`contains`/`like` operators, and the actual unsupported list (`FLATTEN`/`GROUP BY`/parens).
|
|
126
|
+
- **README stale references** (`119 unit tests`, `0.3.x current`, "no OR" FAQ) refreshed.
|
|
127
|
+
|
|
128
|
+
### Tests
|
|
129
|
+
- 137 unit tests (was 119). New since v0.6.0:
|
|
130
|
+
- Cache mode `0600` enforced on save
|
|
131
|
+
- Deleted-note entries purged on next save after load
|
|
132
|
+
- `clearDiskCache` integration
|
|
133
|
+
- Oversized cached content rejected on load
|
|
134
|
+
- DQL: `FROM #` rejected (audit P2-4)
|
|
135
|
+
- DQL: `FROM ""` rejected
|
|
136
|
+
- DQL: trailing `OR` rejected
|
|
137
|
+
- DQL: trailing `AND` rejected
|
|
138
|
+
- DQL: `OR OR` (empty middle group) rejected
|
|
139
|
+
- DQL: `LIKE` with regex specials (`a.b` is literal)
|
|
140
|
+
- DQL: `LIKE` with `\*` matches literal asterisk
|
|
141
|
+
|
|
142
|
+
## [0.6.0] — 2026-05-02
|
|
143
|
+
|
|
144
|
+
Adds an opt-in persistent on-disk cache for warm cold-starts on large vaults.
|
|
145
|
+
|
|
146
|
+
### Added
|
|
147
|
+
- `--persistent-cache` CLI flag — opt-in. When set, the parsed-note cache is loaded from disk on boot and written back on graceful shutdown (SIGINT/SIGTERM/`beforeExit`). On second startup of the same process against an unchanged vault, repeat parses are skipped — net win on tools that walk the whole vault (`get_backlinks`, `search_text`, `list_tags`, `get_unresolved_wikilinks`).
|
|
148
|
+
- `--cache-file <path>` flag to override the default cache file location (useful for sandboxed environments).
|
|
149
|
+
- Default cache location: `$XDG_CACHE_HOME/obsidian-mcp/<vault-hash>.json` if set, otherwise `~/Library/Caches/obsidian-mcp/<hash>.json` on macOS, `~/.cache/obsidian-mcp/<hash>.json` on Linux. Vault path is hashed (sha1, 12 chars) so multiple vaults coexist.
|
|
150
|
+
- Atomic writes: cache is staged to `<file>.tmp` and renamed on success.
|
|
151
|
+
- Schema-versioned cache (`version: 1`) — invalidates whole file if shape ever changes between releases.
|
|
152
|
+
- Stale-entry detection: each entry stores its source mtime; on load, mismatched mtimes are silently dropped.
|
|
153
|
+
- Cross-vault protection: cache is rejected if its `root` field doesn't match the current vault realpath.
|
|
154
|
+
|
|
155
|
+
### Why opt-in (not default)
|
|
156
|
+
- The default fast path (in-memory cache + per-read mtime stat) is already O(1) for repeat reads within a session. Persistent cache only helps **across** process restarts, which most MCP-client workflows don't need (the client keeps the server warm).
|
|
157
|
+
- For users who do restart often (e.g. CI bots, scratch agents on huge vaults), the flag delivers a meaningful warm-cache start. Once we have telemetry from real users, we may flip the default.
|
|
158
|
+
|
|
159
|
+
### Skipped: chokidar-based watch mode
|
|
160
|
+
- Decided to skip for now. The current mtime-on-read check is correct and cheap (one `fs.stat` per read), and chokidar adds ~50KB of dep weight without measurable user-facing benefit at our vault sizes. Will revisit in v0.7+ if a benchmark says otherwise.
|
|
161
|
+
|
|
162
|
+
### Tests
|
|
163
|
+
- 126 unit tests (was 119). 7 new for persistent-cache: opt-in default-off, write-then-read round-trip, mtime invalidation, vault-root rejection, version mismatch rejection, corrupt-file graceful fallback, and cache file write atomicity.
|
|
164
|
+
|
|
165
|
+
## [0.5.0] — 2026-05-02
|
|
166
|
+
|
|
167
|
+
Stricter TypeScript, lint/format with Biome, and DQL gains `OR` + `LIKE`.
|
|
168
|
+
|
|
169
|
+
### Added (DQL)
|
|
170
|
+
- `OR` between predicate groups: `WHERE a = 1 OR b = 2`. `OR` has lower precedence than `AND`, so `a = 1 AND b = 2 OR c = 3` parses as `(a = 1 AND b = 2) OR (c = 3)`. Quote-aware tokenizer ensures `"OR"` inside a string is data, not a clause boundary.
|
|
171
|
+
- `like` operator: SQL-LIKE-style wildcard matching, case-insensitive. `*` is the wildcard, `\*` is a literal asterisk. Works on string fields and on string elements of array fields. Examples: `file.name like "draft*"`, `status like "*progress*"`.
|
|
172
|
+
|
|
173
|
+
### Changed (DQL parse model — backward compatible at the query level)
|
|
174
|
+
- `DataviewQuery.where` is now `Predicate[][]` (disjunction of conjunctions) instead of `Predicate[]`. Querie strings without `OR` produce a single-element outer array, so existing AND-only queries keep working unchanged.
|
|
175
|
+
|
|
176
|
+
### Code quality
|
|
177
|
+
- TypeScript strict++: enabled `noUncheckedIndexedAccess` and `noImplicitOverride`. Surfaced and fixed real defensive-coding gaps in `dql.ts` and `parser.ts` where regex match groups and array indexing could return `undefined`. (`exactOptionalPropertyTypes` was tried and removed — fights too hard with Zod-inferred types.)
|
|
178
|
+
- **Biome 2** added as a lint+format toolchain: `npm run lint`, `npm run lint:fix`, `npm run format`. CI gains a dedicated `lint` job. `prepublishOnly` now runs `lint && build && test`. Codebase formatted to a consistent house style (line-width 120, double quotes, trailing-comma none).
|
|
179
|
+
- All `catch (err: any)` replaced with `catch (err) { if (isErrnoException(err)) ... }` for type-safe error handling.
|
|
180
|
+
|
|
181
|
+
### Tests
|
|
182
|
+
- 119 unit tests (was 112). New coverage: `OR` parsing, mixed AND/OR precedence, `LIKE` parsing, `LIKE` matching with leading/trailing wildcards, `LIKE` case-insensitivity. Plus 2 quote-aware-keyword tests now covering `OR`.
|
|
183
|
+
|
|
184
|
+
## [0.4.0] — 2026-05-02
|
|
185
|
+
|
|
186
|
+
Two new vault-introspection tools, three new workflow prompts, and CI-driven coverage.
|
|
187
|
+
|
|
188
|
+
### Added (read tools)
|
|
189
|
+
- `obsidian_get_unresolved_wikilinks` — find every `[[wikilink]]` (and `![[embed]]`) whose target doesn't resolve. Vault-hygiene utility for finding broken links, typos, and intended-but-not-yet-created notes. Args: `folder?`, `include_embeds?`, `limit?`. Returns `{ from_path, target, raw, kind, alias, section, block, line, snippet }`.
|
|
190
|
+
- `obsidian_get_outbound_links` — symmetric counterpart to `obsidian_get_backlinks`. For one note, lists every link it points to with each one's resolution status. Args: `path?`, `title?`, `include_embeds?`, `include_unresolved?`. Returns `{ from_path, from_title, links: [...] }`.
|
|
191
|
+
|
|
192
|
+
### Added (prompts)
|
|
193
|
+
- `weekly_review` — aggregates the past 7 days of edits, groups by tag, surfaces "shipped / open / stuck" per group, ends with a 2-sentence reflection on actual vs. intended energy spend.
|
|
194
|
+
- `extract_todos` — greps TODO / FIXME / QUESTION across the vault (optionally filtered by `folder` and/or `tag`), groups verbatim hits by note, picks one highest-leverage next action.
|
|
195
|
+
- `process_inbox` — walks an inbox folder (`folder` required) and for each note proposes Move / Merge / Promote / Archive based on tags, content, and inbound/outbound links. Doesn't actually move anything — proposal-only.
|
|
196
|
+
|
|
197
|
+
### Added (CI / observability)
|
|
198
|
+
- `npm run test:coverage` — vitest with the v8 coverage provider.
|
|
199
|
+
- New CI job `coverage`: runs on every push/PR, uploads the full HTML report as a workflow artifact (`coverage-report`).
|
|
200
|
+
- README badges now include `tests-112-passing` and `coverage-83%-lines`.
|
|
201
|
+
|
|
202
|
+
### Tests
|
|
203
|
+
- 112 unit tests (was 103). New coverage: 4 cases for `get_unresolved_wikilinks` (basic detection, filtered out resolved, folder filter, embeds toggle), 5 cases for `get_outbound_links` (basic listing, embed toggle, unresolved marking, unresolved filter, alias/section/block preservation).
|
|
204
|
+
- Coverage on this release: **83% lines · 79% statements · 73% branches · 67% functions** (the function gap is mostly MCP wiring in `index.ts`, which is exercised by the smoke test rather than unit tests).
|
|
205
|
+
|
|
206
|
+
### Surface size
|
|
207
|
+
- 10 read tools (was 8) + 2 opt-in write tools.
|
|
208
|
+
- 2 MCP resources.
|
|
209
|
+
- 6 MCP prompts (was 3).
|
|
210
|
+
|
|
211
|
+
## [0.3.3] — 2026-05-02
|
|
212
|
+
|
|
213
|
+
Dependency triage — all 7 outstanding Dependabot major-version PRs landed in a single verified bump. Each was tested locally (full test suite + JSON-RPC smoke against a synthetic vault) before bundling.
|
|
214
|
+
|
|
215
|
+
### Dependencies
|
|
216
|
+
- `@types/node` 22 → 25 (devDep)
|
|
217
|
+
- `typescript` 5 → 6 (devDep) — required adding `types: ["node"]` to `tsconfig.json`. TS 6 dropped the implicit fallback that auto-discovered `@types/node` ambient globals; `process`, `Buffer`, and `node:*` modules need an explicit type-resolution hint now.
|
|
218
|
+
- `commander` 12 → 14 (runtime) — no API surface change in our usage.
|
|
219
|
+
- `zod` 3 → 4 (runtime) — `z.string().optional()`, `z.boolean().optional()`, `z.record(z.string(), z.unknown())` all migrate cleanly. No app code changes.
|
|
220
|
+
- `vitest` 2 → 4 (devDep) — also resolves the moderate-severity vulnerabilities flagged by `npm audit` in the `vite` / `esbuild` chain (Dependabot security PRs #8 and #9 superseded).
|
|
221
|
+
|
|
222
|
+
### Tests
|
|
223
|
+
- 103 unit tests, all green on the new dependency stack.
|
|
224
|
+
- Smoke green: 17 checks, all 10 MCP tools + 2 resources + 3 prompts verified against the synthetic CI vault.
|
|
225
|
+
|
|
226
|
+
### Notes
|
|
227
|
+
- Zero application code changes — pure dependency updates with one tsconfig tweak.
|
|
228
|
+
- Dependabot PRs #3 — #9 closed as superseded by this release.
|
|
229
|
+
|
|
230
|
+
## [0.3.2] — 2026-05-02
|
|
231
|
+
|
|
232
|
+
External read-only audit pass closed four real findings.
|
|
233
|
+
|
|
234
|
+
### Security & correctness
|
|
235
|
+
- **P2** `listMarkdown(folder)` now `lstat`s and realpath-checks the start directory before walking. Previously, passing a vault-internal symlink that pointed *outside* the vault as the `folder` argument would enumerate the external directory's `.md` files (reads still failed downstream, but the listing leaked filenames). Fix: empty list returned in that case.
|
|
236
|
+
- **P2** `--max-file-bytes` and `--cache-size` are now validated as positive finite integers at server boot. Previously, passing `NaN` / `Infinity` / floats / negative values silently disabled the size guard and produced unpredictable cache behavior. The server now exits with a clear error.
|
|
237
|
+
- **P2** `obsidian_read_note` now honors its documented contract — `path` works with *or* without the `.md` extension, matching the schema description and the parallel behavior of `obsidian_create_note`.
|
|
238
|
+
- **P3** Inline tag regex is now Unicode-aware: `#русский`, `#日本語`, `#café-au-lait`, `#русский/путь` all parse correctly. Previously the regex started with `[A-Za-z]` and silently dropped non-ASCII tags, contradicting the README's i18n promise.
|
|
239
|
+
|
|
240
|
+
### Packaging
|
|
241
|
+
- `docs/api.md` and `SECURITY.md` are now included in the npm tarball — README links from the published package no longer 404.
|
|
242
|
+
- CI: `actions/setup-node@v4` → `v6` on `main` (dependabot superseded).
|
|
243
|
+
|
|
244
|
+
### Docs
|
|
245
|
+
- README quick-start no longer hard-codes a stale boot-message version string.
|
|
246
|
+
|
|
247
|
+
### Tests
|
|
248
|
+
- 103 unit tests (was 86). New regression coverage for every audit finding above:
|
|
249
|
+
- `listMarkdown(folder)` returns `[]` for symlinked-out start directory (P2-1).
|
|
250
|
+
- `parsePositiveInt` rejects NaN / Infinity / non-integer / non-positive / non-numeric (P2-2).
|
|
251
|
+
- `obsidian_read_note` accepts paths with and without `.md` (P2-3).
|
|
252
|
+
- Cyrillic / CJK / accented inline tags parse correctly; mid-word `#` does not produce a tag (P3-1).
|
|
253
|
+
|
|
254
|
+
## [0.3.1] — 2026-05-02
|
|
255
|
+
|
|
256
|
+
### Security
|
|
257
|
+
- `obsidian_create_note` now realpath-checks the *parent directory* of the target before writing. Previously, a parent dir that was a symlink resolving outside the vault would let a write escape the vault root. With this fix, such writes are refused.
|
|
258
|
+
|
|
259
|
+
### Fixed
|
|
260
|
+
- Cache eviction is now a true **LRU** instead of FIFO — re-reading a cached entry bumps it to the freshest slot. README/CHANGELOG already advertised LRU; behavior now matches docs.
|
|
261
|
+
- Dropped a small dead-code path in `obsidian_list_tags` (an unused `WeakMap`).
|
|
262
|
+
|
|
263
|
+
### Added
|
|
264
|
+
- `obsidian_dataview_query` now applies a default row cap of **1000** when the query has no explicit `LIMIT`. Prevents runaway responses on huge vaults.
|
|
265
|
+
- CI gains a dedicated **smoke job** that builds a synthetic vault and runs the JSON-RPC end-to-end against the real binary.
|
|
266
|
+
- CI gains an **`npm audit --audit-level=high`** job.
|
|
267
|
+
- CI hardened with `permissions: contents: read`, `timeout-minutes`, and concurrency cancellation.
|
|
268
|
+
- New tests (86 total, was 79): LRU eviction order, internal-symlink rejection in walker, path-form wikilink backlink, mtime moves forward across write→append, write refusal when parent dir is a symlink to outside the vault, default-row-cap behavior in DQL.
|
|
269
|
+
- `SECURITY.md`, GitHub issue templates (bug / feature), PR template, FUNDING.yml.
|
|
270
|
+
|
|
271
|
+
### Docs
|
|
272
|
+
- Major README rewrite for launch readiness: value-prop lead, comparison table vs filesystem MCPs, "who is this for?" section, ASCII architecture diagram, FAQ, transactional install / `npx` / global blocks.
|
|
273
|
+
- `docs/api.md`: documented tag-counting semantics (`fm + inline == count`) and the default DQL row cap.
|
|
274
|
+
|
|
275
|
+
## [0.3.0] — 2026-05-02
|
|
276
|
+
|
|
277
|
+
### Added
|
|
278
|
+
- `obsidian_list_tags` — every unique tag in the vault with frontmatter / inline counts. Sorted by usage.
|
|
279
|
+
- **Opt-in write tools** behind `--enable-write`:
|
|
280
|
+
- `obsidian_create_note` — creates a new note with optional frontmatter; refuses overwrite by default.
|
|
281
|
+
- `obsidian_append_to_note` — appends a markdown block to an existing note (`path` or `title`).
|
|
282
|
+
- **MCP resources**:
|
|
283
|
+
- `obsidian://vault/info` — vault metadata (root, note count, limits, write flag).
|
|
284
|
+
- `obsidian://note/<relative-path>` — every note as a browsable resource via `ResourceTemplate`.
|
|
285
|
+
- **MCP prompts**: `summarize_recent_edits`, `review_tag`, `find_orphans`.
|
|
286
|
+
- **Tool annotations**: every read tool tagged `readOnlyHint: true, idempotentHint: true`; write tools tagged `readOnlyHint: false`.
|
|
287
|
+
- New CLI flags: `--enable-write`, `--max-file-bytes <n>`, `--cache-size <n>`.
|
|
288
|
+
|
|
289
|
+
### Security & robustness
|
|
290
|
+
- Vault walker skips symbolic links and refuses to descend into directories whose realpath exits the vault.
|
|
291
|
+
- `realpath`-based safety check on every read/write target — prevents symlink-escape attacks even if a link is created after server boot.
|
|
292
|
+
- File-size guard (default 5 MB) on every read and write — blocks oversized binary-renamed-md from blowing memory.
|
|
293
|
+
- Parsed-note cache is now bounded (default 1024 entries) with FIFO eviction — predictable memory ceiling on huge vaults.
|
|
294
|
+
- DQL parser respects quoted strings: `WHERE x = "foo SORT bar"` no longer prematurely splits on `SORT` / `WHERE` / `LIMIT` / `AND` keywords inside string literals.
|
|
295
|
+
|
|
296
|
+
### Changed
|
|
297
|
+
- `obsidian_resolve_wikilink` now also accepts `![[…]]` syntax in its `wikilink` argument.
|
|
298
|
+
- `obsidian_read_note` output now includes `embeds` alongside `wikilinks`.
|
|
299
|
+
- `package.json` — dropped `main` field (CLI-only package), added `publishConfig.access = public`, added `CHANGELOG.md` to `files`, `prepublishOnly` now runs build *and* tests.
|
|
300
|
+
- CLI no longer runs `main()` on bare module import (guarded by `import.meta.url` check).
|
|
301
|
+
|
|
302
|
+
### Docs
|
|
303
|
+
- New `CONTRIBUTING.md` with scope guidelines.
|
|
304
|
+
- `.editorconfig` for consistent style across editors.
|
|
305
|
+
- README gains a Troubleshooting section, an `npx`-based MCP wiring snippet, and write-flag docs.
|
|
306
|
+
|
|
307
|
+
### Tests
|
|
308
|
+
- 79 unit tests (was 57). New coverage: symlink rejection, oversized-file refusal, malformed YAML fallback, Unicode titles/tags, DQL keyword-in-string, write-tool happy paths and refusals.
|
|
309
|
+
|
|
310
|
+
## [0.2.0] — 2026-05-02
|
|
311
|
+
|
|
312
|
+
### Added
|
|
313
|
+
- `obsidian_get_backlinks` — list every note that wikilinks (or embeds) the target. Returns ranked hits with snippets and link kind (`wikilink` / `embed` / `mixed`). `include_embeds` flag, default `true`.
|
|
314
|
+
- `obsidian_dataview_query` — basic Dataview-style queries: `LIST` / `TABLE col1, col2 FROM ("folder" | #tag) [WHERE field op value [AND …]] [SORT field [ASC|DESC]] [LIMIT n]`. Operators: `=`, `!=`, `contains`. Special fields: `file.name`, `file.path`, `file.mtime`, `file.tags`. Other identifiers read frontmatter.
|
|
315
|
+
- Parser now extracts `![[…]]` embeds separately from `[[…]]` wikilinks; both surface in `obsidian_read_note` output.
|
|
316
|
+
- Vault gets an mtime-keyed parse cache — repeat reads of an unchanged note are now O(1).
|
|
317
|
+
- GitHub Actions CI on Node 18 / 20 / 22.
|
|
318
|
+
|
|
319
|
+
### Changed
|
|
320
|
+
- `obsidian_resolve_wikilink` now also accepts the `![[Embed]]` syntax in its input.
|
|
321
|
+
- Read paths route through the new cache, removing redundant `readFile` + `parseNote` work in tools that scan the whole vault.
|
|
322
|
+
|
|
323
|
+
### Notes
|
|
324
|
+
- Dataview implementation is intentionally minimal — no expressions, function calls, joins, or `FLATTEN`. It covers the common LIST/TABLE-with-WHERE shape and explicitly degrades for anything fancier.
|
|
325
|
+
|
|
326
|
+
## [0.1.0] — 2026-05-02
|
|
327
|
+
|
|
328
|
+
### Added
|
|
329
|
+
- Initial Phase 1 release.
|
|
330
|
+
- Five MCP tools: `obsidian_list_notes`, `obsidian_read_note`, `obsidian_resolve_wikilink`, `obsidian_search_text`, `obsidian_get_recent_edits`.
|
|
331
|
+
- Stdio transport via `@modelcontextprotocol/sdk` 1.29.
|
|
332
|
+
- Wikilink resolver covers aliases (`Note|alias`), section refs (`Note#Heading`), block refs (`Note^id`), and `..` relative paths.
|
|
333
|
+
- Path-traversal guards on every read; walker skips `.git`, `.obsidian`, `.trash`, `node_modules`, and dot-dirs.
|
|
334
|
+
- 33 unit tests + JSON-RPC smoke test against a real 117-note vault.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alex (@OomkaBear)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|