feat: add main features

Agents for developpement added + frontend add + backend added. Git viewer created + agent and template creator + layout and project creator
This commit is contained in:
2026-06-06 01:27:01 +02:00
parent 55b3bee2c8
commit 307ae71857
273 changed files with 48740 additions and 0 deletions

View File

@ -0,0 +1,69 @@
/**
* Pure helper that folds a flat list of changed file paths into a directory
* tree, so the Git panel can show changes as a file tree (L8 visual). Kept free
* of React for straightforward unit testing.
*/
import type { GitFileStatus } from "@/domain";
/** A node in the changed-files tree: a directory or a file leaf. */
export interface GitTreeNode {
/** Last path segment (folder or file name). */
name: string;
/** Full repo-relative path of this node. */
path: string;
/** Whether this node is a directory (has children) or a file leaf. */
isDir: boolean;
/** For file leaves: whether the change is staged. */
staged: boolean;
/** Child nodes (empty for files). */
children: GitTreeNode[];
}
/**
* Builds the directory tree for a set of changed files. Directories come before
* files at each level, both alphabetically sorted.
*/
export function buildFileTree(files: GitFileStatus[]): GitTreeNode[] {
const root: GitTreeNode = {
name: "",
path: "",
isDir: true,
staged: false,
children: [],
};
for (const file of files) {
const parts = file.path.split("/").filter(Boolean);
let node = root;
parts.forEach((part, i) => {
const isLeaf = i === parts.length - 1;
const path = parts.slice(0, i + 1).join("/");
let child = node.children.find(
(c) => c.name === part && c.isDir === !isLeaf,
);
if (!child) {
child = {
name: part,
path,
isDir: !isLeaf,
staged: file.staged,
children: [],
};
node.children.push(child);
}
node = child;
});
}
sort(root);
return root.children;
}
function sort(node: GitTreeNode): void {
node.children.sort((a, b) => {
if (a.isDir !== b.isDir) return a.isDir ? -1 : 1;
return a.name.localeCompare(b.name);
});
node.children.forEach(sort);
}