Commit Graph

51 Commits

Author SHA1 Message Date
Mauricio Wolff 071678e52a feat: preview MCP SDK v2 dual-era support 2026-08-15 11:11:46 +02:00
bitbonsai b10a5b2d7a feat: add read-only server mode 2026-08-09 11:18:53 +02:00
bitbonsai 272888b9d0 fix(security): block hidden vault paths 2026-08-08 19:24:51 +02:00
kartik7704 7aced58210 fix: recognize indented/empty ATX headings, strip optional closing sequence
Per CommonMark: headings may be indented up to 3 spaces, may have no text
(bare #), and may end in an optional closing run of #s (preceded by a
space, followed only by trailing spaces) that isn't part of the heading
text. getNoteOutline missed all three.

Adds 5 regression tests. dist rebuilt.
2026-08-06 15:32:48 +00:00
kartik7704 75492433f7 fix: track fence marker length/char, reject trailing-text closers, allow indented fences
Addresses the remaining fence state-machine bugs from review:
- track the opening fence's character and marker count, only close on a
  run of the same character with length >= the opener's (a shorter run
  no longer falsely closes a longer one)
- a closer may only be followed by whitespace; a fence-looking line with
  trailing text (e.g. a language tag) is no longer misread as a closer
- allow fence markers indented up to 3 leading spaces, per CommonMark

Adds 6 regression tests covering each case plus mismatched-character and
longer-closer scenarios. dist rebuilt.
2026-08-06 15:15:04 +00:00
kartik7704 656f017c6f fix: address review feedback on get_note_outline / read_note_lines
- getNoteOutline and readNoteLines now normalizePath() before the
  pathFilter.isAllowed() check, matching every other method - previously
  both skipped it, so read_note_lines could read files under .obsidian/
  that every other tool is blocked from touching.
