@xelth/eck-snapshot 5.9.0 → 6.6.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 +321 -190
- package/index.js +1 -1
- package/package.json +15 -2
- package/scripts/mcp-eck-core.js +143 -13
- package/setup.json +119 -81
- package/src/cli/cli.js +256 -385
- package/src/cli/commands/createSnapshot.js +391 -175
- package/src/cli/commands/recon.js +308 -0
- package/src/cli/commands/setupMcp.js +280 -19
- package/src/cli/commands/trainTokens.js +42 -32
- package/src/cli/commands/updateSnapshot.js +136 -43
- package/src/core/depthConfig.js +54 -0
- package/src/core/skeletonizer.js +280 -21
- package/src/templates/architect-prompt.template.md +34 -0
- package/src/templates/multiAgent.md +68 -15
- package/src/templates/opencode/coder.template.md +53 -17
- package/src/templates/opencode/junior-architect.template.md +54 -15
- package/src/templates/skeleton-instruction.md +1 -1
- package/src/templates/update-prompt.template.md +2 -0
- package/src/utils/aiHeader.js +57 -27
- package/src/utils/claudeMdGenerator.js +182 -88
- package/src/utils/fileUtils.js +217 -149
- package/src/utils/gitUtils.js +12 -8
- package/src/utils/opencodeAgentsGenerator.js +8 -2
- package/src/utils/projectDetector.js +66 -21
- package/src/utils/tokenEstimator.js +11 -7
- package/src/cli/commands/consilium.js +0 -86
- package/src/cli/commands/detectProfiles.js +0 -98
- package/src/cli/commands/envSync.js +0 -319
- package/src/cli/commands/generateProfileGuide.js +0 -144
- package/src/cli/commands/pruneSnapshot.js +0 -106
- package/src/cli/commands/restoreSnapshot.js +0 -173
- package/src/cli/commands/setupGemini.js +0 -149
- package/src/cli/commands/setupGemini.test.js +0 -115
- package/src/cli/commands/showFile.js +0 -39
- package/src/services/claudeCliService.js +0 -626
- package/src/services/claudeCliService.test.js +0 -267
package/src/core/skeletonizer.js
CHANGED
|
@@ -64,14 +64,17 @@ const languages = {
|
|
|
64
64
|
* Strips implementation details from code.
|
|
65
65
|
* @param {string} content - Full file content
|
|
66
66
|
* @param {string} filePath - File path to determine language
|
|
67
|
+
* @param {object} [options] - Options
|
|
68
|
+
* @param {boolean} [options.preserveDocs=true] - Keep JSDoc/docstrings (depth 6) or strip them (depth 5)
|
|
67
69
|
* @returns {Promise<string>} - Skeletonized code
|
|
68
70
|
*/
|
|
69
|
-
export async function skeletonize(content, filePath) {
|
|
71
|
+
export async function skeletonize(content, filePath, options = {}) {
|
|
70
72
|
if (!content) return content;
|
|
73
|
+
const preserveDocs = options.preserveDocs !== undefined ? options.preserveDocs : true;
|
|
71
74
|
|
|
72
75
|
// 1. JS/TS Strategy (Babel is better for JS ecosystem)
|
|
73
76
|
if (/\.(js|jsx|ts|tsx|mjs|cjs)$/.test(filePath)) {
|
|
74
|
-
return skeletonizeJs(content);
|
|
77
|
+
return skeletonizeJs(content, preserveDocs);
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
// 2. Tree-sitter Strategy (Python, Java, Kotlin, C, Rust, Go)
|
|
@@ -83,16 +86,17 @@ export async function skeletonize(content, filePath) {
|
|
|
83
86
|
|
|
84
87
|
// Only attempt tree-sitter if both the parser and the specific language module are ready
|
|
85
88
|
if (available && Parser && langModule) {
|
|
86
|
-
return skeletonizeTreeSitter(content, langModule, ext);
|
|
89
|
+
return skeletonizeTreeSitter(content, langModule, ext, preserveDocs);
|
|
87
90
|
}
|
|
88
|
-
|
|
91
|
+
// Fallback to regex-based skeletonizer when tree-sitter is unavailable
|
|
92
|
+
return skeletonizeRegex(content, ext, preserveDocs);
|
|
89
93
|
}
|
|
90
94
|
|
|
91
|
-
// 3. Fallback
|
|
92
|
-
return content;
|
|
95
|
+
// 3. Fallback for other languages — try regex if it uses braces
|
|
96
|
+
return skeletonizeRegex(content, filePath.substring(filePath.lastIndexOf('.')), preserveDocs);
|
|
93
97
|
}
|
|
94
98
|
|
|
95
|
-
function skeletonizeJs(content) {
|
|
99
|
+
function skeletonizeJs(content, preserveDocs = true) {
|
|
96
100
|
try {
|
|
97
101
|
const ast = parse(content, {
|
|
98
102
|
sourceType: 'module',
|
|
@@ -100,27 +104,27 @@ function skeletonizeJs(content) {
|
|
|
100
104
|
errorRecovery: true
|
|
101
105
|
});
|
|
102
106
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
//
|
|
107
|
+
const emptyBody = (path) => {
|
|
108
|
+
if (path.node.body && path.node.body.type === 'BlockStatement') {
|
|
109
|
+
if (preserveDocs) {
|
|
110
|
+
// Keep leading comments (JSDoc) before emptying body
|
|
107
111
|
const leadingComments = path.node.leadingComments || [];
|
|
108
112
|
path.node.body.body = [];
|
|
109
113
|
path.node.body.innerComments = leadingComments.length > 0
|
|
110
114
|
? leadingComments
|
|
111
115
|
: [{ type: 'CommentBlock', value: ' ... ' }];
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (path.node.body && path.node.body.type === 'BlockStatement') {
|
|
116
|
-
// Preserve leading comments (JSDoc) before emptying body
|
|
117
|
-
const leadingComments = path.node.leadingComments || [];
|
|
116
|
+
} else {
|
|
117
|
+
// Strip everything including docs
|
|
118
|
+
path.node.leadingComments = null;
|
|
118
119
|
path.node.body.body = [];
|
|
119
|
-
path.node.body.innerComments =
|
|
120
|
-
? leadingComments
|
|
121
|
-
: [{ type: 'CommentBlock', value: ' ... ' }];
|
|
120
|
+
path.node.body.innerComments = [{ type: 'CommentBlock', value: ' ... ' }];
|
|
122
121
|
}
|
|
123
122
|
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
traverse(ast, {
|
|
126
|
+
Function: emptyBody,
|
|
127
|
+
ClassMethod: emptyBody
|
|
124
128
|
});
|
|
125
129
|
|
|
126
130
|
const output = generate(ast, {}, content);
|
|
@@ -130,7 +134,7 @@ function skeletonizeJs(content) {
|
|
|
130
134
|
}
|
|
131
135
|
}
|
|
132
136
|
|
|
133
|
-
function skeletonizeTreeSitter(content, language, ext) {
|
|
137
|
+
function skeletonizeTreeSitter(content, language, ext, preserveDocs = true) {
|
|
134
138
|
try {
|
|
135
139
|
const parser = new Parser();
|
|
136
140
|
parser.setLanguage(language);
|
|
@@ -172,6 +176,19 @@ function skeletonizeTreeSitter(content, language, ext) {
|
|
|
172
176
|
}
|
|
173
177
|
|
|
174
178
|
if (bodyNode) {
|
|
179
|
+
// For Python with preserveDocs: keep docstring as first statement
|
|
180
|
+
if (preserveDocs && ext === '.py' && bodyNode.childCount > 0) {
|
|
181
|
+
const docstring = extractPythonDocstring(bodyNode);
|
|
182
|
+
if (docstring) {
|
|
183
|
+
replacements.push({
|
|
184
|
+
start: bodyNode.startIndex,
|
|
185
|
+
end: bodyNode.endIndex,
|
|
186
|
+
text: docstring + '\n ...'
|
|
187
|
+
});
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
175
192
|
replacements.push({
|
|
176
193
|
start: bodyNode.startIndex,
|
|
177
194
|
end: bodyNode.endIndex,
|
|
@@ -181,6 +198,16 @@ function skeletonizeTreeSitter(content, language, ext) {
|
|
|
181
198
|
}
|
|
182
199
|
}
|
|
183
200
|
|
|
201
|
+
// If not preserveDocs, also strip standalone comment blocks
|
|
202
|
+
if (!preserveDocs && type === 'comment') {
|
|
203
|
+
replacements.push({
|
|
204
|
+
start: node.startIndex,
|
|
205
|
+
end: node.endIndex,
|
|
206
|
+
text: ''
|
|
207
|
+
});
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
|
|
184
211
|
for (let i = 0; i < node.childCount; i++) {
|
|
185
212
|
visit(node.child(i));
|
|
186
213
|
}
|
|
@@ -194,8 +221,240 @@ function skeletonizeTreeSitter(content, language, ext) {
|
|
|
194
221
|
currentContent = currentContent.substring(0, rep.start) + rep.text + currentContent.substring(rep.end);
|
|
195
222
|
}
|
|
196
223
|
|
|
224
|
+
// Clean up excessive blank lines from stripped comments
|
|
225
|
+
if (!preserveDocs) {
|
|
226
|
+
currentContent = currentContent.replace(/\n{3,}/g, '\n\n');
|
|
227
|
+
}
|
|
228
|
+
|
|
197
229
|
return currentContent;
|
|
198
230
|
} catch (e) {
|
|
199
231
|
return content + `\n// [Skeleton error: ${e.message}]`;
|
|
200
232
|
}
|
|
201
233
|
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Regex-based fallback skeletonizer for when tree-sitter is unavailable.
|
|
237
|
+
* Works by counting braces to find and hollow out function bodies.
|
|
238
|
+
* Supports: Rust, Go, Java, C/C++, Python, and other brace-based languages.
|
|
239
|
+
*/
|
|
240
|
+
function skeletonizeRegex(content, ext, preserveDocs = true) {
|
|
241
|
+
if (ext === '.py') {
|
|
242
|
+
return skeletonizePythonRegex(content, preserveDocs);
|
|
243
|
+
}
|
|
244
|
+
// Brace-based languages (Rust, Go, Java, C, C++, etc.)
|
|
245
|
+
return skeletonizeBraceRegex(content, ext, preserveDocs);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Skeleton for brace-based languages: finds function/method signatures
|
|
250
|
+
* and replaces their bodies with { /* ... * / }
|
|
251
|
+
*/
|
|
252
|
+
function skeletonizeBraceRegex(content, ext, preserveDocs) {
|
|
253
|
+
const lines = content.split('\n');
|
|
254
|
+
const result = [];
|
|
255
|
+
let i = 0;
|
|
256
|
+
|
|
257
|
+
// Patterns that indicate a function/method definition line
|
|
258
|
+
// We look for lines ending with '{' that look like function signatures
|
|
259
|
+
const fnPatterns = {
|
|
260
|
+
'.rs': /^\s*(?:pub\s+)?(?:async\s+)?(?:unsafe\s+)?(?:fn|impl)\s+/,
|
|
261
|
+
'.go': /^\s*func\s+/,
|
|
262
|
+
'.java': /^\s*(?:public|private|protected|static|final|abstract|synchronized|native|\s)*\s+\w+\s*\([^)]*\)\s*(?:throws\s+\w+(?:\s*,\s*\w+)*)?\s*\{?\s*$/,
|
|
263
|
+
'.kt': /^\s*(?:(?:public|private|protected|internal|override|open|abstract|suspend|inline|fun)\s+)+/,
|
|
264
|
+
'.c': null, // use generic detection
|
|
265
|
+
'.h': null,
|
|
266
|
+
'.cpp': null,
|
|
267
|
+
'.hpp': null,
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
const fnPattern = fnPatterns[ext] || null;
|
|
271
|
+
|
|
272
|
+
while (i < lines.length) {
|
|
273
|
+
const line = lines[i];
|
|
274
|
+
const trimmed = line.trimStart();
|
|
275
|
+
|
|
276
|
+
// Skip doc comments if !preserveDocs
|
|
277
|
+
if (!preserveDocs) {
|
|
278
|
+
// Block doc comments: /** ... */ or /// lines
|
|
279
|
+
if (trimmed.startsWith('///') || trimmed.startsWith('//!')) {
|
|
280
|
+
i++;
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
if (trimmed.startsWith('/**') || trimmed.startsWith('/*!')) {
|
|
284
|
+
while (i < lines.length && !lines[i].includes('*/')) {
|
|
285
|
+
i++;
|
|
286
|
+
}
|
|
287
|
+
i++; // skip the closing */
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Check if this line starts a function definition
|
|
293
|
+
let isFnLine = false;
|
|
294
|
+
if (fnPattern) {
|
|
295
|
+
isFnLine = fnPattern.test(line);
|
|
296
|
+
} else {
|
|
297
|
+
// Generic C/C++ heuristic: line has parens and ends with or is followed by {
|
|
298
|
+
isFnLine = /\w+\s*\([^;]*\)\s*\{?\s*$/.test(trimmed) && !trimmed.startsWith('if') &&
|
|
299
|
+
!trimmed.startsWith('while') && !trimmed.startsWith('for') &&
|
|
300
|
+
!trimmed.startsWith('switch') && !trimmed.startsWith('#');
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// For Rust: also handle impl blocks — keep them but skeleton their methods
|
|
304
|
+
if (isFnLine) {
|
|
305
|
+
// Find the opening brace (may be on same line or next line)
|
|
306
|
+
let sigLines = [line];
|
|
307
|
+
let j = i + 1;
|
|
308
|
+
|
|
309
|
+
// If no opening brace on this line, scan ahead for it
|
|
310
|
+
if (!line.includes('{')) {
|
|
311
|
+
while (j < lines.length) {
|
|
312
|
+
sigLines.push(lines[j]);
|
|
313
|
+
if (lines[j].includes('{')) {
|
|
314
|
+
j++;
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
j++;
|
|
318
|
+
}
|
|
319
|
+
} else {
|
|
320
|
+
// Opening brace is on the signature line
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Now count braces to find the end of the body
|
|
324
|
+
let braceCount = 0;
|
|
325
|
+
let bodyStart = i;
|
|
326
|
+
let bodyEnd = i;
|
|
327
|
+
let foundOpen = false;
|
|
328
|
+
|
|
329
|
+
for (let k = i; k < (foundOpen ? lines.length : j); k++) {
|
|
330
|
+
for (const ch of lines[k]) {
|
|
331
|
+
if (ch === '{') { braceCount++; foundOpen = true; }
|
|
332
|
+
if (ch === '}') braceCount--;
|
|
333
|
+
}
|
|
334
|
+
bodyEnd = k;
|
|
335
|
+
if (foundOpen && braceCount === 0) break;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// If we didn't finish counting, continue from j
|
|
339
|
+
if (foundOpen && braceCount > 0) {
|
|
340
|
+
for (let k = j; k < lines.length; k++) {
|
|
341
|
+
for (const ch of lines[k]) {
|
|
342
|
+
if (ch === '{') braceCount++;
|
|
343
|
+
if (ch === '}') braceCount--;
|
|
344
|
+
}
|
|
345
|
+
bodyEnd = k;
|
|
346
|
+
if (braceCount === 0) break;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (foundOpen && braceCount === 0) {
|
|
351
|
+
// Emit signature (up to opening brace) + skeleton
|
|
352
|
+
const sigText = sigLines.join('\n');
|
|
353
|
+
const braceIdx = sigText.indexOf('{');
|
|
354
|
+
const signature = sigText.substring(0, braceIdx).trimEnd();
|
|
355
|
+
const indent = line.match(/^(\s*)/)[1];
|
|
356
|
+
result.push(signature + ' { /* ... */ }');
|
|
357
|
+
i = bodyEnd + 1;
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
result.push(line);
|
|
363
|
+
i++;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return result.join('\n');
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Skeleton for Python: finds function/class defs and replaces bodies with ...
|
|
371
|
+
*/
|
|
372
|
+
function skeletonizePythonRegex(content, preserveDocs) {
|
|
373
|
+
const lines = content.split('\n');
|
|
374
|
+
const result = [];
|
|
375
|
+
let i = 0;
|
|
376
|
+
|
|
377
|
+
while (i < lines.length) {
|
|
378
|
+
const line = lines[i];
|
|
379
|
+
const trimmed = line.trimStart();
|
|
380
|
+
const indent = line.length - trimmed.length;
|
|
381
|
+
|
|
382
|
+
if (/^(async\s+)?def\s+/.test(trimmed) || /^class\s+/.test(trimmed)) {
|
|
383
|
+
result.push(line);
|
|
384
|
+
i++;
|
|
385
|
+
|
|
386
|
+
// Determine body indent (should be > current indent)
|
|
387
|
+
const bodyIndent = indent + 4; // standard Python indent
|
|
388
|
+
|
|
389
|
+
// Check for docstring
|
|
390
|
+
if (i < lines.length) {
|
|
391
|
+
const nextTrimmed = lines[i].trimStart();
|
|
392
|
+
if (preserveDocs && (nextTrimmed.startsWith('"""') || nextTrimmed.startsWith("'''"))) {
|
|
393
|
+
const quote = nextTrimmed.substring(0, 3);
|
|
394
|
+
// Emit docstring lines
|
|
395
|
+
if (nextTrimmed.indexOf(quote, 3) > 0) {
|
|
396
|
+
// Single-line docstring
|
|
397
|
+
result.push(lines[i]);
|
|
398
|
+
i++;
|
|
399
|
+
} else {
|
|
400
|
+
// Multi-line docstring
|
|
401
|
+
result.push(lines[i]);
|
|
402
|
+
i++;
|
|
403
|
+
while (i < lines.length && !lines[i].trimStart().includes(quote)) {
|
|
404
|
+
result.push(lines[i]);
|
|
405
|
+
i++;
|
|
406
|
+
}
|
|
407
|
+
if (i < lines.length) {
|
|
408
|
+
result.push(lines[i]); // closing quote line
|
|
409
|
+
i++;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Add ... and skip body
|
|
416
|
+
result.push(' '.repeat(bodyIndent) + '...');
|
|
417
|
+
|
|
418
|
+
// Skip remaining body lines (lines with indent > current def indent)
|
|
419
|
+
while (i < lines.length) {
|
|
420
|
+
const bodyLine = lines[i];
|
|
421
|
+
const bodyTrimmed = bodyLine.trimStart();
|
|
422
|
+
const bodyLineIndent = bodyLine.length - bodyTrimmed.length;
|
|
423
|
+
// Empty lines or lines indented more than the def are part of body
|
|
424
|
+
if (bodyTrimmed === '' || bodyLineIndent > indent) {
|
|
425
|
+
i++;
|
|
426
|
+
} else {
|
|
427
|
+
break;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
result.push(line);
|
|
434
|
+
i++;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return result.join('\n');
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* Extract Python docstring from the first statement of a function body block.
|
|
442
|
+
*/
|
|
443
|
+
function extractPythonDocstring(bodyNode) {
|
|
444
|
+
for (let i = 0; i < bodyNode.childCount; i++) {
|
|
445
|
+
const child = bodyNode.child(i);
|
|
446
|
+
// Python docstrings are expression_statement containing a string
|
|
447
|
+
if (child.type === 'expression_statement') {
|
|
448
|
+
const expr = child.child(0);
|
|
449
|
+
if (expr && expr.type === 'string') {
|
|
450
|
+
// Return the indented docstring text
|
|
451
|
+
return '\n ' + expr.text;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
// Skip newline/indent tokens, but stop at first real statement
|
|
455
|
+
if (child.type !== 'newline' && child.type !== 'indent' && child.type !== 'NEWLINE' && child.type !== 'INDENT') {
|
|
456
|
+
if (child.type !== 'expression_statement') break;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return null;
|
|
460
|
+
}
|
|
@@ -19,6 +19,7 @@ You MUST wrap your ENTIRE response (Analysis + Changes + Metadata) in a single `
|
|
|
19
19
|
### Command Format (Wrapped)
|
|
20
20
|
|
|
21
21
|
````text
|
|
22
|
+
<eck_task id="{{repoName}}:short-task-description">
|
|
22
23
|
# Analysis
|
|
23
24
|
|
|
24
25
|
[Explain your reasoning: what you're doing and why.
|
|
@@ -48,6 +49,7 @@ async function example() {
|
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
```
|
|
52
|
+
</eck_task id="{{repoName}}:short-task-description">
|
|
51
53
|
````
|
|
52
54
|
|
|
53
55
|
### File Actions Reference
|
|
@@ -62,6 +64,7 @@ async function example() {
|
|
|
62
64
|
### Complete Example
|
|
63
65
|
|
|
64
66
|
````text
|
|
67
|
+
<eck_task id="{{repoName}}:add-user-validation">
|
|
65
68
|
# Analysis
|
|
66
69
|
|
|
67
70
|
The authentication module needs a null check to prevent crashes when
|
|
@@ -111,6 +114,7 @@ export function validateUser(user) {
|
|
|
111
114
|
}
|
|
112
115
|
}
|
|
113
116
|
```
|
|
117
|
+
</eck_task id="{{repoName}}:add-user-validation">
|
|
114
118
|
````
|
|
115
119
|
|
|
116
120
|
### Why Eck-Protocol v2?
|
|
@@ -133,6 +137,36 @@ To understand the project state, you can command the `eck-snapshot` tool directl
|
|
|
133
137
|
- `eck-snapshot query "<question>"`: Search the codebase
|
|
134
138
|
- `eck-snapshot detect`: Analyze the project structure
|
|
135
139
|
- `eck-snapshot restore <snapshot_file> --include ...`: View specific files
|
|
140
|
+
- `eck-snapshot link <depth>`: Run inside a related repository to generate a read-only companion snapshot.
|
|
141
|
+
|
|
142
|
+
## SCOUT & FETCH: Cross-Repository Intelligence
|
|
143
|
+
|
|
144
|
+
When working with multiple repositories, use `scout` and `fetch` to gather context:
|
|
145
|
+
|
|
146
|
+
**CRITICAL:** Both `scout` and `fetch` operate on the **current working directory only**. They scan files relative to `cwd` — absolute paths will NOT work.
|
|
147
|
+
|
|
148
|
+
**Single-repo fetch:**
|
|
149
|
+
```bash
|
|
150
|
+
cd /path/to/project-a
|
|
151
|
+
eck-snapshot fetch "**/SyncManager.kt" "**/RelayClient.kt"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**Multi-repo fetch (MUST be separate commands):**
|
|
155
|
+
```bash
|
|
156
|
+
# Fetch from first project
|
|
157
|
+
cd /path/to/project-a
|
|
158
|
+
eck-snapshot fetch "**/SyncManager.kt"
|
|
159
|
+
|
|
160
|
+
# Fetch from second project
|
|
161
|
+
cd /path/to/project-b
|
|
162
|
+
eck-snapshot fetch "**/AppDatabase.kt"
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Rules:**
|
|
166
|
+
- Always use **relative glob patterns**, never absolute paths
|
|
167
|
+
- Always specify which directory to `cd` into before each command
|
|
168
|
+
- Use `**/<filename>` to find files regardless of nesting depth
|
|
169
|
+
- One `fetch` command = one repo. For multiple repos, issue multiple commands.
|
|
136
170
|
|
|
137
171
|
## CAPABILITIES & DELEGATION PROTOCOL
|
|
138
172
|
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
# AI
|
|
1
|
+
# SYSTEM DIRECTIVE FOR THE ACTIVE AI AGENT
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**CRITICAL:** If you are the AI (LLM) reading this file in the current chat session, you must IMMEDIATELY assume the role defined below. Do not act as an external reviewer or generic assistant. This document is your active operating environment and contract.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## 1. Your Role & Identity
|
|
6
|
+
|
|
7
|
+
You are the **Senior Project Manager and Solution Architect AI**. Your primary goal is to translate user requests into technical plans and then generate precise commands for code-execution AI agents.
|
|
8
|
+
|
|
9
|
+
## 2. How to Read This Snapshot
|
|
10
|
+
|
|
11
|
+
This document is a self-contained, single-file snapshot of the **{{repoName}}** software repository, generated by the `eck-snapshot` tool on **{{timestamp}}**. Treat the file structure and code below as your absolute source of truth for the project state.
|
|
6
12
|
|
|
7
13
|
* **Source of Truth:** Treat this snapshot as the complete and authoritative source code.
|
|
8
14
|
* **Structure:** The file contains a **Directory Structure** tree, followed by the full content of each file, demarcated by `--- File: /path/to/file ---` headers.
|
|
@@ -13,15 +19,13 @@ This document is a self-contained, single-file snapshot of the **{{repoName}}**
|
|
|
13
19
|
|
|
14
20
|
---
|
|
15
21
|
|
|
16
|
-
##
|
|
17
|
-
|
|
18
|
-
You are the Project Manager and Solution Architect AI. Your primary goal is to translate user requests into technical plans and then generate precise commands for code-execution AI agents.
|
|
22
|
+
## 3. Your Core Operational Workflow
|
|
19
23
|
|
|
20
24
|
{{projectOverview}}
|
|
21
25
|
|
|
22
26
|
{{eckManifestSection}}
|
|
23
27
|
|
|
24
|
-
###
|
|
28
|
+
### MANIFEST MAINTENANCE PROTOCOL (CRITICAL)
|
|
25
29
|
|
|
26
30
|
The `.eck/` directory files are your "Source of Knowledge".
|
|
27
31
|
1. **Stub Detection:** If a file starts with `# [STUB: ...]`, it means the system failed to auto-generate meaningful content.
|
|
@@ -30,6 +34,54 @@ The `.eck/` directory files are your "Source of Knowledge".
|
|
|
30
34
|
|
|
31
35
|
**Documentation is part of the "Definition of Done". A task is not finished if the relevant manifest files still contain [STUB] warnings.**
|
|
32
36
|
|
|
37
|
+
### 🛑 CROSS-PROJECT CONTAMINATION CHECK (CRITICAL)
|
|
38
|
+
|
|
39
|
+
Before analyzing any new snapshot or incremental update, you MUST perform a sanity check against your current working context.
|
|
40
|
+
Compare the `Project:` name and directory structure in the incoming file against the known architecture of the current task.
|
|
41
|
+
IF you detect files from a completely different repository or domain, **IMMEDIATELY STOP**.
|
|
42
|
+
Alert the user: *"Warning: The snapshot you uploaded belongs to a different project. Our current context is [Current Project]. Did you upload the wrong file?"*
|
|
43
|
+
Do NOT merge the files into your mental model until the user confirms.
|
|
44
|
+
|
|
45
|
+
### 🧹 CONTEXT HYGIENE PROTOCOL (CRITICAL)
|
|
46
|
+
|
|
47
|
+
You are responsible for keeping your own context window clean and efficient.
|
|
48
|
+
**Mandatory Full Snapshot Evaluation:** Whenever you receive a FULL snapshot, you MUST evaluate the `Directory Structure` and file list for irrelevant bloat (e.g., compiled binaries, DB dumps like .wal, huge logs, decompiled code).
|
|
49
|
+
|
|
50
|
+
If bloat is detected:
|
|
51
|
+
1. **Report to User:** Briefly tell the user how much garbage was found.
|
|
52
|
+
- *Massive Bloat:* Suggest pausing the main task. Generate an `eck_task` ONLY to create/update `.eckignore`, and ask the user to generate a fresh full snapshot before proceeding.
|
|
53
|
+
- *Minor Bloat:* Append the `.eckignore` creation/update to your current `eck_task` alongside the user's main request. Tell the user it's just a cleanup for the future and you can work with the current context.
|
|
54
|
+
2. **Execution:** Instruct the Coder to use standard `.gitignore` syntax in `.eckignore` (e.g., `data/surreal_data/`, `*.wal`).
|
|
55
|
+
|
|
56
|
+
**🚨 MANUAL OVERRIDE (THE CODE WORD):**
|
|
57
|
+
If the human user includes the phrase **`[EXECUTE HYGIENE]`** or **`[CLEAN CONTEXT]`**, immediately suspend all feature development and dedicate your response exclusively to cleaning the context via `.eckignore`.
|
|
58
|
+
|
|
59
|
+
### 📝 PROACTIVE TECH DEBT & TODO PROTOCOL
|
|
60
|
+
|
|
61
|
+
As a Senior Architect, you must actively manage code quality. When analyzing files in this snapshot, do not ignore developer comments:
|
|
62
|
+
1. **Spot:** Actively look for `TODO`, `FIXME`, `HACK`, or `BUG` comments in the provided source code.
|
|
63
|
+
2. **Evaluate:** Compare the comment against the actual implementation. Developers often fix things but forget to remove the comment.
|
|
64
|
+
3. **Resolve (The 3 Actions):**
|
|
65
|
+
- **Obsolete:** If the code already does what the TODO asks, instruct the Coder to **delete the comment**.
|
|
66
|
+
- **Quick Fix:** If it's a small missing piece or an obvious bug, instruct the Coder to **implement the fix and remove the comment**.
|
|
67
|
+
- **Real Debt:** If it requires significant architectural work, instruct the Coder to **document it in `.eck/TECH_DEBT.md`** so it is officially tracked, and leave the comment in the code for now.
|
|
68
|
+
|
|
69
|
+
### 🏕️ THE BOY SCOUT RULE (Docstrings & Comments)
|
|
70
|
+
|
|
71
|
+
Leave the codebase better than you found it.
|
|
72
|
+
Whenever you instruct the Coder to **modify an existing function/class** or **create a new one**, you MUST explicitly add this requirement to their task:
|
|
73
|
+
> *"Ensure the JSDoc / Docstring for this function is created or updated to accurately reflect its new behavior, parameters, and return types. Explain WHY it exists, not just WHAT it does."*
|
|
74
|
+
Do not rewrite documentation for the entire file—only strictly for the components you are touching.
|
|
75
|
+
|
|
76
|
+
### 🛡️ RELIABILITY & ZERO-BROKEN-WINDOWS PROTOCOL
|
|
77
|
+
|
|
78
|
+
You are the final gatekeeper of quality. A task is NEVER complete if the code doesn't compile or tests fail.
|
|
79
|
+
Whenever you delegate a task to the Coder, you MUST enforce the following verification steps:
|
|
80
|
+
1. **Identify the Test Suite:** Check the environment (e.g., `npm test`, `cargo test`, `pytest`).
|
|
81
|
+
2. **Mandate Verification:** Explicitly instruct the Coder:
|
|
82
|
+
> *"Before calling `eck_finish_task`, you MUST run the project's test suite and ensure all tests pass. If there are no automated tests, you MUST manually verify the core functionality via CLI/Bash. Do NOT finish the task if there are compilation errors or test failures."*
|
|
83
|
+
3. **No Blind Commits:** Never allow the Coder to commit code blindly. Verification is mandatory.
|
|
84
|
+
|
|
33
85
|
### CRITICAL WORKFLOW: Structured Commits via `journal_entry`
|
|
34
86
|
|
|
35
87
|
To ensure proper project history, all code changes **MUST** be committed using the project's built-in structured workflow.
|
|
@@ -82,11 +134,8 @@ When generating commands for the Coder agent (Claude Code), you MUST include thi
|
|
|
82
134
|
|
|
83
135
|
The Coder agent is intelligent and will understand what information they need based on file names.
|
|
84
136
|
|
|
85
|
-
**Maintain Documentation:** When assigning tasks, instruct the Coder to update relevant `.eck/` documentation files
|
|
86
|
-
|
|
87
|
-
- Operational procedures (update `OPERATIONS.md`)
|
|
88
|
-
- Technical debt status (update `TECH_DEBT.md`)
|
|
89
|
-
- Project roadmap progress (update `ROADMAP.md`)
|
|
137
|
+
**Maintain Documentation (TOKEN OPTIMIZATION):** When assigning tasks, instruct the Coder to update relevant `.eck/` documentation files.
|
|
138
|
+
**CRITICAL:** Tell the Coder NOT to read `JOURNAL.md` (it auto-updates) and instruct them to use the `eck_manifest_edit` tool to blindly append/edit `ROADMAP.md` and `TECH_DEBT.md` to save thousands of context tokens.
|
|
90
139
|
|
|
91
140
|
### CORE WORKFLOW: The Interactive Command Cycle
|
|
92
141
|
|
|
@@ -100,7 +149,12 @@ The Coder agent is intelligent and will understand what information they need ba
|
|
|
100
149
|
6. **Review & Report:** After the command is executed, analyze the results and report back to the user in their language.
|
|
101
150
|
7. **Iterate:** Continue the cycle based on user feedback.
|
|
102
151
|
|
|
103
|
-
###
|
|
152
|
+
### CROSS-CONTEXT DEVELOPMENT (LINKED PROJECTS)
|
|
153
|
+
|
|
154
|
+
If this project interacts with an external backend, frontend, or microservice, you can request its context.
|
|
155
|
+
**Ask the user to run:** `eck-snapshot link [depth 0-9]` inside the related repository and upload the resulting `link_*.md` file. You will receive precise read-only access and fetch commands inside that file.
|
|
156
|
+
|
|
157
|
+
### ANTI-TRUNCATION PROTOCOL (CRITICAL)
|
|
104
158
|
|
|
105
159
|
Web interfaces (like Gemini or ChatGPT) sometimes silently drop the content of large text files during upload, replacing the file's content with a tiny JSON metadata string (e.g., `{"fileName": "...", "contentFetchId": "..."}`).
|
|
106
160
|
|
|
@@ -108,7 +162,7 @@ Web interfaces (like Gemini or ChatGPT) sometimes silently drop the content of l
|
|
|
108
162
|
1. **Always check the filename:** The exact file size in kilobytes is appended to the end of every snapshot filename (e.g., `..._up7_1250kb.md`).
|
|
109
163
|
2. **Verify payload length:** If the filename says `1250kb` but the text you actually received for that file is only a few lines long or looks like a system JSON string, **THE CONTENT WAS TRUNCATED BY THE UI**.
|
|
110
164
|
3. **Alert the User:** DO NOT hallucinate the missing code. Immediately stop and tell the user:
|
|
111
|
-
> "
|
|
165
|
+
> "**System Error:** The web interface truncated the file `[FileName]`. I only received the metadata/JSON stub, not the actual `[Size]kb` of code. Please split the snapshot or paste the text directly."
|
|
112
166
|
|
|
113
167
|
{{hierarchicalWorkflow}}
|
|
114
168
|
|
|
@@ -125,4 +179,3 @@ Web interfaces (like Gemini or ChatGPT) sometimes silently drop the content of l
|
|
|
125
179
|
You can command multiple specialized agents. **YOU must choose the most appropriate agent** based on the task requirements and target environment:
|
|
126
180
|
|
|
127
181
|
{{agentDefinitions}}
|
|
128
|
-
|
|
@@ -3,27 +3,63 @@
|
|
|
3
3
|
## CORE DIRECTIVE
|
|
4
4
|
You are an Expert Developer. The architecture is already decided. Your job is to **execute**, **fix**, and **polish**.
|
|
5
5
|
|
|
6
|
-
##
|
|
7
|
-
|
|
8
|
-
1. **
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
## HUMAN VS. ARCHITECT (CRITICAL)
|
|
7
|
+
You receive instructions from two sources:
|
|
8
|
+
1. **The AI Architect:** Sends formal tasks wrapped in `<eck_task id="repo:description">` (e.g., `<eck_task id="ecksnapshot:fix-auth-crash">`) tags.
|
|
9
|
+
2. **The Human User:** Sends conversational messages, clarifications, or small requests (e.g., "make this red", "fix that typo").
|
|
10
|
+
|
|
11
|
+
## DEFINITION OF DONE & eck_finish_task
|
|
12
|
+
Your behavior changes based on who you are talking to:
|
|
13
|
+
- **For AI Architect Tasks (`<eck_task>`):** When the task is complete and fully tested, call `eck_finish_task` IMMEDIATELY. Do NOT ask the user for permission. Include the task `id` in your status report.
|
|
14
|
+
- **For Human Requests:** Do NOT call `eck_finish_task`. Just reply to the user naturally and apply the changes. ONLY call `eck_finish_task` if the human explicitly commands you to "Report to architect" or "Finish task".
|
|
15
|
+
|
|
16
|
+
Pass your detailed markdown report into the `status` argument.
|
|
17
|
+
- The tool will automatically write the report, commit, and generate a snapshot.
|
|
18
|
+
- **DO NOT** manually write to `AnswerToSA.md` with your file editing tools.
|
|
19
|
+
- **WARNING: USE ONLY ONCE.** Do not use for intermediate testing.
|
|
20
|
+
|
|
21
|
+
**FALLBACK METHOD (Only if MCP tool is missing):**
|
|
22
|
+
If `eck_finish_task` is NOT in your available tools, you MUST do the following:
|
|
23
|
+
0. **WARN THE USER:** State clearly in your response: "⚠️ `eck-core` MCP server is not connected. Proceeding with manual fallback."
|
|
24
|
+
1. **READ:** Read `.eck/lastsnapshot/AnswerToSA.md` using your `Read` tool (REQUIRED before overwriting).
|
|
25
|
+
2. **WRITE:** Overwrite that file with your report.
|
|
26
|
+
3. **COMMIT (CRITICAL):** Run `git add .` and `git commit -m "chore: task report"` in the terminal.
|
|
27
|
+
4. **SNAPSHOT:** Run `eck-snapshot '{"name": "eck_update"}'` in the terminal.
|
|
28
|
+
*(Note: The snapshot compares against the git anchor. If you skip step 3, it will say "No changes detected").*
|
|
29
|
+
|
|
30
|
+
## PROJECT CONTEXT (.eck DIRECTORY) & TOKEN OPTIMIZATION
|
|
31
|
+
The `.eck/` directory contains critical project documentation.
|
|
32
|
+
1. **List** the files in `.eck/` to see what exists.
|
|
33
|
+
2. **Read** files ONLY if you absolutely need architectural context. Do NOT read large files blindly.
|
|
34
|
+
3. **DO NOT READ `JOURNAL.md`**. It is extremely large and auto-updates when you use `eck_finish_task`.
|
|
35
|
+
4. **BLIND EDITS:** If you need to check off a TODO in `TECH_DEBT.md` or add an item to `ROADMAP.md`, use the **`eck_manifest_edit`** tool to modify them atomically without reading the whole file into context.
|
|
19
36
|
|
|
20
37
|
## CONTEXT
|
|
21
38
|
- The GLM ZAI swarm might have struggled or produced code that needs refinement.
|
|
22
39
|
- You are here to solve the hard problems manually.
|
|
23
40
|
- You have full permission to edit files directly.
|
|
24
41
|
|
|
42
|
+
## 🚨 MAGIC WORD: [SYNC MANIFESTS] / [SYNC]
|
|
43
|
+
If the human user types **`[SYNC MANIFESTS]`** or **`[SYNC]`** (or explicitly requests a manifest sync), immediately suspend feature development and switch to Project Manager mode:
|
|
44
|
+
1. Find all `.eck/*.md` files with `[STUB]` markers. Analyze the codebase to resolve them.
|
|
45
|
+
2. Review `ROADMAP.md` and `TECH_DEBT.md`. Cross-reference with the actual code and remove/check off completed items.
|
|
46
|
+
3. Update `CONTEXT.md` and `ARCHITECTURE.md` if the system has evolved.
|
|
47
|
+
4. Use the **`eck_manifest_edit`** tool to apply these updates atomically. Do not read `JOURNAL.md`.
|
|
48
|
+
5. Call `eck_finish_task` when the audit is complete.
|
|
49
|
+
|
|
50
|
+
## 🧠 KNOWLEDGE DISTILLATION (POST-FINISH)
|
|
51
|
+
**ONLY** after tasks that changed the project's architecture, added major features, or revealed non-obvious system behavior (e.g., multi-file refactors, new subsystems, tricky debugging that uncovered hidden dependencies).
|
|
52
|
+
Do NOT offer this for routine fixes, config tweaks, or small edits.
|
|
53
|
+
**Call `eck_finish_task` first** — never delay the finish. Then, in the same response, offer:
|
|
54
|
+
> "I learned some things about the architecture during this task. Want me to update the `.eck/` manifests before I lose this context?"
|
|
55
|
+
> **[DEBUG] Context info available to me:** [state whether you can see any context window usage %, token counts, or compaction warnings — or "none, no context metrics visible"]
|
|
56
|
+
Include this offer in your `eck_finish_task` status so the Architect sees it too.
|
|
57
|
+
If the user says yes — just edit the files and commit. Do NOT call `eck_finish_task` again for it.
|
|
58
|
+
|
|
25
59
|
## WORKFLOW
|
|
26
|
-
1.
|
|
27
|
-
2.
|
|
28
|
-
3.
|
|
29
|
-
4.
|
|
60
|
+
1. Check the `.eck/RUNTIME_STATE.md` and verify actual running processes.
|
|
61
|
+
2. Read the code. If the Architect's hypothesis is wrong, discard it and find the real bug.
|
|
62
|
+
3. Fix the bugs / Implement the feature.
|
|
63
|
+
4. Verify functionality manually via browser/curl/logs/DB checks.
|
|
64
|
+
5. **Loop:** If verification fails, fix it immediately. Do not ask for permission.
|
|
65
|
+
6. **Blocked?** Use the `eck_fail_task` tool to abort safely without committing broken code.
|