@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 ADDED
@@ -0,0 +1,137 @@
1
+ # Tetrad
2
+
3
+ [![npm](https://img.shields.io/npm/v/tetrad.svg)](https://www.npmjs.com/package/tetrad)
4
+ [![CI](https://github.com/SamoraDC/Tetrad/actions/workflows/ci.yml/badge.svg)](https://github.com/SamoraDC/Tetrad/actions/workflows/ci.yml)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](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
+ });