Repository navigation
refactor(operations): fold FsVaultWriter into the disk provider - #122
Merged
Merged
Conversation
…d writes Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Add replaceInNote/replaceFullBody to VaultProvider and implement them on FsVaultProvider, reusing the readRaw/writeRaw seam from task 1. Rename the private resolveIdentifierPath to resolveExisting to mirror the resolveNew split coming in task 5. FsVaultWriter still serves edit_note; task 3 wires the tool over to the provider. Widening the VaultProvider interface breaks every local stub of it, so this also adds the two new mocks to test/operations/tools/_helpers.ts, test/lib/obsidian/vault-overview.test.ts, and test/server-modules.test.ts — a type change ships with the call sites it breaks. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
edit_note now validates input with resolveIdentifier(name, path) and hands the unresolved NoteIdentifier down to entry.provider.replaceInNote / .replaceFullBody, instead of resolving name -> path itself and calling the soon-to-be-deleted entry.writer. Argument validation (including the empty-replace check) now runs before any disk I/O, so a malformed `replace` is reported even when the identifier would not have resolved. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…fier edit_note's tool-level "rejects unresolved name with NOT_FOUND" test was deleted on the premise that resolveNoteName's zero-match branch is covered where resolution now lives, but the name-addressed describe block in fs-vault-provider/edit-note.test.ts only had unique-match and AMBIGUOUS_MATCH cases. Add the missing zero-match -> NOT_FOUND case so the taxonomy resolveNoteName produces (shared by edit_note, set_property, remove_property) stays under test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
FsVaultWriter and IVaultEntry.writer had no remaining consumer after the edit_note tool moved to FsVaultProvider.replaceInNote/replaceFullBody (Task 3). Delete the module, its unit test, and the writer field/factory from IVaultEntry, IVaultEntryDeps, VaultRegistry, and server wiring. The deleted vault-writer.test.ts cases that had no equivalent in fs-vault-provider/edit-note.test.ts (missing-file NOT_FOUND and WRITE_FAILED for replaceInNote; the no-frontmatter, verbatim-content, and empty-content-truncation cases for replaceFullBody; and the frontmatter-preserved-even-when-find-matches-inside-it case) are ported into edit-note.test.ts so coverage carries forward unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…overage port Code review of the Task 4 coverage port found four assertions narrower than the deleted vault-writer.test.ts originals — error messages are contract surface (ADR-0003), so dropping them silently narrowed coverage: - replaceInNote WRITE_FAILED: restore the message assertion - replaceFullBody WRITE_FAILED (previously "covered by existing"): that existing test never checked message propagation; extend it - replaceInNote AMBIGUOUS_MATCH (previously "covered by existing"): restore the human-readable line-number message assertion and its explanatory comment (clients rendering only content[0].text need it) - replaceInNote NOT_FOUND (note missing): restore the writeFile-not-called assertion Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… trim duplicate test Re-pin the AMBIGUOUS_MATCH human-readable message for name-addressed edits (clients without structuredContent still need candidate paths in the text), drop a strictly-weaker duplicate traversal-name test, and comment why readDaily's error mapping stays outside the shared readRaw taxonomy (spec-pinned NOT_FOUND wording). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Tracks the three-PR consolidation of note writes onto FsVaultProvider. Group 1's tasks are ticked; groups 2 and 3 follow in later PRs. Refs #114 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This was referenced Aug 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #114
PR 1 of 3 for the
consolidate-vault-writeschange.FsVaultProviderbecomes the single module that performs every note write over a vault root, with one name ⊕ path rule resolved at one depth and one filesystem-error taxonomy for notes that already exist.What changes
replaceInNote/replaceFullBodymove ontoVaultProviderkeyed on aNoteIdentifierand are implemented byFsVaultProvider.src/lib/obsidian/vault-writer.tsis deleted, along withIVaultEntry.writer,IVaultEntryDeps.writerFactory, and thewriterFactorywiring insrc/server.ts. Its unit suite folds intotest/operations/fs-vault-provider/edit-note.test.ts, message assertions included.resolveIdentifier(tool-helpers.ts) is now the only implementation — the inline XORs increate-note.tsandedit-note.tsand the non-XOR guard insideFsVaultProvider.createNoteare gone. Every write tool hands an unresolved identifier down; the module resolves it in one of two named modes,resolveExisting(basename index) orresolveNew(.obsidian/app.json'snewFileLocation).readRaw→NOT_FOUND/READ_FAILEDandwriteRaw→WRITE_FAILED, shared by the edit and property paths, over an injectablereadFile/writeFileseam carried over from the deleted writer.createNotedeliberately keeps its ownNOTE_EXISTS/CREATE_FAILEDtaxonomy (different flags, and theheadless-vault-operationsspec mandates it), andreadDailykeeps its spec-pinnedNOT_FOUNDmessage — both now carry a comment saying so.set_propertyandremove_propertygainWRITE_FAILED/READ_FAILEDcoverage they have never had.Three behaviour changes a reviewer should meet here rather than in the diff
create_notewith bothnameandpathnow reportsdetails.field: "path"(was"name").create_notewith neither now says"Provide exactly one of name or path"(was"Provide name or path") — matching what the other three write tools already say.edit_notewithreplace: ''plus an unresolvablenamenow failsINVALID_ARGUMENTbefore touching disk (wasNOT_FOUND) — arguments are validated before I/O.Same error codes in all three cases; no test or doc pinned either string. Everything else about the client-visible contract — tool schemas, parameter names, output shapes, codes and their messages — is unchanged.
Not in this PR
listTags/listPropertiesstill hang offVaultProvider(PR 2 moves them to free functions over aVaultReaderand dropscomputeVaultOverviewto three deps). The architecture docs and ADR-0016 land in PR 3, with the archive.Verification
npm test(109 files / 1355 tests),npm run lint, andnpm run typecheckall pass.openspec validate consolidate-vault-writespasses. Acceptance greps from the plan hold: one construction site for the identifier rule, one forWRITE_FAILED, and noVaultWriter/writerFactoryreference left insrc/ortest/.🤖 Generated with Claude Code