mirror of
https://github.com/logancyang/obsidian-copilot.git
synced 2026-07-22 07:50:24 +00:00
fix(miyo): strip vault folder-name prefix from indexed paths (#2390)
Miyo returns indexed file paths prefixed with the owning folder name (the vault name), but getVaultRelativeMiyoPath was stripping the absolute filesystem path prefix instead. As a result, the "List Indexed Files" command rendered every entry as a broken Obsidian link (e.g. [[MyVault/notes/foo.md]] instead of [[notes/foo.md]]). Switch the strip logic to match what Miyo actually returns. Files from other vaults pass through unchanged so cross-vault search results stay intact. Always return a forward-slash-normalized path so callers see a consistent separator. Drop the now-unused getVaultBasePath helper. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
37bea9a65c
commit
94737297b7
2 changed files with 69 additions and 47 deletions
|
|
@ -2,7 +2,7 @@ jest.mock("@/plusUtils", () => ({
|
|||
isSelfHostAccessValid: jest.fn(),
|
||||
}));
|
||||
|
||||
import { getMiyoFolderName } from "@/miyo/miyoUtils";
|
||||
import { getMiyoFolderName, getVaultRelativeMiyoPath } from "@/miyo/miyoUtils";
|
||||
|
||||
describe("getMiyoFolderName", () => {
|
||||
it("uses the vault folder name even when an adapter exposes an absolute path", () => {
|
||||
|
|
@ -18,3 +18,44 @@ describe("getMiyoFolderName", () => {
|
|||
expect(folderName).toBe("graham-essays-main");
|
||||
});
|
||||
});
|
||||
|
||||
describe("getVaultRelativeMiyoPath", () => {
|
||||
const buildApp = (vaultName: string) =>
|
||||
({
|
||||
vault: {
|
||||
getName: () => vaultName,
|
||||
},
|
||||
}) as any;
|
||||
|
||||
it("strips the current vault folder-name prefix", () => {
|
||||
expect(getVaultRelativeMiyoPath(buildApp("MyVault"), "MyVault/notes/foo.md")).toBe(
|
||||
"notes/foo.md"
|
||||
);
|
||||
});
|
||||
|
||||
it("returns the normalized path unchanged when the prefix matches a different vault", () => {
|
||||
expect(getVaultRelativeMiyoPath(buildApp("MyVault"), "OtherVault/notes/foo.md")).toBe(
|
||||
"OtherVault/notes/foo.md"
|
||||
);
|
||||
});
|
||||
|
||||
it("normalizes separators even when the prefix does not match", () => {
|
||||
expect(getVaultRelativeMiyoPath(buildApp("MyVault"), "OtherVault\\notes\\foo.md")).toBe(
|
||||
"OtherVault/notes/foo.md"
|
||||
);
|
||||
});
|
||||
|
||||
it("only strips the leading prefix once", () => {
|
||||
expect(getVaultRelativeMiyoPath(buildApp("Test"), "Test/Test/foo.md")).toBe("Test/foo.md");
|
||||
});
|
||||
|
||||
it("normalizes backslash separators before stripping", () => {
|
||||
expect(getVaultRelativeMiyoPath(buildApp("MyVault"), "MyVault\\notes\\foo.md")).toBe(
|
||||
"notes/foo.md"
|
||||
);
|
||||
});
|
||||
|
||||
it("returns the normalized path when the vault folder name is empty", () => {
|
||||
expect(getVaultRelativeMiyoPath(buildApp(""), "notes\\foo.md")).toBe("notes/foo.md");
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,6 +2,16 @@ import { isSelfHostAccessValid } from "@/plusUtils";
|
|||
import { CopilotSettings } from "@/settings/model";
|
||||
import { App, FileSystemAdapter, Platform } from "obsidian";
|
||||
|
||||
/**
|
||||
* Convert backslashes to forward slashes and trim trailing slashes.
|
||||
*
|
||||
* @param path - Filesystem path.
|
||||
* @returns Normalized path.
|
||||
*/
|
||||
function normalizeFilesystemPath(path: string): string {
|
||||
return path.replace(/\\/g, "/").replace(/\/+$/, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the user-configured Miyo server URL, or "" to fall back to local service discovery.
|
||||
* Uses `|| ""` to guard against undefined when loaded from older saved settings.
|
||||
|
|
@ -67,57 +77,28 @@ export function getMiyoAbsolutePath(app: App, vaultRelativePath: string): string
|
|||
}
|
||||
|
||||
/**
|
||||
* Convert a Miyo file path back to a vault-relative path when it belongs to the current vault.
|
||||
* Convert a Miyo file path to a vault-relative path when it belongs to the current vault.
|
||||
*
|
||||
* Miyo always returns paths prefixed with their owning folder name. When the
|
||||
* prefix matches the current vault's folder name, strip it to get a
|
||||
* vault-relative path. Files from other vaults pass through unchanged. The
|
||||
* returned path is always normalized to forward slashes.
|
||||
*
|
||||
* @param app - Obsidian application instance.
|
||||
* @param miyoPath - Path returned by Miyo.
|
||||
* @returns Vault-relative path when the file is inside the current vault, otherwise the original path.
|
||||
* @param miyoPath - Path returned by Miyo (e.g., "MyVault/notes/foo.md").
|
||||
* @returns Normalized vault-relative path when inside the current vault, otherwise the normalized original path.
|
||||
*/
|
||||
export function getVaultRelativeMiyoPath(app: App, miyoPath: string): string {
|
||||
const vaultPath = getVaultBasePath(app);
|
||||
if (!vaultPath) {
|
||||
return miyoPath;
|
||||
}
|
||||
|
||||
const normalizedVaultPath = normalizeFilesystemPath(vaultPath);
|
||||
const normalizedMiyoPath = normalizeFilesystemPath(miyoPath);
|
||||
const prefix = `${normalizedVaultPath}/`;
|
||||
|
||||
if (normalizedMiyoPath.startsWith(prefix)) {
|
||||
return normalizedMiyoPath.slice(prefix.length);
|
||||
const folderName = getMiyoFolderName(app);
|
||||
if (!folderName) {
|
||||
return normalizedMiyoPath;
|
||||
}
|
||||
|
||||
return miyoPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the base path for the current vault when available.
|
||||
*
|
||||
* @param app - Obsidian application instance.
|
||||
* @returns Vault base path or undefined when unavailable.
|
||||
*/
|
||||
export function getVaultBasePath(app: App): string | undefined {
|
||||
const adapter = app.vault.adapter;
|
||||
if (adapter instanceof FileSystemAdapter) {
|
||||
return adapter.getBasePath();
|
||||
}
|
||||
|
||||
const adapterAny = adapter as unknown as { getBasePath?: () => string; basePath?: string };
|
||||
if (typeof adapterAny.getBasePath === "function") {
|
||||
return adapterAny.getBasePath();
|
||||
}
|
||||
if (typeof adapterAny.basePath === "string") {
|
||||
return adapterAny.basePath;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a filesystem path for prefix comparisons across platforms.
|
||||
*
|
||||
* @param path - Filesystem path.
|
||||
* @returns Normalized path with forward slashes and no trailing slash.
|
||||
*/
|
||||
function normalizeFilesystemPath(path: string): string {
|
||||
return path.replace(/\\/g, "/").replace(/\/+$/, "");
|
||||
const folderPrefix = `${folderName}/`;
|
||||
if (normalizedMiyoPath.startsWith(folderPrefix)) {
|
||||
return normalizedMiyoPath.slice(folderPrefix.length);
|
||||
}
|
||||
|
||||
return normalizedMiyoPath;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue