@samoradc/tetrad 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +137 -0
- package/bin/tetrad.js +47 -0
- package/package.json +53 -0
- package/scripts/install.js +187 -0
package/README.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# Tetrad
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/tetrad)
|
|
4
|
+
[](https://github.com/SamoraDC/Tetrad/actions/workflows/ci.yml)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
> Quadruple Consensus MCP Server for Claude Code
|
|
8
|
+
|
|
9
|
+
**Tetrad** is a high-performance MCP (Model Context Protocol) server that orchestrates three AI-powered CLI tools (Codex, Gemini CLI, Qwen) to validate all code produced by Claude Code.
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### 1. Initialize in your project
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx tetrad init
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
This will:
|
|
20
|
+
- Create `tetrad.toml` configuration file
|
|
21
|
+
- Create `.tetrad/` directory for the database
|
|
22
|
+
- Add `.tetrad/` to your `.gitignore`
|
|
23
|
+
|
|
24
|
+
### 2. Add to Claude Code
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Add as MCP server (available in all projects)
|
|
28
|
+
claude mcp add --scope user tetrad -- npx tetrad serve
|
|
29
|
+
|
|
30
|
+
# Or for current project only
|
|
31
|
+
claude mcp add tetrad -- npx tetrad serve
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 3. Verify
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Check version
|
|
38
|
+
npx tetrad version
|
|
39
|
+
|
|
40
|
+
# Check CLI availability
|
|
41
|
+
npx tetrad status
|
|
42
|
+
|
|
43
|
+
# Diagnose issues
|
|
44
|
+
npx tetrad doctor
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Commands
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npx tetrad init # Initialize config in current directory
|
|
51
|
+
npx tetrad serve # Start MCP server (used by Claude Code)
|
|
52
|
+
npx tetrad status # Show CLI status (codex, gemini, qwen)
|
|
53
|
+
npx tetrad config # Interactive configuration
|
|
54
|
+
npx tetrad doctor # Diagnose configuration issues
|
|
55
|
+
npx tetrad version # Show version
|
|
56
|
+
npx tetrad evaluate -c CODE # Manual code evaluation (without MCP)
|
|
57
|
+
npx tetrad history # Show evaluation history from ReasoningBank
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Manual MCP Configuration
|
|
61
|
+
|
|
62
|
+
Add to your `.mcp.json`:
|
|
63
|
+
|
|
64
|
+
```json
|
|
65
|
+
{
|
|
66
|
+
"mcpServers": {
|
|
67
|
+
"tetrad": {
|
|
68
|
+
"type": "stdio",
|
|
69
|
+
"command": "npx",
|
|
70
|
+
"args": ["tetrad", "serve"]
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Requirements
|
|
77
|
+
|
|
78
|
+
Tetrad requires at least one of these AI CLI tools:
|
|
79
|
+
|
|
80
|
+
- **Codex CLI** (OpenAI): `npm install -g @openai/codex`
|
|
81
|
+
- **Gemini CLI** (Google): `npm install -g @google/gemini-cli`
|
|
82
|
+
- **Qwen CLI** (Alibaba): `pip install dashscope`
|
|
83
|
+
|
|
84
|
+
## Features
|
|
85
|
+
|
|
86
|
+
- **Quadruple Consensus**: 4 AI models must agree to approve code
|
|
87
|
+
- **ReasoningBank**: Continuous learning system with SQLite
|
|
88
|
+
- **High Performance**: Written in Rust
|
|
89
|
+
- **LRU Cache**: Result caching with configurable TTL
|
|
90
|
+
- **Hook System**: Pre/post evaluation callbacks
|
|
91
|
+
- **Auto .gitignore**: Automatically ignores local data
|
|
92
|
+
|
|
93
|
+
## Configuration
|
|
94
|
+
|
|
95
|
+
After `npx tetrad init`, edit `tetrad.toml`:
|
|
96
|
+
|
|
97
|
+
```toml
|
|
98
|
+
[general]
|
|
99
|
+
log_level = "info"
|
|
100
|
+
timeout_secs = 60
|
|
101
|
+
|
|
102
|
+
[executors.codex]
|
|
103
|
+
enabled = true
|
|
104
|
+
command = "codex"
|
|
105
|
+
args = ["exec", "--json"]
|
|
106
|
+
|
|
107
|
+
[executors.gemini]
|
|
108
|
+
enabled = true
|
|
109
|
+
command = "gemini"
|
|
110
|
+
args = ["-o", "json"]
|
|
111
|
+
|
|
112
|
+
[executors.qwen]
|
|
113
|
+
enabled = true
|
|
114
|
+
command = "qwen"
|
|
115
|
+
|
|
116
|
+
[consensus]
|
|
117
|
+
default_rule = "strong" # golden, strong, weak
|
|
118
|
+
min_score = 70
|
|
119
|
+
max_loops = 3
|
|
120
|
+
|
|
121
|
+
[reasoning]
|
|
122
|
+
enabled = true
|
|
123
|
+
db_path = ".tetrad/tetrad.db"
|
|
124
|
+
|
|
125
|
+
[cache]
|
|
126
|
+
enabled = true
|
|
127
|
+
capacity = 1000
|
|
128
|
+
ttl_secs = 300
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Documentation
|
|
132
|
+
|
|
133
|
+
Full documentation: [GitHub Repository](https://github.com/SamoraDC/Tetrad)
|
|
134
|
+
|
|
135
|
+
## License
|
|
136
|
+
|
|
137
|
+
MIT
|
package/bin/tetrad.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Tetrad MCP - CLI wrapper
|
|
5
|
+
*
|
|
6
|
+
* This script executes the Tetrad binary with the provided arguments.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { spawn } = require('child_process');
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
|
|
13
|
+
const BINARY_NAME = process.platform === 'win32' ? 'tetrad.exe' : 'tetrad';
|
|
14
|
+
const binaryPath = path.join(__dirname, BINARY_NAME);
|
|
15
|
+
|
|
16
|
+
// Check if binary exists
|
|
17
|
+
if (!fs.existsSync(binaryPath)) {
|
|
18
|
+
console.error('Error: Tetrad binary not found.');
|
|
19
|
+
console.error('');
|
|
20
|
+
console.error('The binary should have been installed during npm install.');
|
|
21
|
+
console.error('Try reinstalling: npm install -g tetrad');
|
|
22
|
+
console.error('');
|
|
23
|
+
console.error('Or install manually:');
|
|
24
|
+
console.error(' cargo install tetrad');
|
|
25
|
+
console.error(' sudo cp ~/.cargo/bin/tetrad /usr/local/bin/');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Pass all arguments to the binary
|
|
30
|
+
const args = process.argv.slice(2);
|
|
31
|
+
|
|
32
|
+
const child = spawn(binaryPath, args, {
|
|
33
|
+
stdio: 'inherit',
|
|
34
|
+
env: process.env,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
child.on('error', (err) => {
|
|
38
|
+
console.error(`Failed to start Tetrad: ${err.message}`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
child.on('exit', (code, signal) => {
|
|
43
|
+
if (signal) {
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
process.exit(code || 0);
|
|
47
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@samoradc/tetrad",
|
|
3
|
+
"version": "0.1.6",
|
|
4
|
+
"description": "Quadruple Consensus MCP Server for Claude Code - Validates code using Codex, Gemini and Qwen",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"claude",
|
|
8
|
+
"claude-code",
|
|
9
|
+
"code-review",
|
|
10
|
+
"ai",
|
|
11
|
+
"consensus",
|
|
12
|
+
"codex",
|
|
13
|
+
"gemini",
|
|
14
|
+
"qwen"
|
|
15
|
+
],
|
|
16
|
+
"author": "SamoraDC",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/SamoraDC/Tetrad.git"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/SamoraDC/Tetrad#readme",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/SamoraDC/Tetrad/issues"
|
|
25
|
+
},
|
|
26
|
+
"bin": {
|
|
27
|
+
"tetrad": "bin/tetrad.js"
|
|
28
|
+
},
|
|
29
|
+
"scripts": {
|
|
30
|
+
"postinstall": "node scripts/install.js"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"tar": "^6.2.0",
|
|
34
|
+
"adm-zip": "^0.5.10"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"bin/",
|
|
38
|
+
"scripts/",
|
|
39
|
+
"README.md"
|
|
40
|
+
],
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=16.0.0"
|
|
43
|
+
},
|
|
44
|
+
"os": [
|
|
45
|
+
"darwin",
|
|
46
|
+
"linux",
|
|
47
|
+
"win32"
|
|
48
|
+
],
|
|
49
|
+
"cpu": [
|
|
50
|
+
"x64",
|
|
51
|
+
"arm64"
|
|
52
|
+
]
|
|
53
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Tetrad MCP - Binary installer
|
|
5
|
+
*
|
|
6
|
+
* Downloads the correct pre-compiled binary for the current platform
|
|
7
|
+
* from GitHub Releases.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const https = require('https');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const { execSync } = require('child_process');
|
|
14
|
+
const zlib = require('zlib');
|
|
15
|
+
|
|
16
|
+
const PACKAGE_VERSION = require('../package.json').version;
|
|
17
|
+
const GITHUB_REPO = 'SamoraDC/Tetrad';
|
|
18
|
+
const BINARY_NAME = process.platform === 'win32' ? 'tetrad.exe' : 'tetrad';
|
|
19
|
+
|
|
20
|
+
// Map Node.js platform/arch to Rust target triples
|
|
21
|
+
const PLATFORM_MAP = {
|
|
22
|
+
'darwin-x64': 'x86_64-apple-darwin',
|
|
23
|
+
'darwin-arm64': 'aarch64-apple-darwin',
|
|
24
|
+
'linux-x64': 'x86_64-unknown-linux-gnu',
|
|
25
|
+
'linux-arm64': 'aarch64-unknown-linux-gnu',
|
|
26
|
+
'win32-x64': 'x86_64-pc-windows-msvc',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
function getPlatformKey() {
|
|
30
|
+
return `${process.platform}-${process.arch}`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getTargetTriple() {
|
|
34
|
+
const key = getPlatformKey();
|
|
35
|
+
const triple = PLATFORM_MAP[key];
|
|
36
|
+
|
|
37
|
+
if (!triple) {
|
|
38
|
+
console.error(`Unsupported platform: ${key}`);
|
|
39
|
+
console.error(`Supported platforms: ${Object.keys(PLATFORM_MAP).join(', ')}`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return triple;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getDownloadUrl(version, target) {
|
|
47
|
+
const ext = process.platform === 'win32' ? 'zip' : 'tar.gz';
|
|
48
|
+
return `https://github.com/${GITHUB_REPO}/releases/download/v${version}/tetrad-${target}.${ext}`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function downloadFile(url) {
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
const followRedirects = (url, redirectCount = 0) => {
|
|
54
|
+
if (redirectCount > 5) {
|
|
55
|
+
reject(new Error('Too many redirects'));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
https.get(url, (response) => {
|
|
60
|
+
if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
|
|
61
|
+
followRedirects(response.headers.location, redirectCount + 1);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (response.statusCode !== 200) {
|
|
66
|
+
reject(new Error(`Failed to download: HTTP ${response.statusCode}`));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const chunks = [];
|
|
71
|
+
response.on('data', (chunk) => chunks.push(chunk));
|
|
72
|
+
response.on('end', () => resolve(Buffer.concat(chunks)));
|
|
73
|
+
response.on('error', reject);
|
|
74
|
+
}).on('error', reject);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
followRedirects(url);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function extractTarGz(buffer, destDir) {
|
|
82
|
+
const tar = require('tar');
|
|
83
|
+
const tmpFile = path.join(destDir, 'temp.tar.gz');
|
|
84
|
+
|
|
85
|
+
// Write buffer to temp file
|
|
86
|
+
fs.writeFileSync(tmpFile, buffer);
|
|
87
|
+
|
|
88
|
+
// Extract using tar
|
|
89
|
+
await tar.extract({
|
|
90
|
+
file: tmpFile,
|
|
91
|
+
cwd: destDir,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Clean up temp file
|
|
95
|
+
fs.unlinkSync(tmpFile);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function extractZip(buffer, destDir) {
|
|
99
|
+
const AdmZip = require('adm-zip');
|
|
100
|
+
const zip = new AdmZip(buffer);
|
|
101
|
+
zip.extractAllTo(destDir, true);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function installBinaryFromCargo() {
|
|
105
|
+
console.log('Attempting to install via cargo...');
|
|
106
|
+
try {
|
|
107
|
+
execSync('cargo install tetrad', { stdio: 'inherit' });
|
|
108
|
+
|
|
109
|
+
// Find the installed binary
|
|
110
|
+
const cargoHome = process.env.CARGO_HOME || path.join(require('os').homedir(), '.cargo');
|
|
111
|
+
const cargoBin = path.join(cargoHome, 'bin', BINARY_NAME);
|
|
112
|
+
|
|
113
|
+
if (fs.existsSync(cargoBin)) {
|
|
114
|
+
const destPath = path.join(__dirname, '..', 'bin', BINARY_NAME);
|
|
115
|
+
fs.copyFileSync(cargoBin, destPath);
|
|
116
|
+
fs.chmodSync(destPath, 0o755);
|
|
117
|
+
console.log('Successfully installed tetrad via cargo');
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
} catch (err) {
|
|
121
|
+
console.log('Cargo installation failed, will try GitHub releases...');
|
|
122
|
+
}
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function main() {
|
|
127
|
+
const binDir = path.join(__dirname, '..', 'bin');
|
|
128
|
+
const binaryPath = path.join(binDir, BINARY_NAME);
|
|
129
|
+
|
|
130
|
+
// Skip if binary already exists
|
|
131
|
+
if (fs.existsSync(binaryPath)) {
|
|
132
|
+
console.log('Tetrad binary already installed');
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Ensure bin directory exists
|
|
137
|
+
if (!fs.existsSync(binDir)) {
|
|
138
|
+
fs.mkdirSync(binDir, { recursive: true });
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const target = getTargetTriple();
|
|
142
|
+
const url = getDownloadUrl(PACKAGE_VERSION, target);
|
|
143
|
+
|
|
144
|
+
console.log(`Installing Tetrad v${PACKAGE_VERSION} for ${target}...`);
|
|
145
|
+
console.log(`Downloading from: ${url}`);
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
const buffer = await downloadFile(url);
|
|
149
|
+
|
|
150
|
+
if (process.platform === 'win32') {
|
|
151
|
+
await extractZip(buffer, binDir);
|
|
152
|
+
} else {
|
|
153
|
+
await extractTarGz(buffer, binDir);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Make binary executable
|
|
157
|
+
if (process.platform !== 'win32') {
|
|
158
|
+
fs.chmodSync(binaryPath, 0o755);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
console.log('Tetrad installed successfully!');
|
|
162
|
+
|
|
163
|
+
} catch (err) {
|
|
164
|
+
console.error(`Failed to download pre-built binary: ${err.message}`);
|
|
165
|
+
console.log('');
|
|
166
|
+
console.log('Trying fallback installation via cargo...');
|
|
167
|
+
|
|
168
|
+
const cargoInstalled = await installBinaryFromCargo();
|
|
169
|
+
|
|
170
|
+
if (!cargoInstalled) {
|
|
171
|
+
console.error('');
|
|
172
|
+
console.error('Could not install Tetrad automatically.');
|
|
173
|
+
console.error('');
|
|
174
|
+
console.error('Please install manually:');
|
|
175
|
+
console.error(' 1. Install Rust: https://rustup.rs/');
|
|
176
|
+
console.error(' 2. Run: cargo install tetrad');
|
|
177
|
+
console.error(' 3. Copy binary: sudo cp ~/.cargo/bin/tetrad /usr/local/bin/');
|
|
178
|
+
console.error('');
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
main().catch((err) => {
|
|
185
|
+
console.error('Installation failed:', err);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
});
|