@aladac/hu 0.1.0-a1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/.tool-versions +1 -0
  2. package/CLAUDE.md +122 -0
  3. package/HOOKS-DATA-INTEGRATION.md +457 -0
  4. package/SAMPLE.md +378 -0
  5. package/TODO.md +25 -0
  6. package/biome.json +51 -0
  7. package/commands/bootstrap.md +13 -0
  8. package/commands/c.md +1 -0
  9. package/commands/check-name.md +62 -0
  10. package/commands/disk.md +141 -0
  11. package/commands/docs/archive.md +27 -0
  12. package/commands/docs/check-internal.md +53 -0
  13. package/commands/docs/cleanup.md +65 -0
  14. package/commands/docs/consolidate.md +72 -0
  15. package/commands/docs/get.md +101 -0
  16. package/commands/docs/list.md +61 -0
  17. package/commands/docs/sync.md +64 -0
  18. package/commands/docs/update.md +49 -0
  19. package/commands/plans/clear.md +23 -0
  20. package/commands/plans/create.md +71 -0
  21. package/commands/plans/list.md +21 -0
  22. package/commands/plans/sync.md +38 -0
  23. package/commands/reinstall.md +20 -0
  24. package/commands/replicate.md +303 -0
  25. package/commands/warp.md +0 -0
  26. package/doc/README.md +35 -0
  27. package/doc/claude-code/capabilities.md +202 -0
  28. package/doc/claude-code/directory-structure.md +246 -0
  29. package/doc/claude-code/hooks.md +348 -0
  30. package/doc/claude-code/overview.md +109 -0
  31. package/doc/claude-code/plugins.md +273 -0
  32. package/doc/claude-code/sdk-protocols.md +202 -0
  33. package/document-manifest.toml +29 -0
  34. package/justfile +39 -0
  35. package/package.json +33 -0
  36. package/plans/compiled-watching-feather.md +217 -0
  37. package/plans/crispy-crafting-pnueli.md +103 -0
  38. package/plans/greedy-booping-coral.md +146 -0
  39. package/plans/imperative-sleeping-flamingo.md +192 -0
  40. package/plans/jaunty-sprouting-marble.md +171 -0
  41. package/plans/jiggly-discovering-lake.md +68 -0
  42. package/plans/magical-nibbling-spark.md +144 -0
  43. package/plans/mellow-kindling-acorn.md +110 -0
  44. package/plans/recursive-questing-engelbart.md +65 -0
  45. package/plans/serialized-roaming-kernighan.md +227 -0
  46. package/plans/structured-wondering-wirth.md +230 -0
  47. package/plans/vectorized-dreaming-iverson.md +191 -0
  48. package/plans/velvety-enchanting-ocean.md +92 -0
  49. package/plans/wiggly-sparking-pixel.md +48 -0
  50. package/plans/zippy-shimmying-fox.md +188 -0
  51. package/plugins/installed_plugins.json +4 -0
  52. package/sample-hooks.json +298 -0
  53. package/settings.json +24 -0
  54. package/settings.local.json +7 -0
  55. package/src/commands/bump.ts +130 -0
  56. package/src/commands/disk.ts +419 -0
  57. package/src/commands/docs.ts +729 -0
  58. package/src/commands/plans.ts +259 -0
  59. package/src/commands/utils.ts +299 -0
  60. package/src/index.ts +26 -0
  61. package/src/lib/colors.ts +87 -0
  62. package/src/lib/exec.ts +25 -0
  63. package/src/lib/fs.ts +119 -0
  64. package/src/lib/html.ts +205 -0
  65. package/src/lib/spinner.ts +42 -0
  66. package/src/types/index.ts +61 -0
  67. package/tests/lib/colors.test.ts +69 -0
  68. package/tests/lib/fs.test.ts +65 -0
  69. package/tsconfig.json +20 -0
  70. package/vitest.config.ts +15 -0
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env npx tsx
2
+ /**
3
+ * Version bumping script
4
+ * Usage: npx tsx src/commands/bump.ts [patch|minor|major]
5
+ * - No args: bump pre-release number (1.0.0-pre1 -> 1.0.0-pre2)
6
+ * - patch: bump patch version (1.0.0-pre1 -> 1.0.1-pre1, or 1.0.0 -> 1.0.1)
7
+ * - minor: bump minor version (1.0.0 -> 1.1.0, or 1.0.0-pre1 -> 1.1.0-pre1)
8
+ * - major: bump major version (1.0.0 -> 2.0.0)
9
+ */
10
+
11
+ import { execSync } from 'node:child_process';
12
+ import { readFileSync, writeFileSync } from 'node:fs';
13
+ import { join } from 'node:path';
14
+
15
+ const ROOT_DIR = join(import.meta.dirname, '../..');
16
+
17
+ interface VersionParts {
18
+ major: number;
19
+ minor: number;
20
+ patch: number;
21
+ pre: number | null;
22
+ }
23
+
24
+ function parseVersion(version: string): VersionParts {
25
+ const match = version.match(/^(\d+)\.(\d+)\.(\d+)(-pre(\d+))?$/);
26
+ if (!match) {
27
+ throw new Error(`Cannot parse version '${version}'`);
28
+ }
29
+ return {
30
+ major: Number.parseInt(match[1], 10),
31
+ minor: Number.parseInt(match[2], 10),
32
+ patch: Number.parseInt(match[3], 10),
33
+ pre: match[5] ? Number.parseInt(match[5], 10) : null,
34
+ };
35
+ }
36
+
37
+ function formatVersion(parts: VersionParts): string {
38
+ const base = `${parts.major}.${parts.minor}.${parts.patch}`;
39
+ return parts.pre !== null ? `${base}-pre${parts.pre}` : base;
40
+ }
41
+
42
+ function bumpVersion(current: string, type?: string): string {
43
+ const parts = parseVersion(current);
44
+
45
+ switch (type) {
46
+ case 'major':
47
+ case '--major':
48
+ parts.major++;
49
+ parts.minor = 0;
50
+ parts.patch = 0;
51
+ if (parts.pre !== null) parts.pre = 1;
52
+ break;
53
+
54
+ case 'minor':
55
+ case '--minor':
56
+ parts.minor++;
57
+ parts.patch = 0;
58
+ if (parts.pre !== null) parts.pre = 1;
59
+ break;
60
+
61
+ case 'patch':
62
+ case '--patch':
63
+ parts.patch++;
64
+ if (parts.pre !== null) parts.pre = 1;
65
+ break;
66
+
67
+ default:
68
+ // Bump pre-release number
69
+ if (parts.pre !== null) {
70
+ parts.pre++;
71
+ } else {
72
+ parts.pre = 1;
73
+ }
74
+ break;
75
+ }
76
+
77
+ return formatVersion(parts);
78
+ }
79
+
80
+ function exec(cmd: string): string {
81
+ return execSync(cmd, { cwd: ROOT_DIR, encoding: 'utf-8' }).trim();
82
+ }
83
+
84
+ function run(cmd: string): void {
85
+ execSync(cmd, { cwd: ROOT_DIR, stdio: 'inherit' });
86
+ }
87
+
88
+ async function main() {
89
+ const arg = process.argv[2];
90
+
91
+ // Read current version from package.json
92
+ const pkgPath = join(ROOT_DIR, 'package.json');
93
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
94
+ const currentVersion = pkg.version;
95
+
96
+ console.log(`Current version: ${currentVersion}`);
97
+
98
+ // Calculate new version
99
+ const newVersion = bumpVersion(currentVersion, arg);
100
+ console.log(`New version: ${newVersion}`);
101
+
102
+ // Update package.json
103
+ pkg.version = newVersion;
104
+ writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
105
+
106
+ // Update version in index.ts
107
+ const indexPath = join(ROOT_DIR, 'src/index.ts');
108
+ let indexContent = readFileSync(indexPath, 'utf-8');
109
+ indexContent = indexContent.replace(/version: '[^']+'/, `version: '${newVersion}'`);
110
+ writeFileSync(indexPath, indexContent);
111
+
112
+ console.log('Updated package.json and src/index.ts');
113
+
114
+ // Reinstall
115
+ console.log('Reinstalling...');
116
+ run('npm install && npm link');
117
+
118
+ // Git commit, tag, and push
119
+ run('git add package.json package-lock.json src/index.ts');
120
+ run(`git commit -m "chore: Bump version to ${newVersion}"`);
121
+ run(`git tag "v${newVersion}"`);
122
+ run('git push origin HEAD --tags');
123
+
124
+ console.log(`\nDone! Version ${newVersion} installed and pushed.`);
125
+ }
126
+
127
+ main().catch((err) => {
128
+ console.error(err.message);
129
+ process.exit(1);
130
+ });
@@ -0,0 +1,419 @@
1
+ /**
2
+ * Disk space analysis commands
3
+ */
4
+
5
+ import { defineCommand } from 'citty';
6
+ import {
7
+ c,
8
+ colorizeSize,
9
+ formatSize,
10
+ parseSize,
11
+ printHeader,
12
+ printSubHeader,
13
+ progressBar,
14
+ } from '../lib/colors.ts';
15
+ import { exec } from '../lib/exec.ts';
16
+ import { startSpinner, stopSpinner } from '../lib/spinner.ts';
17
+ import type { CleanupSuggestion, SpaceHogCheck } from '../types/index.ts';
18
+
19
+ // ─────────────────────────────────────────────────────────────
20
+ // Analysis Functions
21
+ // ─────────────────────────────────────────────────────────────
22
+
23
+ async function getDiskOverview(): Promise<void> {
24
+ startSpinner('Analyzing APFS volumes...');
25
+
26
+ const dfOutput = exec('df -h /System/Volumes/Data');
27
+ const lines = dfOutput.split('\n');
28
+
29
+ let used = '0G';
30
+ let avail = '0G';
31
+ let capacity = '0%';
32
+ let total = '0G';
33
+ if (lines[1]) {
34
+ const parts = lines[1].split(/\s+/);
35
+ total = parts[1];
36
+ used = parts[2];
37
+ avail = parts[3];
38
+ capacity = parts[4];
39
+ }
40
+
41
+ stopSpinner(true, 'APFS volumes analyzed');
42
+
43
+ printHeader('💾 DISK OVERVIEW');
44
+
45
+ const pct = Number.parseInt(capacity) || 0;
46
+ console.log(` ${c.bold}Data Volume${c.reset} (/System/Volumes/Data)`);
47
+ console.log();
48
+ console.log(` ${progressBar(pct, 40)} ${c.bold}${capacity}${c.reset}`);
49
+ console.log();
50
+ console.log(
51
+ ` ${c.green}●${c.reset} Used: ${c.bold}${used}${c.reset} ${c.blue}●${c.reset} Free: ${c.bold}${avail}${c.reset} ${c.dim}Total: ${total}${c.reset}`,
52
+ );
53
+ }
54
+
55
+ async function getHomeBreakdown(): Promise<void> {
56
+ startSpinner('Scanning home directory...');
57
+
58
+ const output = exec('sudo du -sh ~/* ~/.* 2>/dev/null | sort -hr | head -20');
59
+ const lines = output.split('\n').filter((l) => l.trim());
60
+
61
+ stopSpinner(true, 'Home directory scanned');
62
+
63
+ printHeader('🏠 HOME DIRECTORY BREAKDOWN');
64
+
65
+ const rows = lines
66
+ .map((line) => {
67
+ const match = line.match(/^([\d.]+[KMGTP]?)\s+(.+)$/i);
68
+ if (!match) return null;
69
+ const [, size, path] = match;
70
+ const shortPath = path.replace(process.env.HOME || '', '~');
71
+ return `${colorizeSize(size.padStart(8))} ${shortPath}`;
72
+ })
73
+ .filter((row): row is string => row !== null);
74
+
75
+ for (const row of rows) {
76
+ console.log(` ${row}`);
77
+ }
78
+ }
79
+
80
+ async function getLibraryBreakdown(): Promise<void> {
81
+ startSpinner('Analyzing ~/Library...');
82
+
83
+ const output = exec('sudo du -sh ~/Library/*/ 2>/dev/null | sort -hr | head -20');
84
+ const lines = output.split('\n').filter((l) => l.trim());
85
+
86
+ stopSpinner(true, 'Library analyzed');
87
+
88
+ printHeader('📚 LIBRARY BREAKDOWN');
89
+
90
+ const rows = lines
91
+ .map((line) => {
92
+ const match = line.match(/^([\d.]+[KMGTP]?)\s+(.+)$/i);
93
+ if (!match) return null;
94
+ const [, size, path] = match;
95
+ const shortPath = path.replace(`${process.env.HOME || ''}/Library/`, '').replace(/\/$/, '');
96
+ return `${colorizeSize(size.padStart(8))} ${shortPath}`;
97
+ })
98
+ .filter((row): row is string => row !== null);
99
+
100
+ for (const row of rows) {
101
+ console.log(` ${row}`);
102
+ }
103
+ }
104
+
105
+ async function getCommonHogs(): Promise<void> {
106
+ printHeader('🐷 COMMON SPACE HOGS');
107
+
108
+ const checks: SpaceHogCheck[] = [
109
+ { name: 'Ollama models', cmd: 'sudo du -sh ~/.ollama/models/ 2>/dev/null' },
110
+ { name: 'LM Studio models', cmd: 'sudo du -sh ~/.lmstudio/models 2>/dev/null' },
111
+ { name: 'asdf versions', cmd: 'sudo du -sh ~/.asdf/installs 2>/dev/null' },
112
+ {
113
+ name: 'Homebrew',
114
+ cmd: 'sudo du -sh /opt/homebrew/Cellar 2>/dev/null || sudo du -sh /usr/local/Cellar 2>/dev/null',
115
+ },
116
+ {
117
+ name: 'Docker VM',
118
+ cmd: 'sudo du -sh ~/Library/Containers/com.docker.docker/Data/vms/ 2>/dev/null',
119
+ },
120
+ { name: 'Trash', cmd: 'sudo du -sh ~/.Trash/ 2>/dev/null' },
121
+ {
122
+ name: 'StabilityMatrix',
123
+ cmd: 'sudo du -sh ~/Library/Application\\ Support/StabilityMatrix/Models 2>/dev/null',
124
+ },
125
+ { name: 'Downloads', cmd: 'sudo du -sh ~/Downloads 2>/dev/null' },
126
+ ];
127
+
128
+ for (const check of checks) {
129
+ startSpinner(`Checking ${check.name}...`);
130
+ const output = exec(check.cmd);
131
+ const match = output.match(/^([\d.]+[KMGTP]?)/i);
132
+ const size = match ? match[1] : 'N/A';
133
+ stopSpinner(size !== 'N/A', `${check.name}: ${colorizeSize(size)}`);
134
+ }
135
+ }
136
+
137
+ interface ModelInfo {
138
+ name: string;
139
+ size: string;
140
+ sizeBytes: number;
141
+ }
142
+
143
+ async function getModelsBreakdown(): Promise<void> {
144
+ printHeader('🤖 AI MODELS');
145
+
146
+ // StabilityMatrix models
147
+ printSubHeader('StabilityMatrix');
148
+ startSpinner('Scanning StabilityMatrix models...');
149
+
150
+ const smPath = '~/Library/Application\\ Support/StabilityMatrix/Models';
151
+ const smOutput = exec(
152
+ `find ${smPath} -type f \\( -name "*.safetensors" -o -name "*.ckpt" -o -name "*.pt" \\) -exec du -sh {} \\; 2>/dev/null | sort -hr`,
153
+ );
154
+
155
+ const smModels: ModelInfo[] = smOutput
156
+ .split('\n')
157
+ .filter((l) => l.trim())
158
+ .map((line) => {
159
+ const match = line.match(/^([\d.]+[KMGTP]?)\s+(.+)$/i);
160
+ if (!match) return null;
161
+ const [, size, path] = match;
162
+ const name =
163
+ path
164
+ .split('/')
165
+ .pop()
166
+ ?.replace(/\.(safetensors|ckpt|pt)$/, '') || path;
167
+ return { name, size, sizeBytes: parseSize(size) };
168
+ })
169
+ .filter((m): m is ModelInfo => m !== null);
170
+
171
+ const smTotal = smModels.reduce((acc, m) => acc + m.sizeBytes, 0);
172
+ const smTotalStr = formatSize(smTotal);
173
+
174
+ stopSpinner(true, `Found ${smModels.length} models (${smTotalStr})`);
175
+
176
+ for (const model of smModels) {
177
+ console.log(
178
+ ` ${c.dim}•${c.reset} ${model.name} ${c.dim}—${c.reset} ${colorizeSize(model.size)}`,
179
+ );
180
+ }
181
+
182
+ console.log();
183
+
184
+ // LM Studio models
185
+ printSubHeader('LM Studio');
186
+ startSpinner('Scanning LM Studio models...');
187
+
188
+ const lmOutput = exec(
189
+ 'find ~/.lmstudio/models -type f -name "*.safetensors" -exec du -sh {} \\; 2>/dev/null | sort -hr',
190
+ );
191
+
192
+ // Group by model directory
193
+ const lmFiles = lmOutput
194
+ .split('\n')
195
+ .filter((l) => l.trim())
196
+ .map((line) => {
197
+ const match = line.match(/^([\d.]+[KMGTP]?)\s+(.+)$/i);
198
+ if (!match) return null;
199
+ const [, size, path] = match;
200
+ // Extract model name from path (parent directory)
201
+ const parts = path.split('/');
202
+ const modelName = parts[parts.length - 2] || 'unknown';
203
+ return { modelName, size, sizeBytes: parseSize(size) };
204
+ })
205
+ .filter((m): m is { modelName: string; size: string; sizeBytes: number } => m !== null);
206
+
207
+ // Aggregate by model name
208
+ const lmModels = new Map<string, number>();
209
+ for (const file of lmFiles) {
210
+ const existing = lmModels.get(file.modelName) || 0;
211
+ lmModels.set(file.modelName, existing + file.sizeBytes);
212
+ }
213
+
214
+ const lmModelList: ModelInfo[] = Array.from(lmModels.entries())
215
+ .map(([name, sizeBytes]) => ({ name, size: formatSize(sizeBytes), sizeBytes }))
216
+ .sort((a, b) => b.sizeBytes - a.sizeBytes);
217
+
218
+ const lmTotal = lmModelList.reduce((acc, m) => acc + m.sizeBytes, 0);
219
+ const lmTotalStr = formatSize(lmTotal);
220
+
221
+ stopSpinner(true, `Found ${lmModelList.length} models (${lmTotalStr})`);
222
+
223
+ for (const model of lmModelList) {
224
+ console.log(
225
+ ` ${c.dim}•${c.reset} ${model.name} ${c.dim}—${c.reset} ${colorizeSize(model.size)}`,
226
+ );
227
+ }
228
+ }
229
+
230
+ async function getCleanupSuggestions(): Promise<void> {
231
+ printHeader('🧹 CLEANUP SUGGESTIONS');
232
+
233
+ const suggestions: CleanupSuggestion[] = [];
234
+
235
+ // Check Trash
236
+ const trashSize = exec('sudo du -sh ~/.Trash/ 2>/dev/null').match(/^([\d.]+[KMGTP]?)/i);
237
+ if (trashSize && parseSize(trashSize[1]) > 100 * 1024 * 1024) {
238
+ suggestions.push({
239
+ item: 'Trash',
240
+ size: trashSize[1],
241
+ cmd: 'rm -rf ~/.Trash/*',
242
+ });
243
+ }
244
+
245
+ // Check Homebrew
246
+ const brewCleanable = exec('brew cleanup -n 2>/dev/null | tail -1');
247
+ if (brewCleanable.includes('would be removed')) {
248
+ suggestions.push({
249
+ item: 'Homebrew cache',
250
+ size: 'varies',
251
+ cmd: 'brew cleanup && brew autoremove',
252
+ });
253
+ }
254
+
255
+ // Check npm cache
256
+ const npmCache = exec('npm cache ls 2>/dev/null | wc -l').trim();
257
+ if (Number.parseInt(npmCache) > 100) {
258
+ suggestions.push({
259
+ item: 'npm cache',
260
+ size: 'varies',
261
+ cmd: 'npm cache clean --force',
262
+ });
263
+ }
264
+
265
+ // Check pip cache
266
+ const pipCache = exec('pip cache info 2>/dev/null | grep "Package index"');
267
+ if (pipCache) {
268
+ suggestions.push({
269
+ item: 'pip cache',
270
+ size: 'varies',
271
+ cmd: 'pip cache purge',
272
+ });
273
+ }
274
+
275
+ if (suggestions.length === 0) {
276
+ console.log(` ${c.green}✓${c.reset} ${c.dim}No obvious cleanup targets found${c.reset}`);
277
+ } else {
278
+ for (const s of suggestions) {
279
+ console.log(
280
+ ` ${c.yellow}●${c.reset} ${c.bold}${s.item}${c.reset} (${colorizeSize(s.size)})`,
281
+ );
282
+ console.log(` ${c.dim}$ ${s.cmd}${c.reset}`);
283
+ }
284
+ }
285
+ }
286
+
287
+ // ─────────────────────────────────────────────────────────────
288
+ // Subcommands
289
+ // ─────────────────────────────────────────────────────────────
290
+
291
+ const overviewCommand = defineCommand({
292
+ meta: {
293
+ name: 'overview',
294
+ description: 'Show APFS volume disk usage overview',
295
+ },
296
+ run: async () => {
297
+ printBanner();
298
+ await getDiskOverview();
299
+ printFooter();
300
+ },
301
+ });
302
+
303
+ const homeCommand = defineCommand({
304
+ meta: {
305
+ name: 'home',
306
+ description: 'Show home directory breakdown',
307
+ },
308
+ run: async () => {
309
+ printBanner();
310
+ await getHomeBreakdown();
311
+ printFooter();
312
+ },
313
+ });
314
+
315
+ const libraryCommand = defineCommand({
316
+ meta: {
317
+ name: 'library',
318
+ description: 'Show ~/Library breakdown',
319
+ },
320
+ run: async () => {
321
+ printBanner();
322
+ await getLibraryBreakdown();
323
+ printFooter();
324
+ },
325
+ });
326
+
327
+ const hogsCommand = defineCommand({
328
+ meta: {
329
+ name: 'hogs',
330
+ description: 'Check common space hogs',
331
+ },
332
+ run: async () => {
333
+ printBanner();
334
+ await getCommonHogs();
335
+ printFooter();
336
+ },
337
+ });
338
+
339
+ const cleanupCommand = defineCommand({
340
+ meta: {
341
+ name: 'cleanup',
342
+ description: 'Show cleanup suggestions',
343
+ },
344
+ run: async () => {
345
+ printBanner();
346
+ await getCleanupSuggestions();
347
+ printFooter();
348
+ },
349
+ });
350
+
351
+ const modelsCommand = defineCommand({
352
+ meta: {
353
+ name: 'models',
354
+ description: 'List AI models (StabilityMatrix, LM Studio)',
355
+ },
356
+ run: async () => {
357
+ printBanner();
358
+ await getModelsBreakdown();
359
+ printFooter();
360
+ },
361
+ });
362
+
363
+ const inventoryCommand = defineCommand({
364
+ meta: {
365
+ name: 'inventory',
366
+ description: 'Full disk space analysis (default)',
367
+ },
368
+ run: async () => {
369
+ printBanner();
370
+ await getDiskOverview();
371
+ await getHomeBreakdown();
372
+ await getLibraryBreakdown();
373
+ await getCommonHogs();
374
+ await getCleanupSuggestions();
375
+ printFooter();
376
+ },
377
+ });
378
+
379
+ // ─────────────────────────────────────────────────────────────
380
+ // UI Helpers
381
+ // ─────────────────────────────────────────────────────────────
382
+
383
+ function printBanner(): void {
384
+ console.log();
385
+ console.log(`${c.bold}${c.magenta}╔════════════════════════════════════════╗${c.reset}`);
386
+ console.log(
387
+ `${c.bold}${c.magenta}║${c.reset} ${c.bold}💾 Disk Space Inventory${c.reset} ${c.bold}${c.magenta}║${c.reset}`,
388
+ );
389
+ console.log(`${c.bold}${c.magenta}╚════════════════════════════════════════╝${c.reset}`);
390
+ }
391
+
392
+ function printFooter(): void {
393
+ console.log();
394
+ console.log(`${c.dim}─────────────────────────────────────────${c.reset}`);
395
+ console.log(
396
+ `${c.dim}Run: hu disk [overview|home|library|hogs|models|cleanup|inventory]${c.reset}`,
397
+ );
398
+ console.log();
399
+ }
400
+
401
+ // ─────────────────────────────────────────────────────────────
402
+ // Main Command
403
+ // ─────────────────────────────────────────────────────────────
404
+
405
+ export const diskCommand = defineCommand({
406
+ meta: {
407
+ name: 'disk',
408
+ description: 'Disk space analysis tools',
409
+ },
410
+ subCommands: {
411
+ inventory: inventoryCommand,
412
+ overview: overviewCommand,
413
+ home: homeCommand,
414
+ library: libraryCommand,
415
+ hogs: hogsCommand,
416
+ models: modelsCommand,
417
+ cleanup: cleanupCommand,
418
+ },
419
+ });