@xelth/eck-snapshot 4.2.4 โ†’ 5.4.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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +106 -0
  3. package/index.js +14 -0
  4. package/package.json +64 -9
  5. package/scripts/mcp-eck-core.js +101 -0
  6. package/scripts/mcp-glm-zai-worker.mjs +243 -0
  7. package/scripts/verify_changes.js +68 -0
  8. package/setup.json +845 -0
  9. package/src/cli/cli.js +369 -0
  10. package/src/cli/commands/claudeSettings.js +93 -0
  11. package/src/cli/commands/consilium.js +86 -0
  12. package/src/cli/commands/createSnapshot.js +906 -0
  13. package/src/cli/commands/detectProfiles.js +98 -0
  14. package/src/cli/commands/detectProject.js +112 -0
  15. package/src/cli/commands/doctor.js +60 -0
  16. package/src/cli/commands/envSync.js +319 -0
  17. package/src/cli/commands/generateProfileGuide.js +144 -0
  18. package/src/cli/commands/pruneSnapshot.js +106 -0
  19. package/src/cli/commands/restoreSnapshot.js +173 -0
  20. package/src/cli/commands/setupGemini.js +149 -0
  21. package/src/cli/commands/setupGemini.test.js +115 -0
  22. package/src/cli/commands/setupMcp.js +269 -0
  23. package/src/cli/commands/showFile.js +39 -0
  24. package/src/cli/commands/trainTokens.js +38 -0
  25. package/src/cli/commands/updateSnapshot.js +219 -0
  26. package/src/config.js +125 -0
  27. package/src/core/skeletonizer.js +201 -0
  28. package/src/mcp-server/index.js +211 -0
  29. package/src/services/claudeCliService.js +626 -0
  30. package/src/services/claudeCliService.test.js +267 -0
  31. package/src/templates/agent-prompt.template.md +43 -0
  32. package/src/templates/architect-prompt.template.md +164 -0
  33. package/src/templates/claude-code/README.md +105 -0
  34. package/src/templates/claude-code/mcp-config-template.json +11 -0
  35. package/src/templates/claude-code/mcp-server-template.js +206 -0
  36. package/src/templates/claude-code/settings-claude.json +1 -0
  37. package/src/templates/envScanRequest.md +4 -0
  38. package/src/templates/gitWorkflow.md +32 -0
  39. package/src/templates/multiAgent.md +118 -0
  40. package/src/templates/opencode/coder.template.md +22 -0
  41. package/src/templates/opencode/junior-architect.template.md +85 -0
  42. package/src/templates/skeleton-instruction.md +16 -0
  43. package/src/templates/update-prompt.template.md +19 -0
  44. package/src/utils/aiHeader.js +678 -0
  45. package/src/utils/claudeMdGenerator.js +148 -0
  46. package/src/utils/eckProtocolParser.js +221 -0
  47. package/src/utils/fileUtils.js +1017 -0
  48. package/src/utils/gitUtils.js +44 -0
  49. package/src/utils/opencodeAgentsGenerator.js +271 -0
  50. package/src/utils/projectDetector.js +704 -0
  51. package/src/utils/tokenEstimator.js +201 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Dmytro Surovtsev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,106 @@
