filemayor 2.1.0 → 4.0.5
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/LICENSE +90 -90
- package/README.md +96 -96
- package/core/ai/planner.js +42 -0
- package/core/ai/sentry.js +92 -0
- package/core/ai/strategist.js +186 -0
- package/core/ai/validator.js +116 -0
- package/core/analyzer.js +163 -152
- package/core/categories.js +235 -235
- package/core/cleaner.js +527 -527
- package/core/config.js +562 -562
- package/core/emergency-halt.js +104 -0
- package/core/engine/apply-engine.js +69 -0
- package/core/engine/cure-engine.js +70 -0
- package/core/engine/dedupe-engine.js +77 -0
- package/core/engine/explain-engine.js +114 -0
- package/core/engine/preview-engine.js +49 -0
- package/core/fs-abstraction.js +271 -0
- package/core/guardrail.js +115 -0
- package/core/index.js +135 -79
- package/core/intent-interpreter.js +301 -0
- package/core/jailer.js +151 -0
- package/core/license.js +403 -337
- package/core/metadata-store.js +104 -0
- package/core/organizer.js +414 -528
- package/core/reporter.js +783 -653
- package/core/scanner.js +466 -436
- package/core/security.js +370 -317
- package/core/sop-parser.js +564 -564
- package/core/telemetry.js +74 -0
- package/core/vault.js +179 -0
- package/core/watcher.js +478 -478
- package/index.js +895 -685
- package/package.json +3 -3
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════
|
|
5
|
+
* FILEMAYOR FS v3.0 — INTENT-READY FILESYSTEM ABSTRACTION
|
|
6
|
+
* Async, safe, transactional, and fully rollbackable.
|
|
7
|
+
* ═══════════════════════════════════════════════════════════════════
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const fs = require('fs').promises;
|
|
13
|
+
const fssync = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const os = require('os');
|
|
16
|
+
const crypto = require('crypto');
|
|
17
|
+
const { validatePath, isFileSafe, isDirSafe, canRead, canWrite } = require('./security');
|
|
18
|
+
const { formatBytes } = require('./scanner');
|
|
19
|
+
|
|
20
|
+
class FileMayorFS {
|
|
21
|
+
constructor(options = {}) {
|
|
22
|
+
this.options = {
|
|
23
|
+
useJournal: true,
|
|
24
|
+
dryRun: false,
|
|
25
|
+
trashPath: path.join(os.tmpdir(), 'filemayor_trash'),
|
|
26
|
+
journalPath: path.join(os.homedir(), '.filemayor-master-journal.ndjson'),
|
|
27
|
+
...options
|
|
28
|
+
};
|
|
29
|
+
this.sessionJournal = [];
|
|
30
|
+
this.stats = {
|
|
31
|
+
opsSucceeded: 0,
|
|
32
|
+
opsFailed: 0,
|
|
33
|
+
totalBytesProcessed: 0,
|
|
34
|
+
filesMoved: 0,
|
|
35
|
+
filesDeleted: 0
|
|
36
|
+
};
|
|
37
|
+
fssync.mkdirSync(this.options.trashPath, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** ------------------------
|
|
41
|
+
* Enhanced Snapshot
|
|
42
|
+
* -------------------------*/
|
|
43
|
+
async createSnapshot(filePath) {
|
|
44
|
+
try {
|
|
45
|
+
const stats = await fs.stat(filePath);
|
|
46
|
+
return {
|
|
47
|
+
path: filePath,
|
|
48
|
+
size: stats.size,
|
|
49
|
+
mtime: stats.mtimeMs,
|
|
50
|
+
hash: crypto.createHash('sha256').update(filePath + stats.mtimeMs).digest('hex')
|
|
51
|
+
};
|
|
52
|
+
} catch {
|
|
53
|
+
return { path: filePath };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** ------------------------
|
|
58
|
+
* Async Move
|
|
59
|
+
* -------------------------*/
|
|
60
|
+
async move(source, destination) {
|
|
61
|
+
const result = { source, destination, action: 'move', status: 'pending' };
|
|
62
|
+
|
|
63
|
+
const sourceCheck = isFileSafe(source);
|
|
64
|
+
if (!sourceCheck.safe) throw new Error(`Source unsafe: ${sourceCheck.reason}`);
|
|
65
|
+
|
|
66
|
+
const destValidation = validatePath(destination);
|
|
67
|
+
if (!destValidation.valid) throw new Error(`Destination invalid: ${destValidation.error}`);
|
|
68
|
+
|
|
69
|
+
const snapshot = await this.createSnapshot(source);
|
|
70
|
+
|
|
71
|
+
if (this.options.dryRun) {
|
|
72
|
+
result.status = 'dry-run';
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const destDir = path.dirname(destination);
|
|
78
|
+
await fs.mkdir(destDir, { recursive: true });
|
|
79
|
+
|
|
80
|
+
// WAL: write pending entry BEFORE the operation
|
|
81
|
+
const opId = crypto.randomUUID();
|
|
82
|
+
await this._journalPending(opId, source, destination, 'move', snapshot);
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
await fs.rename(source, destination);
|
|
86
|
+
} catch (err) {
|
|
87
|
+
if (err.code === 'EXDEV') {
|
|
88
|
+
await fs.copyFile(source, destination);
|
|
89
|
+
await fs.unlink(source);
|
|
90
|
+
} else throw err;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// WAL: record completion AFTER the operation
|
|
94
|
+
await this._journalDone(opId);
|
|
95
|
+
|
|
96
|
+
result.status = 'success';
|
|
97
|
+
this.stats.opsSucceeded++;
|
|
98
|
+
this.stats.filesMoved++;
|
|
99
|
+
this.stats.totalBytesProcessed += snapshot.size || 0;
|
|
100
|
+
|
|
101
|
+
} catch (err) {
|
|
102
|
+
result.status = 'error';
|
|
103
|
+
result.error = err.message;
|
|
104
|
+
this.stats.opsFailed++;
|
|
105
|
+
throw err;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/** ------------------------
|
|
112
|
+
* Safe Delete with Trash
|
|
113
|
+
* -------------------------*/
|
|
114
|
+
async delete(target) {
|
|
115
|
+
const check = isFileSafe(target);
|
|
116
|
+
if (!check.safe) throw new Error(`Target unsafe: ${check.reason}`);
|
|
117
|
+
|
|
118
|
+
const snapshot = await this.createSnapshot(target);
|
|
119
|
+
|
|
120
|
+
if (this.options.dryRun) return { target, status: 'dry-run' };
|
|
121
|
+
|
|
122
|
+
const trashFile = path.join(this.options.trashPath, path.basename(target) + '-' + Date.now());
|
|
123
|
+
await fs.rename(target, trashFile);
|
|
124
|
+
|
|
125
|
+
this.stats.opsSucceeded++;
|
|
126
|
+
this.stats.filesDeleted++;
|
|
127
|
+
this.stats.totalBytesProcessed += snapshot.size || 0;
|
|
128
|
+
|
|
129
|
+
await this._logToJournal(target, trashFile, 'delete', snapshot);
|
|
130
|
+
|
|
131
|
+
return { target, status: 'success' };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** ------------------------
|
|
135
|
+
* Journaling (WAL)
|
|
136
|
+
* -------------------------*/
|
|
137
|
+
async _journalWriteLine(entry) {
|
|
138
|
+
if (!this.options.useJournal) return;
|
|
139
|
+
try {
|
|
140
|
+
const line = JSON.stringify(entry) + '\n';
|
|
141
|
+
fssync.appendFileSync(this.options.journalPath, line, 'utf8');
|
|
142
|
+
} catch (err) {
|
|
143
|
+
console.error(`[FAIL] Journal write failed: ${err.message}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async _logToJournal(source, destination, action, snapshot) {
|
|
148
|
+
// WAL: record intent BEFORE operation (called pre-move),
|
|
149
|
+
// then update to 'done' AFTER (called post-move).
|
|
150
|
+
// This is handled by _journalPending / _journalDone.
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async _journalPending(id, source, destination, action, snapshot) {
|
|
154
|
+
const entry = {
|
|
155
|
+
id,
|
|
156
|
+
timestamp: new Date().toISOString(),
|
|
157
|
+
action,
|
|
158
|
+
source,
|
|
159
|
+
destination,
|
|
160
|
+
snapshot,
|
|
161
|
+
status: 'pending',
|
|
162
|
+
};
|
|
163
|
+
this.sessionJournal.push(entry);
|
|
164
|
+
await this._journalWriteLine(entry);
|
|
165
|
+
return entry;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async _journalDone(id) {
|
|
169
|
+
await this._journalWriteLine({ id, status: 'done', completedAt: new Date().toISOString() });
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** ------------------------
|
|
173
|
+
* Rollback
|
|
174
|
+
* -------------------------*/
|
|
175
|
+
async rollback() {
|
|
176
|
+
const entries = new Map();
|
|
177
|
+
const done = new Set();
|
|
178
|
+
|
|
179
|
+
if (fssync.existsSync(this.options.journalPath)) {
|
|
180
|
+
const lines = fssync.readFileSync(this.options.journalPath, 'utf8').split('\n');
|
|
181
|
+
for (const line of lines) {
|
|
182
|
+
if (!line.trim()) continue;
|
|
183
|
+
try {
|
|
184
|
+
const rec = JSON.parse(line);
|
|
185
|
+
if (rec.status === 'pending') entries.set(rec.id, rec);
|
|
186
|
+
if (rec.status === 'done') done.add(rec.id);
|
|
187
|
+
} catch { /* skip malformed lines */ }
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Add session-only pending entries not yet on disk
|
|
192
|
+
for (const e of this.sessionJournal) {
|
|
193
|
+
if (!entries.has(e.id)) entries.set(e.id, e);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Reverse-order rollback of moves that never completed
|
|
197
|
+
const toRollback = [...entries.values()]
|
|
198
|
+
.filter(e => !done.has(e.id))
|
|
199
|
+
.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
|
|
200
|
+
|
|
201
|
+
console.log(`[SYS] Rolling back ${toRollback.length} incomplete operations...`);
|
|
202
|
+
|
|
203
|
+
for (const entry of toRollback) {
|
|
204
|
+
try {
|
|
205
|
+
if (fssync.existsSync(entry.destination)) {
|
|
206
|
+
await fs.rename(entry.destination, entry.source);
|
|
207
|
+
await this._journalWriteLine({ id: entry.id, status: 'rolled-back', rolledBackAt: new Date().toISOString() });
|
|
208
|
+
}
|
|
209
|
+
} catch (err) {
|
|
210
|
+
console.error(`[FAIL] Rollback failed for ${entry.source}: ${err.message}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
this.sessionJournal = [];
|
|
215
|
+
console.log('[SYS] Rollback complete.');
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
getJournal() {
|
|
219
|
+
return this.sessionJournal;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const JOURNAL_PATH = path.join(os.homedir(), '.filemayor-master-journal.ndjson');
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Standalone rollback function that reads the master journal on disk
|
|
227
|
+
* and reverses all completed operations (status === 'done').
|
|
228
|
+
* Returns { reversed: Array<entry>, count: number }.
|
|
229
|
+
*/
|
|
230
|
+
async function rollback(journalPath) {
|
|
231
|
+
const entries = new Map();
|
|
232
|
+
const done = new Set();
|
|
233
|
+
|
|
234
|
+
if (fssync.existsSync(journalPath)) {
|
|
235
|
+
const lines = fssync.readFileSync(journalPath, 'utf8').split('\n');
|
|
236
|
+
for (const line of lines) {
|
|
237
|
+
if (!line.trim()) continue;
|
|
238
|
+
try {
|
|
239
|
+
const rec = JSON.parse(line);
|
|
240
|
+
if (rec.status === 'pending') entries.set(rec.id, rec);
|
|
241
|
+
if (rec.status === 'done') done.add(rec.id);
|
|
242
|
+
} catch { /* skip malformed lines */ }
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Rollback moves that completed successfully (status === 'done')
|
|
247
|
+
const toRollback = [...entries.values()]
|
|
248
|
+
.filter(e => done.has(e.id))
|
|
249
|
+
.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
|
|
250
|
+
|
|
251
|
+
const reversed = [];
|
|
252
|
+
for (const entry of toRollback) {
|
|
253
|
+
try {
|
|
254
|
+
if (fssync.existsSync(entry.destination)) {
|
|
255
|
+
await fs.rename(entry.destination, entry.source);
|
|
256
|
+
fssync.appendFileSync(journalPath,
|
|
257
|
+
JSON.stringify({ id: entry.id, status: 'rolled-back', rolledBackAt: new Date().toISOString() }) + '\n',
|
|
258
|
+
'utf8');
|
|
259
|
+
reversed.push(entry);
|
|
260
|
+
}
|
|
261
|
+
} catch (err) {
|
|
262
|
+
console.error(`[FAIL] Rollback failed for ${entry.source}: ${err.message}`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return { reversed, count: reversed.length };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
module.exports = FileMayorFS;
|
|
270
|
+
module.exports.JOURNAL_PATH = JOURNAL_PATH;
|
|
271
|
+
module.exports.rollback = rollback;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════
|
|
5
|
+
* FILEMAYOR CORE — LOGIC GUARDRAIL
|
|
6
|
+
*
|
|
7
|
+
* The final layer of the Chevza Doctrine: INTENTIONALITY.
|
|
8
|
+
* Sits between the AI Intuition Engine and the Jailer.
|
|
9
|
+
* Forces a dry-run preview + user confirmation for high-volume
|
|
10
|
+
* or destructive-pattern operations.
|
|
11
|
+
*
|
|
12
|
+
* Zero-dependency: uses native `readline/promises`.
|
|
13
|
+
* ═══════════════════════════════════════════════════════════════════
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
'use strict';
|
|
17
|
+
|
|
18
|
+
const readline = require('readline/promises');
|
|
19
|
+
const { stdin: input, stdout: output } = require('process');
|
|
20
|
+
const path = require('path');
|
|
21
|
+
|
|
22
|
+
class LogicGuardrail {
|
|
23
|
+
/**
|
|
24
|
+
* @param {number} safetyLimit - Max ops before triggering confirmation (default: 50)
|
|
25
|
+
*/
|
|
26
|
+
constructor(safetyLimit = 50) {
|
|
27
|
+
this.safetyLimit = safetyLimit;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Analyze a batch plan and require user confirmation if suspicious.
|
|
32
|
+
* @param {Array} batch - Array of { source, destination, type?, reason? }
|
|
33
|
+
* @returns {Promise<boolean>} Whether the user approved the batch
|
|
34
|
+
*/
|
|
35
|
+
async verifyBatch(batch) {
|
|
36
|
+
if (!Array.isArray(batch) || batch.length === 0) return true;
|
|
37
|
+
|
|
38
|
+
const operationCount = batch.length;
|
|
39
|
+
|
|
40
|
+
// Auto-pass for small, safe batches
|
|
41
|
+
if (operationCount < this.safetyLimit && !this.isDestructivePattern(batch)) {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ─── Dry Run Summary ─────────────────────────────────────
|
|
46
|
+
console.log('\n' + '═'.repeat(60));
|
|
47
|
+
console.log('⚠️ [LOGIC GUARDRAIL] High-Volume Operation Detected');
|
|
48
|
+
console.log('═'.repeat(60));
|
|
49
|
+
console.log(` Total operations: ${operationCount}`);
|
|
50
|
+
console.log(` Safety limit: ${this.safetyLimit}`);
|
|
51
|
+
|
|
52
|
+
if (this.isDestructivePattern(batch)) {
|
|
53
|
+
console.log('\n 🔴 WARNING: Destructive pattern detected!');
|
|
54
|
+
console.log(' Many files are being moved to a single destination.');
|
|
55
|
+
console.log(' This could indicate an AI "Semantic Wipe" or "Over-Organizer" loop.');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Show preview of first 5 operations
|
|
59
|
+
console.log('\n Preview:');
|
|
60
|
+
const preview = batch.slice(0, 5);
|
|
61
|
+
for (const op of preview) {
|
|
62
|
+
const srcName = path.basename(op.source || '');
|
|
63
|
+
const dstDir = path.dirname(op.destination || '');
|
|
64
|
+
console.log(` ${srcName} → ${dstDir}`);
|
|
65
|
+
}
|
|
66
|
+
if (operationCount > 5) {
|
|
67
|
+
console.log(` ... and ${operationCount - 5} more.`);
|
|
68
|
+
}
|
|
69
|
+
console.log('═'.repeat(60));
|
|
70
|
+
|
|
71
|
+
// ─── User Confirmation (Native Node.js) ─────────────────
|
|
72
|
+
const rl = readline.createInterface({ input, output });
|
|
73
|
+
try {
|
|
74
|
+
const answer = await rl.question('\n Proceed with this batch? (y/N): ');
|
|
75
|
+
return answer.toLowerCase().trim() === 'y';
|
|
76
|
+
} finally {
|
|
77
|
+
rl.close();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Detect if the AI is funneling many files into a single destination.
|
|
83
|
+
* This catches "Over-Organizer Loops" and "Semantic Wipes."
|
|
84
|
+
* @param {Array} batch - The operation batch
|
|
85
|
+
* @returns {boolean} True if the pattern looks destructive
|
|
86
|
+
*/
|
|
87
|
+
isDestructivePattern(batch) {
|
|
88
|
+
if (batch.length < 10) return false;
|
|
89
|
+
|
|
90
|
+
const destDirs = batch.map(b => {
|
|
91
|
+
const dest = b.destination || '';
|
|
92
|
+
return path.dirname(dest).toLowerCase();
|
|
93
|
+
});
|
|
94
|
+
const uniqueDests = new Set(destDirs).size;
|
|
95
|
+
|
|
96
|
+
// If 10+ files all going to 1 directory, it's suspicious
|
|
97
|
+
return (batch.length / uniqueDests) > 10;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Detect "Nesting Hell" — AI creating deeply nested structures
|
|
102
|
+
* @param {Array} batch - The operation batch
|
|
103
|
+
* @param {number} maxDepth - Maximum allowed nesting depth (default: 8)
|
|
104
|
+
* @returns {Array} Entries that exceed the nesting depth
|
|
105
|
+
*/
|
|
106
|
+
detectNestingHell(batch, maxDepth = 8) {
|
|
107
|
+
return batch.filter(op => {
|
|
108
|
+
const dest = op.destination || '';
|
|
109
|
+
const segments = dest.replace(/\\/g, '/').split('/').filter(s => s.length > 0);
|
|
110
|
+
return segments.length > maxDepth;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
module.exports = LogicGuardrail;
|
package/core/index.js
CHANGED
|
@@ -1,79 +1,135 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* ═══════════════════════════════════════════════════════════════════
|
|
5
|
-
* FILEMAYOR CORE — INDEX (Barrel Export)
|
|
6
|
-
* Unified entry point for all core modules
|
|
7
|
-
* ═══════════════════════════════════════════════════════════════════
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
'use strict';
|
|
11
|
-
|
|
12
|
-
const scanner = require('./scanner');
|
|
13
|
-
const organizer = require('./organizer');
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
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
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════
|
|
5
|
+
* FILEMAYOR CORE — INDEX (Barrel Export)
|
|
6
|
+
* Unified entry point for all core modules
|
|
7
|
+
* ═══════════════════════════════════════════════════════════════════
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const scanner = require('./scanner');
|
|
13
|
+
const organizer = require('./organizer');
|
|
14
|
+
const IntentInterpreter = require('./intent-interpreter');
|
|
15
|
+
const FileMayorFS = require('./fs-abstraction');
|
|
16
|
+
const cleaner = require('./cleaner');
|
|
17
|
+
const watcher = require('./watcher');
|
|
18
|
+
const config = require('./config');
|
|
19
|
+
const reporter = require('./reporter');
|
|
20
|
+
const categories = require('./categories');
|
|
21
|
+
const security = require('./security');
|
|
22
|
+
const sopParser = require('./sop-parser');
|
|
23
|
+
const analyzer = require('./analyzer');
|
|
24
|
+
const license = require('./license');
|
|
25
|
+
const ExplainEngine = require('./engine/explain-engine');
|
|
26
|
+
const CureEngine = require('./engine/cure-engine');
|
|
27
|
+
const ApplyEngine = require('./engine/apply-engine');
|
|
28
|
+
const PreviewEngine = require('./engine/preview-engine');
|
|
29
|
+
const DedupeEngine = require('./engine/dedupe-engine');
|
|
30
|
+
const MetadataStore = require('./metadata-store');
|
|
31
|
+
const strategist = require('./ai/strategist');
|
|
32
|
+
const sentry = require('./ai/sentry');
|
|
33
|
+
const planner = require('./ai/planner');
|
|
34
|
+
const validator = require('./ai/validator');
|
|
35
|
+
const { FileMayorJailer, enforceUserSpace } = require('./jailer');
|
|
36
|
+
const Vault = require('./vault');
|
|
37
|
+
const LogicGuardrail = require('./guardrail');
|
|
38
|
+
const { initEmergencyHalt, updateJournalRef, clearEmergencyHalt } = require('./emergency-halt');
|
|
39
|
+
|
|
40
|
+
module.exports = {
|
|
41
|
+
// Scanner
|
|
42
|
+
Scanner: scanner.Scanner,
|
|
43
|
+
scan: scanner.scan,
|
|
44
|
+
scanByCategory: scanner.scanByCategory,
|
|
45
|
+
scanSummary: scanner.scanSummary,
|
|
46
|
+
formatBytes: scanner.formatBytes,
|
|
47
|
+
analyzeDirectory: analyzer.analyzeDirectory,
|
|
48
|
+
|
|
49
|
+
// Organizer
|
|
50
|
+
organize: organizer.organize,
|
|
51
|
+
generatePlan: organizer.generatePlan,
|
|
52
|
+
executePlan: organizer.executePlan,
|
|
53
|
+
rollback: organizer.rollback,
|
|
54
|
+
loadJournal: organizer.loadJournal,
|
|
55
|
+
NAMING_CONVENTIONS: organizer.NAMING_CONVENTIONS,
|
|
56
|
+
|
|
57
|
+
// Intent Interpreter
|
|
58
|
+
IntentInterpreter: IntentInterpreter,
|
|
59
|
+
|
|
60
|
+
// FS Abstraction
|
|
61
|
+
FileMayorFS: FileMayorFS,
|
|
62
|
+
|
|
63
|
+
// Cleaner
|
|
64
|
+
Cleaner: cleaner.Cleaner,
|
|
65
|
+
findJunk: cleaner.findJunk,
|
|
66
|
+
deleteJunk: cleaner.deleteJunk,
|
|
67
|
+
clean: cleaner.clean,
|
|
68
|
+
JUNK_CATEGORIES: cleaner.JUNK_CATEGORIES,
|
|
69
|
+
|
|
70
|
+
// Watcher
|
|
71
|
+
FileWatcher: watcher.FileWatcher,
|
|
72
|
+
|
|
73
|
+
// Config
|
|
74
|
+
loadConfig: config.loadConfig,
|
|
75
|
+
findConfigFile: config.findConfigFile,
|
|
76
|
+
createConfigFile: config.createConfigFile,
|
|
77
|
+
generateTemplate: config.generateTemplate,
|
|
78
|
+
validateConfig: config.validateConfig,
|
|
79
|
+
|
|
80
|
+
// Reporter
|
|
81
|
+
reporter,
|
|
82
|
+
|
|
83
|
+
// Categories
|
|
84
|
+
categorize: categories.categorize,
|
|
85
|
+
getCategories: categories.getCategories,
|
|
86
|
+
mergeCategories: categories.mergeCategories,
|
|
87
|
+
DEFAULT_CATEGORIES: categories.DEFAULT_CATEGORIES,
|
|
88
|
+
|
|
89
|
+
// Security
|
|
90
|
+
validatePath: security.validatePath,
|
|
91
|
+
isFileSafe: security.isFileSafe,
|
|
92
|
+
isDirSafe: security.isDirSafe,
|
|
93
|
+
sanitizeFilename: security.sanitizeFilename,
|
|
94
|
+
checkPermissions: security.checkPermissions,
|
|
95
|
+
|
|
96
|
+
// SOP Parser
|
|
97
|
+
parseSOP: sopParser.parseSOP,
|
|
98
|
+
parseRuleBased: sopParser.parseRuleBased,
|
|
99
|
+
rulesToConfig: sopParser.rulesToConfig,
|
|
100
|
+
FILE_TYPE_ALIASES: sopParser.FILE_TYPE_ALIASES,
|
|
101
|
+
|
|
102
|
+
// License
|
|
103
|
+
activateLicense: license.activateLicense,
|
|
104
|
+
deactivateLicense: license.deactivateLicense,
|
|
105
|
+
getLicenseInfo: license.getLicenseInfo,
|
|
106
|
+
checkProFeature: license.checkProFeature,
|
|
107
|
+
checkBulkLimit: license.checkBulkLimit,
|
|
108
|
+
hasFeature: license.hasFeature,
|
|
109
|
+
|
|
110
|
+
// Intent Agents
|
|
111
|
+
IntentStrategist: strategist,
|
|
112
|
+
MetadataSentry: sentry,
|
|
113
|
+
CurativePlanner: planner,
|
|
114
|
+
SecurityArchitect: validator,
|
|
115
|
+
|
|
116
|
+
// Engines
|
|
117
|
+
ExplainEngine,
|
|
118
|
+
CureEngine,
|
|
119
|
+
ApplyEngine,
|
|
120
|
+
PreviewEngine,
|
|
121
|
+
DedupeEngine,
|
|
122
|
+
MetadataStore,
|
|
123
|
+
|
|
124
|
+
// Hardened Runtime
|
|
125
|
+
FileMayorJailer,
|
|
126
|
+
enforceUserSpace,
|
|
127
|
+
Vault,
|
|
128
|
+
LogicGuardrail,
|
|
129
|
+
initEmergencyHalt,
|
|
130
|
+
updateJournalRef,
|
|
131
|
+
clearEmergencyHalt,
|
|
132
|
+
|
|
133
|
+
// Version
|
|
134
|
+
VERSION: require('../package.json').version || '2.0.0'
|
|
135
|
+
};
|