Skip to content

Commit a72f04f

Browse files
committed
Chipify absolute file paths in @ mentions
1 parent 545cc69 commit a72f04f

4 files changed

Lines changed: 56 additions & 3 deletions

File tree

apps/code/src/main/services/fs/schemas.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const fileEntry = z.object({
2929

3030
export const listRepoFilesOutput = z.array(fileEntry);
3131
export const readRepoFileOutput = z.string().nullable();
32+
export const fileExistsOutput = z.boolean();
3233

3334
export type ListRepoFilesInput = z.infer<typeof listRepoFilesInput>;
3435
export type ReadRepoFileInput = z.infer<typeof readRepoFileInput>;

apps/code/src/main/services/fs/service.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,15 @@ export class FsService {
9797
}
9898
}
9999

100+
async fileExists(filePath: string): Promise<boolean> {
101+
try {
102+
const stat = await fs.promises.stat(path.resolve(filePath));
103+
return stat.isFile();
104+
} catch {
105+
return false;
106+
}
107+
}
108+
100109
async readAbsoluteFile(filePath: string): Promise<string | null> {
101110
try {
102111
return await fs.promises.readFile(path.resolve(filePath), "utf-8");

apps/code/src/main/trpc/routers/fs.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { container } from "../../di/container";
22
import { MAIN_TOKENS } from "../../di/tokens";
33
import {
4+
fileExistsOutput,
45
listRepoFilesInput,
56
listRepoFilesOutput,
67
readAbsoluteFileInput,
@@ -33,6 +34,11 @@ export const fsRouter = router({
3334
.output(readRepoFileOutput)
3435
.query(({ input }) => getService().readAbsoluteFile(input.filePath)),
3536

37+
fileExists: publicProcedure
38+
.input(readAbsoluteFileInput)
39+
.output(fileExistsOutput)
40+
.query(({ input }) => getService().fileExists(input.filePath)),
41+
3642
readFileAsBase64: publicProcedure
3743
.input(readAbsoluteFileInput)
3844
.output(readRepoFileOutput)

apps/code/src/renderer/features/message-editor/suggestions/getSuggestions.ts

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import type { AvailableCommand } from "@agentclientprotocol/sdk";
22
import { CODE_COMMANDS } from "@features/message-editor/commands";
33
import { getAvailableCommandsForTask } from "@features/sessions/stores/sessionStore";
4-
import { fetchRepoFiles, searchFiles } from "@hooks/useRepoFiles";
4+
import {
5+
fetchRepoFiles,
6+
pathToFileItem,
7+
searchFiles,
8+
} from "@hooks/useRepoFiles";
9+
import { trpcClient } from "@renderer/trpc/client";
10+
import { isAbsolutePath } from "@utils/path";
511
import Fuse, { type IFuseOptions } from "fuse.js";
612
import { useDraftStore } from "../stores/draftStore";
713
import type { CommandSuggestionItem, FileSuggestionItem } from "../types";
@@ -39,20 +45,44 @@ function searchCommands(
3945
return results.map((result) => result.item);
4046
}
4147

48+
async function getAbsolutePathSuggestion(
49+
query: string,
50+
): Promise<FileSuggestionItem | null> {
51+
if (!isAbsolutePath(query)) return null;
52+
53+
try {
54+
const exists = await trpcClient.fs.fileExists.query({ filePath: query });
55+
if (!exists) return null;
56+
} catch {
57+
return null;
58+
}
59+
60+
const fileItem = pathToFileItem(query);
61+
return {
62+
id: query,
63+
label: fileItem.name,
64+
description: fileItem.dir || undefined,
65+
filename: fileItem.name,
66+
path: query,
67+
};
68+
}
69+
4270
export async function getFileSuggestions(
4371
sessionId: string,
4472
query: string,
4573
): Promise<FileSuggestionItem[]> {
4674
const repoPath = useDraftStore.getState().contexts[sessionId]?.repoPath;
75+
const absolutePathSuggestion = getAbsolutePathSuggestion(query);
4776

4877
if (!repoPath) {
49-
return [];
78+
const resolved = await absolutePathSuggestion;
79+
return resolved ? [resolved] : [];
5080
}
5181

5282
const { files, fzf } = await fetchRepoFiles(repoPath);
5383
const matched = searchFiles(fzf, files, query);
5484

55-
return matched.map((file) => {
85+
const results: FileSuggestionItem[] = matched.map((file) => {
5686
const parentDir = file.dir ? file.dir.split("/").pop() : undefined;
5787
const label = parentDir ? `${parentDir}/${file.name}` : file.name;
5888

@@ -64,6 +94,13 @@ export async function getFileSuggestions(
6494
path: file.path,
6595
};
6696
});
97+
98+
const resolved = await absolutePathSuggestion;
99+
if (resolved && !results.some((r) => r.id === resolved.id)) {
100+
results.unshift(resolved);
101+
}
102+
103+
return results;
67104
}
68105

69106
export function getCommandSuggestions(

0 commit comments

Comments
 (0)