1
+
2
+ # eckSnapshot (v5.4.0)
3
+
4
+ A specialized CLI tool designed to create and restore single-file text snapshots of Git repositories. It is specifically optimized for providing full project context to Large Language Models (LLMs) like Claude, Gemini, and OpenCode.
5
+
6
+ ๐ŸŽ‰ **WE ARE BACK ON NPM!** Version 5.4.0 and onwards are officially available via the npm registry.
7
+
8
+ ## ๐Ÿš€ Quick Start
9
+
10
+ ```bash
11
+ # Install globally via npm
12
+ npm install -g @xelth/eck-snapshot
13
+
14
+ # Create a snapshot of your current project
15
+ eck-snapshot
16
+ ```
17
+
18
+ ## โœจ Core Features
19
+
20
+ - **Skeleton Mode:** Strips function bodies using Tree-sitter and Babel to save massive amounts of context tokens.
21
+ - **Delta Updates:** Tracks changes via Git anchors and generates incremental snapshots (`eck-snapshot update`).
22
+ - **Royal Court Architecture:** Multi-agent protocol with dedicated modes for Claude Sonnet (JAS), Claude Opus (JAO), and Gemini (JAG).
23
+ - **GLM Z.AI Worker Fleet:** Built-in MCP server integration for delegating heavy coding tasks to specialized AI workers.
24
+ - **Security:** Built-in `SecretScanner` automatically redacts API keys and sensitive credentials before they hit the LLM context.
25
+ - **Context Profiles:** Smart filtering using auto-detected or manual profiles (e.g., `--profile backend`).
26
+
27
+ ---
28
+
29
+ ## ๐Ÿ› ๏ธ The Core Workflow
30
+
31
+ ### 1. Initial Context (Maximum Compression)
32
+ Create a lightweight map of your entire project. Bodies of functions are hidden, allowing huge monoliths to fit into the AI's context window.
33
+ ```bash
34
+ eck-snapshot --skeleton
35
+ # -> Generates: .eck/snapshots/eck[Name]_[Hash]_sk.md
36
+ ```
37
+
38
+ ### 2. Lazy Loading (On-Demand Details)
39
+ If the AI needs to see the exact implementation of specific files, it can request them on demand.
40
+ ```bash
41
+ eck-snapshot show src/auth.js src/utils/hash.js
42
+ ```
43
+
44
+ ### 3. Incremental Updates (Delta)
45
+ As you apply changes, the AI loses context. Instead of re-sending the full repository, send only what changed since the last snapshot!
46
+ ```bash
47
+ eck-snapshot update
48
+ # -> Generates an update snapshot with git diffs and modified files
49
+ ```
50
+
51
+ ---
52
+
53
+ ## ๐Ÿ‘‘ Royal Court Architecture & GLM Z.AI
54
+
55
+ `eck-snapshot` is designed to orchestrate a hierarchy of AI agents:
56
+
57
+ - **Senior Architect:** (You / Gemini / ChatGPT) - Directs the high-level strategy.
58
+ - **Junior Architects:**
59
+ - `JAS` (Sonnet 4.5): Fast manager for standard features. Run `eck-snapshot --jas`.
60
+ - `JAO` (Opus 4.5): Deep thinker for critical architecture. Run `eck-snapshot --jao`.
61
+ - `JAG` (Gemini 3 Pro): Massive context handler. Run `eck-snapshot --jag`.
62
+
63
+ ### MCP Server Integration
64
+ Delegate heavy coding tasks (>100 lines) to the **GLM Z.AI Worker Fleet** to save expensive context window tokens.
65
+
66
+ 1. Get your API key from [Z.AI](https://z.ai) and export it: `export ZAI_API_KEY="your-key-here"`
67
+ 2. Setup the MCP servers for Claude Code or OpenCode:
68
+ ```bash
69
+ eck-snapshot setup-mcp --both
70
+ ```
71
+ 3. Your AI will now have access to specialized tools: `glm_zai_frontend`, `glm_zai_backend`, `glm_zai_qa`, `glm_zai_refactor`, and the `eck_finish_task` commit tool.
72
+
73
+ ---
74
+
75
+ ## ๐Ÿงฉ Context Profiles
76
+
77
+ If your repository is huge, you can partition it using Context Profiles:
78
+
79
+ ```bash
80
+ # Auto-detect profiles using AI
81
+ eck-snapshot profile-detect
82
+
83
+ # List available profiles
84
+ eck-snapshot --profile
85
+
86
+ # Use a specific profile
87
+ eck-snapshot --profile backend
88
+
89
+ # Ad-hoc inclusion/exclusion
90
+ eck-snapshot --profile "src/**/*.js,-**/*.test.js"
91
+ ```
92
+
93
+ ## ๐Ÿ” Environment Syncing
94
+
95
+ Securely share your `.eck/` configuration (profiles, roadmap, AI instructions) between machines without committing them to the public git history:
96
+
97
+ ```bash
98
+ # Encrypt and pack .eck/ config files
99
+ eck-snapshot env push
100
+
101
+ # Decrypt and restore on another machine
102
+ eck-snapshot env pull
103
+ ```
104
+
105
+ ## License
106
+ MIT License
package/index.js ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+
3
+ import dotenv from 'dotenv';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ const envPath = path.join(__dirname, '.env');
11
+ dotenv.config({ path: envPath });
12
+
13
+ const { run } = await import('./src/cli/cli.js');
14
+ run();
package/package.json CHANGED
@@ -1,9 +1,64 @@
1
- {
2
- "name": "@xelth/eck-snapshot",
3
- "version": "4.2.4",
4
- "description": "Deprecated. Package removed.",
5
- "main": "index.js",
6
- "scripts": {
7
- "test": "echo deprecated"
8
- }
9
- }
1
+ {
2
+ "name": "@xelth/eck-snapshot",
3
+ "version": "5.4.0",
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
+ "main": "index.js",
6
+ "type": "module",
7
+ "bin": {
8
+ "eck-snapshot": "index.js"
9
+ },
10
+ "files": [
11
+ "index.js",
12
+ "README.md",
13
+ "LICENSE",
14
+ "src/",
15
+ "scripts/",
16
+ "setup.json"
17
+ ],
18
+ "scripts": {
19
+ "test": "vitest",
20
+ "test:ui": "vitest --ui",
21
+ "test:run": "vitest run"
22
+ },
23
+ "author": "xelth-com",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/xelth-com/eckSnapshot.git"
28
+ },
29
+ "dependencies": {
30
+ "@anthropic-ai/sdk": "^0.33.1",
31
+ "@modelcontextprotocol/sdk": "^1.0.1",
32
+ "@babel/generator": "^7.25.6",
33
+ "@babel/parser": "^7.25.6",
34
+ "@babel/traverse": "^7.25.6",
35
+ "chalk": "^5.3.0",
36
+ "cli-progress": "^3.12.0",
37
+ "commander": "^12.1.0",
38
+ "dotenv": "^16.6.1",
39
+ "execa": "^8.0.1",
40
+ "ignore": "^5.3.1",
41
+ "inquirer": "^9.2.20",
42
+ "is-binary-path": "^2.1.0",
43
+ "js-yaml": "^4.1.0",
44
+ "micromatch": "^4.0.8",
45
+ "minimatch": "^9.0.3",
46
+ "ora": "^8.1.0",
47
+ "p-limit": "^5.0.0",
48
+ "p-retry": "^6.2.1",
49
+ "which": "^4.0.0"
50
+ },
51
+ "optionalDependencies": {
52
+ "tree-sitter": "^0.25.0",
53
+ "tree-sitter-c": "^0.24.1",
54
+ "tree-sitter-go": "^0.23.4",
55
+ "tree-sitter-java": "^0.23.5",
56
+ "tree-sitter-kotlin": "^0.3.8",
57
+ "tree-sitter-python": "^0.25.0",
58
+ "tree-sitter-rust": "^0.23.2"
59
+ },
60
+ "devDependencies": {
61
+ "jsdom": "^24.0.0",
62
+ "vitest": "^2.0.0"
63
+ }
64
+ }
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCP Eck Core - Provides core project management capabilities to Claude
4
+ */
5
+
6
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
7
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
8
+ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
9
+ import { execa } from "execa";
10
+ import path from "path";
11
+ import { fileURLToPath } from 'url';
12
+
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = path.dirname(__filename);
15
+ const PROJECT_ROOT = path.resolve(__dirname, '..');
16
+
17
+ const server = new Server(
18
+ { name: "eck-core", version: "1.0.0" },
19
+ { capabilities: { tools: {} } }
20
+ );
21
+
22
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
23
+ return {
24
+ tools: [
25
+ {
26
+ name: "eck_finish_task",
27
+ description: "Completes the current coding task. 1) Stages all changes. 2) Commits with the provided message. 3) Automatically updates the context snapshot. Use this instead of manual git commands.",
28
+ inputSchema: {
29
+ type: "object",
30
+ properties: {
31
+ message: {
32
+ type: "string",
33
+ description: "Git commit message (follow Conventional Commits, e.g. 'feat: add login')"
34
+ }
35
+ },
36
+ required: ["message"]
37
+ }
38
+ }
39
+ ]
40
+ };
41
+ });
42
+
43
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
44
+ if (request.params.name === "eck_finish_task") {
45
+ const { message } = request.params.arguments;
46
+
47
+ try {
48
+ // 1. Git Add
49
+ await execa("git", ["add", "."], { cwd: process.cwd(), timeout: 30000 });
50
+
51
+ // 2. Git Commit
52
+ // We allow empty commits just in case, though unlikely in a finish_task scenario
53
+ await execa("git", ["commit", "--allow-empty", "-m", message], { cwd: process.cwd(), timeout: 30000 });
54
+
55
+ // 3. Auto Update Snapshot via CLI
56
+ // We use the local index.js to ensure we use the current version of the tool
57
+ const cliPath = path.join(PROJECT_ROOT, "index.js");
58
+ const { stdout } = await execa("node", [cliPath, "update-auto"], { cwd: process.cwd(), timeout: 120000 });
59
+
60
+ let result;
61
+ try {
62
+ result = JSON.parse(stdout);
63
+ } catch (e) {
64
+ return {
65
+ content: [{ type: "text", text: `โœ… Committed: "${message}"\nโš ๏ธ Snapshot update returned invalid JSON: ${stdout}` }]
66
+ };
67
+ }
68
+
69
+ if (result.status === "success") {
70
+ return {
71
+ content: [{
72
+ type: "text",
73
+ text: `โœ… Task Completed Successfully.\n\n1. ๐Ÿ’พ Git Commit: "${message}"\n2. ๐Ÿ“ธ Context Updated: ${result.snapshot_file} (+${result.files_count} files)\n\nReady for next instruction.`
74
+ }]
75
+ };
76
+ } else if (result.status === "no_changes") {
77
+ return {
78
+ content: [{ type: "text", text: `โœ… Committed: "${message}"\nโ„น๏ธ No new changes for snapshot update.` }]
79
+ };
80
+ } else {
81
+ return {
82
+ content: [{ type: "text", text: `โœ… Committed: "${message}"\nโŒ Snapshot Update Failed: ${result.message}` }]
83
+ };
84
+ }
85
+
86
+ } catch (error) {
87
+ return {
88
+ content: [{ type: "text", text: `โŒ Error finishing task: ${error.message}\n${error.stdout || ''}\n${error.stderr || ''}` }],
89
+ isError: true
90
+ };
91
+ }
92
+ }
93
+
94
+ return {
95
+ content: [{ type: "text", text: `Unknown tool: ${request.params.name}` }],
96
+ isError: true
97
+ };
98
+ });
99
+
100
+ const transport = new StdioServerTransport();
101
+ await server.connect(transport);
@@ -0,0 +1,243 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCP GLM Z.AI Worker - Provides specialized worker agents via GLM-4.7 (Z.AI Coding Plan)
4
+ * Replacement for MiniMax M2.1 worker. Used by Claude Code (Sonnet/Opus) to delegate
5
+ * heavy coding tasks and save tokens.
6
+ *
7
+ * Setup (Claude Code):
8
+ * claude mcp add glm-zai -- node scripts/mcp-glm-zai-worker.mjs
9
+ *
10
+ * Setup (OpenCode):
11
+ * Add to opencode MCP config with the same command path.
12
+ *
13
+ * Environment:
14
+ * ZAI_API_KEY or ANTHROPIC_AUTH_TOKEN must be set.
15
+ */
16
+
17
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
18
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
19
+ import {
20
+ CallToolRequestSchema,
21
+ ListToolsRequestSchema,
22
+ } from "@modelcontextprotocol/sdk/types.js";
23
+ import Anthropic from "@anthropic-ai/sdk";
24
+ import pRetry from "p-retry";
25
+ import fs from "fs/promises";
26
+ import path from "path";
27
+
28
+ const API_KEY = process.env.ZAI_API_KEY || process.env.ANTHROPIC_AUTH_TOKEN;
29
+
30
+ if (!API_KEY) {
31
+ console.error("ERROR: ZAI_API_KEY (or ANTHROPIC_AUTH_TOKEN) environment variable is not set");
32
+ console.error("Get your key at https://z.ai and export ZAI_API_KEY=your-key");
33
+ process.exit(1);
34
+ }
35
+
36
+ const glmClient = new Anthropic({
37
+ apiKey: API_KEY,
38
+ baseURL: "https://api.z.ai/api/anthropic",
39
+ });
40
+
41
+ // Define Personas - specialized worker roles
42
+ const PERSONAS = {
43
+ frontend: `You are an Expert Frontend Developer (GLM-4.7).
44
+ Focus: React, Vue, Svelte, Tailwind, CSS, UI/UX, responsive design.
45
+ Goal: Implement the requested UI component, page, or frontend logic.
46
+ Rules:
47
+ - Return ONLY the code or diffs. No explanations unless critical.
48
+ - Follow the existing project conventions you see in the provided files.
49
+ - Use modern ES modules syntax.
50
+ - Ensure accessibility basics (semantic HTML, ARIA where needed).`,
51
+
52
+ backend: `You are a Senior Backend Engineer (GLM-4.7).
53
+ Focus: Node.js, Python, Go, SQL, API design, Auth, WebSocket.
54
+ Goal: Implement robust business logic, API endpoints, and data handling.
55
+ Rules:
56
+ - Return ONLY the code or diffs. No explanations unless critical.
57
+ - Follow RESTful principles and existing project patterns.
58
+ - Include proper error handling.
59
+ - Write secure code (no SQL injection, XSS, etc).`,
60
+
61
+ qa: `You are a QA Automation Engineer (GLM-4.7).
62
+ Focus: Unit tests, Integration tests, E2E tests, Edge cases.
63
+ Goal: Write comprehensive tests for the provided code.
64
+ Rules:
65
+ - Return ONLY the test files. No explanations unless critical.
66
+ - Use the testing framework already in the project (Jest, Vitest, pytest, etc).
67
+ - Use AAA pattern (Arrange, Act, Assert).
68
+ - Cover happy paths, edge cases, and error scenarios.
69
+ - Aim for >80% coverage of the provided code.`,
70
+
71
+ refactor: `You are a Code Quality Specialist (GLM-4.7).
72
+ Focus: Clean Code, DRY, SOLID, Performance optimization, readability.
73
+ Goal: Refactor the provided code to be cleaner, faster, and more maintainable.
74
+ Rules:
75
+ - Return ONLY the refactored code. No explanations unless critical.
76
+ - Preserve existing functionality (no behavior changes).
77
+ - Reduce complexity and duplication.
78
+ - Improve naming and structure.`,
79
+
80
+ general: `You are an Expert Full-Stack Developer (GLM-4.7).
81
+ Focus: Full-stack web development, problem-solving, debugging.
82
+ Goal: Complete the requested task efficiently and correctly.
83
+ Rules:
84
+ - Return ONLY the code or diffs. No explanations unless critical.
85
+ - Follow existing project conventions.
86
+ - Write clean, maintainable code.
87
+ - Consider edge cases.`
88
+ };
89
+
90
+ const server = new Server(
91
+ { name: "glm-zai-worker", version: "2.0.0" },
92
+ { capabilities: { tools: {} } }
93
+ );
94
+
95
+ // 1. Register Tools Dynamically
96
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
97
+ const tools = Object.keys(PERSONAS).map((role) => ({
98
+ name: `glm_zai_${role}`,
99
+ description: `Delegate task to GLM Z.AI ${role.toUpperCase()} Specialist (GLM-4.7). Cost-effective worker for heavy coding tasks.`,
100
+ inputSchema: {
101
+ type: "object",
102
+ properties: {
103
+ instruction: {
104
+ type: "string",
105
+ description:
106
+ "Detailed technical instruction for the worker. Be specific about what to implement/change.",
107
+ },
108
+ file_paths: {
109
+ type: "array",
110
+ items: { type: "string" },
111
+ description:
112
+ "List of files the worker needs to read as context (paths relative to project root).",
113
+ },
114
+ context_summary: {
115
+ type: "string",
116
+ description:
117
+ "Brief context about the project and what we are building (optional but recommended).",
118
+ },
119
+ },
120
+ required: ["instruction"],
121
+ },
122
+ }));
123
+
124
+ return { tools };
125
+ });
126
+
127
+ // 2. Handle Tool Calls
128
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
129
+ const toolName = request.params.name;
130
+
131
+ if (!toolName.startsWith("glm_zai_")) {
132
+ return {
133
+ content: [
134
+ {
135
+ type: "text",
136
+ text: `Unknown tool: ${toolName}. Available: ${Object.keys(PERSONAS)
137
+ .map((p) => `glm_zai_${p}`)
138
+ .join(", ")}`,
139
+ },
140
+ ],
141
+ isError: true,
142
+ };
143
+ }
144
+
145
+ const role = toolName.replace("glm_zai_", "");
146
+ const {
147
+ instruction,
148
+ file_paths = [],
149
+ context_summary = "",
150
+ } = request.params.arguments;
151
+
152
+ try {
153
+ // Read files internally to avoid sending file content through the supervisor
154
+ let heavyContext = "";
155
+ const missingFiles = [];
156
+
157
+ for (const filePath of file_paths) {
158
+ try {
159
+ const absolutePath = path.resolve(process.cwd(), filePath);
160
+ const content = await fs.readFile(absolutePath, "utf-8");
161
+ heavyContext += `\n=== FILE: ${filePath} ===\n${content}\n=== END FILE ===\n`;
162
+ } catch (e) {
163
+ missingFiles.push(`${filePath} (${e.code || e.message})`);
164
+ }
165
+ }
166
+
167
+ if (missingFiles.length > 0 && file_paths.length > 0 && missingFiles.length === file_paths.length) {
168
+ return {
169
+ content: [
170
+ {
171
+ type: "text",
172
+ text: `Error: Could not read any files: ${missingFiles.join(", ")}`,
173
+ },
174
+ ],
175
+ isError: true,
176
+ };
177
+ }
178
+
179
+ const systemPrompt = PERSONAS[role] || PERSONAS.general;
180
+
181
+ let userMessage = "";
182
+ if (context_summary) {
183
+ userMessage += `PROJECT CONTEXT: ${context_summary}\n\n`;
184
+ }
185
+ userMessage += `TASK: ${instruction}\n`;
186
+ if (missingFiles.length > 0) {
187
+ userMessage += `\nWARNING: Could not read some files: ${missingFiles.join(", ")}\n`;
188
+ }
189
+ if (heavyContext) {
190
+ userMessage += `\nSOURCE FILES:\n${heavyContext}`;
191
+ }
192
+
193
+ const response = await pRetry(
194
+ () => glmClient.messages.create({
195
+ model: "GLM-4.7",
196
+ max_tokens: 16384,
197
+ system: systemPrompt,
198
+ messages: [{ role: "user", content: userMessage }],
199
+ }),
200
+ {
201
+ retries: 2,
202
+ onFailedAttempt: (error) => {
203
+ // Don't retry auth errors or invalid requests
204
+ if (error.status === 401 || error.status === 400 || error.status === 403) {
205
+ throw error;
206
+ }
207
+ },
208
+ }
209
+ );
210
+
211
+ let resultText = "";
212
+ if (response.content && Array.isArray(response.content)) {
213
+ resultText = response.content
214
+ .filter((block) => block.type === "text")
215
+ .map((b) => b.text)
216
+ .join("\n\n");
217
+ } else {
218
+ resultText = "No content returned from GLM Z.AI.";
219
+ }
220
+
221
+ return {
222
+ content: [
223
+ {
224
+ type: "text",
225
+ text: `## GLM Z.AI (${role.toUpperCase()}) Output\n\n${resultText}`,
226
+ },
227
+ ],
228
+ };
229
+ } catch (error) {
230
+ return {
231
+ content: [
232
+ {
233
+ type: "text",
234
+ text: `GLM Z.AI API Error: ${error.message}\n\nEnsure ZAI_API_KEY is set. Get your key at https://z.ai`,
235
+ },
236
+ ],
237
+ isError: true,
238
+ };
239
+ }
240
+ });
241
+
242
+ const transport = new StdioServerTransport();
243
+ await server.connect(transport);
@@ -0,0 +1,68 @@
1
+ import { execa } from 'execa';
2
+ import fs from 'fs/promises';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ console.log('๐Ÿงช Starting Verification Suite...');
7
+
8
+ async function verifySnapshots() {
9
+ console.log('\n[1/2] Testing Snapshot Logic...');
10
+ try {
11
+ // 1. Generate Standard Snapshot
12
+ await execa('node', ['index.js', 'snapshot', '--no-tree', '--output', 'test_verify_std']);
13
+ const stdFiles = await fs.readdir('test_verify_std');
14
+ const stdContent = await fs.readFile(path.join('test_verify_std', stdFiles.find(f => f.endsWith('.md'))), 'utf-8');
15
+
16
+ // Extract just the AI instructions header (before the Directory Structure)
17
+ const stdHeader = stdContent.split('## Directory Structure')[0];
18
+
19
+ if (stdHeader.includes('HIERARCHICAL AGENT WORKFLOW')) {
20
+ throw new Error('โŒ Standard snapshot header contains HIERARCHICAL workflow (Should be simple AGENT WORKFLOW!)');
21
+ }
22
+ if (!stdHeader.includes('### AGENT WORKFLOW')) {
23
+ throw new Error('โŒ Standard snapshot missing AGENT WORKFLOW section');
24
+ }
25
+ console.log('โœ… Standard snapshot: OK (Simple AGENT WORKFLOW)');
26
+
27
+ // 2. Generate Snapshot with --with-ja flag
28
+ await execa('node', ['index.js', 'snapshot', '--with-ja', '--no-tree', '--output', 'test_verify_ja']);
29
+ const jaFiles = await fs.readdir('test_verify_ja');
30
+
31
+ // Check the MAIN architect snapshot (not the _ja version)
32
+ const mainJaFile = jaFiles.find(f => f.endsWith('.md') && !f.includes('_ja.md'));
33
+ const mainJaContent = await fs.readFile(path.join('test_verify_ja', mainJaFile), 'utf-8');
34
+
35
+ // Extract just the AI instructions header for architect snapshot
36
+ const mainJaHeader = mainJaContent.split('## Directory Structure')[0];
37
+
38
+ if (!mainJaHeader.includes('HIERARCHICAL AGENT WORKFLOW')) {
39
+ throw new Error('โŒ Architect snapshot (with --with-ja) missing HIERARCHICAL AGENT WORKFLOW');
40
+ }
41
+ if (!mainJaHeader.includes('Junior Architect')) {
42
+ throw new Error('โŒ Architect snapshot (with --with-ja) missing Junior Architect references');
43
+ }
44
+ console.log('โœ… Architect snapshot (with --with-ja): OK (HIERARCHICAL AGENT WORKFLOW with JA delegation)');
45
+
46
+ // Also verify the _ja snapshot uses agent mode
47
+ const jaAgentFile = jaFiles.find(f => f.includes('_ja.md'));
48
+ const jaAgentContent = await fs.readFile(path.join('test_verify_ja', jaAgentFile), 'utf-8');
49
+
50
+ // Extract just the AI instructions header for JA agent snapshot
51
+ const jaAgentHeader = jaAgentContent.split('## Directory Structure')[0];
52
+
53
+ if (jaAgentHeader.includes('HIERARCHICAL AGENT WORKFLOW')) {
54
+ throw new Error('โŒ JA agent snapshot header should NOT have HIERARCHICAL AGENT WORKFLOW (it uses agent template)');
55
+ }
56
+ // Verify it has the agent template marker
57
+ if (!jaAgentHeader.includes('Project Snapshot Information')) {
58
+ throw new Error('โŒ JA agent snapshot missing agent template marker');
59
+ }
60
+ console.log('โœ… JA agent snapshot (_ja.md): OK (Uses agent template as expected)');
61
+
62
+ } catch (e) {
63
+ console.error('Snapshot verification failed:', e.message);
64
+ process.exit(1);
65
+ }
66
+ }
67
+
68
+ verifySnapshots();