···
// Remove any base folder name from the path
const normalizedPath = file.name.replace(/^[^\/]*\//, '');
+
// Skip files in .git directories
+
if (normalizedPath.startsWith('.git/') || normalizedPath === '.git') {
const parts = normalizedPath.split('/');
if (parts.length === 1) {
···
const subMap = extractBlobMap(entry.node as Directory, fullPath);
subMap.forEach((value, key) => blobMap.set(key, value));
+
// Skip subfs nodes - they don't contain blobs in the main tree
+
* Extract all subfs URIs from a directory tree with their mount paths
+
export function extractSubfsUris(
+
currentPath: string = ''
+
): Array<{ uri: string; path: string }> {
+
const uris: Array<{ uri: string; path: string }> = [];
+
for (const entry of directory.entries) {
+
const fullPath = currentPath ? `${currentPath}/${entry.name}` : entry.name;
+
if ('type' in entry.node) {
+
if (entry.node.type === 'subfs') {
+
// Subfs node with subject URI
+
const subfsNode = entry.node as any;
+
if (subfsNode.subject) {
+
uris.push({ uri: subfsNode.subject, path: fullPath });
+
} else if (entry.node.type === 'directory') {
+
// Recursively search subdirectories
+
const subUris = extractSubfsUris(entry.node as Directory, fullPath);
+
* Estimate the JSON size of a directory tree
+
export function estimateDirectorySize(directory: Directory): number {
+
return JSON.stringify(directory).length;
+
* Count files in a directory tree
+
export function countFilesInDirectory(directory: Directory): number {
+
for (const entry of directory.entries) {
+
if ('type' in entry.node && entry.node.type === 'file') {
+
} else if ('type' in entry.node && entry.node.type === 'directory') {
+
count += countFilesInDirectory(entry.node as Directory);
+
* Find all directories in a tree with their paths and sizes
+
export function findLargeDirectories(directory: Directory, currentPath: string = ''): Array<{
+
const result: Array<{ path: string; directory: Directory; size: number; fileCount: number }> = [];
+
for (const entry of directory.entries) {
+
if ('type' in entry.node && entry.node.type === 'directory') {
+
const dirPath = currentPath ? `${currentPath}/${entry.name}` : entry.name;
+
const dir = entry.node as Directory;
+
const size = estimateDirectorySize(dir);
+
const fileCount = countFilesInDirectory(dir);
+
result.push({ path: dirPath, directory: dir, size, fileCount });
+
// Recursively find subdirectories
+
const subdirs = findLargeDirectories(dir, dirPath);
+
result.push(...subdirs);
+
* Replace a directory with a subfs node in the tree
+
export function replaceDirectoryWithSubfs(
+
const pathParts = targetPath.split('/');
+
const targetName = pathParts[pathParts.length - 1];
+
const parentPath = pathParts.slice(0, -1).join('/');
+
// If this is a root-level directory
+
if (pathParts.length === 1) {
+
const newEntries = directory.entries.map(entry => {
+
if (entry.name === targetName && 'type' in entry.node && entry.node.type === 'directory') {
+
$type: 'place.wisp.fs#subfs' as const,
+
type: 'subfs' as const,
+
$type: 'place.wisp.fs#directory' as const,
+
type: 'directory' as const,
+
// Recursively navigate to parent directory
+
const newEntries = directory.entries.map(entry => {
+
if ('type' in entry.node && entry.node.type === 'directory') {
+
const entryPath = entry.name;
+
if (parentPath.startsWith(entryPath) || parentPath === entry.name) {
+
const remainingPath = pathParts.slice(1).join('/');
+
node: replaceDirectoryWithSubfs(entry.node as Directory, remainingPath, subfsUri)
+
$type: 'place.wisp.fs#directory' as const,
+
type: 'directory' as const,