- getNoteOutline now tracks fenced code block state (``` and ~~~) and
  skips lines inside one, so a code sample containing a shell comment or
  markdown example no longer gets misdetected as a real heading.
- getNoteOutline now skips the frontmatter block (both LF and CRLF line
  endings) before scanning for headings, so a YAML comment line doesn't
  get misdetected as an H1.
- readNoteLines clamps both startLine and endLine into [1, lines.length]
  instead of passing raw values to Array.slice, which silently wrapped
  to the end of the file for startLine <= 0 via slice's negative-index
  behavior.

Adds 6 new tests covering fences, LF/CRLF frontmatter, and the three
clamping edge cases. Full suite: 257 passed.
2026-08-06 15:15:03 +00:00
kartik7704 0999004768 fix: update tool-count test for the 2 new tools (16 -> 18) 2026-08-06 15:15:03 +00:00
kk cf9133cbfd feat: add get_note_outline and read_note_lines tools
Returns heading structure (level, text, line) without loading full file content.
read_note_lines reads a specific line range for surgical section access.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

# Conflicts:
#	dist/src/createServer.d.ts.map
#	dist/src/createServer.js
#	dist/src/filesystem.d.ts
#	dist/src/filesystem.d.ts.map
#	dist/src/filesystem.js
#	src/createServer.ts
#	src/filesystem.ts
2026-08-06 15:15:02 +00:00
Mauricio Wolff 5a293c6c87 chore: rebuild dist sourcemaps under TypeScript 7 2026-07-30 14:31:27 +02:00
Mauricio Wolff cf92712ca5 fix: exit when stdio transport closes (#159)
StdioServerTransport only listens for stdin 'data'/'error'; it never
wires up 'end'/'close', so the process never learns when the client
disconnects. Hosts with no MCP lifecycle controls (e.g. Codex 0.146.x)
left orphaned processes accumulating with nothing to reap them.

Exit gracefully via server.close() on stdin EOF and on SIGTERM/SIGINT.
2026-07-30 13:24:50 +02:00
Mauricio Wolff a90fbc3016 fix: resolve path-qualified wiki links like [[folder/Note]]
Obsidian emits path-qualified links when a basename is ambiguous.
findPathForWikiLink matched basenames only, so these always returned
no match. Names containing '/' now match the full vault-relative path.
2026-07-23 12:00:38 +02:00
Mauricio Wolff 639a174579 Merge pull request #101 from renoirb/feat/wiki-link-tool
feat: add wiki_link tool for Obsidian wiki link resolution

# Conflicts:
#	dist/src/filesystem.d.ts.map
2026-07-23 11:58:14 +02:00
Mauricio Wolff 84cd2f629a chore: bump version to 0.12.2
Includes dist rebuild for #151 (normalizePath) and #153
(patch_note $-pattern fix).
2026-07-23 11:38:07 +02:00
Mauricio Wolff d960b89907 fix: insert patch_note replacement literally, no $ pattern expansion
String.replace interprets $$, $&, $` and $' in the replacement even
for plain-string searches, corrupting notes whose newString contains
them. Use a replacer function so newString is inserted verbatim.

Fixes #149
2026-07-23 11:06:20 +02:00
Mauricio Wolff e601d441c6 chore: rebuild dist for yaml engine swap
dist was stale after fde15eb; committed output lacked the
gray-matter engine override.
2026-07-23 11:00:17 +02:00
Renoir Boulanger 7d7faeeed9 chore: rebuild dist/ after wiki_link scope-down
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019gW7q2tDx7Wwx6mFiXx8CG
2026-07-04 03:06:12 -04:00
Renoir Boulanger b6f06301bd missed filtering out of .trash/ 2026-07-04 02:38:43 -04:00
Renoir Boulanger f3ba06bfb8 chore: rebuild dist/ after wiki_link handler extraction
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-07-04 02:38:12 -04:00
Renoir Boulanger 5ed5b4eea5 chore: rebuild dist/ for wiki_link response refactor
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-07-04 02:37:46 -04:00
Renoir Boulanger bfa196a3a1 chore: committing dist/? really needed? 2026-07-04 02:31:46 -04:00
Mauricio Wolff e5f1b5a8b2 feat: scope search_notes with pathPrefix / excludePaths (#126) (#141)
search_notes now accepts optional pathPrefix (restrict to a subtree) and
excludePaths (skip subtrees). Filtering happens before file I/O, so excluded
files are never read or scored, and the result limit is no longer diluted by
results from unwanted directories. Directory-prefix matching is slash-tolerant
and does not over-match sibling names (Projects vs Project-notes). +5 tests.
2026-06-18 23:17:47 +02:00
Mauricio Wolff 8795716b90 Merge commit from fork
PathFilter only denied .git/.obsidian/node_modules at the vault root because
the glob patterns are anchored. Nested copies (tools/cli/node_modules/...,
tools/repo/.git/config, nested .obsidian) were traversable: nested
node_modules polluted listAllTags with garbage tags, and nested .git/.obsidian
exposed their contents (incl. .git/config credentials) under the same
prompt-injection threat model as the case-equivalence bypass.

Deny these restricted names as ANY path segment (case-insensitive), in
addition to the existing glob patterns. Legit paths that merely contain the
substring (gitignore-tips.md, my-node_modules-notes.md) stay allowed. +5 tests.

Bumps to 0.11.5.
2026-06-18 22:15:53 +02:00
Mauricio Wolff 1f44644f0e fix: classify write errors by code, not message substring (#109) (#138)
writeNote mislabeled any error whose message merely contained 'space' as
'No space left on device' (and 'permission'/'access' as permission denied),
producing false ENOSPC reports when the disk had ample space. Replace the
substring matching with a code-based classifier (ENOSPC/EACCES/EPERM/EROFS),
preserve our own clear errors as-is, and keep the original message in the
generic fallback. Adds unit tests for the classifier.

Does not address the secondary same-path write race noted in #109 (no
deterministic repro); the misclassification was the actual false report.
2026-06-18 22:06:18 +02:00
Mauricio Wolff b9ea91a1c6 Merge commit from fork
PathFilter compiled deny-list patterns case-sensitively and matched the
path verbatim, so on case-insensitive filesystems (macOS, Windows) names
like .Git/config, .GIT/config, or .oBsIdIaN/secrets.md slipped past the
restriction while the OS opened the real .git/.obsidian file. Windows
trailing dots/spaces (.git./config, .git /config) bypassed it the same way.

Match case-insensitively and canonicalize each path segment (strip trailing
dots/spaces, drop ./ and empty segments) before checking the deny-list.
Covers isAllowed and isAllowedForListing. Adds the full bypass matrix as
tests. (CWE-178 / CWE-41)
2026-06-17 19:42:53 +02:00
Mauricio Wolff cbf70c5a49 fix: guard undefined/non-string path in PathFilter (closes #107) (#132)
* fix: guard undefined/non-string path in PathFilter (closes #107)

read_note/write_note (and patch/delete/move) threw an unguarded TypeError
'Cannot read properties of undefined (reading 'replace')' when invoked
without a path. Add a typeof guard in PathFilter.isAllowed and
isAllowedForListing that returns a clear 'path is required and must be a
string' error instead. Covers all callers in one place. Adds 3 tests.

* chore: bump version to 0.11.3

Ships the #107 PathFilter undefined-path guard. Patch release.
2026-06-17 18:51:03 +02:00
Mauricio Wolff 488a9076f8 Add trashMode support to delete_note
- none (default): permanent delete (previous behavior)
- local: move to .trash/ inside vault, preserving folder structure
- system: move to OS trash via the trash package
- Add trashMode parameter to tool schema, types, and handler
- Add tests for local and system trash modes
- Update docs: CHANGELOG, README, website
2026-05-25 21:49:39 +02:00
Mauricio Wolff 41cf107fbc Fix patch_note to allow empty newString for text deletion
- Change validation from falsy check to explicit undefined/null check
- Empty string is now a valid way to delete matched text
- Update test to verify deletion behavior
2026-05-25 21:49:14 +02:00
Mauricio Wolff 6e16b482a5 Fix frontmatter formatting loss with AST-aware YAML preservation
- Add preserveStringify() using yaml.parseDocument for AST-aware updates
- Only modified keys are rewritten; unmodified fields keep raw formatting
- Fixes YYYY-MM-DD dates becoming ISO timestamps (#77)
- Fixes HH:MM values parsed as sexagesimal integers (#75)
- Fixes quoted strings losing their quote style (#76)
- Applies to update_frontmatter, manage_tags, and write_note append/prepend
2026-05-25 21:49:14 +02:00
Mauricio Wolff 459c59961d feat: add list_all_tags tool and Obsidian CLI routing in skill (closes #80) 2026-05-25 21:49:14 +02:00
Mauricio Wolff cf7a5fa205 feat: extract createServer factory for library consumers (closes #84) 2026-05-25 21:49:13 +02:00
Mauricio Wolff f435b75f95 build: regenerate dist artifacts
Rebuild compiled dist outputs to match current server, filtering, frontmatter handling, and test sources for the v0.8.2 codebase.
2026-05-25 21:49:11 +02:00
Mauricio Wolff 464a1f40d7 feat: add confirmed binary-safe move_file tool 2026-05-25 21:49:09 +02:00
Mauricio Wolff 57b7d56add build: update dist artifacts for v0.8.1 2026-05-25 21:49:09 +02:00
Mauricio Wolff 5a01eef01d bump version to 0.7.5, update changelog and LLM docs 2026-05-25 21:49:08 +02:00
Mauricio Wolff c23506f8a7 Bump version to 0.7.4 and update website changelog
- Version 0.7.4 includes get_vault_stats tool and improved error messages
- Fixed directory filtering in getVaultStats to skip system directories
2026-05-25 21:49:07 +02:00
Mauricio Wolff e4896186ab fix: increase performance test threshold for CI stability
The pathfilter performance test was failing on CI runners due to
variability in execution speed. Increased threshold from 100ms to 200ms
for 8000 checks to account for slower CI environments while still
catching real performance regressions.

Fixes flaky test: "pathfilter performance with many checks"
2026-05-25 21:49:07 +02:00
Mauricio Wolff 57ba8edeba Bump version to 0.7.3
Changes:
- Fix folder detection for paths with dots in folder names (PR #15)
- Update dependencies: MCP SDK 1.25.1, tsx 4.21.0, vitest 4.0.16 (PR #17)
- Update @types/node to 24.10.1 (PR #14)
- Remove inaccurate link handling claim from README

All tests passing (206 tests)
2026-05-25 21:49:07 +02:00
Mauricio Wolff 50c9aa938b Bump version to 0.7.2 and add integration tests
Version bump accounts for PR #12 security fixes (0.7.1) and website updates.

Add comprehensive integration test suite covering:
- End-to-end service layer workflows
- Special characters in paths (parentheses, brackets, unicode, emoji)
- Regex special chars in content
- Security: path traversal and blocked directories
- Multi-step workflows (search → read → update)
- Performance regression tests

All 102 tests passing.
2026-05-25 21:49:06 +02:00
hellvinz fa776ffcab fix(security): address CodeQL, OpenSSF Scorecard, and npm audit findings (#12)
* ci(security): add CodeQL static analysis workflow

Automated detection of security vulnerabilities in TypeScript code
(path traversal, injection, prototype pollution) to protect users'
personal vault data.

Uses security-extended queries and runs weekly to catch new CVEs.

Ref: https://docs.github.com/en/code-security/code-scanning/introduction-to-code-scanning/about-code-scanning-with-codeql

* ci: add CI workflow with security checks

Prevent supply chain attacks through compromised dependencies by
validating lockfile integrity and running npm audit on every PR.

Lockfile validation detects dependency confusion attacks where
package-lock.json diverges from declared dependencies.

Refs:
- https://docs.npmjs.com/cli/v10/commands/npm-audit
- https://blog.npmjs.org/post/626173315965468672/npm-v7-series-why-keep-package-lockjson

* ci: add Dependabot for automated security updates

Ensure known vulnerabilities (CVEs) in dependencies are patched
promptly without manual tracking.

Major updates stay as separate PRs for careful review of breaking changes.

Ref: https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/about-dependabot-security-updates

* ci: add publish workflow with npm provenance

Allow users to verify that npm packages were built from this exact
GitHub repository and commit, not from a compromised machine.

Verification: npm audit signatures

Requires NPM_TOKEN secret in repository settings.

Ref: https://docs.npmjs.com/generating-provenance-statements

* ci: add OpenSSF Scorecard for security posture tracking

Automated evaluation of security practices (branch protection,
dependency updates, signed releases, etc.) with results visible
in GitHub Security tab.

Helps identify gaps in project security hygiene.

Ref: https://securityscorecards.dev/

* deps: fix npm audit vulnerabilities

Upgrade vitest 1.6.1 → 4.0.15 to resolve transitive vite/esbuild
vulnerabilities. Sync lockfile with package.json 0.7.0.

Refs:
- https://github.com/advisories/GHSA-w48q-cv73-mx4w
- https://github.com/advisories/GHSA-mh29-5h37-fv8m
- https://github.com/advisories/GHSA-67mh-4wv8-2f99

* fix(security): eliminate TOCTOU race conditions

Remove check-then-act patterns that were flagged by CodeQL as
js/file-system-race vulnerabilities.

Instead of access() followed by readFile/unlink/etc, handle ENOENT
errors directly from the operation. Use writeFile with 'wx' flag
for atomic "create if not exists" in moveNote().

Ref: https://cwe.mitre.org/data/definitions/367.html

* fix(security): escape regex special chars in glob patterns

The glob-to-regex conversion wasn't escaping special regex characters,
allowing patterns with characters like . + $ etc to be misinterpreted.

Also normalizes backslashes in patterns for Windows compatibility.

Ref: https://codeql.github.com/codeql-query-help/javascript/js-incomplete-sanitization/

* test(security): use mkdtemp for unpredictable temp directories

Predictable paths in /tmp are vulnerable to symlink attacks.
mkdtemp creates directories with random suffixes, preventing
local attackers from pre-creating malicious symlinks.

Ref: https://codeql.github.com/codeql-query-help/javascript/js-insecure-temporary-file/

* docs: add security policy

Define responsible disclosure process, security scope, and response
timelines for vulnerability reports.

Documents implemented security controls and clarifies what's in/out
of scope for this project vs upstream (MCP protocol, Obsidian).

Ref: https://docs.github.com/en/code-security/getting-started/adding-a-security-policy-to-your-repository
2026-05-25 21:49:06 +02:00
Mauricio Wolff aa759af297 Bump version to 0.7.0 2026-05-25 21:49:04 +02:00
Mauricio Wolff 1a130b06b3 Add Obsidian URI links to response objects
Implements clickable URI links using Obsidian's URI protocol to enable
direct navigation to notes from AI assistant responses.

- Add generateObsidianUri() utility function with proper URI encoding
- Include obsidianUri field in SearchResult, BatchReadResult, and NoteInfo
- Use absolute path format (obsidian:///path/to/note) for compatibility
- Add comprehensive test coverage for URI generation

Resolves #5
2026-05-25 21:49:04 +02:00
Mauricio Wolff 62ebe503dd Add --version and --help CLI flags
- Implement --version/-v flag to display version number
- Implement --help/-h flag to show usage information
- Version now dynamically read from package.json
- Update error message to suggest --help for more info
2026-05-25 21:48:55 +02:00
Mauricio Wolff 38e9a16505 Add built files for v0.6.3 2026-05-25 21:48:55 +02:00
Mauricio Wolff 182deac629 Bump version to 0.6.1
## Changes

- Add comprehensive tests for patch_note feature (16 tests)
  - Single/multiple occurrence handling
  - Empty string validation
  - Special characters and whitespace preservation
  - Case sensitivity
  - Performance testing

- Add validation for empty oldString/newString in patchNote

- Reorganize test structure
  - Move tests from tests/ to src/ (co-location)
  - Merge filesystem, patch, and integration tests into src/filesystem.test.ts
  - Move frontmatter tests to src/frontmatter.test.ts

All 38 tests passing
2026-05-25 21:48:54 +02:00
Mauricio Wolff d3fcc42324 Add patch_note tool for efficient partial note updates
Introduces a new patch_note tool that allows replacing specific strings in notes without rewriting the entire file, reducing token usage and improving performance for small edits.

Features:
- String-based replacement with oldString/newString parameters
- Safety: fails if multiple matches found (unless replaceAll=true)
- Preserves frontmatter and file structure
- Returns match count and detailed success/error messages

Changes:
- Added PatchNoteParams and PatchNoteResult types
- Implemented patchNote() method in FileSystemService
- Added patch_note tool to MCP server
- Comprehensive test coverage (8 new tests)
- Bumped version to 0.6.0
2026-05-25 21:48:54 +02:00
Mauricio Wolff 9d52ecf6b9 Fix YAML frontmatter operations and add comprehensive tests
- Remove js-yaml dependency and use gray-matter for all YAML operations
- Fix write_note, update_frontmatter, and manage_tags YAML serialization errors
- Add comprehensive integration tests for all frontmatter operations
- Tests cover write_note with frontmatter, append/prepend modes, update operations
- Tests cover tag management (add, remove, list) and edge cases
- All 22 tests now passing including frontmatter validation
- Version bump to 0.5.4

Resolves: 'yaml.dump is not a function' error in all frontmatter tools
2026-05-25 21:48:53 +02:00
Mauricio Wolff 21879e8eb3 Fix list_directory to handle '.' path as root directory
- Normalize '.' path to empty string for root directory listing
- Ensure consistent behavior between '.', '/', and '' paths
- All now correctly return both files and directories from vault root
- Version bump to 0.5.3

Resolves issue where LLMs using '.' path only received files without directories.
2026-05-25 21:48:53 +02:00
Mauricio Wolff a071b48fb0 Fix package.json main field and executable permissions
- Change main field from server.ts to dist/server.js
- Add executable permission to compiled JavaScript file
- This resolves the 'env: bun: No such file or directory' error
- Version bump to 0.5.2
2026-05-25 21:48:53 +02:00
Mauricio Wolff 8167ce362d Bump version to 0.5.1
Prepare for npm publish with corrected Node.js compatibility.
2026-05-25 21:48:52 +02:00
Mauricio Wolff 848ce6367c Fix usage message in compiled JavaScript output
Update error message to show correct npx command instead of referencing server.ts file directly.
2026-05-25 21:48:52 +02:00