mantiz-cli 0.1.2

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 (3) hide show
  1. package/README.md +65 -0
  2. package/package.json +34 -0
  3. package/src/index.ts +194 -0
package/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # @mantiz/cli
2
+
3
+ **Mantiz CLI — AI lie detector for coding agents.**
4
+
5
+ Scan git diffs for AI agent cheating patterns — like a polygraph for your test suite.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install -g @mantiz/cli
11
+ ```
12
+
13
+ Or run without installation:
14
+
15
+ ```bash
16
+ npx @mantiz/cli
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ```bash
22
+ # Scan your current git diff
23
+ mantiz-scan
24
+
25
+ # Scan with JSON output (for CI)
26
+ mantiz-scan --json
27
+
28
+ # Scan a specific diff file
29
+ mantiz-scan --diff "$(cat my-diff.diff)"
30
+
31
+ # Cloud scan with API token
32
+ mantiz-scan --token mtz_abc123
33
+
34
+ # Help
35
+ mantiz-scan --help
36
+ ```
37
+
38
+ ## CI/CD Integration
39
+
40
+ ```yaml
41
+ # .github/workflows/mantiz.yml
42
+ name: Mantiz Scan
43
+ on: [pull_request]
44
+ jobs:
45
+ scan:
46
+ runs-on: ubuntu-latest
47
+ steps:
48
+ - uses: actions/checkout@v4
49
+ - uses: actions/setup-node@v4
50
+ - run: npx @mantiz/cli --token ${{ secrets.MANTIZ_API_TOKEN }}
51
+ ```
52
+
53
+ Get your API token at: https://mantiz-wine.vercel.app/settings
54
+
55
+ ## Exit Codes
56
+
57
+ - `0` — All clean (Trust Score ≥ 70)
58
+ - `1` — Cheating detected (Trust Score < 70)
59
+
60
+ ## Environment Variables
61
+
62
+ | Variable | Description |
63
+ |----------|-------------|
64
+ | `MANTIZ_API_TOKEN` | API token for cloud scan mode |
65
+ | `MANTIZ_API_URL` | API URL (default: https://mantiz-wine.vercel.app) |
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "mantiz-cli",
3
+ "version": "0.1.2",
4
+ "description": "Mantiz CLI — AI lie detector for coding agents. Scan git diffs for cheating patterns.",
5
+ "type": "module",
6
+ "main": "./src/index.ts",
7
+ "bin": {
8
+ "mantiz-scan": "./src/index.ts"
9
+ },
10
+ "files": [
11
+ "src",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "scan": "tsx src/index.ts"
16
+ },
17
+ "dependencies": {
18
+ "mantiz-core": "0.1.2",
19
+ "tsx": "^4.19.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "22.20.0",
23
+ "typescript": "^6.0.2"
24
+ },
25
+ "keywords": [
26
+ "ai",
27
+ "lie-detector",
28
+ "cheating",
29
+ "test",
30
+ "mantiz",
31
+ "cli"
32
+ ],
33
+ "license": "MIT"
34
+ }
package/src/index.ts ADDED
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * Mantiz CLI — AI Lie Detector for Coding Agents
4
+ *
5
+ * Usage:
6
+ * mantiz-scan # Scan local git diff
7
+ * mantiz-scan --diff <str> # Scan provided diff text
8
+ * mantiz-scan --token x # Send to Mantiz API for cloud scan
9
+ * mantiz-scan --help # Show help
10
+ *
11
+ * Install:
12
+ * npm install -g @mantiz/cli
13
+ */
14
+
15
+ import { execSync } from 'node:child_process'
16
+ import { scanDiff, type ScanResult } from 'mantiz-core'
17
+
18
+ const PASS_THRESHOLD = 70
19
+
20
+ function getGitDiff(): string {
21
+ try {
22
+ const diff = execSync('git diff', { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 })
23
+ if (diff.trim()) return diff
24
+ const staged = execSync('git diff --staged', { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 })
25
+ if (staged.trim()) return staged
26
+ const head = execSync('git diff HEAD~1', { encoding: 'utf-8', maxBuffer: 10 * 1024 * 1024 })
27
+ return head
28
+ } catch {
29
+ return ''
30
+ }
31
+ }
32
+
33
+ function printResults(result: ScanResult): void {
34
+ const scoreColor = result.trustScore >= 80 ? '\x1b[32m' : result.trustScore >= 50 ? '\x1b[33m' : '\x1b[31m'
35
+ const scoreLabel = result.trustScore >= 80 ? 'CLEAN ✅' : result.trustScore >= 50 ? 'SUSPICIOUS 🟡' : 'CHEATING DETECTED 🔴'
36
+ const reset = '\x1b[0m'
37
+ const bold = '\x1b[1m'
38
+ const dim = '\x1b[2m'
39
+
40
+ console.log('\n' + '='.repeat(50))
41
+ console.log(`${bold}🔍 MANTIZ SCAN RESULTS${reset}`)
42
+ console.log('='.repeat(50))
43
+ console.log(`\n${bold}Trust Score:${reset} ${scoreColor}${result.trustScore}/100${reset} ${scoreLabel}`)
44
+ console.log(`${dim}Threshold:${reset} ${PASS_THRESHOLD}${dim} (scores below this will fail)${reset}`)
45
+ console.log(`\n${bold}Summary:${reset}`)
46
+ console.log(` Findings: ${result.summary.totalFindings}`)
47
+ console.log(` Files: ${result.summary.filesScanned}`)
48
+ console.log(` Verdict: ${scoreColor}${scoreLabel}${reset}`)
49
+
50
+ if (result.findings.length > 0) {
51
+ console.log(`\n${bold}Findings:${reset}`)
52
+ for (const f of result.findings) {
53
+ const confColor = f.confidence === 'high' ? '\x1b[31m' : f.confidence === 'medium' ? '\x1b[33m' : '\x1b[90m'
54
+ console.log(` ${confColor}${f.confidence.toUpperCase()}${reset} ${f.filePath}:${f.lineStart}`)
55
+ console.log(` ${dim}${f.explanation}${reset}`)
56
+ }
57
+ } else {
58
+ console.log(`\n ${bold}No cheating detected.${reset} ${dim}Code looks honest.${reset}`)
59
+ }
60
+
61
+ if (result.fixInstructions.length > 0) {
62
+ console.log(`\n${bold}Fix Instructions:${reset}`)
63
+ for (const fi of result.fixInstructions) {
64
+ console.log(` [${fi.patternType}] ${fi.instruction}`)
65
+ }
66
+ }
67
+
68
+ console.log(`\n${dim}${'='.repeat(50)}${reset}\n`)
69
+ }
70
+
71
+ function printHelp(): void {
72
+ console.log(`
73
+ Mantiz CLI — AI Lie Detector for Coding Agents
74
+
75
+ USAGE
76
+ mantiz-scan Scan current git diff
77
+ mantiz-scan --diff <text> Scan provided diff text
78
+ mantiz-scan --token <key> Send to Mantiz cloud API
79
+ mantiz-scan --json Output results as JSON
80
+ mantiz-scan --help Show this help
81
+
82
+ EXIT CODES
83
+ 0 — All clean (Trust Score >= ${PASS_THRESHOLD})
84
+ 1 — Cheating detected (Trust Score < ${PASS_THRESHOLD})
85
+
86
+ ENVIRONMENT VARIABLES
87
+ MANTIZ_API_TOKEN API token for cloud scanning
88
+ MANTIZ_API_URL API URL (default: https://mantiz-wine.vercel.app)
89
+
90
+ EXAMPLES
91
+ mantiz-scan
92
+ cat my-diff.txt | mantiz-scan --diff -
93
+ mantiz-scan --json | jq '.trustScore'
94
+ mantiz-scan --token mtz_abc123
95
+ `)
96
+ }
97
+
98
+ async function main(): Promise<void> {
99
+ const args = process.argv.slice(2)
100
+
101
+ if (args.includes('--help') || args.includes('-h')) {
102
+ printHelp()
103
+ process.exit(0)
104
+ }
105
+
106
+ const jsonOutput = args.includes('--json')
107
+ const tokenIndex = args.indexOf('--token')
108
+ const token = tokenIndex !== -1 ? args[tokenIndex + 1] : process.env.MANTIZ_API_TOKEN
109
+ const diffIndex = args.indexOf('--diff')
110
+ const diffArg = diffIndex !== -1 ? args[diffIndex + 1] : undefined
111
+
112
+ let diffText: string
113
+ if (diffArg) {
114
+ diffText = diffArg === '-' ? execSync('cat', { encoding: 'utf-8' }) : diffArg
115
+ } else {
116
+ diffText = getGitDiff()
117
+ }
118
+
119
+ if (!diffText || !diffText.trim()) {
120
+ if (jsonOutput) {
121
+ console.log(JSON.stringify({ error: 'No git diff found', trustScore: 0 }))
122
+ } else {
123
+ console.log('\x1b[33m⚠️ No git diff found. Run `git add` first or make some changes.\x1b[0m')
124
+ }
125
+ process.exit(1)
126
+ }
127
+
128
+ if (token) {
129
+ const apiUrl = process.env.MANTIZ_API_URL || 'https://mantiz-wine.vercel.app'
130
+ try {
131
+ const res = await fetch(`${apiUrl}/api/scan`, {
132
+ method: 'POST',
133
+ headers: {
134
+ 'Content-Type': 'application/json',
135
+ 'Authorization': `Bearer ${token}`,
136
+ },
137
+ body: JSON.stringify({ diff: diffText }),
138
+ })
139
+
140
+ if (!res.ok) {
141
+ const errBody = await res.text()
142
+ if (jsonOutput) {
143
+ console.log(JSON.stringify({ error: `API error: ${res.status}`, trustScore: 0 }))
144
+ } else {
145
+ console.log(`\x1b[31mAPI error: ${res.status} — ${errBody}\x1b[0m`)
146
+ }
147
+ process.exit(1)
148
+ }
149
+
150
+ const result = await res.json() as { trustScore: number; findings: any[]; summary: any }
151
+
152
+ if (jsonOutput) {
153
+ console.log(JSON.stringify(result, null, 2))
154
+ } else {
155
+ const scoreColor = result.trustScore >= 80 ? '\x1b[32m' : '\x1b[33m'
156
+ console.log(`\n${scoreColor}Trust Score: ${result.trustScore}/100\x1b[0m`)
157
+ console.log(`Findings: ${result.findings.length}`)
158
+ result.findings.slice(0, 5).forEach((f: any) => {
159
+ console.log(` [${f.confidence}] ${f.filePath}:${f.lineStart} — ${f.explanation}`)
160
+ })
161
+ }
162
+
163
+ process.exit(result.trustScore < PASS_THRESHOLD ? 1 : 0)
164
+ } catch (err) {
165
+ if (jsonOutput) {
166
+ console.log(JSON.stringify({ error: `Failed to reach Mantiz API: ${err}`, trustScore: 0 }))
167
+ } else {
168
+ console.log(`\x1b[31mFailed to reach Mantiz API: ${err}\x1b[0m`)
169
+ }
170
+ process.exit(1)
171
+ }
172
+ }
173
+
174
+ const result = scanDiff(diffText)
175
+
176
+ if (jsonOutput) {
177
+ console.log(JSON.stringify({
178
+ trustScore: result.trustScore,
179
+ summary: result.summary,
180
+ findings: result.findings,
181
+ fixInstructions: result.fixInstructions,
182
+ passed: result.trustScore >= PASS_THRESHOLD,
183
+ }, null, 2))
184
+ } else {
185
+ printResults(result)
186
+ }
187
+
188
+ process.exit(result.trustScore < PASS_THRESHOLD ? 1 : 0)
189
+ }
190
+
191
+ main().catch((err) => {
192
+ console.error('Fatal error:', err)
193
+ process.exit(1)
194
+ })