@vibecheckai/cli 3.2.6 → 3.3.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/bin/registry.js +192 -5
- package/bin/runners/lib/agent-firewall/change-packet/builder.js +280 -6
- package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
- package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
- package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
- package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
- package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
- package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
- package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
- package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
- package/bin/runners/lib/agent-firewall/logger.js +141 -0
- package/bin/runners/lib/agent-firewall/policy/loader.js +312 -4
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +113 -1
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +133 -6
- package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
- package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
- package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
- package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
- package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
- package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
- package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
- package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
- package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
- package/bin/runners/lib/agent-firewall/risk/thresholds.js +321 -0
- package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
- package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
- package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
- package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
- package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
- package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
- package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
- package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
- package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
- package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
- package/bin/runners/lib/analyzers.js +81 -18
- package/bin/runners/lib/authority-badge.js +425 -0
- package/bin/runners/lib/cli-output.js +7 -1
- package/bin/runners/lib/error-handler.js +16 -9
- package/bin/runners/lib/exit-codes.js +275 -0
- package/bin/runners/lib/global-flags.js +37 -0
- package/bin/runners/lib/help-formatter.js +413 -0
- package/bin/runners/lib/logger.js +38 -0
- package/bin/runners/lib/unified-cli-output.js +604 -0
- package/bin/runners/lib/upsell.js +148 -0
- package/bin/runners/runApprove.js +1200 -0
- package/bin/runners/runAuth.js +324 -95
- package/bin/runners/runCheckpoint.js +39 -21
- package/bin/runners/runClassify.js +859 -0
- package/bin/runners/runContext.js +136 -24
- package/bin/runners/runDoctor.js +108 -68
- package/bin/runners/runFix.js +6 -5
- package/bin/runners/runGuard.js +212 -118
- package/bin/runners/runInit.js +3 -2
- package/bin/runners/runMcp.js +130 -52
- package/bin/runners/runPolish.js +43 -20
- package/bin/runners/runProve.js +1 -2
- package/bin/runners/runReport.js +3 -2
- package/bin/runners/runScan.js +63 -44
- package/bin/runners/runShip.js +3 -4
- package/bin/runners/runValidate.js +19 -2
- package/bin/runners/runWatch.js +104 -53
- package/bin/vibecheck.js +106 -19
- package/mcp-server/HARDENING_SUMMARY.md +299 -0
- package/mcp-server/agent-firewall-interceptor.js +367 -31
- package/mcp-server/authority-tools.js +569 -0
- package/mcp-server/conductor/conflict-resolver.js +588 -0
- package/mcp-server/conductor/execution-planner.js +544 -0
- package/mcp-server/conductor/index.js +377 -0
- package/mcp-server/conductor/lock-manager.js +615 -0
- package/mcp-server/conductor/request-queue.js +550 -0
- package/mcp-server/conductor/session-manager.js +500 -0
- package/mcp-server/conductor/tools.js +510 -0
- package/mcp-server/index.js +1149 -243
- package/mcp-server/lib/{api-client.js → api-client.cjs} +40 -4
- package/mcp-server/lib/logger.cjs +30 -0
- package/mcp-server/logger.js +173 -0
- package/mcp-server/package.json +2 -2
- package/mcp-server/premium-tools.js +2 -2
- package/mcp-server/tier-auth.js +245 -35
- package/mcp-server/truth-firewall-tools.js +145 -15
- package/mcp-server/vibecheck-tools.js +2 -2
- package/package.json +2 -3
- package/mcp-server/index.old.js +0 -4137
- package/mcp-server/package-lock.json +0 -165
package/bin/runners/runGuard.js
CHANGED
|
@@ -1,73 +1,127 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* vibecheck guard - Unified trust boundary enforcement
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* vibecheck guard # Run all checks
|
|
8
|
-
* vibecheck guard --claims # Verify AI claims against truthpack
|
|
9
|
-
* vibecheck guard --prompts # Check for prompt injection
|
|
10
|
-
* vibecheck guard --hallucinations # Detect AI hallucination patterns
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
* World-Class AI Guardrails
|
|
6
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
11
7
|
*/
|
|
12
8
|
|
|
13
9
|
const path = require("path");
|
|
14
10
|
const fs = require("fs");
|
|
11
|
+
const { parseGlobalFlags, shouldSuppressOutput, isJsonMode } = require("./lib/global-flags");
|
|
12
|
+
const { EXIT } = require("./lib/exit-codes");
|
|
13
|
+
const {
|
|
14
|
+
ansi,
|
|
15
|
+
sym,
|
|
16
|
+
renderMinimalHeader,
|
|
17
|
+
renderSectionHeader,
|
|
18
|
+
renderVerdict,
|
|
19
|
+
renderSuccess,
|
|
20
|
+
renderError,
|
|
21
|
+
renderWarning,
|
|
22
|
+
renderFooter,
|
|
23
|
+
Spinner,
|
|
24
|
+
getTierFromKey,
|
|
25
|
+
} = require("./lib/unified-cli-output");
|
|
15
26
|
|
|
16
27
|
// Import underlying implementations
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
red: "\x1b[31m",
|
|
29
|
-
magenta: "\x1b[35m",
|
|
30
|
-
};
|
|
28
|
+
let runValidate, runPromptFirewall;
|
|
29
|
+
try {
|
|
30
|
+
runValidate = require("./runValidate").runValidate;
|
|
31
|
+
} catch {
|
|
32
|
+
runValidate = null;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
runPromptFirewall = require("./runPromptFirewall").runPromptFirewall;
|
|
36
|
+
} catch {
|
|
37
|
+
runPromptFirewall = null;
|
|
38
|
+
}
|
|
31
39
|
|
|
32
40
|
function printHelp() {
|
|
33
41
|
console.log(`
|
|
34
|
-
${
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
${
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
42
|
+
${ansi.bold}USAGE${ansi.reset}
|
|
43
|
+
${ansi.cyan}vibecheck guard${ansi.reset} [options]
|
|
44
|
+
|
|
45
|
+
${ansi.dim}Aliases: ai-guard, firewall, validate${ansi.reset}
|
|
46
|
+
|
|
47
|
+
Validate AI-generated code and prompts. Detects prompt injection attempts,
|
|
48
|
+
verifies claims against your codebase (hallucination checking), and ensures
|
|
49
|
+
AI outputs meet your standards.
|
|
50
|
+
|
|
51
|
+
${ansi.bold}CHECK MODES${ansi.reset}
|
|
52
|
+
${ansi.cyan}--claims${ansi.reset} Verify AI claims against truthpack
|
|
53
|
+
${ansi.cyan}--prompts${ansi.reset} Check code for prompt injection
|
|
54
|
+
${ansi.cyan}--hallucinations${ansi.reset} Detect AI hallucination patterns
|
|
55
|
+
${ansi.dim}(default: run all checks)${ansi.reset}
|
|
56
|
+
|
|
57
|
+
${ansi.bold}OPTIONS${ansi.reset}
|
|
58
|
+
${ansi.cyan}--file <path>${ansi.reset} Check specific file(s)
|
|
59
|
+
${ansi.cyan}--strict${ansi.reset} Fail on warnings (default: fail on errors only)
|
|
60
|
+
${ansi.cyan}--json${ansi.reset} Output as JSON (CI integration)
|
|
61
|
+
${ansi.cyan}--quiet, -q${ansi.reset} Suppress non-essential output
|
|
62
|
+
${ansi.cyan}--help, -h${ansi.reset} Show this help
|
|
63
|
+
|
|
64
|
+
${ansi.bold}EXAMPLES${ansi.reset}
|
|
65
|
+
${ansi.dim}# Run all guardrail checks${ansi.reset}
|
|
66
|
+
vibecheck guard
|
|
67
|
+
|
|
68
|
+
${ansi.dim}# Verify AI claims in specific file${ansi.reset}
|
|
69
|
+
vibecheck guard --claims --file api.ts
|
|
70
|
+
|
|
71
|
+
${ansi.dim}# Prompt injection scan only${ansi.reset}
|
|
72
|
+
vibecheck guard --prompts
|
|
73
|
+
|
|
74
|
+
${ansi.dim}# CI pipeline (strict, JSON output)${ansi.reset}
|
|
75
|
+
vibecheck guard --strict --json
|
|
76
|
+
|
|
77
|
+
${ansi.bold}EXIT CODES${ansi.reset}
|
|
78
|
+
0 All checks passed
|
|
79
|
+
1 Warnings found (non-blocking)
|
|
80
|
+
2 Errors found (blocking issues)
|
|
81
|
+
|
|
82
|
+
${ansi.dim}────────────────────────────────────────────────────────────────────${ansi.reset}
|
|
83
|
+
${ansi.dim}Documentation: https://docs.vibecheckai.dev/cli/guard${ansi.reset}
|
|
56
84
|
`);
|
|
57
85
|
}
|
|
58
86
|
|
|
59
87
|
async function runGuard(args = []) {
|
|
88
|
+
const { flags: globalFlags } = parseGlobalFlags(args);
|
|
89
|
+
const quiet = shouldSuppressOutput(globalFlags);
|
|
90
|
+
const json = isJsonMode(globalFlags) || args.includes("--json");
|
|
91
|
+
const startTime = Date.now();
|
|
92
|
+
|
|
60
93
|
// Parse arguments
|
|
61
|
-
if (args.includes("--help") || args.includes("-h")) {
|
|
94
|
+
if (globalFlags.help || args.includes("--help") || args.includes("-h")) {
|
|
62
95
|
printHelp();
|
|
63
|
-
return
|
|
96
|
+
return EXIT.SUCCESS;
|
|
64
97
|
}
|
|
65
98
|
|
|
66
99
|
const runClaims = args.includes("--claims") || (!args.includes("--prompts") && !args.includes("--hallucinations"));
|
|
67
100
|
const runPrompts = args.includes("--prompts") || (!args.includes("--claims") && !args.includes("--hallucinations"));
|
|
68
101
|
const runHallucinations = args.includes("--hallucinations") || (!args.includes("--claims") && !args.includes("--prompts"));
|
|
69
|
-
const jsonOutput = args.includes("--json");
|
|
70
102
|
const strict = args.includes("--strict");
|
|
103
|
+
|
|
104
|
+
// Validate --file if provided
|
|
105
|
+
const fileIndex = args.indexOf("--file");
|
|
106
|
+
if (fileIndex !== -1) {
|
|
107
|
+
const filePath = args[fileIndex + 1];
|
|
108
|
+
if (!filePath || filePath.startsWith("--")) {
|
|
109
|
+
if (json) {
|
|
110
|
+
console.log(JSON.stringify({ success: false, error: "--file requires a path argument" }));
|
|
111
|
+
} else {
|
|
112
|
+
renderError("--file requires a path argument");
|
|
113
|
+
}
|
|
114
|
+
return EXIT.USER_ERROR;
|
|
115
|
+
}
|
|
116
|
+
if (!fs.existsSync(filePath)) {
|
|
117
|
+
if (json) {
|
|
118
|
+
console.log(JSON.stringify({ success: false, error: `File not found: ${filePath}` }));
|
|
119
|
+
} else {
|
|
120
|
+
renderError(`File not found: ${filePath}`);
|
|
121
|
+
}
|
|
122
|
+
return EXIT.NOT_FOUND;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
71
125
|
|
|
72
126
|
const results = {
|
|
73
127
|
claims: null,
|
|
@@ -78,91 +132,131 @@ async function runGuard(args = []) {
|
|
|
78
132
|
warnings: 0,
|
|
79
133
|
};
|
|
80
134
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
135
|
+
try {
|
|
136
|
+
if (!quiet && !json) {
|
|
137
|
+
renderMinimalHeader("guard", "starter");
|
|
138
|
+
renderSectionHeader("Trust Boundary Checks", sym.shield);
|
|
139
|
+
}
|
|
86
140
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
141
|
+
// Run claims verification
|
|
142
|
+
if (runClaims) {
|
|
143
|
+
const spinner = !quiet && !json ? new Spinner("Verifying AI claims against truthpack").start() : null;
|
|
144
|
+
|
|
145
|
+
if (!runValidate) {
|
|
146
|
+
results.claims = { skipped: true, reason: "Validator module not available" };
|
|
147
|
+
spinner?.warn("Claims check skipped: module not available");
|
|
148
|
+
} else {
|
|
149
|
+
try {
|
|
150
|
+
const validateArgs = args.filter(a => !["--claims", "--prompts", "--hallucinations"].includes(a));
|
|
151
|
+
const exitCode = await runValidate(validateArgs);
|
|
152
|
+
results.claims = { exitCode, status: exitCode === 0 ? "pass" : "fail" };
|
|
153
|
+
if (exitCode !== 0) {
|
|
154
|
+
results.errors++;
|
|
155
|
+
results.verdict = "FAIL";
|
|
156
|
+
spinner?.fail("Claim verification failed");
|
|
157
|
+
} else {
|
|
158
|
+
spinner?.succeed("Claims verified");
|
|
159
|
+
}
|
|
160
|
+
} catch (e) {
|
|
161
|
+
results.claims = { error: e.message };
|
|
162
|
+
spinner?.warn(`Claims check failed: ${e.message}`);
|
|
163
|
+
}
|
|
97
164
|
}
|
|
98
|
-
console.log(exitCode === 0
|
|
99
|
-
? ` ${c.green}✓${c.reset} Claims verified`
|
|
100
|
-
: ` ${c.red}✗${c.reset} Claim verification failed`);
|
|
101
|
-
} catch (e) {
|
|
102
|
-
results.claims = { error: e.message };
|
|
103
|
-
console.log(` ${c.yellow}⚠${c.reset} Claims check skipped: ${e.message}`);
|
|
104
165
|
}
|
|
105
|
-
}
|
|
106
166
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
167
|
+
// Run prompt injection detection
|
|
168
|
+
if (runPrompts) {
|
|
169
|
+
const spinner = !quiet && !json ? new Spinner("Scanning for prompt injection vulnerabilities").start() : null;
|
|
170
|
+
|
|
171
|
+
if (!runPromptFirewall) {
|
|
172
|
+
results.prompts = { skipped: true, reason: "Firewall module not available" };
|
|
173
|
+
spinner?.warn("Prompt check skipped: module not available");
|
|
174
|
+
} else {
|
|
175
|
+
try {
|
|
176
|
+
const firewallArgs = args.filter(a => !["--claims", "--prompts", "--hallucinations"].includes(a));
|
|
177
|
+
const exitCode = await runPromptFirewall(firewallArgs);
|
|
178
|
+
results.prompts = { exitCode, status: exitCode === 0 ? "pass" : "fail" };
|
|
179
|
+
if (exitCode !== 0) {
|
|
180
|
+
results.warnings++;
|
|
181
|
+
if (strict) results.verdict = "FAIL";
|
|
182
|
+
spinner?.warn("Prompt injection risks detected");
|
|
183
|
+
} else {
|
|
184
|
+
spinner?.succeed("No prompt injection risks");
|
|
185
|
+
}
|
|
186
|
+
} catch (e) {
|
|
187
|
+
results.prompts = { error: e.message };
|
|
188
|
+
spinner?.warn(`Prompt check failed: ${e.message}`);
|
|
189
|
+
}
|
|
117
190
|
}
|
|
118
|
-
console.log(exitCode === 0
|
|
119
|
-
? ` ${c.green}✓${c.reset} No prompt injection risks`
|
|
120
|
-
: ` ${c.yellow}⚠${c.reset} Prompt injection risks detected`);
|
|
121
|
-
} catch (e) {
|
|
122
|
-
results.prompts = { error: e.message };
|
|
123
|
-
console.log(` ${c.yellow}⚠${c.reset} Prompt check skipped: ${e.message}`);
|
|
124
191
|
}
|
|
125
|
-
}
|
|
126
192
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
193
|
+
// Run hallucination detection
|
|
194
|
+
if (runHallucinations) {
|
|
195
|
+
const spinner = !quiet && !json ? new Spinner("Detecting hallucination patterns").start() : null;
|
|
196
|
+
|
|
197
|
+
if (!runValidate) {
|
|
198
|
+
results.hallucinations = { skipped: true, reason: "Validator module not available" };
|
|
199
|
+
spinner?.warn("Hallucination check skipped: module not available");
|
|
200
|
+
} else {
|
|
201
|
+
try {
|
|
202
|
+
const validateArgs = ["--hallucinations", ...args.filter(a => !["--claims", "--prompts", "--hallucinations"].includes(a))];
|
|
203
|
+
const exitCode = await runValidate(validateArgs);
|
|
204
|
+
results.hallucinations = { exitCode, status: exitCode === 0 ? "pass" : "fail" };
|
|
205
|
+
if (exitCode !== 0) {
|
|
206
|
+
results.warnings++;
|
|
207
|
+
if (strict) results.verdict = "FAIL";
|
|
208
|
+
spinner?.warn("Potential hallucinations detected");
|
|
209
|
+
} else {
|
|
210
|
+
spinner?.succeed("No hallucination patterns");
|
|
211
|
+
}
|
|
212
|
+
} catch (e) {
|
|
213
|
+
results.hallucinations = { error: e.message };
|
|
214
|
+
spinner?.warn(`Hallucination check failed: ${e.message}`);
|
|
215
|
+
}
|
|
138
216
|
}
|
|
139
|
-
console.log(exitCode === 0
|
|
140
|
-
? ` ${c.green}✓${c.reset} No hallucination patterns`
|
|
141
|
-
: ` ${c.yellow}⚠${c.reset} Potential hallucinations detected`);
|
|
142
|
-
} catch (e) {
|
|
143
|
-
results.hallucinations = { error: e.message };
|
|
144
|
-
console.log(` ${c.yellow}⚠${c.reset} Hallucination check skipped: ${e.message}`);
|
|
145
217
|
}
|
|
146
|
-
}
|
|
147
218
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
219
|
+
// Summary
|
|
220
|
+
const duration = Date.now() - startTime;
|
|
221
|
+
|
|
222
|
+
if (!quiet && !json) {
|
|
223
|
+
renderVerdict(results.verdict === "PASS" ? "PASS" : "FAIL", {
|
|
224
|
+
warnings: results.warnings,
|
|
225
|
+
critical: results.errors,
|
|
226
|
+
duration,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
renderFooter({
|
|
230
|
+
nextSteps: results.verdict === "PASS" ? [
|
|
231
|
+
{ cmd: "vibecheck scan", desc: "run full code analysis" },
|
|
232
|
+
{ cmd: "vibecheck ship", desc: "get ship verdict" },
|
|
233
|
+
] : [
|
|
234
|
+
{ cmd: "vibecheck fix --plan-only", desc: "view fix recommendations" },
|
|
235
|
+
],
|
|
236
|
+
docsUrl: "https://docs.vibecheckai.dev/cli/guard",
|
|
237
|
+
});
|
|
238
|
+
}
|
|
157
239
|
|
|
158
|
-
|
|
159
|
-
|
|
240
|
+
if (json) {
|
|
241
|
+
console.log(JSON.stringify({ ...results, duration }, null, 2));
|
|
242
|
+
}
|
|
160
243
|
|
|
161
|
-
|
|
162
|
-
|
|
244
|
+
// Return appropriate exit code
|
|
245
|
+
if (results.verdict === "PASS") {
|
|
246
|
+
return EXIT.SUCCESS;
|
|
247
|
+
} else if (results.errors > 0) {
|
|
248
|
+
return EXIT.BLOCKING;
|
|
249
|
+
} else {
|
|
250
|
+
return EXIT.WARNINGS;
|
|
251
|
+
}
|
|
252
|
+
} catch (error) {
|
|
253
|
+
if (json) {
|
|
254
|
+
console.log(JSON.stringify({ success: false, error: error.message }));
|
|
255
|
+
} else {
|
|
256
|
+
renderError(`Guard check failed: ${error.message}`);
|
|
257
|
+
}
|
|
258
|
+
return EXIT.INTERNAL_ERROR;
|
|
163
259
|
}
|
|
164
|
-
|
|
165
|
-
return results.verdict === "PASS" ? 0 : (results.errors > 0 ? 2 : 1);
|
|
166
260
|
}
|
|
167
261
|
|
|
168
262
|
module.exports = { runGuard };
|
package/bin/runners/runInit.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
const fs = require("fs");
|
|
13
13
|
const path = require("path");
|
|
14
14
|
const { parseGlobalFlags, shouldShowBanner } = require("./lib/global-flags");
|
|
15
|
+
const { EXIT } = require("./lib/exit-codes");
|
|
15
16
|
|
|
16
17
|
// Use enhanced wizard if available
|
|
17
18
|
let InitWizard;
|
|
@@ -1747,7 +1748,7 @@ async function runInit(args) {
|
|
|
1747
1748
|
console.log(` ${colors.info}${ICONS.info}${c.reset} Run ${c.cyan}vibecheck init --repair${c.reset} to fix partial state`);
|
|
1748
1749
|
}
|
|
1749
1750
|
if (!opts.dryRun) {
|
|
1750
|
-
return
|
|
1751
|
+
return EXIT.INTERNAL_ERROR; // Exit on error unless dry-run
|
|
1751
1752
|
}
|
|
1752
1753
|
}
|
|
1753
1754
|
}
|
|
@@ -1765,7 +1766,7 @@ async function runInit(args) {
|
|
|
1765
1766
|
}
|
|
1766
1767
|
}
|
|
1767
1768
|
if (!opts.dryRun) {
|
|
1768
|
-
return
|
|
1769
|
+
return EXIT.INTERNAL_ERROR;
|
|
1769
1770
|
}
|
|
1770
1771
|
}
|
|
1771
1772
|
}
|
package/bin/runners/runMcp.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
const path = require("path");
|
|
9
|
+
const fs = require("fs");
|
|
9
10
|
const http = require("http");
|
|
10
11
|
const { URL } = require("url");
|
|
11
12
|
|
|
@@ -14,6 +15,8 @@ const { buildTruthpack, writeTruthpack } = require("./lib/truth");
|
|
|
14
15
|
const { shipCore } = require("./runShip");
|
|
15
16
|
const { generateRunId } = require("./lib/cli-output");
|
|
16
17
|
const { enforceLimit, enforceFeature, trackUsage } = require("./lib/entitlements");
|
|
18
|
+
const { EXIT } = require("./lib/exit-codes");
|
|
19
|
+
const { parseGlobalFlags, shouldSuppressOutput, isJsonMode } = require("./lib/global-flags");
|
|
17
20
|
|
|
18
21
|
// MCP Server class
|
|
19
22
|
class VibecheckMCPServer {
|
|
@@ -642,8 +645,14 @@ class VibecheckMCPServer {
|
|
|
642
645
|
});
|
|
643
646
|
|
|
644
647
|
this.server.on("error", err => {
|
|
645
|
-
console.error("MCP Server failed to start:", err);
|
|
646
|
-
|
|
648
|
+
console.error("MCP Server failed to start:", err.message);
|
|
649
|
+
if (err.code === "EADDRINUSE") {
|
|
650
|
+
console.error(` Port ${this.port} is already in use. Try a different port with --port`);
|
|
651
|
+
} else if (err.code === "EACCES") {
|
|
652
|
+
console.error(` Permission denied for port ${this.port}. Use a port > 1024`);
|
|
653
|
+
}
|
|
654
|
+
// Emit error event for caller to handle
|
|
655
|
+
this.emit?.("error", err);
|
|
647
656
|
});
|
|
648
657
|
}
|
|
649
658
|
|
|
@@ -658,54 +667,77 @@ class VibecheckMCPServer {
|
|
|
658
667
|
// CLI handler
|
|
659
668
|
async function runMcp(args) {
|
|
660
669
|
const opts = parseArgs(args);
|
|
670
|
+
const { flags: globalFlags } = parseGlobalFlags(args);
|
|
671
|
+
const quiet = shouldSuppressOutput(globalFlags);
|
|
672
|
+
const json = isJsonMode(globalFlags);
|
|
661
673
|
|
|
662
674
|
// Check if we're in free tier and only showing help/config
|
|
663
675
|
const isFreeTier = process.env.VIBECHECK_TIER === "free" || !process.env.VIBECHECK_API_KEY;
|
|
664
676
|
const isHelpOrConfig = opts.help || opts.printConfig || opts.status || opts.test;
|
|
665
677
|
|
|
666
678
|
if (isFreeTier && !isHelpOrConfig) {
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
679
|
+
if (json) {
|
|
680
|
+
console.log(JSON.stringify({ success: false, error: "MCP Server requires STARTER plan or higher" }));
|
|
681
|
+
} else if (!quiet) {
|
|
682
|
+
console.log("\n🔌 MCP Server requires STARTER plan or higher");
|
|
683
|
+
console.log("Use --help to see available options or");
|
|
684
|
+
console.log("Upgrade: https://vibecheckai.dev/pricing\n");
|
|
685
|
+
}
|
|
686
|
+
return EXIT.TIER_REQUIRED;
|
|
673
687
|
}
|
|
674
688
|
|
|
675
689
|
if (opts.help) {
|
|
676
690
|
printHelp();
|
|
677
|
-
return
|
|
691
|
+
return EXIT.SUCCESS;
|
|
678
692
|
}
|
|
679
693
|
|
|
680
694
|
if (opts.printConfig) {
|
|
681
695
|
printClientConfig(opts);
|
|
682
|
-
return
|
|
696
|
+
return EXIT.SUCCESS;
|
|
683
697
|
}
|
|
684
698
|
|
|
685
699
|
if (opts.status) {
|
|
686
700
|
// Check server status
|
|
687
701
|
try {
|
|
688
|
-
const
|
|
702
|
+
const host = opts.host || "127.0.0.1";
|
|
703
|
+
const port = opts.port || 3000;
|
|
704
|
+
const response = await fetch(`http://${host}:${port}/status`);
|
|
689
705
|
const status = await response.json();
|
|
690
706
|
console.log(JSON.stringify(status, null, 2));
|
|
691
|
-
return
|
|
707
|
+
return EXIT.SUCCESS;
|
|
692
708
|
} catch (err) {
|
|
693
|
-
|
|
694
|
-
|
|
709
|
+
if (json) {
|
|
710
|
+
console.log(JSON.stringify({ success: false, error: "Server not running or not reachable" }));
|
|
711
|
+
} else {
|
|
712
|
+
console.error("Server not running or not reachable");
|
|
713
|
+
console.error(" Start the server with: vibecheck mcp");
|
|
714
|
+
}
|
|
715
|
+
return EXIT.NETWORK_ERROR;
|
|
695
716
|
}
|
|
696
717
|
}
|
|
697
718
|
|
|
698
719
|
if (opts.test) {
|
|
699
720
|
// Test connection
|
|
700
721
|
try {
|
|
701
|
-
const
|
|
722
|
+
const host = opts.host || "127.0.0.1";
|
|
723
|
+
const port = opts.port || 3000;
|
|
724
|
+
const response = await fetch(`http://${host}:${port}/tools`);
|
|
702
725
|
const tools = await response.json();
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
726
|
+
if (json) {
|
|
727
|
+
console.log(JSON.stringify({ success: true, toolCount: tools.tools?.length || 0 }));
|
|
728
|
+
} else {
|
|
729
|
+
console.log("✅ Connection successful");
|
|
730
|
+
console.log(`📋 Available tools: ${tools.tools?.length || 0}`);
|
|
731
|
+
}
|
|
732
|
+
return EXIT.SUCCESS;
|
|
706
733
|
} catch (err) {
|
|
707
|
-
|
|
708
|
-
|
|
734
|
+
if (json) {
|
|
735
|
+
console.log(JSON.stringify({ success: false, error: err.message }));
|
|
736
|
+
} else {
|
|
737
|
+
console.error("❌ Connection failed:", err.message);
|
|
738
|
+
console.error(" Ensure the MCP server is running");
|
|
739
|
+
}
|
|
740
|
+
return EXIT.NETWORK_ERROR;
|
|
709
741
|
}
|
|
710
742
|
}
|
|
711
743
|
|
|
@@ -713,42 +745,88 @@ async function runMcp(args) {
|
|
|
713
745
|
let config = {};
|
|
714
746
|
if (opts.config) {
|
|
715
747
|
const configPath = path.resolve(opts.config);
|
|
716
|
-
if (
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
748
|
+
if (!fs.existsSync(configPath)) {
|
|
749
|
+
if (json) {
|
|
750
|
+
console.log(JSON.stringify({ success: false, error: `Config file not found: ${configPath}` }));
|
|
751
|
+
} else {
|
|
752
|
+
console.error(`Config file not found: ${configPath}`);
|
|
753
|
+
}
|
|
754
|
+
return EXIT.NOT_FOUND;
|
|
755
|
+
}
|
|
756
|
+
try {
|
|
757
|
+
config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
758
|
+
} catch (parseErr) {
|
|
759
|
+
if (json) {
|
|
760
|
+
console.log(JSON.stringify({ success: false, error: `Invalid JSON in config: ${parseErr.message}` }));
|
|
761
|
+
} else {
|
|
762
|
+
console.error(`Invalid JSON in config file: ${parseErr.message}`);
|
|
763
|
+
}
|
|
764
|
+
return EXIT.USER_ERROR;
|
|
721
765
|
}
|
|
722
766
|
}
|
|
723
767
|
|
|
724
|
-
//
|
|
725
|
-
const
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
server.start();
|
|
736
|
-
|
|
737
|
-
// Handle shutdown
|
|
738
|
-
process.on("SIGINT", () => {
|
|
739
|
-
console.log("\nShutting down MCP server...");
|
|
740
|
-
server.stop();
|
|
741
|
-
process.exit(0);
|
|
742
|
-
});
|
|
743
|
-
|
|
744
|
-
process.on("SIGTERM", () => {
|
|
745
|
-
console.log("\nShutting down MCP server...");
|
|
746
|
-
server.stop();
|
|
747
|
-
process.exit(0);
|
|
748
|
-
});
|
|
768
|
+
// Validate port
|
|
769
|
+
const port = opts.port || config.server?.port || 3000;
|
|
770
|
+
if (isNaN(port) || port < 1 || port > 65535) {
|
|
771
|
+
if (json) {
|
|
772
|
+
console.log(JSON.stringify({ success: false, error: `Invalid port: ${port}` }));
|
|
773
|
+
} else {
|
|
774
|
+
console.error(`Invalid port: ${port}`);
|
|
775
|
+
console.error(" Port must be a number between 1 and 65535");
|
|
776
|
+
}
|
|
777
|
+
return EXIT.USER_ERROR;
|
|
778
|
+
}
|
|
749
779
|
|
|
750
|
-
|
|
751
|
-
|
|
780
|
+
try {
|
|
781
|
+
// Create and start server
|
|
782
|
+
const server = new VibecheckMCPServer({
|
|
783
|
+
host: opts.host || config.server?.host || "127.0.0.1",
|
|
784
|
+
port: port,
|
|
785
|
+
allowRemote: opts.allowRemote || config.server?.allowRemote || false,
|
|
786
|
+
requireApiKey: opts.requireApiKey !== false,
|
|
787
|
+
apiKey: opts.apiKey || config.auth?.apiKey,
|
|
788
|
+
logLevel: opts.logLevel || config.logging?.level || "info",
|
|
789
|
+
auditLog: opts.auditLog || config.logging?.auditFile
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
// Track if server started successfully
|
|
793
|
+
let serverStarted = false;
|
|
794
|
+
let serverError = null;
|
|
795
|
+
|
|
796
|
+
// Listen for server errors before starting
|
|
797
|
+
server.server?.on?.("error", (err) => {
|
|
798
|
+
serverError = err;
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
server.start();
|
|
802
|
+
serverStarted = true;
|
|
803
|
+
|
|
804
|
+
// Handle shutdown gracefully
|
|
805
|
+
const cleanup = () => {
|
|
806
|
+
if (!quiet) console.log("\nShutting down MCP server...");
|
|
807
|
+
server.stop();
|
|
808
|
+
};
|
|
809
|
+
|
|
810
|
+
process.on("SIGINT", () => {
|
|
811
|
+
cleanup();
|
|
812
|
+
process.exit(EXIT.SUCCESS);
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
process.on("SIGTERM", () => {
|
|
816
|
+
cleanup();
|
|
817
|
+
process.exit(EXIT.SUCCESS);
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
// Keep process alive
|
|
821
|
+
return new Promise(() => {});
|
|
822
|
+
} catch (error) {
|
|
823
|
+
if (json) {
|
|
824
|
+
console.log(JSON.stringify({ success: false, error: error.message }));
|
|
825
|
+
} else {
|
|
826
|
+
console.error(`Failed to start MCP server: ${error.message}`);
|
|
827
|
+
}
|
|
828
|
+
return EXIT.INTERNAL_ERROR;
|
|
829
|
+
}
|
|
752
830
|
}
|
|
753
831
|
|
|
754
832
|
// Argument parsing
|