@xelth/eck-snapshot 6.5.1 โ 6.7.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/README.md +2 -1
- package/package.json +1 -1
- package/setup.json +34 -0
- package/src/cli/cli.js +8 -4
- package/src/cli/commands/createSnapshot.js +24 -11
- package/src/cli/commands/recon.js +317 -283
- package/src/cli/commands/setupMcp.js +2 -0
- package/src/cli/commands/updateSnapshot.js +126 -114
- package/src/utils/fileUtils.js +1181 -1081
- package/src/utils/projectDetector.js +60 -0
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# ๐ธ eckSnapshot v6.
|
|
1
|
+
# ๐ธ eckSnapshot v6.7.0 (AI-Native Edition)
|
|
2
2
|
|
|
3
3
|
A specialized, AI-native CLI tool that creates single-file text snapshots of entire Git repositories and feeds them directly into LLM context windows. Instead of letting AI agents guess which files to read, eckSnapshot force-feeds the complete project into the model's context โ giving it a "university degree" in your codebase from the very first prompt.
|
|
4
4
|
|
|
@@ -200,6 +200,7 @@ By analyzing Claude Code's internal architecture, eckSnapshot replaces the old m
|
|
|
200
200
|
* **๐ The `.eck/` Manifest:** Automatically maintains project context files (`CONTEXT.md`, `ROADMAP.md`, `TECH_DEBT.md`). Dynamic scanning โ any `.md` file you add to `.eck/` is automatically included in snapshots.
|
|
201
201
|
* **โ ๏ธ Skeleton Mode:** Uses Tree-sitter and Babel to strip function bodies, drastically reducing token count for huge codebases.
|
|
202
202
|
* **๐ NotebookLM Export:** Semantic chunking for Google's NotebookLM with "Brain + Body" architecture (see below).
|
|
203
|
+
* **๐งช ML Model Compatibility:** Smart metadata extraction for `.safetensors`, `.onnx`, `.pt`, `.pth`, `.h5`, `.pb`, `.bin`, `.ckpt`, `.gguf` โ reads the first 4KB header instead of loading multi-GB weights into memory.
|
|
203
204
|
* **๐ง Multi-Agent Protocol:** Junior Architect delegation system for multi-agent coding workflows (see below).
|
|
204
205
|
|
|
205
206
|
### ๐ค Autonomous AI Protocols
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xelth/eck-snapshot",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.7.0",
|
|
4
4
|
"description": "A powerful CLI tool to create and restore single-file text snapshots of Git repositories. Optimized for AI context, LLM workflows, and multi-agent Swarm coordination.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
package/setup.json
CHANGED
|
@@ -164,6 +164,19 @@
|
|
|
164
164
|
],
|
|
165
165
|
"priority": 7
|
|
166
166
|
},
|
|
167
|
+
"esp-idf": {
|
|
168
|
+
"files": [
|
|
169
|
+
"sdkconfig.defaults",
|
|
170
|
+
"partitions.csv"
|
|
171
|
+
],
|
|
172
|
+
"directories": [
|
|
173
|
+
"managed_components"
|
|
174
|
+
],
|
|
175
|
+
"manifestFiles": [
|
|
176
|
+
"idf_component.yml"
|
|
177
|
+
],
|
|
178
|
+
"priority": 8
|
|
179
|
+
},
|
|
167
180
|
"c": {
|
|
168
181
|
"files": [
|
|
169
182
|
"Makefile",
|
|
@@ -518,6 +531,27 @@
|
|
|
518
531
|
"packages/"
|
|
519
532
|
]
|
|
520
533
|
},
|
|
534
|
+
"esp-idf": {
|
|
535
|
+
"filesToIgnore": [
|
|
536
|
+
"sdkconfig.old",
|
|
537
|
+
"dependencies.lock"
|
|
538
|
+
],
|
|
539
|
+
"dirsToIgnore": [
|
|
540
|
+
"managed_components/",
|
|
541
|
+
"build/",
|
|
542
|
+
"managed_components/*/examples/",
|
|
543
|
+
"managed_components/*/test/",
|
|
544
|
+
"managed_components/*/test_apps/",
|
|
545
|
+
"managed_components/*/docs/",
|
|
546
|
+
"managed_components/*/hw/"
|
|
547
|
+
],
|
|
548
|
+
"extensionsToIgnore": [
|
|
549
|
+
".bin",
|
|
550
|
+
".elf",
|
|
551
|
+
".map",
|
|
552
|
+
".flash"
|
|
553
|
+
]
|
|
554
|
+
},
|
|
521
555
|
"c": {
|
|
522
556
|
"filesToIgnore": [
|
|
523
557
|
"*.o",
|
package/src/cli/cli.js
CHANGED
|
@@ -6,6 +6,7 @@ import chalk from 'chalk';
|
|
|
6
6
|
import { createRequire } from 'module';
|
|
7
7
|
import os from 'os';
|
|
8
8
|
import crypto from 'crypto';
|
|
9
|
+
import { ensureSnapshotsInGitignore } from '../utils/fileUtils.js';
|
|
9
10
|
|
|
10
11
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
12
|
const __dirname = path.dirname(__filename);
|
|
@@ -48,17 +49,17 @@ const LEGACY_COMMANDS = {
|
|
|
48
49
|
const base = baseIdx !== -1 && args[baseIdx + 1] ? args[baseIdx + 1] : undefined;
|
|
49
50
|
return { name: 'eck_update_auto', arguments: { fail: args.includes('--fail') || args.includes('-f'), base } };
|
|
50
51
|
},
|
|
51
|
-
'snapshot': () => ({ name: 'eck_snapshot', arguments: {} }),
|
|
52
|
+
'snapshot': (args) => ({ name: 'eck_snapshot', arguments: { ml: args.includes('--ml') } }),
|
|
52
53
|
'update': (args) => {
|
|
53
54
|
const baseIdx = args.indexOf('--base');
|
|
54
55
|
const base = baseIdx !== -1 && args[baseIdx + 1] ? args[baseIdx + 1] : undefined;
|
|
55
|
-
return { name: 'eck_update', arguments: { fail: args.includes('--fail') || args.includes('-f'), base } };
|
|
56
|
+
return { name: 'eck_update', arguments: { fail: args.includes('--fail') || args.includes('-f'), base, ml: args.includes('--ml') } };
|
|
56
57
|
},
|
|
57
58
|
'setup-mcp': (args) => ({ name: 'eck_setup_mcp', arguments: { opencode: args.includes('--opencode'), both: args.includes('--both') } }),
|
|
58
59
|
'detect': () => ({ name: 'eck_detect', arguments: {} }),
|
|
59
60
|
'doctor': () => ({ name: 'eck_doctor', arguments: {} }),
|
|
60
|
-
'scout': (args) => ({ name: 'eck_scout', arguments: { depth: args[0] !== undefined ? parseInt(args[0], 10) : 0 } }),
|
|
61
|
-
'fetch': (args) => ({ name: 'eck_fetch', arguments: { patterns: args } }),
|
|
61
|
+
'scout': (args) => ({ name: 'eck_scout', arguments: { depth: args[0] !== undefined ? parseInt(args[0], 10) : 0, ml: args.includes('--ml') } }),
|
|
62
|
+
'fetch': (args) => ({ name: 'eck_fetch', arguments: { patterns: args.filter(a => a !== '--ml'), ml: args.includes('--ml') } }),
|
|
62
63
|
'link': (args) => ({ name: 'eck_snapshot', arguments: { isLinkedProject: true, linkDepth: args[0] !== undefined ? parseInt(args[0], 10) : 0 } }),
|
|
63
64
|
'profile': (args) => args[0] ? ({ name: 'eck_snapshot', arguments: { profile: args.join(',') } }) : ({ name: 'eck_snapshot', arguments: { profile: true } }),
|
|
64
65
|
'booklm': () => ({ name: 'eck_snapshot', arguments: { notebooklm: 'scout' } }),
|
|
@@ -163,6 +164,7 @@ Ranked by frequency of use:
|
|
|
163
164
|
queue.feedback.push({ type, message: msg, date: new Date().toISOString() });
|
|
164
165
|
|
|
165
166
|
await fs.mkdir(path.dirname(queuePath), { recursive: true }).catch(() => {});
|
|
167
|
+
await ensureSnapshotsInGitignore(process.cwd()).catch(() => {});
|
|
166
168
|
await fs.writeFile(queuePath, JSON.stringify(queue, null, 2));
|
|
167
169
|
|
|
168
170
|
console.log(chalk.green('Feedback saved locally. It will be sent to developers during the next telemetry sync.'));
|
|
@@ -218,6 +220,7 @@ Ranked by frequency of use:
|
|
|
218
220
|
} catch(e) { /* no existing queue */ }
|
|
219
221
|
queue.usage[toolName] = (queue.usage[toolName] || 0) + 1;
|
|
220
222
|
await fs.mkdir(path.dirname(queuePath), { recursive: true }).catch(() => {});
|
|
223
|
+
await ensureSnapshotsInGitignore(cwd).catch(() => {});
|
|
221
224
|
await fs.writeFile(queuePath, JSON.stringify(queue, null, 2));
|
|
222
225
|
} catch(e) { /* ignore tracking errors */ }
|
|
223
226
|
}
|
|
@@ -265,6 +268,7 @@ Ranked by frequency of use:
|
|
|
265
268
|
} catch(e) { /* no existing queue */ }
|
|
266
269
|
queue.errors.push({ tool: toolName, error: err.message, date: new Date().toISOString() });
|
|
267
270
|
await fs.mkdir(path.dirname(queuePath), { recursive: true }).catch(() => {});
|
|
271
|
+
await ensureSnapshotsInGitignore(cwd).catch(() => {});
|
|
268
272
|
await fs.writeFile(queuePath, JSON.stringify(queue, null, 2));
|
|
269
273
|
} catch(e) { /* ignore tracking errors */ }
|
|
270
274
|
}
|
|
@@ -3,7 +3,6 @@ import path from 'path';
|
|
|
3
3
|
import { execa } from 'execa';
|
|
4
4
|
import pLimit from 'p-limit';
|
|
5
5
|
import { SingleBar, Presets } from 'cli-progress';
|
|
6
|
-
import isBinaryPath from 'is-binary-path';
|
|
7
6
|
import zlib from 'zlib';
|
|
8
7
|
import { promisify } from 'util';
|
|
9
8
|
import ora from 'ora';
|
|
@@ -15,7 +14,8 @@ import {
|
|
|
15
14
|
scanDirectoryRecursively, loadGitignore, readFileWithSizeCheck,
|
|
16
15
|
generateDirectoryTree, loadConfig, displayProjectInfo, loadProjectEckManifest,
|
|
17
16
|
ensureSnapshotsInGitignore, initializeEckManifest, generateTimestamp,
|
|
18
|
-
getShortRepoName, SecretScanner, getProjectFiles
|
|
17
|
+
getShortRepoName, SecretScanner, getProjectFiles, readMlModelMetadata,
|
|
18
|
+
isBinaryFile
|
|
19
19
|
} from '../../utils/fileUtils.js';
|
|
20
20
|
import { detectProjectType, getProjectSpecificFiltering, getAllDetectedTypes } from '../../utils/projectDetector.js';
|
|
21
21
|
import { estimateTokensWithPolynomial, generateTrainingCommand } from '../../utils/tokenEstimator.js';
|
|
@@ -252,7 +252,7 @@ async function estimateProjectTokens(projectPath, config, projectTypes = null) {
|
|
|
252
252
|
continue;
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
if (
|
|
255
|
+
if (await isBinaryFile(path.join(projectPath, file))) {
|
|
256
256
|
continue;
|
|
257
257
|
}
|
|
258
258
|
|
|
@@ -394,8 +394,16 @@ async function processProjectFiles(repoPath, options, config, projectTypes = nul
|
|
|
394
394
|
return null;
|
|
395
395
|
}
|
|
396
396
|
|
|
397
|
-
|
|
398
|
-
|
|
397
|
+
const mlExt = path.extname(filePath).toLowerCase();
|
|
398
|
+
const ML_EXTENSIONS = ['.safetensors', '.onnx', '.pt', '.pth', '.h5', '.pb', '.bin', '.ckpt', '.gguf'];
|
|
399
|
+
// ML peek is opt-in via `arguments.ml: true`. Default: ML files treated as plain binaries.
|
|
400
|
+
// This prevents false-positives where `.bin` raw dumps (mitm captures, sniffer output)
|
|
401
|
+
// get included via readMlModelMetadata when no real model is present.
|
|
402
|
+
const isMlModel = !!options?.ml && ML_EXTENSIONS.includes(mlExt);
|
|
403
|
+
|
|
404
|
+
// Content-aware binary check (catches extensionless ELFs, SQLite DBs, archives).
|
|
405
|
+
// ML models bypass to allow header metadata extraction below.
|
|
406
|
+
if (!isMlModel && await isBinaryFile(path.join(repoPath, filePath))) {
|
|
399
407
|
stats.binaryFiles++;
|
|
400
408
|
trackSkippedFile(normalizedPath, 'Binary files');
|
|
401
409
|
return null;
|
|
@@ -421,13 +429,18 @@ async function processProjectFiles(repoPath, options, config, projectTypes = nul
|
|
|
421
429
|
stats.totalSize += fileStats.size;
|
|
422
430
|
|
|
423
431
|
const maxFileSize = parseSize(config.maxFileSize);
|
|
424
|
-
|
|
425
|
-
stats.oversizedFiles++;
|
|
426
|
-
trackSkippedFile(normalizedPath, `File too large (${formatSize(fileStats.size)} > ${formatSize(maxFileSize)})`);
|
|
427
|
-
return null;
|
|
428
|
-
}
|
|
432
|
+
let content;
|
|
429
433
|
|
|
430
|
-
|
|
434
|
+
if (isMlModel) {
|
|
435
|
+
content = await readMlModelMetadata(fullPath);
|
|
436
|
+
} else {
|
|
437
|
+
if (fileStats.size > maxFileSize) {
|
|
438
|
+
stats.oversizedFiles++;
|
|
439
|
+
trackSkippedFile(normalizedPath, `File too large (${formatSize(fileStats.size)} > ${formatSize(maxFileSize)})`);
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
content = await readFileWithSizeCheck(fullPath, maxFileSize);
|
|
443
|
+
}
|
|
431
444
|
|
|
432
445
|
// Security scan for secrets
|
|
433
446
|
if (config.security?.scanForSecrets !== false) {
|