refactor(web): show IDENTITY.md in workspace, filter managed skills, hide bootstrap toggle

IDENTITY.md is now user-editable (no longer a system file). Managed skill filter updated from dench to crm/browser. Bootstrap seed toggle hidden from create-workspace dialog.
This commit is contained in:
kumarabhirup 2026-03-03 15:38:41 -08:00
parent 1398e556a1
commit 70ca59a66d
No known key found for this signature in database
GPG Key ID: DB7CA2289CAB0167
5 changed files with 9 additions and 45 deletions

View File

@ -37,7 +37,6 @@ const SKIP_DIRS = new Set([
function listDir(
absDir: string,
filter?: string,
workspaceRoot?: string,
): SuggestItem[] {
let entries: Dirent[];
try {
@ -47,13 +46,8 @@ function listDir(
}
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) => {
@ -90,7 +84,6 @@ function searchFiles(
query: string,
results: SuggestItem[],
maxResults: number,
workspaceRoot: string,
depth = 0,
): void {
if (depth > 6 || results.length >= maxResults) {return;}
@ -103,12 +96,9 @@ 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);
@ -131,7 +121,7 @@ function searchFiles(
}
if (entry.isDirectory()) {
searchFiles(absPath, query, results, maxResults, workspaceRoot, depth + 1);
searchFiles(absPath, query, results, maxResults, depth + 1);
}
}
}
@ -404,7 +394,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, workspaceRoot);
searchFiles(workspaceRoot, searchQuery, fileResults, 15);
// DuckDB search: objects and entries (sequential to avoid lock contention)
const objectResults = await searchObjects(searchQuery, workspaceRoot, 10);
@ -426,15 +416,15 @@ export async function GET(req: Request) {
const resolved = resolvePath(pathQuery, workspaceRoot);
if (!resolved) {
const results: SuggestItem[] = [];
searchFiles(workspaceRoot, pathQuery, results, 20, workspaceRoot);
searchFiles(workspaceRoot, pathQuery, results, 20);
return Response.json({ items: results });
}
const items = listDir(resolved.dir, resolved.filter, workspaceRoot);
const items = listDir(resolved.dir, resolved.filter);
return Response.json({ items });
}
// Default: list workspace root + all objects
const fileItems = listDir(workspaceRoot, undefined, workspaceRoot);
const fileItems = listDir(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));

View File

@ -115,9 +115,6 @@ 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
? `${relativeBase}/${entry.name}`
@ -203,7 +200,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;}
if (entry.name === "crm" || entry.name === "browser") {continue;}
const skillMdPath = join(dir, entry.name, "SKILL.md");
if (!existsSync(skillMdPath)) {continue;}

View File

@ -204,7 +204,7 @@ export function CreateWorkspaceDialog({ isOpen, onClose, onCreated }: CreateWork
</div>
{/* Bootstrap toggle */}
<label className="flex items-center gap-2 cursor-pointer">
<label className="flex items-center gap-2 cursor-pointer hidden">
<input
type="checkbox"
checked={seedBootstrap}

View File

@ -71,7 +71,6 @@ const ALWAYS_SYSTEM_PATTERNS = [
const ROOT_ONLY_SYSTEM_PATTERNS = [
/^workspace\.duckdb/,
/^workspace_context\.yaml$/,
/^IDENTITY\.md$/,
];
function isSystemFile(path: string): boolean {

View File

@ -1,6 +1,6 @@
"use client";
import { useEffect, useState, useRef, useCallback, useMemo } from "react";
import { useEffect, useState, useRef, useCallback } from "react";
import { FileManagerTree, type TreeNode } from "./file-manager-tree";
import { ProfileSwitcher } from "./profile-switcher";
import { CreateWorkspaceDialog } from "./create-workspace-dialog";
@ -389,27 +389,6 @@ function dirDisplayName(dir: string): string {
return dir.split("/").pop() || dir;
}
function filterSidebarTree(nodes: TreeNode[]): TreeNode[] {
const filtered: TreeNode[] = [];
for (const node of nodes) {
// Root identity file is system-managed and hidden in Ironclaw UI.
if (node.path === "IDENTITY.md") {
continue;
}
// Dench is an always-on managed skill; hide it from the sidebar list.
if (node.path === "~skills/dench/SKILL.md") {
continue;
}
const children = node.children ? filterSidebarTree(node.children) : undefined;
if (node.path === "~skills" && (!children || children.length === 0)) {
continue;
}
filtered.push(children ? { ...node, children } : node);
}
return filtered;
}
export function WorkspaceSidebar({
tree,
activePath,
@ -436,7 +415,6 @@ export function WorkspaceSidebar({
}: WorkspaceSidebarProps) {
const isBrowsing = browseDir != null;
const width = mobile ? "280px" : (widthProp ?? 260);
const visibleTree = useMemo(() => filterSidebarTree(tree), [tree]);
const [createWorkspaceOpen, setCreateWorkspaceOpen] = useState(false);
const sidebar = (
@ -594,7 +572,7 @@ export function WorkspaceSidebar({
</div>
) : (
<FileManagerTree
tree={visibleTree}
tree={tree}
activePath={activePath}
onSelect={onSelect}
onRefresh={onRefresh}