@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.
- package/LICENSE +21 -0
- package/README.md +106 -0
- package/index.js +14 -0
- package/package.json +64 -9
- package/scripts/mcp-eck-core.js +101 -0
- package/scripts/mcp-glm-zai-worker.mjs +243 -0
- package/scripts/verify_changes.js +68 -0
- package/setup.json +845 -0
- package/src/cli/cli.js +369 -0
- package/src/cli/commands/claudeSettings.js +93 -0
- package/src/cli/commands/consilium.js +86 -0
- package/src/cli/commands/createSnapshot.js +906 -0
- package/src/cli/commands/detectProfiles.js +98 -0
- package/src/cli/commands/detectProject.js +112 -0
- package/src/cli/commands/doctor.js +60 -0
- package/src/cli/commands/envSync.js +319 -0
- package/src/cli/commands/generateProfileGuide.js +144 -0
- package/src/cli/commands/pruneSnapshot.js +106 -0
- package/src/cli/commands/restoreSnapshot.js +173 -0
- package/src/cli/commands/setupGemini.js +149 -0
- package/src/cli/commands/setupGemini.test.js +115 -0
- package/src/cli/commands/setupMcp.js +269 -0
- package/src/cli/commands/showFile.js +39 -0
- package/src/cli/commands/trainTokens.js +38 -0
- package/src/cli/commands/updateSnapshot.js +219 -0
- package/src/config.js +125 -0
- package/src/core/skeletonizer.js +201 -0
- package/src/mcp-server/index.js +211 -0
- package/src/services/claudeCliService.js +626 -0
- package/src/services/claudeCliService.test.js +267 -0
- package/src/templates/agent-prompt.template.md +43 -0
- package/src/templates/architect-prompt.template.md +164 -0
- package/src/templates/claude-code/README.md +105 -0
- package/src/templates/claude-code/mcp-config-template.json +11 -0
- package/src/templates/claude-code/mcp-server-template.js +206 -0
- package/src/templates/claude-code/settings-claude.json +1 -0
- package/src/templates/envScanRequest.md +4 -0
- package/src/templates/gitWorkflow.md +32 -0
- package/src/templates/multiAgent.md +118 -0
- package/src/templates/opencode/coder.template.md +22 -0
- package/src/templates/opencode/junior-architect.template.md +85 -0
- package/src/templates/skeleton-instruction.md +16 -0
- package/src/templates/update-prompt.template.md +19 -0
- package/src/utils/aiHeader.js +678 -0
- package/src/utils/claudeMdGenerator.js +148 -0
- package/src/utils/eckProtocolParser.js +221 -0
- package/src/utils/fileUtils.js +1017 -0
- package/src/utils/gitUtils.js +44 -0
- package/src/utils/opencodeAgentsGenerator.js +271 -0
- package/src/utils/projectDetector.js +704 -0
- 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.
|
|
4
|
-
"description": "
|
|
5
|
-
"main": "index.js",
|
|
6
|
-
"
|
|
7
|
-
|
|
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();
|