mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-08-18 13:15:51 +00:00
fix(vscode): allow editor mentions for files outside the working directory (#1836)
* fix(vscode): allow editor mentions for files outside the working directory * fix(vscode): quote editor mentions whose paths contain spaces
This commit is contained in:
parent
1b907b07cd
commit
429521b669
2 changed files with 79 additions and 9 deletions
|
|
@ -210,14 +210,21 @@ export class BridgeHandler {
|
|||
selection: vscode.Selection,
|
||||
): Promise<string | null> {
|
||||
const workDirUri = this.getWorkDirUri(webviewId);
|
||||
if (workDirUri === null || !(await isWorkspacePathContained(workDirUri, documentUri))) return null;
|
||||
const relativePath = relativeWorkspacePath(workDirUri, documentUri);
|
||||
if (relativePath === undefined) return null;
|
||||
// Mirror the CLI/TUI: no UI-level directory gate on mentions. Inside the
|
||||
// working directory the mention is relative; outside it (for example a
|
||||
// file under the session's additionalDirs) it falls back to the absolute
|
||||
// path, and the session's tool layer decides readability. Virtual
|
||||
// documents (untitled:, git:, ...) have no meaningful path to mention.
|
||||
if (workDirUri === null || documentUri.scheme !== workDirUri.scheme) return null;
|
||||
const filePath = relativeWorkspacePath(workDirUri, documentUri) ?? documentUri.fsPath;
|
||||
// Quote paths containing spaces, as the CLI/TUI mention completers do, so
|
||||
// whitespace cannot split the path; any line range goes after the quote.
|
||||
const mentionTarget = filePath.includes(" ") ? `"${filePath}"` : filePath;
|
||||
|
||||
if (selection.isEmpty) return `@${relativePath}`;
|
||||
if (selection.isEmpty) return `@${mentionTarget}`;
|
||||
return selection.start.line === selection.end.line
|
||||
? `@${relativePath}:${selection.start.line + 1}`
|
||||
: `@${relativePath}:${selection.start.line + 1}-${selection.end.line + 1}`;
|
||||
? `@${mentionTarget}:${selection.start.line + 1}`
|
||||
: `@${mentionTarget}:${selection.start.line + 1}-${selection.end.line + 1}`;
|
||||
}
|
||||
|
||||
captureFileBaseline(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/**
|
||||
* Scenario: Webview file paths stay inside the selected working directory.
|
||||
* Responsibilities: directory/search/open/mention paths are scoped, normalized, and symlink-safe.
|
||||
* Scenario: Webview file paths and the selected working directory.
|
||||
* Responsibilities: directory/search/open paths are scoped, normalized, and symlink-safe;
|
||||
* editor mentions use relative paths inside the working directory and absolute paths outside.
|
||||
* Wiring: real temporary local files plus the public handler/bridge surfaces;
|
||||
* VS Code host APIs are the only stubbed boundary.
|
||||
* Run: pnpm --filter kimi-code exec vitest run --config vitest.config.ts test/workspace-paths.test.ts
|
||||
|
|
@ -343,7 +344,7 @@ describe("Webview workspace paths (selected-directory containment)", () => {
|
|||
expect(mention).toBe("@src/inside.ts");
|
||||
});
|
||||
|
||||
it("omits an editor mention when the file is outside the selected working directory", async () => {
|
||||
it("builds an absolute editor mention when the file is outside the selected working directory", async () => {
|
||||
const workDir = join(root, "project", "subproject");
|
||||
const sibling = join(root, "project", "sibling.ts");
|
||||
await mkdir(workDir, { recursive: true });
|
||||
|
|
@ -357,6 +358,68 @@ describe("Webview workspace paths (selected-directory containment)", () => {
|
|||
emptySelection(),
|
||||
);
|
||||
|
||||
expect(mention).toBe(`@${sibling}`);
|
||||
});
|
||||
|
||||
it("builds an absolute editor mention when the file is outside the workspace root", async () => {
|
||||
const otherRoot = await mkdtemp(join(tmpdir(), "kimi-vscode-mention-outside-"));
|
||||
extraRoots.push(otherRoot);
|
||||
const outside = join(otherRoot, "App.java");
|
||||
await writeFile(outside, "class App {}");
|
||||
const bridge = createBridge();
|
||||
|
||||
const mention = await bridge.getEditorMention(
|
||||
"view-1",
|
||||
vscodeHost.Uri.file(outside) as vscode.Uri,
|
||||
emptySelection(),
|
||||
);
|
||||
|
||||
expect(mention).toBe(`@${outside}`);
|
||||
});
|
||||
|
||||
it("quotes an absolute editor mention whose path contains spaces", async () => {
|
||||
const otherRoot = await mkdtemp(join(tmpdir(), "kimi vscode mention space-"));
|
||||
extraRoots.push(otherRoot);
|
||||
const outside = join(otherRoot, "App.java");
|
||||
await writeFile(outside, "class App {}");
|
||||
const bridge = createBridge();
|
||||
|
||||
const mention = await bridge.getEditorMention(
|
||||
"view-1",
|
||||
vscodeHost.Uri.file(outside) as vscode.Uri,
|
||||
emptySelection(),
|
||||
);
|
||||
|
||||
expect(mention).toBe(`@"${outside}"`);
|
||||
});
|
||||
|
||||
it("places the line range after the closing quote of a mention with spaces", async () => {
|
||||
const workDir = join(root, "project");
|
||||
const inside = join(workDir, "some dir", "inside.ts");
|
||||
await mkdir(join(workDir, "some dir"), { recursive: true });
|
||||
await writeFile(inside, "inside");
|
||||
const bridge = createBridge();
|
||||
await bridge.handle({ id: "set", method: Methods.SetWorkDir, params: { workDir } }, "view-1");
|
||||
|
||||
const mention = await bridge.getEditorMention(
|
||||
"view-1",
|
||||
vscodeHost.Uri.file(inside) as vscode.Uri,
|
||||
{ isEmpty: false, start: { line: 2 }, end: { line: 4 } } as vscode.Selection,
|
||||
);
|
||||
|
||||
expect(mention).toBe('@"some dir/inside.ts":3-5');
|
||||
});
|
||||
|
||||
it("omits an editor mention for a document that is not on the workspace file system", async () => {
|
||||
const bridge = createBridge();
|
||||
const untitled = vscodeHost.Uri.from({ scheme: "untitled", path: "Untitled-1" });
|
||||
|
||||
const mention = await bridge.getEditorMention(
|
||||
"view-1",
|
||||
untitled as vscode.Uri,
|
||||
emptySelection(),
|
||||
);
|
||||
|
||||
expect(mention).toBeNull();
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue