feat(agents): complete typed paths outside the project after @ (#332)

In the agent composer, an @ query starting with ../, ./ or / lists the contents of the directory typed so far (through path_completions) instead of searching the project file index, so files outside the project can be referenced. Picking a folder inserts @dir/ and keeps completing inside it; picking a file inserts @rel, resolved to an absolute path when sending. Typed paths resolve against Windows project roots as well, keeping the drive.
Цей коміт міститься в:
l0ng-ai authored and GitHub committed 2026-10-30 11:40:32 +08:00
1 джерело 95068f5885
коміт 0d880b9d35
3 files changed
+68 -3

No files matched your search

+18
Переглянути файл
@@ -74,6 +74,24 @@ function inOrder(text: string, query: string): boolean {
return i >= query.length;
}
/** Whether an `@` query is a typed-out path (`../x`, `./x`, `/x`) rather than a project file search. */
export const isPathQuery = (query: string) => /^(\.\.?(\/|$)|\/)/.test(query);
const isDrive = (part: string | undefined) => !!part && /^[A-Za-z]:$/.test(part);
/** `rel` (as typed after `@`) resolved against `root`, `.` and `..` folded lexically. */
export function resolveTyped(root: string, rel: string): string {
const out: string[] = [];
const path = rel.startsWith("/") ? rel : `${root.replace(/\\/g, "/")}/${rel}`;
for (const part of path.split("/")) {
if (part === "..") {
// Never fold away a Windows drive (`C:`).
if (out.length > 1 || !isDrive(out[0])) out.pop();
} else if (part && part !== ".") out.push(part);
}
return isDrive(out[0]) ? out.join("/") : `/${out.join("/")}`;
}
/** `@rel` with a line range suffix when given ("@src/a.rs:10-20"). */
export function mentionOf(rel: string, lines?: { from: number; to: number }): string {
if (!lines) return `@${rel}`;