@vibecheckai/cli 3.2.5 → 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.
Files changed (197) hide show
  1. package/bin/.generated +25 -25
  2. package/bin/dev/run-v2-torture.js +30 -30
  3. package/bin/registry.js +192 -5
  4. package/bin/runners/lib/__tests__/entitlements-v2.test.js +295 -295
  5. package/bin/runners/lib/agent-firewall/change-packet/builder.js +280 -6
  6. package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
  7. package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
  8. package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
  9. package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
  10. package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
  11. package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
  12. package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
  13. package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
  14. package/bin/runners/lib/agent-firewall/logger.js +141 -0
  15. package/bin/runners/lib/agent-firewall/policy/loader.js +312 -4
  16. package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +113 -1
  17. package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +133 -6
  18. package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
  19. package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
  20. package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
  21. package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
  22. package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
  23. package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
  24. package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
  25. package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
  26. package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
  27. package/bin/runners/lib/agent-firewall/risk/thresholds.js +321 -0
  28. package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
  29. package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
  30. package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
  31. package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
  32. package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
  33. package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
  34. package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
  35. package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
  36. package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
  37. package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
  38. package/bin/runners/lib/analyzers.js +81 -18
  39. package/bin/runners/lib/api-client.js +269 -0
  40. package/bin/runners/lib/auth-truth.js +193 -193
  41. package/bin/runners/lib/authority-badge.js +425 -0
  42. package/bin/runners/lib/backup.js +62 -62
  43. package/bin/runners/lib/billing.js +107 -107
  44. package/bin/runners/lib/claims.js +118 -118
  45. package/bin/runners/lib/cli-output.js +7 -1
  46. package/bin/runners/lib/cli-ui.js +540 -540
  47. package/bin/runners/lib/contracts/auth-contract.js +202 -202
  48. package/bin/runners/lib/contracts/env-contract.js +181 -181
  49. package/bin/runners/lib/contracts/external-contract.js +206 -206
  50. package/bin/runners/lib/contracts/guard.js +168 -168
  51. package/bin/runners/lib/contracts/index.js +89 -89
  52. package/bin/runners/lib/contracts/plan-validator.js +311 -311
  53. package/bin/runners/lib/contracts/route-contract.js +199 -199
  54. package/bin/runners/lib/contracts.js +804 -804
  55. package/bin/runners/lib/detect.js +89 -89
  56. package/bin/runners/lib/doctor/autofix.js +254 -254
  57. package/bin/runners/lib/doctor/index.js +37 -37
  58. package/bin/runners/lib/doctor/modules/dependencies.js +325 -325
  59. package/bin/runners/lib/doctor/modules/index.js +46 -46
  60. package/bin/runners/lib/doctor/modules/network.js +250 -250
  61. package/bin/runners/lib/doctor/modules/project.js +312 -312
  62. package/bin/runners/lib/doctor/modules/runtime.js +224 -224
  63. package/bin/runners/lib/doctor/modules/security.js +348 -348
  64. package/bin/runners/lib/doctor/modules/system.js +213 -213
  65. package/bin/runners/lib/doctor/modules/vibecheck.js +394 -394
  66. package/bin/runners/lib/doctor/reporter.js +262 -262
  67. package/bin/runners/lib/doctor/service.js +262 -262
  68. package/bin/runners/lib/doctor/types.js +113 -113
  69. package/bin/runners/lib/doctor/ui.js +263 -263
  70. package/bin/runners/lib/doctor-v2.js +608 -608
  71. package/bin/runners/lib/drift.js +425 -425
  72. package/bin/runners/lib/enforcement.js +72 -72
  73. package/bin/runners/lib/enterprise-detect.js +603 -603
  74. package/bin/runners/lib/enterprise-init.js +942 -942
  75. package/bin/runners/lib/env-resolver.js +417 -417
  76. package/bin/runners/lib/env-template.js +66 -66
  77. package/bin/runners/lib/env.js +189 -189
  78. package/bin/runners/lib/error-handler.js +16 -9
  79. package/bin/runners/lib/exit-codes.js +275 -0
  80. package/bin/runners/lib/extractors/client-calls.js +990 -990
  81. package/bin/runners/lib/extractors/fastify-route-dump.js +573 -573
  82. package/bin/runners/lib/extractors/fastify-routes.js +426 -426
  83. package/bin/runners/lib/extractors/index.js +363 -363
  84. package/bin/runners/lib/extractors/next-routes.js +524 -524
  85. package/bin/runners/lib/extractors/proof-graph.js +431 -431
  86. package/bin/runners/lib/extractors/route-matcher.js +451 -451
  87. package/bin/runners/lib/extractors/truthpack-v2.js +377 -377
  88. package/bin/runners/lib/extractors/ui-bindings.js +547 -547
  89. package/bin/runners/lib/findings-schema.js +281 -281
  90. package/bin/runners/lib/firewall-prompt.js +50 -50
  91. package/bin/runners/lib/global-flags.js +37 -0
  92. package/bin/runners/lib/graph/graph-builder.js +265 -265
  93. package/bin/runners/lib/graph/html-renderer.js +413 -413
  94. package/bin/runners/lib/graph/index.js +32 -32
  95. package/bin/runners/lib/graph/runtime-collector.js +215 -215
  96. package/bin/runners/lib/graph/static-extractor.js +518 -518
  97. package/bin/runners/lib/help-formatter.js +413 -0
  98. package/bin/runners/lib/html-report.js +650 -650
  99. package/bin/runners/lib/llm.js +75 -75
  100. package/bin/runners/lib/logger.js +38 -0
  101. package/bin/runners/lib/meter.js +61 -61
  102. package/bin/runners/lib/missions/evidence.js +126 -126
  103. package/bin/runners/lib/patch.js +40 -40
  104. package/bin/runners/lib/permissions/auth-model.js +213 -213
  105. package/bin/runners/lib/permissions/idor-prover.js +205 -205
  106. package/bin/runners/lib/permissions/index.js +45 -45
  107. package/bin/runners/lib/permissions/matrix-builder.js +198 -198
  108. package/bin/runners/lib/pkgjson.js +28 -28
  109. package/bin/runners/lib/policy.js +295 -295
  110. package/bin/runners/lib/preflight.js +142 -142
  111. package/bin/runners/lib/reality/correlation-detectors.js +359 -359
  112. package/bin/runners/lib/reality/index.js +318 -318
  113. package/bin/runners/lib/reality/request-hashing.js +416 -416
  114. package/bin/runners/lib/reality/request-mapper.js +453 -453
  115. package/bin/runners/lib/reality/safety-rails.js +463 -463
  116. package/bin/runners/lib/reality/semantic-snapshot.js +408 -408
  117. package/bin/runners/lib/reality/toast-detector.js +393 -393
  118. package/bin/runners/lib/reality-findings.js +84 -84
  119. package/bin/runners/lib/receipts.js +179 -179
  120. package/bin/runners/lib/redact.js +29 -29
  121. package/bin/runners/lib/replay/capsule-manager.js +154 -154
  122. package/bin/runners/lib/replay/index.js +263 -263
  123. package/bin/runners/lib/replay/player.js +348 -348
  124. package/bin/runners/lib/replay/recorder.js +331 -331
  125. package/bin/runners/lib/report.js +135 -135
  126. package/bin/runners/lib/route-detection.js +1140 -1140
  127. package/bin/runners/lib/sandbox/index.js +59 -59
  128. package/bin/runners/lib/sandbox/proof-chain.js +399 -399
  129. package/bin/runners/lib/sandbox/sandbox-runner.js +205 -205
  130. package/bin/runners/lib/sandbox/worktree.js +174 -174
  131. package/bin/runners/lib/schema-validator.js +350 -350
  132. package/bin/runners/lib/schemas/contracts.schema.json +160 -160
  133. package/bin/runners/lib/schemas/finding.schema.json +100 -100
  134. package/bin/runners/lib/schemas/mission-pack.schema.json +206 -206
  135. package/bin/runners/lib/schemas/proof-graph.schema.json +176 -176
  136. package/bin/runners/lib/schemas/reality-report.schema.json +162 -162
  137. package/bin/runners/lib/schemas/share-pack.schema.json +180 -180
  138. package/bin/runners/lib/schemas/ship-report.schema.json +117 -117
  139. package/bin/runners/lib/schemas/truthpack-v2.schema.json +303 -303
  140. package/bin/runners/lib/schemas/validator.js +438 -438
  141. package/bin/runners/lib/score-history.js +282 -282
  142. package/bin/runners/lib/share-pack.js +239 -239
  143. package/bin/runners/lib/snippets.js +67 -67
  144. package/bin/runners/lib/unified-cli-output.js +604 -0
  145. package/bin/runners/lib/upsell.js +658 -510
  146. package/bin/runners/lib/usage.js +153 -153
  147. package/bin/runners/lib/validate-patch.js +156 -156
  148. package/bin/runners/lib/verdict-engine.js +628 -628
  149. package/bin/runners/reality/engine.js +917 -917
  150. package/bin/runners/reality/flows.js +122 -122
  151. package/bin/runners/reality/report.js +378 -378
  152. package/bin/runners/reality/session.js +193 -193
  153. package/bin/runners/runAgent.d.ts +5 -0
  154. package/bin/runners/runApprove.js +1200 -0
  155. package/bin/runners/runAuth.js +324 -95
  156. package/bin/runners/runCheckpoint.js +39 -21
  157. package/bin/runners/runClassify.js +859 -0
  158. package/bin/runners/runContext.js +136 -24
  159. package/bin/runners/runDoctor.js +108 -68
  160. package/bin/runners/runFirewall.d.ts +5 -0
  161. package/bin/runners/runFirewallHook.d.ts +5 -0
  162. package/bin/runners/runFix.js +6 -5
  163. package/bin/runners/runGuard.js +262 -168
  164. package/bin/runners/runInit.js +3 -2
  165. package/bin/runners/runMcp.js +130 -52
  166. package/bin/runners/runPolish.js +43 -20
  167. package/bin/runners/runProve.js +1 -2
  168. package/bin/runners/runReport.js +3 -2
  169. package/bin/runners/runScan.js +145 -44
  170. package/bin/runners/runShip.js +3 -4
  171. package/bin/runners/runTruth.d.ts +5 -0
  172. package/bin/runners/runValidate.js +19 -2
  173. package/bin/runners/runWatch.js +104 -53
  174. package/bin/vibecheck.js +106 -19
  175. package/mcp-server/HARDENING_SUMMARY.md +299 -0
  176. package/mcp-server/agent-firewall-interceptor.js +367 -31
  177. package/mcp-server/authority-tools.js +569 -0
  178. package/mcp-server/conductor/conflict-resolver.js +588 -0
  179. package/mcp-server/conductor/execution-planner.js +544 -0
  180. package/mcp-server/conductor/index.js +377 -0
  181. package/mcp-server/conductor/lock-manager.js +615 -0
  182. package/mcp-server/conductor/request-queue.js +550 -0
  183. package/mcp-server/conductor/session-manager.js +500 -0
  184. package/mcp-server/conductor/tools.js +510 -0
  185. package/mcp-server/index.js +1199 -208
  186. package/mcp-server/lib/api-client.cjs +305 -0
  187. package/mcp-server/lib/logger.cjs +30 -0
  188. package/mcp-server/logger.js +173 -0
  189. package/mcp-server/package.json +2 -2
  190. package/mcp-server/premium-tools.js +2 -2
  191. package/mcp-server/tier-auth.js +351 -136
  192. package/mcp-server/tools/index.js +72 -72
  193. package/mcp-server/truth-firewall-tools.js +145 -15
  194. package/mcp-server/vibecheck-tools.js +2 -2
  195. package/package.json +2 -3
  196. package/mcp-server/index.old.js +0 -4137
  197. package/mcp-server/package-lock.json +0 -165
