Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 11 additions & 31 deletions electron/main/fileReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1040,41 +1040,21 @@ export class FileReader {
return [];
}

const allFiles: FileInfo[] = [];
const taskDirs = fs.readdirSync(projectPath);

for (const taskDir of taskDirs) {
if (!taskDir.startsWith('task_')) continue;

const taskPath = path.join(projectPath, taskDir);
const stats = fs.statSync(taskPath);

if (stats.isDirectory()) {
const taskId = taskDir.replace('task_', '');
const taskFiles = this.getFilesRecursive(taskPath, taskPath);

const enrichedFiles = taskFiles.map((file) => {
const fileDir = path.dirname(file.path);
const relativeParentPath = path.relative(projectPath, fileDir);

return {
...file,
task_id: taskId,
project_id: projectId,
relativePath:
relativeParentPath === '.' ? '' : relativeParentPath,
};
});
const allFiles = this.getFilesRecursive(projectPath, projectPath).map(
(file) => {
const relativePath = path.relative(projectPath, file.path);
const taskMatch = relativePath.match(/^task_([^/\\]+)/);

allFiles.push(...enrichedFiles);
return {
...file,
task_id: taskMatch?.[1],
project_id: projectId,
relativePath: relativePath === '.' ? '' : relativePath,
};
}
}
);

return allFiles.sort((a, b) => {
// Sort by task_id first, then by file path
if (a.task_id !== b.task_id) {
return a.task_id!.localeCompare(b.task_id!);
}
return a.path.localeCompare(b.path);
});
} catch (err) {
Expand Down
67 changes: 42 additions & 25 deletions src/components/Folder/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -365,8 +365,12 @@ interface FileInfo {

function getNormalizedTreeRelativePath(file: FileInfo): string {
const rel = (file.relativePath || '').replace(/\\/g, '/').replace(/^\/+/, '');
if (rel) return rel;
return (file.path || file.name || '').replace(/\\/g, '/').replace(/^\/+/, '');
const name = (file.name || '').replace(/\\/g, '/').replace(/^\/+/, '');
if (rel) {
const relBasename = rel.split('/').filter(Boolean).at(-1);
return relBasename === name || !name ? rel : `${rel}/${name}`;
}
return name || (file.path || '').replace(/\\/g, '/').replace(/^\/+/, '');
}

function getComparableRelativePath(file?: FileInfo | null): string {
Expand Down Expand Up @@ -434,9 +438,10 @@ function getFileBreadcrumbSegments(
if (file.isRemote) {
return [options.remoteRootLabel, file.name];
}
const rel = (file.relativePath || '').replace(/\\/g, '/').trim();
const folders = rel ? rel.split('/').filter(Boolean) : [];
return [options.projectRootLabel, ...folders, file.name];
const segments = getNormalizedTreeRelativePath(file)
.split('/')
.filter(Boolean);
return [options.projectRootLabel, ...segments];
}

// FileTree component to render nested file structure
Expand Down Expand Up @@ -959,29 +964,11 @@ export default function Folder({ data: _data }: { data?: Agent }) {
const folderMap = new Map<string, FileTreeNode>();
folderMap.set('', root);

const sortedFiles = [...files].sort((left, right) => {
const leftRelativePath = getNormalizedTreeRelativePath(left);
const rightRelativePath = getNormalizedTreeRelativePath(right);
const leftDepth = leftRelativePath.split('/').filter(Boolean).length;
const rightDepth = rightRelativePath.split('/').filter(Boolean).length;

if (leftDepth !== rightDepth) {
return leftDepth - rightDepth;
}

return leftRelativePath.localeCompare(rightRelativePath);
});

for (const file of sortedFiles) {
const normalizedRelativePath = getNormalizedTreeRelativePath(file);
const pathSegments = normalizedRelativePath.split('/').filter(Boolean);
const folderSegments = pathSegments.slice(0, -1);
const fileName = pathSegments[pathSegments.length - 1] || file.name;

const ensureFolderNode = (segments: string[]): FileTreeNode => {
let parentNode = root;
let currentFolderPath = '';

for (const segment of folderSegments) {
for (const segment of segments) {
currentFolderPath = currentFolderPath
? `${currentFolderPath}/${segment}`
: segment;
Expand All @@ -1002,6 +989,36 @@ export default function Folder({ data: _data }: { data?: Agent }) {
parentNode = folderNode;
}

return parentNode;
};

const sortedFiles = [...files].sort((left, right) => {
const leftRelativePath = getNormalizedTreeRelativePath(left);
const rightRelativePath = getNormalizedTreeRelativePath(right);
const leftDepth = leftRelativePath.split('/').filter(Boolean).length;
const rightDepth = rightRelativePath.split('/').filter(Boolean).length;

if (leftDepth !== rightDepth) {
return leftDepth - rightDepth;
}

return leftRelativePath.localeCompare(rightRelativePath);
});

for (const file of sortedFiles) {
const normalizedRelativePath = getNormalizedTreeRelativePath(file);
const pathSegments = normalizedRelativePath.split('/').filter(Boolean);
if (!pathSegments.length) continue;

if (file.isFolder) {
ensureFolderNode(pathSegments);
continue;
}

const folderSegments = pathSegments.slice(0, -1);
const fileName = pathSegments[pathSegments.length - 1] || file.name;
const parentNode = ensureFolderNode(folderSegments);

parentNode.children!.push({
name: fileName || file.name,
path: file.path,
Expand Down