feat(web): improve suggest-files and tree route with better error handling
This commit is contained in:
parent
f3fffec97f
commit
f23b7133cb
@ -34,7 +34,11 @@ const SKIP_DIRS = new Set([
|
||||
]);
|
||||
|
||||
/** List entries in a directory, sorted folders-first then alphabetically. */
|
||||
function listDir(absDir: string, filter?: string): SuggestItem[] {
|
||||
function listDir(
|
||||
absDir: string,
|
||||
filter?: string,
|
||||
workspaceRoot?: string,
|
||||
): SuggestItem[] {
|
||||
let entries: Dirent[];
|
||||
try {
|
||||
entries = readdirSync(absDir, { withFileTypes: true });
|
||||
@ -43,9 +47,13 @@ function listDir(absDir: string, filter?: string): SuggestItem[] {
|
||||
}
|
||||
|
||||
const lowerFilter = filter?.toLowerCase();
|
||||
const hideRootIdentity =
|
||||
typeof workspaceRoot === "string" &&
|
||||
resolve(absDir) === resolve(workspaceRoot);
|
||||
|
||||
const sorted = entries
|
||||
.filter((e) => !e.name.startsWith("."))
|
||||
.filter((e) => !(hideRootIdentity && e.name === "IDENTITY.md"))
|
||||
.filter((e) => !(e.isDirectory() && SKIP_DIRS.has(e.name)))
|
||||
.filter((e) => !lowerFilter || e.name.toLowerCase().includes(lowerFilter))
|
||||
.toSorted((a, b) => {
|
||||
@ -82,6 +90,7 @@ function searchFiles(
|
||||
query: string,
|
||||
results: SuggestItem[],
|
||||
maxResults: number,
|
||||
workspaceRoot: string,
|
||||
depth = 0,
|
||||
): void {
|
||||
if (depth > 6 || results.length >= maxResults) {return;}
|
||||
@ -94,10 +103,12 @@ function searchFiles(
|
||||
}
|
||||
|
||||
const lowerQuery = query.toLowerCase();
|
||||
const hideRootIdentity = resolve(absDir) === resolve(workspaceRoot);
|
||||
|
||||
for (const entry of entries) {
|
||||
if (results.length >= maxResults) {return;}
|
||||
if (entry.name.startsWith(".")) {continue;}
|
||||
if (hideRootIdentity && entry.name === "IDENTITY.md") {continue;}
|
||||
if (entry.isDirectory() && SKIP_DIRS.has(entry.name)) {continue;}
|
||||
|
||||
const absPath = join(absDir, entry.name);
|
||||
@ -120,7 +131,7 @@ function searchFiles(
|
||||
}
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
searchFiles(absPath, query, results, maxResults, depth + 1);
|
||||
searchFiles(absPath, query, results, maxResults, workspaceRoot, depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -393,7 +404,7 @@ export async function GET(req: Request) {
|
||||
if (searchQuery) {
|
||||
// File search: workspace only (skip expensive home dir traversal)
|
||||
const fileResults: SuggestItem[] = [];
|
||||
searchFiles(workspaceRoot, searchQuery, fileResults, 15);
|
||||
searchFiles(workspaceRoot, searchQuery, fileResults, 15, workspaceRoot);
|
||||
|
||||
// DuckDB search: objects and entries (sequential to avoid lock contention)
|
||||
const objectResults = await searchObjects(searchQuery, workspaceRoot, 10);
|
||||
@ -415,15 +426,15 @@ export async function GET(req: Request) {
|
||||
const resolved = resolvePath(pathQuery, workspaceRoot);
|
||||
if (!resolved) {
|
||||
const results: SuggestItem[] = [];
|
||||
searchFiles(workspaceRoot, pathQuery, results, 20);
|
||||
searchFiles(workspaceRoot, pathQuery, results, 20, workspaceRoot);
|
||||
return Response.json({ items: results });
|
||||
}
|
||||
const items = listDir(resolved.dir, resolved.filter);
|
||||
const items = listDir(resolved.dir, resolved.filter, workspaceRoot);
|
||||
return Response.json({ items });
|
||||
}
|
||||
|
||||
// Default: list workspace root + all objects
|
||||
const fileItems = listDir(workspaceRoot);
|
||||
const fileItems = listDir(workspaceRoot, undefined, workspaceRoot);
|
||||
const objectItems = await searchObjects("", workspaceRoot, 20);
|
||||
// Deduplicate: if an object also appears as a folder, keep the object version
|
||||
const objectNames = new Set(objectItems.map((o) => o.name));
|
||||
|
||||
@ -115,6 +115,8 @@ function buildTree(
|
||||
for (const entry of sorted) {
|
||||
// .object.yaml is consumed for metadata; only show it as a visible node when revealing hidden files
|
||||
if (entry.name === ".object.yaml" && !showHidden) {continue;}
|
||||
// Keep the root identity system file out of the workspace sidebar tree.
|
||||
if (!relativeBase && entry.name === "IDENTITY.md") {continue;}
|
||||
|
||||
const absPath = join(absDir, entry.name);
|
||||
const relPath = relativeBase
|
||||
@ -200,6 +202,7 @@ function buildSkillsVirtualFolder(): TreeNode | null {
|
||||
const entries = readdirSync(dir, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
if (!entry.isDirectory() || seen.has(entry.name)) {continue;}
|
||||
if (entry.name === "dench") {continue;}
|
||||
const skillMdPath = join(dir, entry.name, "SKILL.md");
|
||||
if (!existsSync(skillMdPath)) {continue;}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user