@@ -0,0 +1,305 @@
1
+ /**
2
+ * API Client for Vibecheck Dashboard Integration
3
+ *
4
+ * Handles communication with the web dashboard API for:
5
+ * - Creating scan records
6
+ * - Updating scan progress
7
+ * - Submitting scan results
8
+ * - Broadcasting real-time updates
9
+ */
10
+
11
+ "use strict";
12
+
13
+ const https = require("https");
14
+ const http = require("http");
15
+ const { logger } = require("./logger.cjs");
16
+
17
+ // Configuration
18
+ const API_BASE_URL = process.env.VIBECHECK_API_URL || "https://api.vibecheckai.dev";
19
+ const API_TIMEOUT = 30000; // 30 seconds
20
+
21
+ /**
22
+ * Make HTTP request to API
23
+ */
24
+ async function makeRequest(path, options = {}) {
25
+ const url = new URL(path, API_BASE_URL);
26
+ const isHttps = url.protocol === "https:";
27
+ const client = isHttps ? https : http;
28
+
29
+ const defaultOptions = {
30
+ method: "POST",
31
+ headers: {
32
+ "Content-Type": "application/json",
33
+ "User-Agent": "vibecheck-cli/3.3.0",
34
+ },
35
+ timeout: API_TIMEOUT,
36
+ };
37
+
38
+ const requestOptions = {
39
+ ...defaultOptions,
40
+ ...options,
41
+ hostname: url.hostname,
42
+ port: url.port || (isHttps ? 443 : 80),
43
+ path: url.pathname + url.search,
44
+ };
45
+
46
+ // Add Authorization header if API key is available
47
+ const apiKey = process.env.VIBECHECK_API_KEY || getApiKey();
48
+ if (apiKey) {
49
+ requestOptions.headers.Authorization = `Bearer ${apiKey}`;
50
+ }
51
+
52
+ return new Promise((resolve, reject) => {
53
+ const req = client.request(requestOptions, (res) => {
54
+ let data = "";
55
+
56
+ res.on("data", (chunk) => {
57
+ data += chunk;
58
+ });
59
+
60
+ res.on("end", () => {
61
+ try {
62
+ const jsonData = data ? JSON.parse(data) : {};
63
+ resolve({
64
+ ok: res.statusCode >= 200 && res.statusCode < 300,
65
+ status: res.statusCode,
66
+ data: jsonData,
67
+ });
68
+ } catch (err) {
69
+ resolve({
70
+ ok: false,
71
+ status: res.statusCode,
72
+ data: { error: "Invalid JSON response" },
73
+ });
74
+ }
75
+ });
76
+ });
77
+
78
+ req.on("error", (err) => {
79
+ logger.debug(`API request failed: ${err.message}`);
80
+ resolve({
81
+ ok: false,
82
+ error: err.message,
83
+ data: { error: err.message },
84
+ });
85
+ });
86
+
87
+ req.on("timeout", () => {
88
+ req.destroy();
89
+ resolve({
90
+ ok: false,
91
+ error: "Request timeout",
92
+ data: { error: "Request timeout" },
93
+ });
94
+ });
95
+
96
+ if (options.body) {
97
+ req.write(JSON.stringify(options.body));
98
+ }
99
+
100
+ req.end();
101
+ });
102
+ }
103
+
104
+ /**
105
+ * Get API key from environment or config
106
+ */
107
+ function getApiKey() {
108
+ // Try various environment variables
109
+ const envVars = [
110
+ "VIBECHECK_API_KEY",
111
+ "VIBECHECK_TOKEN",
112
+ "API_KEY",
113
+ "TOKEN",
114
+ ];
115
+
116
+ for (const envVar of envVars) {
117
+ if (process.env[envVar]) {
118
+ return process.env[envVar];
119
+ }
120
+ }
121
+
122
+ // Try to read from config file
123
+ try {
124
+ const fs = require("fs");
125
+ const path = require("path");
126
+ const os = require("os");
127
+
128
+ const configPaths = [
129
+ path.join(os.homedir(), ".vibecheck", "config.json"),
130
+ path.join(process.cwd(), ".vibecheckrc.json"),
131
+ path.join(process.cwd(), "vibecheck.config.json"),
132
+ ];
133
+
134
+ for (const configPath of configPaths) {
135
+ if (fs.existsSync(configPath)) {
136
+ const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
137
+ if (config.apiKey || config.token) {
138
+ return config.apiKey || config.token;
139
+ }
140
+ }
141
+ }
142
+ } catch (err) {
143
+ // Ignore config file errors
144
+ }
145
+
146
+ return null;
147
+ }
148
+
149
+ // =============================================================================
150
+ // SECURITY: Input Validation
151
+ // =============================================================================
152
+
153
+ /**
154
+ * Validate scanId format to prevent path injection.
155
+ *
156
+ * SECURITY FIX: scanId is interpolated into URLs like `/api/scans/${scanId}/progress`.
157
+ * Without validation, an attacker could inject path segments:
158
+ * scanId = "../../admin/delete"
159
+ * → URL becomes "/api/scans/../../admin/delete/progress"
160
+ *
161
+ * @param {string} scanId - The scan ID to validate
162
+ * @returns {string} - The validated scanId
163
+ * @throws {Error} - If scanId is invalid
164
+ */
165
+ function validateScanId(scanId) {
166
+ if (!scanId || typeof scanId !== 'string') {
167
+ throw new Error('scanId is required and must be a string');
168
+ }
169
+
170
+ // Only allow alphanumeric, hyphens, underscores (no dots, slashes, etc.)
171
+ // Max length 64 to prevent abuse
172
+ if (!/^[a-zA-Z0-9_-]{1,64}$/.test(scanId)) {
173
+ throw new Error('Invalid scanId format - must be alphanumeric with hyphens/underscores only, max 64 chars');
174
+ }
175
+
176
+ return scanId;
177
+ }
178
+
179
+ /**
180
+ * Create a new scan record
181
+ */
182
+ async function createScan(options) {
183
+ const {
184
+ repositoryId,
185
+ repositoryUrl,
186
+ localPath,
187
+ branch = "main",
188
+ enableLLM = false,
189
+ } = options;
190
+
191
+ const response = await makeRequest("/api/scans", {
192
+ body: {
193
+ repositoryId,
194
+ repositoryUrl,
195
+ localPath,
196
+ branch,
197
+ enableLLM,
198
+ },
199
+ });
200
+
201
+ if (!response.ok) {
202
+ throw new Error(`Failed to create scan: ${response.data?.error || response.error}`);
203
+ }
204
+
205
+ return response.data.data;
206
+ }
207
+
208
+ /**
209
+ * Update scan progress
210
+ */
211
+ async function updateScanProgress(scanId, progress, status = null) {
212
+ const validatedId = validateScanId(scanId);
213
+
214
+ const response = await makeRequest(`/api/scans/${validatedId}/progress`, {
215
+ body: {
216
+ progress,
217
+ status,
218
+ },
219
+ });
220
+
221
+ if (!response.ok) {
222
+ logger.debug(`Failed to update scan progress: ${response.data?.error || response.error}`);
223
+ }
224
+
225
+ return response.data;
226
+ }
227
+
228
+ /**
229
+ * Submit scan results
230
+ */
231
+ async function submitScanResults(scanId, results) {
232
+ const validatedId = validateScanId(scanId);
233
+
234
+ const {
235
+ verdict,
236
+ score,
237
+ findings,
238
+ filesScanned,
239
+ linesScanned,
240
+ durationMs,
241
+ metadata = {},
242
+ } = results;
243
+
244
+ const response = await makeRequest(`/api/scans/${validatedId}/complete`, {
245
+ body: {
246
+ verdict,
247
+ score,
248
+ findings,
249
+ filesScanned,
250
+ linesScanned,
251
+ durationMs,
252
+ metadata,
253
+ },
254
+ });
255
+
256
+ if (!response.ok) {
257
+ throw new Error(`Failed to submit scan results: ${response.data?.error || response.error}`);
258
+ }
259
+
260
+ return response.data;
261
+ }
262
+
263
+ /**
264
+ * Report scan error
265
+ */
266
+ async function reportScanError(scanId, error) {
267
+ const validatedId = validateScanId(scanId);
268
+
269
+ const response = await makeRequest(`/api/scans/${validatedId}/error`, {
270
+ body: {
271
+ error: error.message || String(error),
272
+ stack: error.stack,
273
+ },
274
+ });
275
+
276
+ if (!response.ok) {
277
+ logger.debug(`Failed to report scan error: ${response.data?.error || response.error}`);
278
+ }
279
+
280
+ return response.data;
281
+ }
282
+
283
+ /**
284
+ * Check if API is available
285
+ */
286
+ async function isApiAvailable() {
287
+ try {
288
+ const response = await makeRequest("/api/health", {
289
+ method: "GET",
290
+ timeout: 5000,
291
+ });
292
+ return response.ok;
293
+ } catch (err) {
294
+ return false;
295
+ }
296
+ }
297
+
298
+ module.exports = {
299
+ createScan,
300
+ updateScanProgress,
301
+ submitScanResults,
302
+ reportScanError,
303
+ isApiAvailable,
304
+ getApiKey,
305
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Simple logger for MCP server
3
+ * Outputs to stderr to avoid interfering with MCP stdio protocol
4
+ */
5
+
6
+ "use strict";
7
+
8
+ const DEBUG = process.env.VIBECHECK_DEBUG === "true" || process.env.DEBUG === "true";
9
+
10
+ const logger = {
11
+ debug(...args) {
12
+ if (DEBUG) {
13
+ console.error("[DEBUG]", ...args);
14
+ }
15
+ },
16
+
17
+ info(...args) {
18
+ console.error("[INFO]", ...args);
19
+ },
20
+
21
+ warn(...args) {
22
+ console.error("[WARN]", ...args);
23
+ },
24
+
25
+ error(...args) {
26
+ console.error("[ERROR]", ...args);
27
+ },
28
+ };
29
+
30
+ module.exports = { logger };
@@ -0,0 +1,173 @@
1
+ /**
2
+ * VibeCheck MCP Server Logger
3
+ *
4
+ * Centralized logging utility for all MCP server modules.
5
+ * Avoids console.log/warn/error in production code.
6
+ */
7
+
8
+ "use strict";
9
+
10
+ /**
11
+ * Log levels
12
+ */
13
+ export const LOG_LEVELS = {
14
+ DEBUG: 0,
15
+ INFO: 1,
16
+ WARN: 2,
17
+ ERROR: 3,
18
+ SILENT: 4,
19
+ };
20
+
21
+ /**
22
+ * Current log level (can be set via environment)
23
+ */
24
+ let currentLevel = LOG_LEVELS.INFO;
25
+
26
+ // Set from environment
27
+ if (process.env.VIBECHECK_LOG_LEVEL) {
28
+ const envLevel = process.env.VIBECHECK_LOG_LEVEL.toUpperCase();
29
+ if (LOG_LEVELS[envLevel] !== undefined) {
30
+ currentLevel = LOG_LEVELS[envLevel];
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Log buffer for testing/inspection
36
+ */
37
+ const logBuffer = [];
38
+ const MAX_BUFFER_SIZE = 1000;
39
+
40
+ /**
41
+ * Format a log message
42
+ * @param {string} level - Log level
43
+ * @param {string} module - Module name
44
+ * @param {string} message - Log message
45
+ * @returns {string} Formatted message
46
+ */
47
+ function formatMessage(level, module, message) {
48
+ const timestamp = new Date().toISOString();
49
+ return `[${timestamp}] [${level}] [${module}] ${message}`;
50
+ }
51
+
52
+ /**
53
+ * Write a log entry
54
+ * @param {number} level - Log level number
55
+ * @param {string} levelName - Level name
56
+ * @param {string} module - Module name
57
+ * @param {string} message - Message
58
+ * @param {Error} [error] - Optional error object
59
+ */
60
+ function writeLog(level, levelName, module, message, error = null) {
61
+ if (level < currentLevel) return;
62
+
63
+ const formatted = formatMessage(levelName, module, message);
64
+
65
+ // Add to buffer
66
+ logBuffer.push({
67
+ timestamp: new Date(),
68
+ level: levelName,
69
+ module,
70
+ message,
71
+ error: error ? { message: error.message, stack: error.stack } : null,
72
+ });
73
+
74
+ // Trim buffer
75
+ if (logBuffer.length > MAX_BUFFER_SIZE) {
76
+ logBuffer.shift();
77
+ }
78
+
79
+ // Write to stderr (MCP servers should write logs to stderr, stdout is for JSON-RPC)
80
+ if (level >= LOG_LEVELS.WARN) {
81
+ process.stderr.write(formatted + '\n');
82
+ } else if (process.env.VIBECHECK_DEBUG || currentLevel === LOG_LEVELS.DEBUG) {
83
+ process.stderr.write(formatted + '\n');
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Create a logger for a specific module
89
+ * @param {string} moduleName - Module name
90
+ * @returns {Object} Logger instance
91
+ */
92
+ export function createLogger(moduleName) {
93
+ return {
94
+ debug: (message) => writeLog(LOG_LEVELS.DEBUG, 'DEBUG', moduleName, message),
95
+ info: (message) => writeLog(LOG_LEVELS.INFO, 'INFO', moduleName, message),
96
+ warn: (message, error = null) => writeLog(LOG_LEVELS.WARN, 'WARN', moduleName, message, error),
97
+ error: (message, error = null) => writeLog(LOG_LEVELS.ERROR, 'ERROR', moduleName, message, error),
98
+ };
99
+ }
100
+
101
+ /**
102
+ * Set the global log level
103
+ * @param {string|number} level - Level name or number
104
+ */
105
+ export function setLogLevel(level) {
106
+ if (typeof level === 'string') {
107
+ const upperLevel = level.toUpperCase();
108
+ if (LOG_LEVELS[upperLevel] !== undefined) {
109
+ currentLevel = LOG_LEVELS[upperLevel];
110
+ }
111
+ } else if (typeof level === 'number') {
112
+ currentLevel = level;
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Get current log level
118
+ * @returns {number} Current level
119
+ */
120
+ export function getLogLevel() {
121
+ return currentLevel;
122
+ }
123
+
124
+ /**
125
+ * Get recent log entries
126
+ * @param {number} count - Number of entries
127
+ * @returns {Object[]} Log entries
128
+ */
129
+ export function getRecentLogs(count = 100) {
130
+ return logBuffer.slice(-count);
131
+ }
132
+
133
+ /**
134
+ * Clear log buffer
135
+ */
136
+ export function clearLogs() {
137
+ logBuffer.length = 0;
138
+ }
139
+
140
+ /**
141
+ * Get error message safely from any error type
142
+ * @param {unknown} error - Error object
143
+ * @returns {string} Error message
144
+ */
145
+ export function getErrorMessage(error) {
146
+ if (error instanceof Error) {
147
+ return error.message;
148
+ }
149
+ if (typeof error === 'string') {
150
+ return error;
151
+ }
152
+ if (error && typeof error === 'object' && 'message' in error) {
153
+ return String(error.message);
154
+ }
155
+ return String(error);
156
+ }
157
+
158
+ // Pre-created loggers for common modules
159
+ export const conductorLogger = createLogger('Conductor');
160
+ export const lawbookLogger = createLogger('Lawbook');
161
+ export const timeMachineLogger = createLogger('TimeMachine');
162
+ export const clearanceLogger = createLogger('Clearance');
163
+ export const firewallLogger = createLogger('Firewall');
164
+
165
+ export default {
166
+ createLogger,
167
+ setLogLevel,
168
+ getLogLevel,
169
+ getRecentLogs,
170
+ clearLogs,
171
+ getErrorMessage,
172
+ LOG_LEVELS,
173
+ };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibecheck-mcp-server",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "description": "Professional MCP server for vibecheck - Intelligent development environment vibechecks",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -24,7 +24,7 @@
24
24
  "@modelcontextprotocol/sdk": "^1.0.0"
25
25
  },
26
26
  "engines": {
27
- "node": ">=18.0.0"
27
+ "node": ">=20.11"
28
28
  },
29
29
  "author": "vibecheck",
30
30
  "license": "MIT",
@@ -16,7 +16,7 @@
16
16
  import fs from 'fs/promises';
17
17
  import path from 'path';
18
18
  import { execSync, spawn } from 'child_process';
19
- import { checkFeatureAccess } from "./tier-auth.js";
19
+ import { getFeatureAccessStatus } from "./tier-auth.js";
20
20
 
21
21
  // State management (in-memory for MCP session, persisted to disk)
22
22
  class MCPState {
@@ -434,7 +434,7 @@ export async function handlePremiumTool(name, args, logger) {
434
434
 
435
435
  const requiredFeature = featureMap[name];
436
436
  if (requiredFeature) {
437
- const access = await checkFeatureAccess(requiredFeature, args?.apiKey);
437
+ const access = await getFeatureAccessStatus(requiredFeature, args?.apiKey);
438
438
  if (!access.hasAccess) {
439
439
  return {
440
440
  content: [{