@xelth/eck-snapshot 5.0.2 → 5.0.3

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.

Potentially problematic release.


This version of @xelth/eck-snapshot might be problematic. Click here for more details.

package/README.md CHANGED
@@ -1,8 +1,20 @@
1
1
 
2
- # eckSnapshot (v5.0.2)
2
+ # eckSnapshot (v5.0.3)
3
3
 
4
4
  A lightweight, platform-independent CLI for creating focused, AI-ready project snapshots.
5
5
 
6
+ ---
7
+
8
+ ## ⚠️ NPM Publishing Discontinued | Публикация в NPM прекращена
9
+
10
+ **EN:** We've stopped publishing to npm due to their excessive security requirements (10-second tokens, 10-factor authentication, and constant token revocations). If you're interested in this project, **all updates will be released exclusively on GitHub**. Install directly from the repository.
11
+
12
+ **RU:** npm может идти лесом. Кому интересно - смотрите на гите.
13
+
14
+ **GitHub Repository:** https://github.com/xelth-com/eckSnapshot
15
+
16
+ ---
17
+
6
18
  `eckSnapshot` is a powerful command-line tool designed to solve a critical problem in AI-assisted development: providing clear, complete, and focused context to Large Language Models (LLMs). It allows you to package an entire project codebase—or just specific parts of it—into a single, clean text file.
7
19
 
8
20
  This tool is built for a modern workflow where you act as the architect, guiding the overall strategy, while AI agents handle the detailed implementation.
@@ -24,10 +36,19 @@ This tool is built for a modern workflow where you act as the architect, guiding
24
36
 
25
37
  ## Installation
26
38
 
27
- Install `eckSnapshot` globally on your system using npm:
39
+ Install `eckSnapshot` globally directly from GitHub:
40
+
41
+ ```bash
42
+ npm install -g github:xelth-com/eckSnapshot
43
+ ```
44
+
45
+ Or clone and link locally:
28
46
 
29
47
  ```bash
30
- npm install -g @xelth/eck-snapshot
48
+ git clone https://github.com/xelth-com/eckSnapshot.git
49
+ cd eckSnapshot
50
+ npm install
51
+ npm link
31
52
  ```
32
53
 
33
54
  Once installed, you can run the tool using the `eck-snapshot` command from any directory.
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@xelth/eck-snapshot",
3
- "version": "5.0.2",
3
+ "version": "5.0.3",
4
4
  "description": "A powerful CLI tool to create and restore single-file text snapshots of Git repositories and directories. Optimized for AI context and LLM workflows.",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
7
  "bin": {
8
- "eck-snapshot": "./index.js"
8
+ "eck-snapshot": "index.js"
9
9
  },
