fix(vault): pass vault= as top-level obsidian cli option
The vault=<name> argument was appended after the subcommand (obsidian bases vault=Work), but the Obsidian CLI only honors it as a top-level option before the subcommand. Placed after, the subcommand consumed/ignored it and the command bound to whichever vault had window focus, so vault://<name>?op=... silently queried the wrong vault. Prepend the vault arg in #runCli and #vaultInfo so it precedes the subcommand (obsidian vault=Work bases), matching the CLI's documented top-level-option semantics. Fixes #7771
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed `vault://<name>?op=...` commands targeting the focused/most-recently-active vault instead of the named one. The `vault=<name>` argument was appended after the Obsidian CLI subcommand (`obsidian bases vault=Work`), but the CLI only honors it as a top-level option before the subcommand (`obsidian vault=Work bases`); it is now prepended so the named vault is queried (and opened) regardless of window focus ([#7771](https://github.com/can1357/oh-my-pi/issues/7771)).
|
||||
|
||||
## [17.2.9] - 2026-08-05
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
@@ -787,7 +787,7 @@ export class VaultProtocolHandler implements ProtocolHandler {
|
||||
const cacheKey = parsed.ref.active ? "_" : (parsed.ref.vault ?? "_");
|
||||
let cliInfo = cachedVaultInfo.get(cacheKey);
|
||||
if (cliInfo === undefined) {
|
||||
const result = await this.#spawn(["vault", "info", ...this.#vaultCliArg(parsed.ref)], context);
|
||||
const result = await this.#spawn([...this.#vaultCliArg(parsed.ref), "vault", "info"], context);
|
||||
assertCliSuccess("vault info", result);
|
||||
cliInfo = result.stdout.trim();
|
||||
cachedVaultInfo.set(cacheKey, cliInfo);
|
||||
@@ -926,7 +926,7 @@ export class VaultProtocolHandler implements ProtocolHandler {
|
||||
context?: ResolveContext,
|
||||
): Promise<InternalResource> {
|
||||
const invocation = buildObsidianCliInvocation(parsed);
|
||||
const args = [...invocation.args, ...this.#vaultCliArg(parsed.ref)];
|
||||
const args = [...this.#vaultCliArg(parsed.ref), ...invocation.args];
|
||||
const result = await this.#spawn(args, context);
|
||||
assertCliSuccess(invocation.opLabel, result);
|
||||
return {
|
||||
|
||||
@@ -183,6 +183,26 @@ describe("VaultProtocolHandler", () => {
|
||||
expect(spawnSpy.mock.calls[0][1]).toEqual(["vault", "info", "path"]);
|
||||
});
|
||||
});
|
||||
|
||||
it("targets a named vault by prepending vault= before the vault info subcommand", async () => {
|
||||
await withTempDir(async tempDir => {
|
||||
const root = path.join(tempDir, "work-vault");
|
||||
await fs.mkdir(root, { recursive: true });
|
||||
await Bun.write(path.join(root, "note.md"), "note");
|
||||
VaultProtocolHandler.setVaultDirectoryForTests({ Work: root });
|
||||
const spawnSpy = vi.spyOn(vaultProtocol, "spawnObsidian").mockResolvedValue({
|
||||
stdout: `name\tWork\npath\t${root}\n`,
|
||||
stderr: "",
|
||||
exitCode: 0,
|
||||
});
|
||||
const handler = testHandler(vaultProtocol.spawnObsidian);
|
||||
|
||||
await handler.resolve(resourceUrl("vault://Work"));
|
||||
|
||||
expect(spawnSpy).toHaveBeenCalledTimes(1);
|
||||
expect(spawnSpy.mock.calls[0][1]).toEqual(["vault=Work", "vault", "info"]);
|
||||
});
|
||||
});
|
||||
it("writes files through the protocol hook and resolves cached vault paths for edit plumbing", async () => {
|
||||
await withTempDir(async tempDir => {
|
||||
const root = path.join(tempDir, "vault");
|
||||
@@ -290,31 +310,31 @@ describe("VaultProtocolHandler", () => {
|
||||
}
|
||||
|
||||
expect(calls).toEqual({
|
||||
outline: ["outline", "path=Note.md", "format=md", "vault=Work"],
|
||||
backlinks: ["backlinks", "path=Note.md", "counts", "format=tsv", "vault=Work"],
|
||||
links: ["links", "path=Note.md", "vault=Work"],
|
||||
fileTags: ["tags", "path=Note.md", "counts", "format=json", "vault=Work"],
|
||||
fileProperties: ["properties", "path=Note.md", "format=yaml", "vault=Work"],
|
||||
fileTasks: ["tasks", "path=Note.md", "verbose", "format=json", "vault=Work"],
|
||||
wordcount: ["wordcount", "path=Note.md", "vault=Work"],
|
||||
history: ["history", "path=Note.md", "vault=Work"],
|
||||
base: ["base:query", "path=Note.md", "view=Main", "format=md", "vault=Work"],
|
||||
search: ["search:context", "query=plan", "path=Folder", "limit=5", "case", "format=json", "vault=Work"],
|
||||
daily: ["daily:read", "vault=Work"],
|
||||
dailyPath: ["daily:path", "vault=Work"],
|
||||
vaultTags: ["tags", "counts", "format=json", "vault=Work"],
|
||||
tag: ["tag", "name=#todo", "verbose", "vault=Work"],
|
||||
vaultTasks: ["tasks", "todo", "verbose", "format=json", "vault=Work"],
|
||||
orphans: ["orphans", "vault=Work"],
|
||||
unresolved: ["unresolved", "counts", "verbose", "format=json", "vault=Work"],
|
||||
deadends: ["deadends", "vault=Work"],
|
||||
bases: ["bases", "vault=Work"],
|
||||
bookmarks: ["bookmarks", "verbose", "format=json", "vault=Work"],
|
||||
recents: ["recents", "vault=Work"],
|
||||
templates: ["templates", "vault=Work"],
|
||||
aliases: ["aliases", "verbose", "format=json", "vault=Work"],
|
||||
vaultProperties: ["properties", "counts", "format=yaml", "vault=Work"],
|
||||
property: ["property:read", "name=status", "path=Note.md", "vault=Work"],
|
||||
outline: ["vault=Work", "outline", "path=Note.md", "format=md"],
|
||||
backlinks: ["vault=Work", "backlinks", "path=Note.md", "counts", "format=tsv"],
|
||||
links: ["vault=Work", "links", "path=Note.md"],
|
||||
fileTags: ["vault=Work", "tags", "path=Note.md", "counts", "format=json"],
|
||||
fileProperties: ["vault=Work", "properties", "path=Note.md", "format=yaml"],
|
||||
fileTasks: ["vault=Work", "tasks", "path=Note.md", "verbose", "format=json"],
|
||||
wordcount: ["vault=Work", "wordcount", "path=Note.md"],
|
||||
history: ["vault=Work", "history", "path=Note.md"],
|
||||
base: ["vault=Work", "base:query", "path=Note.md", "view=Main", "format=md"],
|
||||
search: ["vault=Work", "search:context", "query=plan", "path=Folder", "limit=5", "case", "format=json"],
|
||||
daily: ["vault=Work", "daily:read"],
|
||||
dailyPath: ["vault=Work", "daily:path"],
|
||||
vaultTags: ["vault=Work", "tags", "counts", "format=json"],
|
||||
tag: ["vault=Work", "tag", "name=#todo", "verbose"],
|
||||
vaultTasks: ["vault=Work", "tasks", "todo", "verbose", "format=json"],
|
||||
orphans: ["vault=Work", "orphans"],
|
||||
unresolved: ["vault=Work", "unresolved", "counts", "verbose", "format=json"],
|
||||
deadends: ["vault=Work", "deadends"],
|
||||
bases: ["vault=Work", "bases"],
|
||||
bookmarks: ["vault=Work", "bookmarks", "verbose", "format=json"],
|
||||
recents: ["vault=Work", "recents"],
|
||||
templates: ["vault=Work", "templates"],
|
||||
aliases: ["vault=Work", "aliases", "verbose", "format=json"],
|
||||
vaultProperties: ["vault=Work", "properties", "counts", "format=yaml"],
|
||||
property: ["vault=Work", "property:read", "name=status", "path=Note.md"],
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user