@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.
Files changed (84) hide show
  1. package/bin/registry.js +192 -5
  2. package/bin/runners/lib/agent-firewall/change-packet/builder.js +280 -6
  3. package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
  4. package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
  5. package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
  6. package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
  7. package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
  8. package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
  9. package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
  10. package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
  11. package/bin/runners/lib/agent-firewall/logger.js +141 -0
  12. package/bin/runners/lib/agent-firewall/policy/loader.js +312 -4
  13. package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +113 -1
  14. package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +133 -6
  15. package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
  16. package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
  17. package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
  18. package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
  19. package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
  20. package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
  21. package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
  22. package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
  23. package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
  24. package/bin/runners/lib/agent-firewall/risk/thresholds.js +321 -0
  25. package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
  26. package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
  27. package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
  28. package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
  29. package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
  30. package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
  31. package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
  32. package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
  33. package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
  34. package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
  35. package/bin/runners/lib/analyzers.js +81 -18
  36. package/bin/runners/lib/authority-badge.js +425 -0
  37. package/bin/runners/lib/cli-output.js +7 -1
  38. package/bin/runners/lib/error-handler.js +16 -9
  39. package/bin/runners/lib/exit-codes.js +275 -0
  40. package/bin/runners/lib/global-flags.js +37 -0
  41. package/bin/runners/lib/help-formatter.js +413 -0
  42. package/bin/runners/lib/logger.js +38 -0
  43. package/bin/runners/lib/unified-cli-output.js +604 -0
  44. package/bin/runners/lib/upsell.js +148 -0
  45. package/bin/runners/runApprove.js +1200 -0
  46. package/bin/runners/runAuth.js +324 -95
  47. package/bin/runners/runCheckpoint.js +39 -21
  48. package/bin/runners/runClassify.js +859 -0
  49. package/bin/runners/runContext.js +136 -24
  50. package/bin/runners/runDoctor.js +108 -68
  51. package/bin/runners/runFix.js +6 -5
  52. package/bin/runners/runGuard.js +212 -118
  53. package/bin/runners/runInit.js +3 -2
  54. package/bin/runners/runMcp.js +130 -52
  55. package/bin/runners/runPolish.js +43 -20
  56. package/bin/runners/runProve.js +1 -2
  57. package/bin/runners/runReport.js +3 -2
  58. package/bin/runners/runScan.js +63 -44
  59. package/bin/runners/runShip.js +3 -4
  60. package/bin/runners/runValidate.js +19 -2
  61. package/bin/runners/runWatch.js +104 -53
  62. package/bin/vibecheck.js +106 -19
  63. package/mcp-server/HARDENING_SUMMARY.md +299 -0
  64. package/mcp-server/agent-firewall-interceptor.js +367 -31
  65. package/mcp-server/authority-tools.js +569 -0
  66. package/mcp-server/conductor/conflict-resolver.js +588 -0
  67. package/mcp-server/conductor/execution-planner.js +544 -0
  68. package/mcp-server/conductor/index.js +377 -0
  69. package/mcp-server/conductor/lock-manager.js +615 -0
  70. package/mcp-server/conductor/request-queue.js +550 -0
  71. package/mcp-server/conductor/session-manager.js +500 -0
  72. package/mcp-server/conductor/tools.js +510 -0
  73. package/mcp-server/index.js +1149 -243
  74. package/mcp-server/lib/{api-client.js → api-client.cjs} +40 -4
  75. package/mcp-server/lib/logger.cjs +30 -0
  76. package/mcp-server/logger.js +173 -0
  77. package/mcp-server/package.json +2 -2
  78. package/mcp-server/premium-tools.js +2 -2
  79. package/mcp-server/tier-auth.js +245 -35
  80. package/mcp-server/truth-firewall-tools.js +145 -15
  81. package/mcp-server/vibecheck-tools.js +2 -2
  82. package/package.json +2 -3
  83. package/mcp-server/index.old.js +0 -4137
  84. package/mcp-server/package-lock.json +0 -165
@@ -12,7 +12,7 @@
12
12
 
13
13
  const https = require("https");
14
14
  const http = require("http");
15
- const { logger } = require("./logger");
15
+ const { logger } = require("./logger.cjs");
16
16
 
17
17
  // Configuration
18
18
  const API_BASE_URL = process.env.VIBECHECK_API_URL || "https://api.vibecheckai.dev";
@@ -146,6 +146,36 @@ function getApiKey() {
146
146
  return null;
147
147
  }
148
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
+
149
179
  /**
150
180
  * Create a new scan record
151
181
  */
@@ -179,7 +209,9 @@ async function createScan(options) {
179
209
  * Update scan progress
180
210
  */
181
211
  async function updateScanProgress(scanId, progress, status = null) {
182
- const response = await makeRequest(`/api/scans/${scanId}/progress`, {
212
+ const validatedId = validateScanId(scanId);
213
+
214
+ const response = await makeRequest(`/api/scans/${validatedId}/progress`, {
183
215
  body: {
184
216
  progress,
185
217
  status,
@@ -197,6 +229,8 @@ async function updateScanProgress(scanId, progress, status = null) {
197
229
  * Submit scan results
198
230
  */
199
231
  async function submitScanResults(scanId, results) {
232
+ const validatedId = validateScanId(scanId);
233
+
200
234
  const {
201
235
  verdict,
202
236
  score,
@@ -207,7 +241,7 @@ async function submitScanResults(scanId, results) {
207
241
  metadata = {},
208
242
  } = results;
209
243
 
210
- const response = await makeRequest(`/api/scans/${scanId}/complete`, {
244
+ const response = await makeRequest(`/api/scans/${validatedId}/complete`, {
211
245
  body: {
212
246
  verdict,
213
247
  score,
@@ -230,7 +264,9 @@ async function submitScanResults(scanId, results) {
230
264
  * Report scan error
231
265
  */
232
266
  async function reportScanError(scanId, error) {
233
- const response = await makeRequest(`/api/scans/${scanId}/error`, {
267
+ const validatedId = validateScanId(scanId);
268
+
269
+ const response = await makeRequest(`/api/scans/${validatedId}/error`, {
234
270
  body: {
235
271
  error: error.message || String(error),
236
272
  stack: error.stack,
@@ -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.6",
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: [{