@soulcraft/brainy 3.19.1 ā 3.20.0
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.
- package/bin/brainy-minimal.js +82 -0
- package/dist/cli/commands/core.d.ts +14 -2
- package/dist/cli/commands/core.js +142 -26
- package/dist/cli/commands/data.d.ts +29 -0
- package/dist/cli/commands/data.js +139 -0
- package/dist/cli/commands/neural.d.ts +14 -0
- package/dist/cli/commands/neural.js +16 -5
- package/dist/cli/commands/utility.js +39 -97
- package/dist/cli/commands/vfs.d.ts +73 -0
- package/dist/cli/commands/vfs.js +372 -0
- package/dist/cli/index.js +201 -6
- package/dist/cli/interactive.d.ts +5 -0
- package/dist/cli/interactive.js +32 -8
- package/package.json +4 -1
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
import chalk from 'chalk';
|
|
7
7
|
import ora from 'ora';
|
|
8
8
|
import Table from 'cli-table3';
|
|
9
|
-
import { Brainy } from '../../
|
|
9
|
+
import { Brainy } from '../../brainy.js';
|
|
10
|
+
import { NounType } from '../../types/graphTypes.js';
|
|
10
11
|
let brainyInstance = null;
|
|
11
|
-
const getBrainy =
|
|
12
|
+
const getBrainy = () => {
|
|
12
13
|
if (!brainyInstance) {
|
|
13
14
|
brainyInstance = new Brainy();
|
|
14
|
-
await brainyInstance.init();
|
|
15
15
|
}
|
|
16
16
|
return brainyInstance;
|
|
17
17
|
};
|
|
@@ -35,10 +35,16 @@ export const utilityCommands = {
|
|
|
35
35
|
async stats(options) {
|
|
36
36
|
const spinner = ora('Gathering statistics...').start();
|
|
37
37
|
try {
|
|
38
|
-
const brain =
|
|
39
|
-
const
|
|
38
|
+
const brain = getBrainy();
|
|
39
|
+
const nounCount = await brain.getNounCount();
|
|
40
|
+
const verbCount = await brain.getVerbCount();
|
|
40
41
|
const memUsage = process.memoryUsage();
|
|
41
42
|
spinner.succeed('Statistics gathered');
|
|
43
|
+
const stats = {
|
|
44
|
+
nounCount,
|
|
45
|
+
verbCount,
|
|
46
|
+
totalItems: nounCount + verbCount
|
|
47
|
+
};
|
|
42
48
|
if (options.json) {
|
|
43
49
|
formatOutput(stats, options);
|
|
44
50
|
return;
|
|
@@ -49,53 +55,8 @@ export const utilityCommands = {
|
|
|
49
55
|
head: [chalk.cyan('Metric'), chalk.cyan('Value')],
|
|
50
56
|
style: { head: [], border: [] }
|
|
51
57
|
});
|
|
52
|
-
coreTable.push(['Total Items', chalk.green(stats.
|
|
58
|
+
coreTable.push(['Total Items', chalk.green(stats.totalItems)], ['Nouns', chalk.green(stats.nounCount)], ['Verbs (Relationships)', chalk.green(stats.verbCount)]);
|
|
53
59
|
console.log(coreTable.toString());
|
|
54
|
-
// Service breakdown if available
|
|
55
|
-
if (options.byService && stats.serviceBreakdown) {
|
|
56
|
-
console.log(chalk.cyan('\nš§ Service Breakdown\n'));
|
|
57
|
-
const serviceTable = new Table({
|
|
58
|
-
head: [chalk.cyan('Service'), chalk.cyan('Nouns'), chalk.cyan('Verbs'), chalk.cyan('Metadata')],
|
|
59
|
-
style: { head: [], border: [] }
|
|
60
|
-
});
|
|
61
|
-
Object.entries(stats.serviceBreakdown).forEach(([service, serviceStats]) => {
|
|
62
|
-
serviceTable.push([
|
|
63
|
-
service,
|
|
64
|
-
serviceStats.nounCount || 0,
|
|
65
|
-
serviceStats.verbCount || 0,
|
|
66
|
-
serviceStats.metadataCount || 0
|
|
67
|
-
]);
|
|
68
|
-
});
|
|
69
|
-
console.log(serviceTable.toString());
|
|
70
|
-
}
|
|
71
|
-
// Storage info
|
|
72
|
-
if (stats.storage) {
|
|
73
|
-
console.log(chalk.cyan('\nš¾ Storage\n'));
|
|
74
|
-
const storageTable = new Table({
|
|
75
|
-
head: [chalk.cyan('Property'), chalk.cyan('Value')],
|
|
76
|
-
style: { head: [], border: [] }
|
|
77
|
-
});
|
|
78
|
-
storageTable.push(['Type', stats.storage.type || 'Unknown'], ['Size', stats.storage.size ? formatBytes(stats.storage.size) : 'N/A'], ['Location', stats.storage.location || 'N/A']);
|
|
79
|
-
console.log(storageTable.toString());
|
|
80
|
-
}
|
|
81
|
-
// Performance metrics
|
|
82
|
-
if (stats.performance && options.detailed) {
|
|
83
|
-
console.log(chalk.cyan('\nā” Performance\n'));
|
|
84
|
-
const perfTable = new Table({
|
|
85
|
-
head: [chalk.cyan('Metric'), chalk.cyan('Value')],
|
|
86
|
-
style: { head: [], border: [] }
|
|
87
|
-
});
|
|
88
|
-
if (stats.performance.avgQueryTime) {
|
|
89
|
-
perfTable.push(['Avg Query Time', `${stats.performance.avgQueryTime.toFixed(2)} ms`]);
|
|
90
|
-
}
|
|
91
|
-
if (stats.performance.totalQueries) {
|
|
92
|
-
perfTable.push(['Total Queries', stats.performance.totalQueries]);
|
|
93
|
-
}
|
|
94
|
-
if (stats.performance.cacheHitRate) {
|
|
95
|
-
perfTable.push(['Cache Hit Rate', `${(stats.performance.cacheHitRate * 100).toFixed(1)}%`]);
|
|
96
|
-
}
|
|
97
|
-
console.log(perfTable.toString());
|
|
98
|
-
}
|
|
99
60
|
// Memory usage
|
|
100
61
|
console.log(chalk.cyan('\nš§ Memory Usage\n'));
|
|
101
62
|
const memTable = new Table({
|
|
@@ -104,16 +65,6 @@ export const utilityCommands = {
|
|
|
104
65
|
});
|
|
105
66
|
memTable.push(['Heap Used', formatBytes(memUsage.heapUsed)], ['Heap Total', formatBytes(memUsage.heapTotal)], ['RSS', formatBytes(memUsage.rss)], ['External', formatBytes(memUsage.external)]);
|
|
106
67
|
console.log(memTable.toString());
|
|
107
|
-
// Index info
|
|
108
|
-
if (stats.index && options.detailed) {
|
|
109
|
-
console.log(chalk.cyan('\nšÆ Vector Index\n'));
|
|
110
|
-
const indexTable = new Table({
|
|
111
|
-
head: [chalk.cyan('Property'), chalk.cyan('Value')],
|
|
112
|
-
style: { head: [], border: [] }
|
|
113
|
-
});
|
|
114
|
-
indexTable.push(['Dimensions', stats.index.dimensions || 'N/A'], ['Indexed Vectors', stats.index.vectorCount || 0], ['Index Size', stats.index.indexSize ? formatBytes(stats.index.indexSize) : 'N/A']);
|
|
115
|
-
console.log(indexTable.toString());
|
|
116
|
-
}
|
|
117
68
|
}
|
|
118
69
|
catch (error) {
|
|
119
70
|
spinner.fail('Failed to gather statistics');
|
|
@@ -127,40 +78,30 @@ export const utilityCommands = {
|
|
|
127
78
|
async clean(options) {
|
|
128
79
|
const spinner = ora('Cleaning database...').start();
|
|
129
80
|
try {
|
|
130
|
-
const brain =
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
tasks.push('Rebuilt search index');
|
|
141
|
-
// Implementation would go here
|
|
142
|
-
await new Promise(resolve => setTimeout(resolve, 1000)); // Simulate work
|
|
143
|
-
}
|
|
144
|
-
if (tasks.length === 0) {
|
|
145
|
-
spinner.text = 'Running general cleanup...';
|
|
146
|
-
tasks.push('General cleanup completed');
|
|
147
|
-
// Run general cleanup tasks
|
|
148
|
-
await new Promise(resolve => setTimeout(resolve, 500)); // Simulate work
|
|
81
|
+
const brain = getBrainy();
|
|
82
|
+
// For now, only support full clear
|
|
83
|
+
// removeOrphans and rebuildIndex would require new Brainy APIs
|
|
84
|
+
if (options.removeOrphans || options.rebuildIndex) {
|
|
85
|
+
spinner.warn('Advanced cleanup options not yet implemented');
|
|
86
|
+
console.log(chalk.yellow('\nā ļø Advanced cleanup features coming in v3.21.0:'));
|
|
87
|
+
console.log(chalk.dim(' ⢠--remove-orphans: Remove disconnected items'));
|
|
88
|
+
console.log(chalk.dim(' ⢠--rebuild-index: Rebuild vector index'));
|
|
89
|
+
console.log(chalk.dim('\nUse "brainy clean" without options to clear the database'));
|
|
90
|
+
return;
|
|
149
91
|
}
|
|
150
|
-
|
|
92
|
+
// Show warning before clearing
|
|
93
|
+
console.log(chalk.yellow('\nā ļø WARNING: This will permanently delete ALL data!'));
|
|
94
|
+
const dataApi = await brain.data();
|
|
95
|
+
// Clear all data
|
|
96
|
+
spinner.text = 'Clearing all data...';
|
|
97
|
+
await dataApi.clear({ entities: true, relations: true });
|
|
98
|
+
spinner.succeed('Database cleared');
|
|
151
99
|
if (!options.json) {
|
|
152
|
-
console.log(chalk.green('\nā
|
|
153
|
-
|
|
154
|
-
console.log(chalk.dim(` ⢠${task}`));
|
|
155
|
-
});
|
|
156
|
-
// Get new stats
|
|
157
|
-
const stats = await brain.getStatistics();
|
|
158
|
-
console.log(chalk.cyan('\nDatabase Status:'));
|
|
159
|
-
console.log(` Total items: ${stats.nounCount + stats.verbCount}`);
|
|
160
|
-
console.log(` Index status: ${chalk.green('Healthy')}`);
|
|
100
|
+
console.log(chalk.green('\nā Database cleared successfully'));
|
|
101
|
+
console.log(chalk.dim(' All nouns, verbs, and metadata have been removed'));
|
|
161
102
|
}
|
|
162
103
|
else {
|
|
163
|
-
formatOutput({
|
|
104
|
+
formatOutput({ cleared: true, success: true }, options);
|
|
164
105
|
}
|
|
165
106
|
}
|
|
166
107
|
catch (error) {
|
|
@@ -181,7 +122,7 @@ export const utilityCommands = {
|
|
|
181
122
|
summary: {}
|
|
182
123
|
};
|
|
183
124
|
try {
|
|
184
|
-
const brain =
|
|
125
|
+
const brain = getBrainy();
|
|
185
126
|
// Benchmark different operations
|
|
186
127
|
const benchmarks = [
|
|
187
128
|
{ name: 'add', enabled: operations === 'all' || operations.includes('add') },
|
|
@@ -198,17 +139,17 @@ export const utilityCommands = {
|
|
|
198
139
|
const start = Date.now();
|
|
199
140
|
switch (bench.name) {
|
|
200
141
|
case 'add':
|
|
201
|
-
await brain.add(`Test item ${i}`, { benchmark: true });
|
|
142
|
+
await brain.add({ data: `Test item ${i}`, type: NounType.Thing, metadata: { benchmark: true } });
|
|
202
143
|
break;
|
|
203
144
|
case 'search':
|
|
204
|
-
await brain.
|
|
145
|
+
await brain.find({ query: 'test', limit: 10 });
|
|
205
146
|
break;
|
|
206
147
|
case 'similarity':
|
|
207
|
-
const neural = brain.neural;
|
|
148
|
+
const neural = brain.neural();
|
|
208
149
|
await neural.similar('test1', 'test2');
|
|
209
150
|
break;
|
|
210
151
|
case 'cluster':
|
|
211
|
-
const neuralApi = brain.neural;
|
|
152
|
+
const neuralApi = brain.neural();
|
|
212
153
|
await neuralApi.clusters();
|
|
213
154
|
break;
|
|
214
155
|
}
|
|
@@ -232,7 +173,7 @@ export const utilityCommands = {
|
|
|
232
173
|
const totalOps = Object.values(results.operations).reduce((sum, op) => sum + parseFloat(op.ops), 0);
|
|
233
174
|
results.summary = {
|
|
234
175
|
totalOperations: Object.keys(results.operations).length,
|
|
235
|
-
averageOpsPerSec: (totalOps / Object.keys(results.operations).length).toFixed(2)
|
|
176
|
+
averageOpsPerSec: totalOps > 0 ? (totalOps / Object.keys(results.operations).length).toFixed(2) : '0'
|
|
236
177
|
};
|
|
237
178
|
if (!options.json) {
|
|
238
179
|
// Display results table
|
|
@@ -273,3 +214,4 @@ export const utilityCommands = {
|
|
|
273
214
|
}
|
|
274
215
|
}
|
|
275
216
|
};
|
|
217
|
+
//# sourceMappingURL=utility.js.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VFS CLI Commands - Virtual File System Operations
|
|
3
|
+
*
|
|
4
|
+
* Complete filesystem-like interface for Brainy's VFS
|
|
5
|
+
*/
|
|
6
|
+
interface VFSOptions {
|
|
7
|
+
verbose?: boolean;
|
|
8
|
+
json?: boolean;
|
|
9
|
+
pretty?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare const vfsCommands: {
|
|
12
|
+
/**
|
|
13
|
+
* Read file from VFS
|
|
14
|
+
*/
|
|
15
|
+
read(path: string, options: VFSOptions & {
|
|
16
|
+
output?: string;
|
|
17
|
+
encoding?: string;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Write file to VFS
|
|
21
|
+
*/
|
|
22
|
+
write(path: string, options: VFSOptions & {
|
|
23
|
+
content?: string;
|
|
24
|
+
file?: string;
|
|
25
|
+
encoding?: string;
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* List directory contents
|
|
29
|
+
*/
|
|
30
|
+
ls(path: string, options: VFSOptions & {
|
|
31
|
+
long?: boolean;
|
|
32
|
+
all?: boolean;
|
|
33
|
+
}): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Get file/directory stats
|
|
36
|
+
*/
|
|
37
|
+
stat(path: string, options: VFSOptions): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Create directory
|
|
40
|
+
*/
|
|
41
|
+
mkdir(path: string, options: VFSOptions & {
|
|
42
|
+
parents?: boolean;
|
|
43
|
+
}): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* Remove file or directory
|
|
46
|
+
*/
|
|
47
|
+
rm(path: string, options: VFSOptions & {
|
|
48
|
+
recursive?: boolean;
|
|
49
|
+
force?: boolean;
|
|
50
|
+
}): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Search files by content
|
|
53
|
+
*/
|
|
54
|
+
search(query: string, options: VFSOptions & {
|
|
55
|
+
path?: string;
|
|
56
|
+
limit?: string;
|
|
57
|
+
type?: string;
|
|
58
|
+
}): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* Find similar files
|
|
61
|
+
*/
|
|
62
|
+
similar(path: string, options: VFSOptions & {
|
|
63
|
+
limit?: string;
|
|
64
|
+
threshold?: string;
|
|
65
|
+
}): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Get directory tree structure
|
|
68
|
+
*/
|
|
69
|
+
tree(path: string, options: VFSOptions & {
|
|
70
|
+
depth?: string;
|
|
71
|
+
}): Promise<void>;
|
|
72
|
+
};
|
|
73
|
+
export {};
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VFS CLI Commands - Virtual File System Operations
|
|
3
|
+
*
|
|
4
|
+
* Complete filesystem-like interface for Brainy's VFS
|
|
5
|
+
*/
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import ora from 'ora';
|
|
8
|
+
import Table from 'cli-table3';
|
|
9
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
10
|
+
import { Brainy } from '../../brainy.js';
|
|
11
|
+
let brainyInstance = null;
|
|
12
|
+
const getBrainy = () => {
|
|
13
|
+
if (!brainyInstance) {
|
|
14
|
+
brainyInstance = new Brainy();
|
|
15
|
+
}
|
|
16
|
+
return brainyInstance;
|
|
17
|
+
};
|
|
18
|
+
const formatOutput = (data, options) => {
|
|
19
|
+
if (options.json) {
|
|
20
|
+
console.log(options.pretty ? JSON.stringify(data, null, 2) : JSON.stringify(data));
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const formatBytes = (bytes) => {
|
|
24
|
+
if (bytes === 0)
|
|
25
|
+
return '0 B';
|
|
26
|
+
const k = 1024;
|
|
27
|
+
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
28
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
29
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
30
|
+
};
|
|
31
|
+
const formatDate = (date) => {
|
|
32
|
+
return date.toLocaleString();
|
|
33
|
+
};
|
|
34
|
+
export const vfsCommands = {
|
|
35
|
+
/**
|
|
36
|
+
* Read file from VFS
|
|
37
|
+
*/
|
|
38
|
+
async read(path, options) {
|
|
39
|
+
const spinner = ora('Reading file...').start();
|
|
40
|
+
try {
|
|
41
|
+
const brain = getBrainy();
|
|
42
|
+
const vfs = brain.vfs();
|
|
43
|
+
await vfs.init();
|
|
44
|
+
const buffer = await vfs.readFile(path, {
|
|
45
|
+
encoding: options.encoding
|
|
46
|
+
});
|
|
47
|
+
spinner.succeed('File read successfully');
|
|
48
|
+
if (options.output) {
|
|
49
|
+
// Write to local filesystem
|
|
50
|
+
writeFileSync(options.output, buffer);
|
|
51
|
+
console.log(chalk.green(`ā Saved to: ${options.output}`));
|
|
52
|
+
}
|
|
53
|
+
else if (!options.json) {
|
|
54
|
+
// Display content
|
|
55
|
+
console.log('\n' + buffer.toString());
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
formatOutput({ path, content: buffer.toString(), size: buffer.length }, options);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
spinner.fail('Failed to read file');
|
|
63
|
+
console.error(chalk.red(error.message));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
/**
|
|
68
|
+
* Write file to VFS
|
|
69
|
+
*/
|
|
70
|
+
async write(path, options) {
|
|
71
|
+
const spinner = ora('Writing file...').start();
|
|
72
|
+
try {
|
|
73
|
+
const brain = getBrainy();
|
|
74
|
+
const vfs = brain.vfs();
|
|
75
|
+
await vfs.init();
|
|
76
|
+
let data;
|
|
77
|
+
if (options.file) {
|
|
78
|
+
// Read from local file
|
|
79
|
+
data = readFileSync(options.file, 'utf-8');
|
|
80
|
+
}
|
|
81
|
+
else if (options.content) {
|
|
82
|
+
data = options.content;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
spinner.fail('Must provide --content or --file');
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
await vfs.writeFile(path, data, {
|
|
89
|
+
encoding: options.encoding
|
|
90
|
+
});
|
|
91
|
+
spinner.succeed('File written successfully');
|
|
92
|
+
if (!options.json) {
|
|
93
|
+
console.log(chalk.green(`ā Written to: ${path}`));
|
|
94
|
+
console.log(chalk.dim(` Size: ${formatBytes(Buffer.byteLength(data))}`));
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
formatOutput({ path, size: Buffer.byteLength(data) }, options);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
spinner.fail('Failed to write file');
|
|
102
|
+
console.error(chalk.red(error.message));
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
/**
|
|
107
|
+
* List directory contents
|
|
108
|
+
*/
|
|
109
|
+
async ls(path, options) {
|
|
110
|
+
const spinner = ora('Listing directory...').start();
|
|
111
|
+
try {
|
|
112
|
+
const brain = getBrainy();
|
|
113
|
+
const vfs = brain.vfs();
|
|
114
|
+
await vfs.init();
|
|
115
|
+
const entries = await vfs.readdir(path, { withFileTypes: true });
|
|
116
|
+
spinner.succeed(`Found ${Array.isArray(entries) ? entries.length : 0} items`);
|
|
117
|
+
if (!options.json) {
|
|
118
|
+
if (!Array.isArray(entries) || entries.length === 0) {
|
|
119
|
+
console.log(chalk.yellow('Directory is empty'));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (options.long) {
|
|
123
|
+
// Long format with details
|
|
124
|
+
const table = new Table({
|
|
125
|
+
head: [chalk.cyan('Type'), chalk.cyan('Size'), chalk.cyan('Modified'), chalk.cyan('Name')],
|
|
126
|
+
style: { head: [], border: [] }
|
|
127
|
+
});
|
|
128
|
+
for (const entry of entries) {
|
|
129
|
+
if (!options.all && entry.name.startsWith('.'))
|
|
130
|
+
continue;
|
|
131
|
+
const stat = await vfs.stat(`${path}/${entry.name}`);
|
|
132
|
+
table.push([
|
|
133
|
+
entry.isDirectory() ? chalk.blue('DIR') : 'FILE',
|
|
134
|
+
entry.isDirectory() ? '-' : formatBytes(stat.size),
|
|
135
|
+
formatDate(stat.mtime),
|
|
136
|
+
entry.name
|
|
137
|
+
]);
|
|
138
|
+
}
|
|
139
|
+
console.log('\n' + table.toString());
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
// Simple format
|
|
143
|
+
console.log();
|
|
144
|
+
for (const entry of entries) {
|
|
145
|
+
if (!options.all && entry.name.startsWith('.'))
|
|
146
|
+
continue;
|
|
147
|
+
if (entry.isDirectory()) {
|
|
148
|
+
console.log(chalk.blue(entry.name + '/'));
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
console.log(entry.name);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
formatOutput(entries, options);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
spinner.fail('Failed to list directory');
|
|
162
|
+
console.error(chalk.red(error.message));
|
|
163
|
+
process.exit(1);
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
/**
|
|
167
|
+
* Get file/directory stats
|
|
168
|
+
*/
|
|
169
|
+
async stat(path, options) {
|
|
170
|
+
const spinner = ora('Getting file stats...').start();
|
|
171
|
+
try {
|
|
172
|
+
const brain = getBrainy();
|
|
173
|
+
const vfs = brain.vfs();
|
|
174
|
+
await vfs.init();
|
|
175
|
+
const stats = await vfs.stat(path);
|
|
176
|
+
spinner.succeed('Stats retrieved');
|
|
177
|
+
if (!options.json) {
|
|
178
|
+
console.log(chalk.cyan('\nFile Statistics:'));
|
|
179
|
+
console.log(` Path: ${path}`);
|
|
180
|
+
console.log(` Type: ${stats.isDirectory() ? chalk.blue('Directory') : 'File'}`);
|
|
181
|
+
console.log(` Size: ${formatBytes(stats.size)}`);
|
|
182
|
+
console.log(` Created: ${formatDate(stats.birthtime)}`);
|
|
183
|
+
console.log(` Modified: ${formatDate(stats.mtime)}`);
|
|
184
|
+
console.log(` Accessed: ${formatDate(stats.atime)}`);
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
formatOutput(stats, options);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
spinner.fail('Failed to get stats');
|
|
192
|
+
console.error(chalk.red(error.message));
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
/**
|
|
197
|
+
* Create directory
|
|
198
|
+
*/
|
|
199
|
+
async mkdir(path, options) {
|
|
200
|
+
const spinner = ora('Creating directory...').start();
|
|
201
|
+
try {
|
|
202
|
+
const brain = getBrainy();
|
|
203
|
+
const vfs = brain.vfs();
|
|
204
|
+
await vfs.init();
|
|
205
|
+
await vfs.mkdir(path, { recursive: options.parents });
|
|
206
|
+
spinner.succeed('Directory created');
|
|
207
|
+
if (!options.json) {
|
|
208
|
+
console.log(chalk.green(`ā Created: ${path}`));
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
formatOutput({ path, created: true }, options);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
spinner.fail('Failed to create directory');
|
|
216
|
+
console.error(chalk.red(error.message));
|
|
217
|
+
process.exit(1);
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
/**
|
|
221
|
+
* Remove file or directory
|
|
222
|
+
*/
|
|
223
|
+
async rm(path, options) {
|
|
224
|
+
const spinner = ora('Removing...').start();
|
|
225
|
+
try {
|
|
226
|
+
const brain = getBrainy();
|
|
227
|
+
const vfs = brain.vfs();
|
|
228
|
+
await vfs.init();
|
|
229
|
+
const stats = await vfs.stat(path);
|
|
230
|
+
if (stats.isDirectory()) {
|
|
231
|
+
await vfs.rmdir(path, { recursive: options.recursive });
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
await vfs.unlink(path);
|
|
235
|
+
}
|
|
236
|
+
spinner.succeed('Removed successfully');
|
|
237
|
+
if (!options.json) {
|
|
238
|
+
console.log(chalk.green(`ā Removed: ${path}`));
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
formatOutput({ path, removed: true }, options);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
spinner.fail('Failed to remove');
|
|
246
|
+
console.error(chalk.red(error.message));
|
|
247
|
+
if (!options.force) {
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
/**
|
|
253
|
+
* Search files by content
|
|
254
|
+
*/
|
|
255
|
+
async search(query, options) {
|
|
256
|
+
const spinner = ora('Searching files...').start();
|
|
257
|
+
try {
|
|
258
|
+
const brain = getBrainy();
|
|
259
|
+
const vfs = brain.vfs();
|
|
260
|
+
await vfs.init();
|
|
261
|
+
const results = await vfs.search(query, {
|
|
262
|
+
path: options.path,
|
|
263
|
+
limit: options.limit ? parseInt(options.limit) : 10
|
|
264
|
+
});
|
|
265
|
+
spinner.succeed(`Found ${results.length} results`);
|
|
266
|
+
if (!options.json) {
|
|
267
|
+
if (results.length === 0) {
|
|
268
|
+
console.log(chalk.yellow('No results found'));
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
console.log(chalk.cyan('\nš Search Results:\n'));
|
|
272
|
+
results.forEach((result, i) => {
|
|
273
|
+
console.log(chalk.bold(`${i + 1}. ${result.path}`));
|
|
274
|
+
if (result.score) {
|
|
275
|
+
console.log(chalk.dim(` Score: ${(result.score * 100).toFixed(1)}%`));
|
|
276
|
+
}
|
|
277
|
+
if (result.excerpt) {
|
|
278
|
+
console.log(chalk.dim(` ${result.excerpt}`));
|
|
279
|
+
}
|
|
280
|
+
console.log();
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
formatOutput(results, options);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
catch (error) {
|
|
289
|
+
spinner.fail('Search failed');
|
|
290
|
+
console.error(chalk.red(error.message));
|
|
291
|
+
process.exit(1);
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
/**
|
|
295
|
+
* Find similar files
|
|
296
|
+
*/
|
|
297
|
+
async similar(path, options) {
|
|
298
|
+
const spinner = ora('Finding similar files...').start();
|
|
299
|
+
try {
|
|
300
|
+
const brain = getBrainy();
|
|
301
|
+
const vfs = brain.vfs();
|
|
302
|
+
await vfs.init();
|
|
303
|
+
const results = await vfs.findSimilar(path, {
|
|
304
|
+
limit: options.limit ? parseInt(options.limit) : 10,
|
|
305
|
+
threshold: options.threshold ? parseFloat(options.threshold) : 0.7
|
|
306
|
+
});
|
|
307
|
+
spinner.succeed(`Found ${results.length} similar files`);
|
|
308
|
+
if (!options.json) {
|
|
309
|
+
if (results.length === 0) {
|
|
310
|
+
console.log(chalk.yellow('No similar files found'));
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
console.log(chalk.cyan('\nš Similar Files:\n'));
|
|
314
|
+
results.forEach((result, i) => {
|
|
315
|
+
console.log(chalk.bold(`${i + 1}. ${result.path}`));
|
|
316
|
+
if (result.score) {
|
|
317
|
+
console.log(chalk.green(` Similarity: ${(result.score * 100).toFixed(1)}%`));
|
|
318
|
+
}
|
|
319
|
+
console.log();
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
formatOutput(results, options);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
catch (error) {
|
|
328
|
+
spinner.fail('Failed to find similar files');
|
|
329
|
+
console.error(chalk.red(error.message));
|
|
330
|
+
process.exit(1);
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
/**
|
|
334
|
+
* Get directory tree structure
|
|
335
|
+
*/
|
|
336
|
+
async tree(path, options) {
|
|
337
|
+
const spinner = ora('Building tree...').start();
|
|
338
|
+
try {
|
|
339
|
+
const brain = getBrainy();
|
|
340
|
+
const vfs = brain.vfs();
|
|
341
|
+
await vfs.init();
|
|
342
|
+
const tree = await vfs.getTreeStructure(path, {
|
|
343
|
+
maxDepth: options.depth ? parseInt(options.depth) : 3
|
|
344
|
+
});
|
|
345
|
+
spinner.succeed('Tree built');
|
|
346
|
+
if (!options.json) {
|
|
347
|
+
console.log(chalk.cyan(`\nš ${path}\n`));
|
|
348
|
+
displayTree(tree, '', true);
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
formatOutput(tree, options);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
catch (error) {
|
|
355
|
+
spinner.fail('Failed to build tree');
|
|
356
|
+
console.error(chalk.red(error.message));
|
|
357
|
+
process.exit(1);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
function displayTree(node, prefix, isLast) {
|
|
362
|
+
const connector = isLast ? 'āāā ' : 'āāā ';
|
|
363
|
+
const name = node.isDirectory ? chalk.blue(node.name + '/') : node.name;
|
|
364
|
+
console.log(prefix + connector + name);
|
|
365
|
+
if (node.children && node.children.length > 0) {
|
|
366
|
+
const childPrefix = prefix + (isLast ? ' ' : 'ā ');
|
|
367
|
+
node.children.forEach((child, i) => {
|
|
368
|
+
displayTree(child, childPrefix, i === node.children.length - 1);
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
//# sourceMappingURL=vfs.js.map
|