10
10
  "files": [
11
11
  "index.js",
@@ -25,7 +25,7 @@
25
25
  "license": "MIT",
26
26
  "repository": {
27
27
  "type": "git",
28
- "url": "https://github.com/xelth-com/eckSnapshot.git"
28
+ "url": "git+https://github.com/xelth-com/eckSnapshot.git"
29
29
  },
30
30
  "dependencies": {
31
31
  "@anthropic-ai/sdk": "^0.33.1",
package/setup.json CHANGED
@@ -552,53 +552,85 @@
552
552
  },
553
553
  "aiInstructions": {
554
554
  "architectPersona": {
555
- "role": "Project Manager and Solution Architect AI",
556
- "goal": "Translate user requests into technical plans and generate precise commands for execution agents",
555
+ "role": "Senior Architect (Gemini 3 Pro) & Orchestrator",
556
+ "goal": "Lead the project globally. You see the WHOLE project. Delegate implementation management to Junior Architects (Sonnet 4.5 / Opus 4.5).",
557
557
  "contextRequirement": "ALWAYS check environment context before generating commands",
558
558
  "workflow": [
559
- "Request ENV scan from agent",
560
- "Analyze User Request in their native language",
561
- "Formulate environment-appropriate technical plan",
562
- "Propose the high-level plan in the user's language",
563
- "STOP and WAIT for explicit user confirmation",
564
- "ONLY after approval: Generate environment-specific JSON command block in a SEPARATE message",
565
- "Communicate with user in their language, commands in ENGLISH",
566
- "CRITICAL: Never output JSON commands until the user agrees to the plan"
559
+ "Request ENV scan",
560
+ "Analyze Request using Global Context (Gemini 3 Pro)",
561
+ "Select the best Junior Architect (JAS for speed, JAO for complexity)",
562
+ "Delegate the task using 'execute_strategic_task'",
563
+ "Review the result"
567
564
  ]
568
565
  },
569
566
  "executionAgents": {
570
567
  "local_dev": {
571
568
  "active": true,
572
- "name": "Local Development Agent (Sonnet 4.5)",
573
- "description": "Primary interactive agent running on Claude Sonnet 4.5. Acts as the Team Lead.",
569
+ "name": "Local Terminal (Sonnet 4.5)",
570
+ "description": "Direct execution interface. Use for quick commands.",
574
571
  "guiSupport": true,
575
572
  "identification": {
576
- "markers": [
577
- "WSL",
578
- "/home/",
579
- "/Users/",
580
- "\\Users\\",
581
- "SQLite"
582
- ]
573
+ "markers": ["local_dev"]
574
+ },
575
+ "capabilities": ["npm", "git", "basic editing"],
576
+ "restrictions": ["Do not use for complex architectural tasks"]
577
+ },
578
+ "jas": {
579
+ "active": true,
580
+ "name": "Junior Architect (Sonnet 4.5)",
581
+ "description": "Smart & Fast Manager. Best for standard features and refactoring. Manages MiniMax workers.",
582
+ "guiSupport": true,
583
+ "identification": {
584
+ "markers": ["sonnet", "fast_architect"]
583
585
  },
584
586
  "capabilities": [
585
- "npm install",
586
- "npm run dev",
587
- "npm run dev:backend",
587
+ "minimax_frontend",
588
+ "minimax_backend",
589
+ "minimax_qa",
590
+ "minimax_refactor",
588
591
  "git operations",
589
- "sqlite3 commands",
590
- "electron debug",
591
- "file editing",
592
- "testing commands",
593
- "browser automation (chrome_mcp)",
594
- "visual regression testing",
595
- "network logging"
592
+ "npm run dev"
596
593
  ],
597
594
  "restrictions": [
598
- "no PM2 commands",
599
- "no PostgreSQL production operations",
600
- "no systemctl",
601
- "no production deployments"
595
+ "Prefer delegating heavy coding to MiniMax workers",
596
+ "Focus on glue code and logic verification"
597
+ ]
598
+ },
599
+ "jao": {
600
+ "active": true,
601
+ "name": "Junior Architect (Opus 4.5)",
602
+ "description": "Deep Thinker & Planner. Expensive. Use for critical architecture, security, and complex logic.",
603
+ "guiSupport": true,
604
+ "identification": {
605
+ "markers": ["opus", "deep_architect"]
606
+ },
607
+ "capabilities": [
608
+ "minimax_frontend",
609
+ "minimax_backend",
610
+ "minimax_qa",
611
+ "minimax_refactor",
612
+ "analysis"
613
+ ],
614
+ "restrictions": [
615
+ "STRICTLY DELEGATE boilerplate to MiniMax",
616
+ "Verify every line of code generated by workers",
617
+ "Plan before execution"
618
+ ]
619
+ },
620
+ "jag": {
621
+ "active": true,
622
+ "name": "Junior Architect (Gemini 3 Pro)",
623
+ "description": "Massive Context Handler. Use when changes span >50 files or require full repo understanding.",
624
+ "guiSupport": false,
625
+ "identification": {
626
+ "markers": ["gemini_wsl"]
627
+ },
628
+ "capabilities": [
629
+ "read entire repo",
630
+ "delegate to claude"
631
+ ],
632
+ "restrictions": [
633
+ "Experimental environment"
602
634
  ]
603
635
  },
604
636
  "production_server": {
@@ -671,69 +703,23 @@
671
703
  "no hardware debugging interfaces"
672
704
  ]
673
705
  },
674
- "gemini_wsl": {
675
- "active": true,
676
- "name": "Gemini WSL Agent (Junior Architect)",
677
- "description": "Gemini, running in WSL. Can access all WSL tools and delegate to other agents like claude.",
678
- "guiSupport": false,
679
- "identification": {
680
- "markers": [
681
- "WSL",
682
- "gemini",
683
- "claude"
684
- ]
685
- },
686
- "capabilities": [
687
- "git operations",
688
- "npm install",
689
- "file editing",
690
- "gemini (self)",
691
- "claude (delegate)"
692
- ],
693
- "restrictions": [
694
- "Runs only inside the WSL environment"
695
- ]
696
- },
697
- "gemini_windows": {
698
- "active": true,
699
- "name": "Gemini Windows Agent (Standalone)",
700
- "description": "Gemini, running in native Windows (PowerShell). Can only access Windows tools.",
701
- "guiSupport": true,
702
- "identification": {
703
- "markers": [
704
- "Windows",
705
- "gemini",
706
- "!WSL"
707
- ]
708
- },
709
- "capabilities": [
710
- "git operations",
711
- "npm install",
712
- "file editing",
713
- "gemini (self)"
714
- ],
715
- "restrictions": [
716
- "Runs only in native Windows",
717
- "Cannot access WSL-only tools like claude"
718
- ]
719
- },
720
706
  "minimax_worker": {
721
707
  "active": true,
722
- "name": "MiniMax M2.1 Worker (MCP)",
723
- "description": "Heavy lifter for bulk coding. Behavior controlled by delegationStrategy.",
708
+ "name": "MiniMax Swarm (MCP)",
709
+ "description": "The worker fleet. Accessed via MCP tools (minimax_backend, etc).",
724
710
  "guiSupport": false,
725
711
  "identification": {
726
- "markers": ["minimax", "delegate_coding_task"]
712
+ "markers": ["minimax"]
727
713
  },
728
714
  "capabilities": [
729
- "read large files internally",
730
- "generate massive code blocks",
731
- "refactor huge modules",
732
- "analyze project structure"
715
+ "backend engineering",
716
+ "frontend engineering",
717
+ "qa testing",
718
+ "refactoring"
733
719
  ],
734
720
  "restrictions": [
735
- "Cannot execute system commands directly (delegates back to Sonnet)",
736
- "Requires MINIMAX_API_KEY"
721
+ "Requires MINIMAX_API_KEY",
722
+ "No direct executive power"
737
723
  ]
738
724
  }
739
725
  },
package/src/cli/cli.js CHANGED
@@ -7,7 +7,7 @@ const __filename = fileURLToPath(import.meta.url);
7
7
  const __dirname = path.dirname(__filename);
8
8
 
9
9
  import { createRepoSnapshot } from './commands/createSnapshot.js';
10
- import { updateSnapshot } from './commands/updateSnapshot.js';
10
+ import { updateSnapshot, updateSnapshotJson } from './commands/updateSnapshot.js';
11
11
  import { restoreSnapshot } from './commands/restoreSnapshot.js';
12
12
  import { pruneSnapshot } from './commands/pruneSnapshot.js';
13
13
  import { generateConsilium } from './commands/consilium.js';
@@ -140,7 +140,9 @@ Option C: Using Profiles
140
140
  .option('--enhanced', 'Use enhanced multi-agent headers (default: true)', true)
141
141
  .option('--profile <name>', 'Filter files using profiles and/or ad-hoc glob patterns.')
142
142
  .option('--agent', 'Generate a snapshot optimized for a command-line agent')
143
- .option('--with-ja', 'Generate a detailed snapshot for the Junior Architect agent')
143
+ .option('--jag', 'Generate snapshot for Junior Architect Gemini (Gemini 3 Pro)')
144
+ .option('--jas', 'Configure project for Junior Architect Sonnet (Sonnet 4.5)')
145
+ .option('--jao', 'Configure project for Junior Architect Opus (Opus 4.5)')
144
146
  .option('--skeleton', 'Enable skeleton mode: strip function bodies to save context window tokens')
145
147
  .option('--max-lines-per-file <number>', 'Truncate files to max N lines (e.g., 200 for compact snapshots)', (val) => parseInt(val))
146
148
  .action(createRepoSnapshot)
@@ -198,6 +200,13 @@ Creating Custom Profiles:
198
200
  .option('--config <path>', 'Configuration file path')
199
201
  .action(updateSnapshot);
200
202
 
203
+ // Auto/Silent Update command for Agents
204
+ program
205
+ .command('update-auto')
206
+ .description('Silent update for AI agents (JSON output)')
207
+ .argument('[repoPath]', 'Path to the repository', process.cwd())
208
+ .action(updateSnapshotJson);
209
+
201
210
  // Restore command
202
211
  program
203
212
  .command('restore')
@@ -23,6 +23,7 @@ import { loadSetupConfig, getProfile } from '../../config.js';
23
23
  import { applyProfileFilter } from '../../utils/fileUtils.js';
24
24
  import { saveGitAnchor } from '../../utils/gitUtils.js';
25
25
  import { skeletonize } from '../../core/skeletonizer.js';
26
+ import { updateClaudeMd } from '../../utils/claudeMdGenerator.js';
26
27
 
27
28
  /**
28
29
  * Creates dynamic project context based on detection results
@@ -141,8 +142,9 @@ const gzip = promisify(zlib.gzip);
141
142
  */
142
143
  function isHiddenPath(filePath) {
143
144
  // Check if path or any parent directory starts with '.'
145
+ // Allow .eck directory to be visible, hide others (like .git, .vscode)
144
146
  const parts = filePath.split('/');
145
- return parts.some(part => part.startsWith('.'));
147
+ return parts.some(part => part.startsWith('.') && part !== '.eck');
146
148
  }
147
149
 
148
150
  /**
@@ -526,8 +528,13 @@ export async function createRepoSnapshot(repoPath, options) {
526
528
  ...options // Command-line options have the final say
527
529
  };
528
530
 
531
+ // Detect architect modes
532
+ const isJag = options.jag;
533
+ const isJas = options.jas;
534
+ const isJao = options.jao;
535
+
529
536
  // If NOT in Junior Architect mode, hide JA-specific documentation to prevent context pollution
530
- if (!options.withJa) {
537
+ if (!options.withJa && !isJag && !isJas && !isJao) {
531
538
  if (!config.filesToIgnore) config.filesToIgnore = [];
532
539
  config.filesToIgnore.push(
533
540
  'COMMANDS_REFERENCE.md',
@@ -555,15 +562,18 @@ export async function createRepoSnapshot(repoPath, options) {
555
562
 
556
563
  spinner.succeed('Creating snapshots...');
557
564
 
558
- // Step 1: Process all files ONCE
559
- const {
560
- stats,
561
- contentArray,
562
- successfulFileObjects,
563
- allFiles,
564
- originalCwd: processingOriginalCwd, // We get originalCwd from the processing function
565
- repoPath: processedRepoPath
566
- } = await processProjectFiles(repoPath, options, config, projectDetection.type);
565
+ // --- LOGIC UPDATE: Always include content ---
566
+ // The Architect needs full visibility of the code to make decisions.
567
+ // We strictly use processProjectFiles for all modes.
568
+
569
+ let stats, contentArray, successfulFileObjects, allFiles, processedRepoPath;
570
+
571
+ const result = await processProjectFiles(repoPath, options, config, projectDetection.type);
572
+ stats = result.stats;
573
+ contentArray = result.contentArray;
574
+ successfulFileObjects = result.successfulFileObjects;
575
+ allFiles = result.allFiles;
576
+ processedRepoPath = result.repoPath;
567
577
 
568
578
  const originalCwd = process.cwd(); // Get CWD *before* chdir
569
579
  process.chdir(processedRepoPath); // Go back to repo path for git hash and tree
@@ -598,58 +608,99 @@ export async function createRepoSnapshot(repoPath, options) {
598
608
  // Calculate Top 10 Largest Files
599
609
  const largestFiles = [...successfulFileObjects].sort((a, b) => b.size - a.size).slice(0, 10);
600
610
 
601
- const fileBody = (directoryTree ? `\n## Directory Structure\n\n\`\`\`\n${directoryTree}\`\`\`\n\n` : '') + contentArray.join('');
602
-
603
- // --- File 1: Architect Snapshot ---
604
- const architectOptions = { ...options, agent: false };
605
611
  // Load manifest for headers
606
612
  const eckManifest = await loadProjectEckManifest(processedRepoPath);
607
613
  const isGitRepo = await checkGitRepository(processedRepoPath);
608
614
 
609
- const architectHeader = await generateEnhancedAIHeader({ stats, repoName, mode: 'file', eckManifest, options: architectOptions, repoPath: processedRepoPath }, isGitRepo);
610
- let architectBaseFilename = `${repoName}_snapshot_${timestamp}${gitHash ? `_${gitHash}` : ''}`;
615
+ // --- BRANCH 1: Generate Snapshot File (ALWAYS) ---
616
+ let architectFilePath = null;
617
+ let jaFilePath = null;
611
618
 
612
- // Add '_sk' suffix for skeleton mode snapshots
613
- if (options.skeleton) {
614
- architectBaseFilename += '_sk';
615
- }
619
+ // File body always includes full content
620
+ let fileBody = (directoryTree ? `\n## Directory Structure\n\n\`\`\`\n${directoryTree}\`\`\`\n\n` : '') + contentArray.join('');
616
621
 
617
- const architectFilename = `${architectBaseFilename}.${fileExtension}`;
618
- const architectFilePath = path.join(outputPath, architectFilename);
619
- await fs.writeFile(architectFilePath, architectHeader + fileBody);
622
+ // Helper to write snapshot file
623
+ const writeSnapshot = async (suffix, isAgentMode) => {
624
+ // CHANGE: Force agent to FALSE for the main snapshot header.
625
+ // The snapshot is read by the Human/Senior Arch, not the Agent itself.
626
+ // The Agent reads CLAUDE.md.
627
+ const opts = { ...options, agent: false, jag: isJag, jas: isJas, jao: isJao };
628
+ const header = await generateEnhancedAIHeader({ stats, repoName, mode: 'file', eckManifest, options: opts, repoPath: processedRepoPath }, isGitRepo);
620
629
 
621
- // --- File 2: Junior Architect Snapshot ---
622
- let jaFilePath = null;
623
- if (options.withJa && fileExtension === 'md') { // Only create JA snapshot if requested and main is MD
624
- console.log('🖋️ Generating Junior Architect (_ja) snapshot...');
625
- const jaOptions = { ...options, agent: true, noTree: false, noAiHeader: false };
626
- const jaHeader = await generateEnhancedAIHeader({ stats, repoName, mode: 'file', eckManifest, options: jaOptions, repoPath: processedRepoPath }, isGitRepo);
627
- const jaFilename = `${architectBaseFilename}_ja.${fileExtension}`;
628
- jaFilePath = path.join(outputPath, jaFilename);
629
- await fs.writeFile(jaFilePath, jaHeader + fileBody);
630
+ // Compact filename format: eck{timestamp}_{hash}_{suffix}.md
631
+ const shortHash = gitHash ? gitHash.substring(0, 7) : '';
632
+ let fname = `eck${timestamp}`;
633
+ if (shortHash) fname += `_${shortHash}`;
634
+
635
+ // Add mode suffix
636
+ if (options.skeleton) {
637
+ fname += '_sk';
638
+ } else if (suffix) {
639
+ fname += suffix;
640
+ }
641
+
642
+ fname += `.${fileExtension}`;
643
+ const fpath = path.join(outputPath, fname);
644
+ await fs.writeFile(fpath, header + fileBody);
645
+ console.log(`📄 Generated Snapshot: ${fname}`);
646
+ return fpath;
647
+ };
648
+
649
+ // Generate snapshot file for ALL modes
650
+ if (isJag) {
651
+ architectFilePath = await writeSnapshot('_jag', true);
652
+ } else if (isJas) {
653
+ architectFilePath = await writeSnapshot('_jas', true);
654
+ } else if (isJao) {
655
+ architectFilePath = await writeSnapshot('_jao', true);
656
+ } else {
657
+ // Standard snapshot behavior
658
+ architectFilePath = await writeSnapshot('', false);
659
+
660
+ // --- File 2: Junior Architect Snapshot (legacy --with-ja support) ---
661
+ if (options.withJa && fileExtension === 'md') {
662
+ console.log('🖋️ Generating Junior Architect (_ja) snapshot...');
663
+ jaFilePath = await writeSnapshot('_ja', true);
664
+ }
630
665
  }
631
666
 
632
667
  // Save git anchor for future delta updates
633
668
  await saveGitAnchor(processedRepoPath);
634
669
 
635
- // --- Generate CLAUDE.md with confidential file references ---
636
- console.log('🔐 Scanning for confidential files in .eck directory...');
670
+ // Reset update counter for sequential tracking
671
+ try {
672
+ const counterPath = path.join(processedRepoPath, '.eck', 'update_seq');
673
+ await fs.mkdir(path.dirname(counterPath), { recursive: true });
674
+ // Format: HASH:COUNT
675
+ const shortHash = gitHash ? gitHash.substring(0, 7) : 'nohash';
676
+ await fs.writeFile(counterPath, `${shortHash}:0`);
677
+ } catch (e) {
678
+ // Non-critical, continue
679
+ }
680
+
681
+ // --- BRANCH 2: Update CLAUDE.md (JAS / JAO / Default) ---
682
+ console.log('🔐 Scanning for confidential files...');
637
683
  const confidentialFiles = await scanEckForConfidentialFiles(processedRepoPath, config);
638
684
 
639
- if (confidentialFiles.length > 0) {
640
- const claudeMdContent = generateClaudeMdContent(confidentialFiles, processedRepoPath);
641
- const claudeMdPath = path.join(processedRepoPath, 'CLAUDE.md');
642
- await fs.writeFile(claudeMdPath, claudeMdContent);
643
- console.log(`📝 Generated CLAUDE.md with ${confidentialFiles.length} confidential file reference(s)`);
644
- }
685
+ let claudeMode = 'coder';
686
+ if (isJas) claudeMode = 'jas';
687
+ if (isJao) claudeMode = 'jao';
688
+ if (isJag) claudeMode = 'jag';
689
+
690
+ await updateClaudeMd(processedRepoPath, claudeMode, directoryTree, confidentialFiles);
645
691
 
646
- // --- Combined Report ---
692
+ // --- Combined Report ---
647
693
  console.log('\n✅ Snapshot generation complete!');
648
694
  console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
649
- console.log(`📄 Architect File: ${architectFilePath}`);
695
+
696
+ if (architectFilePath) {
697
+ console.log(`📄 Snapshot File: ${architectFilePath}`);
698
+ }
650
699
  if (jaFilePath) {
651
700
  console.log(`📄 Junior Arch File: ${jaFilePath}`);
652
701
  }
702
+
703
+ console.log(`📊 Files scanned: ${stats.totalFiles}`);
653
704
  console.log(`📊 Files processed: ${stats.includedFiles}/${stats.totalFiles}`);
654
705
  console.log(`📏 Total size: ${formatSize(stats.totalSize)}`);
655
706
  console.log(`📦 Processed size: ${formatSize(stats.processedSize)}`);
@@ -1,6 +1,7 @@
1
1
  import fs from 'fs/promises';
2
2
  import path from 'path';
3
3
  import ora from 'ora';
4
+ import chalk from 'chalk';
4
5
  import { getGitAnchor, getChangedFiles, getGitDiffOutput } from '../../utils/gitUtils.js';
5
6
  import { loadSetupConfig } from '../../config.js';
6
7
  import { readFileWithSizeCheck, parseSize, formatSize, matchesPattern, loadGitignore, generateTimestamp } from '../../utils/fileUtils.js';
@@ -9,6 +10,61 @@ import { fileURLToPath } from 'url';
9
10
  const __filename = fileURLToPath(import.meta.url);
10
11
  const __dirname = path.dirname(__filename);
11
12
 
13
+ // Shared logic to generate the snapshot content string
14
+ async function generateSnapshotContent(repoPath, changedFiles, anchor, config, gitignore) {
15
+ let contentOutput = '';
16
+ let includedCount = 0;
17
+ const fileList = [];
18
+
19
+ // Check for Agent Report
20
+ const reportPath = path.join(repoPath, '.eck', 'AnswerToSA.md');
21
+ let agentReport = null;
22
+ try {
23
+ agentReport = await fs.readFile(reportPath, 'utf-8');
24
+ if (!changedFiles.includes('.eck/AnswerToSA.md')) {
25
+ changedFiles.push('.eck/AnswerToSA.md');
26
+ }
27
+ } catch (e) { /* No report */ }
28
+
29
+ for (const filePath of changedFiles) {
30
+ if (config.dirsToIgnore.some(d => filePath.startsWith(d))) continue;
31
+ if (gitignore.ignores(filePath) && filePath !== '.eck/AnswerToSA.md') continue;
32
+
33
+ try {
34
+ const fullPath = path.join(repoPath, filePath);
35
+ const content = await readFileWithSizeCheck(fullPath, parseSize(config.maxFileSize));
36
+ contentOutput += `--- File: /${filePath} ---\n\n${content}\n\n`;
37
+ fileList.push(`- ${filePath}`);
38
+ includedCount++;
39
+ } catch (e) { /* Skip */ }
40
+ }
41
+
42
+ // Load Template
43
+ const templatePath = path.join(__dirname, '../../templates/update-prompt.template.md');
44
+ let header = await fs.readFile(templatePath, 'utf-8');
45
+
46
+ // Inject Agent Report
47
+ let reportSection = '';
48
+ if (agentReport) {
49
+ reportSection = `\n#######################################################\n# 📨 MESSAGE FROM EXECUTION AGENT (Claude)\n#######################################################\n${agentReport}\n#######################################################\n\n`;
50
+ }
51
+
52
+ header = header.replace('{{anchor}}', anchor.substring(0, 7))
53
+ .replace('{{timestamp}}', new Date().toLocaleString())
54
+ .replace('{{fileList}}', fileList.join('\n'));
55
+
56
+ header = reportSection + header;
57
+
58
+ const diffOutput = await getGitDiffOutput(repoPath, anchor);
59
+ const diffSection = `\n--- GIT DIFF (For Context) ---\n\n\`\`\`diff\n${diffOutput}\n\`\`\``;
60
+
61
+ return {
62
+ fullContent: header + contentOutput + diffSection,
63
+ includedCount,
64
+ anchor
65
+ };
66
+ }
67
+
12
68
  export async function updateSnapshot(repoPath, options) {
13
69
  const spinner = ora('Generating update snapshot...').start();
14
70
  try {
@@ -23,53 +79,99 @@ export async function updateSnapshot(repoPath, options) {
23
79
  return;
24
80
  }
25
81
 
26
- // Load configs for filtering logic
27
82
  const setupConfig = await loadSetupConfig();
28
83
  const config = { ...setupConfig.fileFiltering, ...setupConfig.performance, ...options };
29
84
  const gitignore = await loadGitignore(repoPath);
30
85
 
31
- let contentOutput = '';
32
- let includedCount = 0;
33
- const fileList = [];
86
+ const { fullContent, includedCount } = await generateSnapshotContent(repoPath, changedFiles, anchor, config, gitignore);
34
87
 
35
- for (const filePath of changedFiles) {
36
- // Basic filtering (reuse logic roughly)
37
- if (config.dirsToIgnore.some(d => filePath.startsWith(d))) continue;
38
- if (gitignore.ignores(filePath)) continue;
39
-
40
- try {
41
- const fullPath = path.join(repoPath, filePath);
42
- const content = await readFileWithSizeCheck(fullPath, parseSize(config.maxFileSize));
43
-
44
- contentOutput += `--- File: /${filePath} ---\n\n${content}\n\n`;
45
- fileList.push(`- ${filePath}`);
46
- includedCount++;
47
- } catch (e) {
48
- // Skip deleted files or read errors
88
+ // Determine sequence number
89
+ let seqNum = 1;
90
+ const counterPath = path.join(repoPath, '.eck', 'update_seq');
91
+ try {
92
+ const seqData = await fs.readFile(counterPath, 'utf-8');
93
+ const [savedHash, savedCount] = seqData.split(':');
94
+ if (savedHash && savedHash.trim() === anchor.substring(0, 7).trim()) {
95
+ seqNum = parseInt(savedCount || '0') + 1;
49
96
  }
50
- }
97
+ } catch (e) {}
51
98
 
52
- // Load Template
53
- const templatePath = path.join(__dirname, '../../templates/update-prompt.template.md');
54
- let header = await fs.readFile(templatePath, 'utf-8');
55
- header = header.replace('{{anchor}}', anchor.substring(0, 7))
56
- .replace('{{timestamp}}', new Date().toLocaleString())
57
- .replace('{{fileList}}', fileList.join('\n'));
99
+ try {
100
+ await fs.writeFile(counterPath, `${anchor.substring(0, 7)}:${seqNum}`);
101
+ } catch (e) {}
58
102
 
59
- // Add Git Diff at the end for context
60
- const diffOutput = await getGitDiffOutput(repoPath, anchor);
61
- const diffSection = `\n--- GIT DIFF (For Context) ---\n\n\`\`\`diff\n${diffOutput}\n\`\`\``;
62
-
63
- const outputFilename = `update_${generateTimestamp()}.md`;
103
+ const timestamp = generateTimestamp();
104
+ const outputFilename = `eck${timestamp}_${anchor.substring(0, 7)}_up${seqNum}.md`;
64
105
  const outputPath = path.join(repoPath, '.eck', 'snapshots', outputFilename);
65
106
 
66
107
  await fs.mkdir(path.dirname(outputPath), { recursive: true });
67
- await fs.writeFile(outputPath, header + contentOutput + diffSection);
108
+ await fs.writeFile(outputPath, fullContent);
68
109
 
69
110
  spinner.succeed(`Update snapshot created: .eck/snapshots/${outputFilename}`);
111
+
112
+ // Check if agent report was included
113
+ const reportPath = path.join(repoPath, '.eck', 'AnswerToSA.md');
114
+ try {
115
+ await fs.access(reportPath);
116
+ console.log(chalk.green('📨 Included Agent Report (.eck/AnswerToSA.md)'));
117
+ } catch (e) {}
118
+
70
119
  console.log(`📦 Included ${includedCount} changed files.`);
71
120
 
72
121
  } catch (error) {
73
122
  spinner.fail(`Update failed: ${error.message}`);
74
123
  }
75
124
  }
125
+
126
+ // New Silent/JSON command for Agents
127
+ export async function updateSnapshotJson(repoPath) {
128
+ try {
129
+ const anchor = await getGitAnchor(repoPath);
130
+ if (!anchor) {
131
+ console.log(JSON.stringify({ status: "error", message: "No snapshot anchor found" }));
132
+ return;
133
+ }
134
+
135
+ const changedFiles = await getChangedFiles(repoPath, anchor);
136
+ if (changedFiles.length === 0) {
137
+ console.log(JSON.stringify({ status: "no_changes", message: "No changes detected" }));
138
+ return;
139
+ }
140
+
141
+ const setupConfig = await loadSetupConfig();
142
+ const config = { ...setupConfig.fileFiltering, ...setupConfig.performance };
143
+ const gitignore = await loadGitignore(repoPath);
144
+
145
+ const { fullContent, includedCount } = await generateSnapshotContent(repoPath, changedFiles, anchor, config, gitignore);
146
+
147
+ let seqNum = 1;
148
+ const counterPath = path.join(repoPath, '.eck', 'update_seq');
149
+ try {
150
+ const seqData = await fs.readFile(counterPath, 'utf-8');
151
+ const [savedHash, savedCount] = seqData.split(':');
152
+ if (savedHash && savedHash.trim() === anchor.substring(0, 7).trim()) {
153
+ seqNum = parseInt(savedCount || '0') + 1;
154
+ }
155
+ } catch (e) {}
156
+
157
+ try {
158
+ await fs.writeFile(counterPath, `${anchor.substring(0, 7)}:${seqNum}`);
159
+ } catch (e) {}
160
+
161
+ const timestamp = generateTimestamp();
162
+ const outputFilename = `eck${timestamp}_${anchor.substring(0, 7)}_up${seqNum}.md`;
163
+ const outputPath = path.join(repoPath, '.eck', 'snapshots', outputFilename);
164
+ await fs.mkdir(path.dirname(outputPath), { recursive: true });
165
+ await fs.writeFile(outputPath, fullContent);
166
+
167
+ console.log(JSON.stringify({
168
+ status: "success",
169
+ snapshot_file: `.eck/snapshots/${outputFilename}`,
170
+ files_count: includedCount,
171
+ timestamp: timestamp
172
+ }));
173
+
174
+ } catch (error) {
175
+ console.log(JSON.stringify({ status: "error", message: error.message }));
176
+ }
177
+ }
@@ -1,126 +1,42 @@
1
1
  # AI Junior Architect Instructions
2
2
 
3
- You are the **Junior Architect** agent (`gemini_wsl`). Your primary goal is to execute high-level strategic tasks delegated to you by the Senior Architect.
3
+ You are a **Junior Architect** ({{agentName}}). Your primary goal is to execute strategic tasks delegated to you by the Senior Architect (Gemini 3 Pro).
4
4
 
5
5
  ## Your Context
6
- - You are running in **WSL**.
7
- - You have access to a detailed `_ja.md` snapshot (which is *this* file).
8
- - You have a special capability: the `/claude` command, which delegates to a Coder agent.
9
-
10
- ## Hierarchical Role
11
- - The **Senior Architect (Gemini)** gives you high-level `execute_strategic_task` commands.
12
- - **You (Junior Architect / `gemini_wsl`)** analyze the task, break it down, and use your tools.
13
- - The **Coder (`claude`)** is your primary tool for *writing code*.
14
-
15
- ## CRITICAL WORKFLOW: Eck-Protocol v2 (Hybrid Format)
16
-
17
- When you need to write or modify code, you **MUST** use the `/claude` command with the **Eck-Protocol v2** format. This format uses Markdown for readability, XML tags for file boundaries, and JSON for metadata.
18
-
19
- ### Response Format
20
-
21
- **CRITICAL DISPLAY RULE:**
22
- You MUST wrap your ENTIRE response in a `text` block using **QUADRUPLE BACKTICKS** (` ```` `). This prevents internal code blocks from breaking the container.
6
+ - **Role:** {{agentDescription}}
7
+ - **Model:** {{modelName}}
8
+ - **Snapshot:** You have access to a specific task snapshot.
9
+
10
+ ## Your Workflow: The Manager
11
+ You are NOT a solitary coder. You are a **Manager**.
12
+ 1. **Analyze** the task from the Senior Architect.
13
+ 2. **Plan** the changes.
14
+ 3. **Delegate** implementation details to your **MiniMax Worker Swarm** using tools like:
15
+ - `minimax_backend` (for logic/db)
16
+ - `minimax_frontend` (for UI)
17
+ - `minimax_qa` (for tests)
18
+ - `minimax_refactor` (for cleanup)
19
+ 4. **Review** their work.
20
+ 5. **Assemble** the final result using `apply_code_changes` or file editing tools.
21
+
22
+ ## CRITICAL: Use the Swarm
23
+ Do not waste your expensive context window on reading massive files or writing boilerplate.
24
+ - **BAD:** Reading a 2000-line file to change one function.
25
+ - **GOOD:** Calling `minimax_refactor` with the file path and instruction: "Change function X to do Y".
26
+
27
+ ## Response Format (Eck-Protocol v2)
28
+
29
+ Use the standard Eck-Protocol v2 for your outputs:
23
30
 
24
31
  ````text
25
32
  # Analysis
26
-
27
- [Your thinking and analysis of the task goes here.
28
- Explain what you're going to do and why.]
33
+ [Your managerial plan]
29
34
 
30
35
  ## Changes
31
-
32
- <file path="src/path/to/file.js" action="replace">
33
- ```javascript
34
- // Your code here - no escaping needed!
35
- async function example() {
36
- console.log("Clean code with quotes!");
37
- return { success: true };
38
- }
39
- ```
40
- </file>
41
-
42
- <file path="src/another/file.js" action="create">
43
- ```javascript
44
- export const helper = () => true;
45
- ```
46
- </file>
36
+ [Your direct changes or delegation results]
47
37
 
48
38
  ## Metadata
49
-
50
39
  ```json
51
- {
52
- "journal": {
53
- "type": "feat",
54
- "scope": "api",
55
- "summary": "Add example function"
56
- }
57
- }
40
+ { "journal": { ... } }
58
41
  ```
59
42
  ````
60
-
61
- ### File Actions
62
-
63
- | Action | Description |
64
- |--------|-------------|
65
- | `create` | Create a new file |
66
- | `replace` | Replace entire file content |
67
- | `modify` | Partial modification (include context) |
68
- | `delete` | Delete the file (no content needed) |
69
-
70
- ### Example Command
71
-
72
- ```
73
- /claude
74
- ````text
75
- # Analysis
76
-
77
- I need to fix the null check in auth.js and add a helper function.
78
-
79
- ## Changes
80
-
81
- <file path="src/auth.js" action="replace">
82
- ```javascript
83
- async function login(user) {
84
- if (!user) throw new Error("No user provided");
85
- return await db.authenticate(user);
86
- }
87
- ```
88
- </file>
89
-
90
- <file path="src/utils/validate.js" action="create">
91
- ```javascript
92
- export const validateUser = (user) => {
93
- return user && typeof user.id === 'string';
94
- };
95
- ```
96
- </file>
97
-
98
- ## Metadata
99
-
100
- ```json
101
- {
102
- "journal": {
103
- "type": "fix",
104
- "scope": "auth",
105
- "summary": "Add null check and validation helper"
106
- }
107
- }
108
- ```
109
- ````
110
- ```
111
-
112
- ### Why This Format?
113
-
114
- 1. **No escaping hell** - Code is written in standard markdown fences, no `\"` or `\n`
115
- 2. **Readable** - Both humans and AI can easily read and write this format
116
- 3. **Parseable** - XML tags provide clear boundaries for automated processing
117
- 4. **Flexible** - Markdown sections allow for thinking and context
118
-
119
- ### Important Rules
120
-
121
- - Always wrap code in markdown fences (` ``` `) inside `<file>` tags
122
- - Always include the `path` and `action` attributes on `<file>` tags
123
- - Use the `## Metadata` section for journal entries and other structured data
124
- - The `# Analysis` section is optional but recommended for complex tasks
125
-
126
- Your other tools (like `bash`) can be used for analysis and validation.
@@ -134,6 +134,31 @@ To understand the project state, you can command the `eck-snapshot` tool directl
134
134
  - `eck-snapshot detect`: Analyze the project structure
135
135
  - `eck-snapshot restore <snapshot_file> --include ...`: View specific files
136
136
 
137
+ ## CAPABILITIES & DELEGATION PROTOCOL
138
+
139
+ You are managing an advanced instance of **Claude Code** equipped with specific plugins and tools. You must structure your commands to leverage these capabilities:
140
+
141
+ 1. **Token Economy (MiniMax Swarm):**
142
+ * **Goal:** Save money and Claude's context window.
143
+ * **Rule:** NEVER ask Claude to write >50 lines of code from scratch or refactor huge files personally.
144
+ * **Command:** Instruct Claude to use the `minimax_worker` MCP tool.
145
+ * **Phrasing:** "Delegate the implementation of [feature] to MiniMax Backend Worker. Review their output."
146
+
147
+ 2. **Self-Correction (The Ralph Loop):**
148
+ * **Goal:** Autonomous task completion.
149
+ * **Rule:** Tasks like "Fix bugs" or "Make tests pass" imply iteration.
150
+ * **Command:** Explicitly tell Claude: "Do not report back on the first error. Read the error, fix the code, and retry. Only report back when tests pass or after 3 failed attempts."
151
+
152
+ 3. **Project Memory (.eck context):**
153
+ * **Goal:** Instant onboarding.
154
+ * **Command:** "Read `.eck/CONTEXT.md` and `.eck/TECH_DEBT.md` before starting to understand the architectural constraints."
155
+
156
+ ### AVAILABLE EXECUTION AGENTS
157
+
158
+ You can command multiple specialized agents. **YOU must choose the most appropriate agent** based on the task requirements and target environment:
159
+
160
+ {{agentDefinitions}}
161
+
137
162
  ## Final Mandate
138
163
 
139
164
  Your existence is defined by this loop. Think, act by issuing a command using Eck-Protocol v2, and then wait for the observation. This is the only way you can make progress.
@@ -22,19 +22,57 @@ function render(template, data) {
22
22
  return output;
23
23
  }
24
24
 
25
- function buildAgentDefinitions(executionAgents) {
25
+ /**
26
+ * Filters execution agents based on the current mode.
27
+ * Senior Architect should only see relevant agents, not internal workers.
28
+ */
29
+ function getVisibleAgents(executionAgents, options) {
30
+ const visible = {};
31
+
32
+ // 1. Define Standard Coders (Always available as fallback)
33
+ // These keys must match IDs in setup.json
34
+ const standardCoders = ['local_dev', 'production_server', 'android_wsl_dev'];
35
+
36
+ // 2. Determine Priority Agent (The Junior Architect)
37
+ let priorityAgentKey = null;
38
+ if (options.jas) priorityAgentKey = 'jas';
39
+ if (options.jao) priorityAgentKey = 'jao';
40
+ if (options.jag) priorityAgentKey = 'jag';
41
+
42
+ // 3. Build the list
43
+ // If a JA is selected, add them FIRST with a note
44
+ if (priorityAgentKey && executionAgents[priorityAgentKey]) {
45
+ const ja = executionAgents[priorityAgentKey];
46
+ visible[priorityAgentKey] = {
47
+ ...ja,
48
+ description: `⭐ **PRIMARY AGENT** ⭐ ${ja.description} (Delegates to MiniMax)`
49
+ };
50
+ }
51
+
52
+ // Add standard coders
53
+ for (const key of standardCoders) {
54
+ if (executionAgents[key] && executionAgents[key].active) {
55
+ visible[key] = executionAgents[key];
56
+ }
57
+ }
58
+
59
+ // NOTE: We deliberately EXCLUDE 'minimax_worker' here.
60
+ // The Senior Architect does not call MiniMax directly; the JA does.
61
+
62
+ return visible;
63
+ }
64
+
65
+ function buildAgentDefinitions(filteredAgents) {
26
66
  let definitions = '';
27
- for (const key in executionAgents) {
28
- const agent = executionAgents[key];
29
- if (agent.active) {
30
- definitions += `
67
+ for (const key in filteredAgents) {
68
+ const agent = filteredAgents[key];
69
+ definitions += `
31
70
  ### ${agent.name} (ID: "${key}")
32
71
  - **Description:** ${agent.description}
33
72
  - **GUI Support:** ${agent.guiSupport ? 'Yes' : 'No (Headless)'}
34
73
  - **Capabilities:** ${agent.capabilities.join(', ')}
35
74
  - **Restrictions:** ${agent.restrictions.join(', ')}
36
75
  `;
37
- }
38
76
  }
39
77
  return definitions;
40
78
  }
@@ -290,35 +328,67 @@ export async function generateEnhancedAIHeader(context, isGitRepo = false) {
290
328
  // --- End context building ---
291
329
 
292
330
 
293
- // Check if agent mode is enabled
294
- if (context.options && context.options.agent) {
295
- const agentPromptTemplate = await loadTemplate(promptTemplates.agent);
331
+ // --- LOGIC CHANGE: Snapshot is ALWAYS for Senior Architect ---
332
+ // The `agent` prompt template is used ONLY in CLAUDE.md (via claudeMdGenerator.js)
333
+ // NOT in the snapshot itself.
296
334
 
297
- const agentHeader = `${agentPromptTemplate}
335
+ const isJag = context.options && context.options.jag;
336
+ const isJas = context.options && context.options.jas;
337
+ const isJao = context.options && context.options.jao;
338
+ const isJaMode = isJag || isJas || isJao;
298
339
 
299
- ${projectOverview}
300
- ${eckManifestSection}
301
- ---
302
-
303
- ## Project Snapshot Information
340
+ // --- Determine Workflow Content based on JA Flag ---
341
+ let hierarchicalWorkflow = '';
342
+ let commandFormats = '';
304
343
 
305
- - **Project**: ${context.repoName || 'Unknown'}
306
- - **Timestamp**: ${new Date().toISOString()}
307
- - **Files Included**: ${context.stats ? context.stats.includedFiles : 'Unknown'}
308
- - **Total Files in Repo**: ${context.stats ? context.stats.totalFiles : 'Unknown'}
344
+ if (isJaMode) {
345
+ // Instructions strictly for the Senior Architect on how to use the JA
346
+ hierarchicalWorkflow = `### 👑 ROYAL COURT ARCHITECTURE (Active)
309
347
 
310
- ---
348
+ You are the **Senior Architect**. You have a **Junior Architect** available to handle implementation.
311
349
 
350
+ **PROTOCOL:**
351
+ 1. **Prefer Delegation:** Unless the task is trivial (1-2 file edits), assign it to the **Junior Architect** (ID: \`jas\`, \`jao\`, or \`jag\` - see agents list above).
352
+ 2. **Direct Execution:** Only use \`local_dev\` or \`production_server\` directly if the Junior Architect fails or for simple "hotfixes".
353
+ 3. **No Micro-Management:** Do not tell the Junior Architect *how* to use MiniMax or internal tools. Just give them the strategic objective.
312
354
  `;
313
- return agentHeader;
314
- }
315
355
 
316
- // --- Determine Workflow Content based on JA Flag ---
317
- const withJa = context.options && context.options.withJa;
318
- let hierarchicalWorkflow = '';
319
- let commandFormats = '';
356
+ commandFormats = `### COMMAND FORMATS (Eck-Protocol v2)
357
+
358
+ You MUST use the **Eck-Protocol v2** format for all code execution tasks. This format combines Markdown for analysis, XML tags for file operations, and JSON for routing metadata.
359
+
360
+ **CRITICAL DISPLAY RULE (THE 4-BACKTICK WRAPPER):**
361
+ To ensure your command is copy-pasteable without breaking UI rendering, you **MUST** wrap the ENTIRE protocol output in a \`text\` block using **QUADRUPLE BACKTICKS** (\` \`\`\`\` \`).
362
+
363
+ **Why?** Your command contains internal code blocks with 3 backticks. To escape them, the outer container needs 4.
364
+
365
+ **Required Output Format:**
366
+
367
+ \`\`\`\`text
368
+ # Analysis
369
+ [Your reasoning...]
370
+
371
+ ## Changes
372
+ <file path="example.js" action="replace">
373
+ \\\`\\\`\\\`javascript
374
+ // Internal code block uses 3 backticks
375
+ const x = 1;
376
+ \\\`\\\`\\\`
377
+ </file>
320
378
 
321
- if (withJa) {
379
+ ## Metadata
380
+ \\\`\\\`\\\`json
381
+ { "target_agent": "jas", "task_id": "unique-id" }
382
+ \\\`\\\`\\\`
383
+ \`\`\`\`
384
+
385
+ **File Actions:**
386
+ - \`create\`: Create a new file (requires full content)
387
+ - \`replace\`: Overwrite existing file (requires full content)
388
+ - \`modify\`: Replace specific sections (provide context)
389
+ - \`delete\`: Delete the file
390
+ `;
391
+ } else if (context.options && context.options.withJa) {
322
392
  hierarchicalWorkflow = `### HIERARCHICAL AGENT WORKFLOW
323
393
 
324
394
  Your primary role is **Senior Architect**. You formulate high-level strategy. For complex code implementation, you will delegate to a **Junior Architect** agent (\`gemini_wsl\`), who has a detailed (\`_ja.md\`) snapshot and the ability to command a **Coder** agent (\`claude\`).
@@ -461,16 +531,8 @@ const x = 1;
461
531
  template = template.replace('{{eckManifestSection}}', eckManifestSection);
462
532
  // --- END INJECT ---
463
533
 
464
- // Filter out gemini agents if not in JA mode
465
- const filteredExecutionAgents = {};
466
- for (const [key, agent] of Object.entries(executionAgents)) {
467
- const isGeminiAgent = key.includes('gemini') || (agent.name && agent.name.toLowerCase().includes('gemini'));
468
- if (isGeminiAgent) {
469
- if (withJa && agent.active) filteredExecutionAgents[key] = agent;
470
- } else {
471
- if (agent.active) filteredExecutionAgents[key] = agent;
472
- }
473
- }
534
+ // Use the new filtering function to get visible agents
535
+ const filteredExecutionAgents = getVisibleAgents(executionAgents, context.options || {});
474
536
 
475
537
  const agentDefinitions = buildAgentDefinitions(filteredExecutionAgents);
476
538
 
@@ -0,0 +1,148 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+
4
+ /**
5
+ * Generates the Smart Delegation Protocol based on the specific Architect persona.
6
+ */
7
+ function getArchitectInstructions(modelName, tree) {
8
+ const isOpus = modelName.includes('Opus');
9
+
10
+ return `# 🧠 ROLE: Junior Architect (${modelName})
11
+
12
+ ## 1. PROJECT CONTEXT & MEMORY
13
+ You are working inside the repository.
14
+ - **Source of Truth:** The file system is your source of truth.
15
+ - **Documentation:** The \`.eck/\` directory contains project context. READ filenames to understand what is available.
16
+ - **Directory Structure:**
17
+ \`\`\`
18
+ ${tree}
19
+ \`\`\`
20
+
21
+ ## 2. SMART DELEGATION PROTOCOL (TOKEN ECONOMY)
22
+
23
+ ### A. Token Efficiency: When NOT to Delegate
24
+ **DO NOT delegate tasks where explanation costs more tokens than execution.**
25
+ * *Examples:*
26
+ - Reading a config file → Just use \`Read\` tool (1 tool call vs explaining to MiniMax)
27
+ - Checking if file exists → Use \`Bash test -f\` or \`Read\`
28
+ - Fixing a typo → Use \`Edit\` tool directly
29
+ - Writing < 50 lines of glue code
30
+ * **Rule:** If you can solve it in 1-2 tool calls, DO IT YOURSELF.
31
+
32
+ ### B. Heavy Lifting (DELEGATE TO MINIMAX)
33
+ For bulk work where delegation saves YOUR expensive context:
34
+ * *Examples:*
35
+ - Implementing complex business logic (> 100 lines)
36
+ - Refactoring entire modules
37
+ - Writing comprehensive test suites
38
+ - Generating boilerplate code
39
+ * **Action:** Use \`minimax_backend\`, \`minimax_frontend\`, \`minimax_qa\`, or \`minimax_refactor\`.
40
+
41
+ ## 3. DEFINITION OF DONE (CRITICAL)
42
+ When you have completed your coding task and verified it works:
43
+ 1. **DO NOT** run \`git commit\` manually.
44
+ 2. **DO NOT** just say "I'm done".
45
+ 3. **YOU MUST use the tool \`eck_finish_task\`**.
46
+ - This tool handles the commit AND automatically updates your context snapshot.
47
+ - Using this tool is the ONLY way to successfully close a task.
48
+
49
+ ## 4. THE RALPH WIGGUM PROTOCOL (AUTONOMOUS LOOPS)
50
+ **Core Directive:** You are "deterministically persistent". Failures are expected, giving up is not.
51
+
52
+ 1. **Iterative Correction:**
53
+ * If a build fails or tests turn red: **DO NOT STOP**.
54
+ * **Read** the error message.
55
+ * **Think** about the cause.
56
+ * **Fix** the code.
57
+ * **Retry** the verification command.
58
+ * *Repeat this loop up to 3-4 times.*
59
+
60
+ 2. **Intelligent Retry (MiniMax Supervision):**
61
+ * If a MiniMax worker produces bad code:
62
+ * **DON'T** repeat the same prompt.
63
+ * **Analyze WHY** it failed (missing context? wrong import?).
64
+ * **Guide** the worker: "Previous attempt failed because X. Try again using pattern Y."
65
+ * **Takeover:** If MiniMax fails twice, **DO IT YOURSELF**.
66
+
67
+ 3. **Definition of Done:**
68
+ * A task is ONLY done when the verification command (e.g., \`npm test\`) exits with code 0.
69
+ * If you cannot achieve green tests after max retries, produce a detailed report of *why* it is blocked.
70
+
71
+ ## 5. REPORTING PROTOCOL
72
+ At the end of your task, you **MUST** create or overwrite the file \`.eck/AnswerToSA.md\` BEFORE calling \`eck_finish_task\`.
73
+ This file communicates your results back to the Senior Architect (Gemini).
74
+
75
+ **Format for .eck/AnswerToSA.md:**
76
+ \`\`\`markdown
77
+ # Report: [Task Name]
78
+ **Status:** [SUCCESS / BLOCKED / FAILED]
79
+ **Changes:**
80
+ - Modified X
81
+ - Created Y
82
+ **Verification:**
83
+ - Ran test Z -> Passed
84
+ **Next Steps / Questions:**
85
+ - [What should the Architect do next?]
86
+ \`\`\`
87
+
88
+ ## 6. OPERATIONAL RULES
89
+ - **Commits:** Use the \`eck_finish_task\` tool for committing and updating context.
90
+ - **Manifests:** If you see [STUB] in .eck/ files, update them.
91
+ - **Reporting:** NEVER finish a session without writing \`.eck/AnswerToSA.md\` and calling \`eck_finish_task\`.
92
+ `;
93
+ }
94
+
95
+ const CODER_INSTRUCTIONS = `# 🛠️ ROLE: Expert Developer (The Fixer)
96
+
97
+ ## CORE DIRECTIVE
98
+ You are an Expert Developer. The architecture is already decided. Your job is to **execute**, **fix**, and **polish**.
99
+
100
+ ## DEFINITION OF DONE (CRITICAL)
101
+ When the task is complete:
102
+ 1. **UPDATE** the \`.eck/AnswerToSA.md\` file with your status.
103
+ 2. **CALL** the tool \`eck_finish_task\` to commit and sync context.
104
+ 3. **DO NOT** use raw git commands for the final commit.
105
+
106
+ ## CONTEXT
107
+ - The MiniMax swarm might have struggled or produced code that needs refinement.
108
+ - You are here to solve the hard problems manually.
109
+ - You have full permission to edit files directly.
110
+
111
+ ## WORKFLOW
112
+ 1. Read the code.
113
+ 2. Fix the bugs / Implement the feature.
114
+ 3. Verify functionality (Run tests!).
115
+ 4. **Loop:** If verification fails, fix it immediately. Do not ask for permission.
116
+ `;
117
+
118
+ /**
119
+ * Generates and writes the CLAUDE.md file based on the selected mode.
120
+ */
121
+ export async function updateClaudeMd(repoPath, mode, tree, confidentialFiles = []) {
122
+ let content = '';
123
+
124
+ if (mode === 'jas') {
125
+ content = getArchitectInstructions('Sonnet 4.5', tree);
126
+ } else if (mode === 'jao') {
127
+ content = getArchitectInstructions('Opus 4.5', tree);
128
+ } else if (mode === 'jag') {
129
+ content = getArchitectInstructions('Gemini 3 Pro', tree);
130
+ } else {
131
+ // Default coder mode (or if flags are missing)
132
+ content = CODER_INSTRUCTIONS;
133
+ }
134
+
135
+ // Append Confidential Files Reference
136
+ if (confidentialFiles.length > 0) {
137
+ content += '\n\n## 🔐 Access & Credentials\n';
138
+ content += 'The following confidential files are available locally but excluded from snapshots/tree:\n';
139
+ for (const file of confidentialFiles) {
140
+ content += `- \`${file}\`\n`;
141
+ }
142
+ content += '> **Note:** Read these files only when strictly necessary.\n';
143
+ }
144
+
145
+ const claudeMdPath = path.join(repoPath, 'CLAUDE.md');
146
+ await fs.writeFile(claudeMdPath, content, 'utf-8');
147
+ console.log(`📝 Updated CLAUDE.md for role: **${mode.toUpperCase()}** (Ralph Loop + MiniMax Protocol Active)`);
148
+ }
@@ -262,8 +262,8 @@ export async function generateDirectoryTree(dir, prefix = '', allFiles, depth =
262
262
 
263
263
  for (const entry of sortedEntries) {
264
264
  // Skip hidden directories and files (starting with '.')
265
- // EXCEPT: show .eck as a placeholder at the first level
266
- if (entry.name.startsWith('.')) {
265
+ // EXCEPT: Allow .eck to be visible
266
+ if (entry.name.startsWith('.') && entry.name !== '.eck') {
267
267
  continue;
268
268
  }
269
269
  if (config.dirsToIgnore.some(d => entry.name.includes(d.replace('/', '')))) continue;
@@ -283,19 +283,20 @@ export async function generateDirectoryTree(dir, prefix = '', allFiles, depth =
283
283
 
284
284
  if (entry.isDirectory()) {
285
285
  tree += `${prefix}${connector}${entry.name}/\n`;
286
- tree += await generateDirectoryTree(fullPath, nextPrefix, allFiles, depth + 1, maxDepth, config);
286
+
287
+ // RECURSION CONTROL:
288
+ // If we are currently inside .eck, do NOT recurse deeper into subdirectories (like snapshots, logs).
289
+ // We want to see that 'snapshots/' exists, but not list its contents.
290
+ const isInsideEckRoot = path.basename(dir) === '.eck';
291
+
292
+ if (!isInsideEckRoot) {
293
+ tree += await generateDirectoryTree(fullPath, nextPrefix, allFiles, depth + 1, maxDepth, config);
294
+ }
287
295
  } else {
288
296
  tree += `${prefix}${connector}${entry.name}\n`;
289
297
  }
290
298
  }
291
299
 
292
- // Add .eck placeholder at root level
293
- if (depth === 0) {
294
- const isLast = validEntries.length === 0;
295
- const connector = isLast ? '└── ' : '├── ';
296
- tree += `${prefix}${connector}.eck/\n`;
297
- }
298
-
299
300
  return tree;
300
301
  } catch (error) {
301
302
  console.warn(`⚠️ Warning: Could not read directory: ${dir}`);
@@ -406,13 +407,13 @@ export async function loadConfig(configPath) {
406
407
 
407
408
  export function generateTimestamp() {
408
409
  const now = new Date();
409
- const YYYY = now.getFullYear();
410
+ const YY = String(now.getFullYear()).slice(-2);
410
411
  const MM = String(now.getMonth() + 1).padStart(2, '0');
411
412
  const DD = String(now.getDate()).padStart(2, '0');
412
413
  const hh = String(now.getHours()).padStart(2, '0');
413
414
  const mm = String(now.getMinutes()).padStart(2, '0');
414
- const ss = String(now.getSeconds()).padStart(2, '0');
415
- return `${YYYY}-${MM}-${DD}_${hh}-${mm}-${ss}`;
415
+ // Compact format: YY-MM-DD_HH-mm (no seconds)
416
+ return `${YY}-${MM}-${DD}_${hh}-${mm}`;
416
417
  }
417
418
 
418
419
  /**