Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | 1x 1x 49x 10x 10x 10x 10x 17x 1x 1x 17x 12x 12x 12x 12x 12x 1x 1x 12x 12x 9x 9x 1x 15x 15x 15x 13x 13x 13x 13x 15x 15x 15x 3x 3x 3x 3x 3x 1x 1x 3x 4x 4x 1x 1x 1x 1x 1x 1x 1x 3x 15x 15x 15x 1x 1x 49x 5x 5x 49x 49x 49x | /**
* Read-only filesystem helpers used by the Settings storage report.
* Walks are synchronous because the Settings UI already blocks while it renders.
*/
import { node } from "./binary-manager";
import { sharedBinDir, sharedModelsDir, vaultsRootDir } from "./vault-registry";
import type { VaultRegistryEntry } from "./types";
export interface StorageReport {
sharedRoot: string;
binBytes: number;
modelsBytes: number;
vaults: VaultStorage[];
totalBytes: number;
}
export interface VaultStorage {
id: string;
displayName: string;
dataDir: string;
bytes: number;
}
export function dirSizeBytes(path: string): number {
if (!node.existsSync(path)) return 0;
let total = 0;
let entries: string[];
try {
entries = node.readdirSync(path) as string[];
} catch {
return 0;
}
for (const name of entries) {
const child = node.join(path, name);
let stat: ReturnType<typeof node.statSync>;
try {
stat = node.statSync(child);
} catch {
continue;
}
total += stat.isDirectory() ? dirSizeBytes(child) : stat.size;
}
return total;
}
export function reportFor(sharedRoot: string, entries: VaultRegistryEntry[]): StorageReport {
const binBytes = dirSizeBytes(sharedBinDir(sharedRoot));
const modelsBytes = dirSizeBytes(sharedModelsDir(sharedRoot));
const vaults: VaultStorage[] = entries.map((entry) => ({
id: entry.id,
displayName: entry.displayName,
dataDir: entry.dataDir,
bytes: dirSizeBytes(entry.dataDir),
}));
// Catch vault subfolders that exist on disk but aren't in the registry.
const vaultsRoot = vaultsRootDir(sharedRoot);
if (node.existsSync(vaultsRoot)) {
const registeredDirs = new Set(entries.map((e) => e.dataDir));
let names: string[];
try {
names = node.readdirSync(vaultsRoot) as string[];
} catch {
names = [];
}
for (const name of names) {
const path = node.join(vaultsRoot, name);
if (registeredDirs.has(path)) continue;
vaults.push({
id: name,
displayName: name,
dataDir: path,
bytes: dirSizeBytes(path),
});
}
}
const totalBytes = binBytes + modelsBytes + vaults.reduce((sum, v) => sum + v.bytes, 0);
return { sharedRoot, binBytes, modelsBytes, vaults, totalBytes };
}
const BYTE_UNITS = ["B", "KB", "MB", "GB", "TB"] as const;
export function formatBytes(bytes: number): string {
if (!bytes) return "0 B";
const exp = Math.min(BYTE_UNITS.length - 1, Math.floor(Math.log10(bytes) / 3));
const value = bytes / 10 ** (exp * 3);
const precision = value >= 100 ? 0 : value >= 10 ? 1 : 2;
return `${value.toFixed(precision)} ${BYTE_UNITS[exp]}`;
}
|