@vibecheckai/cli 3.4.0 → 3.5.1

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 (228) hide show
  1. package/bin/registry.js +154 -338
  2. package/bin/runners/context/generators/mcp.js +13 -15
  3. package/bin/runners/context/proof-context.js +1 -248
  4. package/bin/runners/lib/analysis-core.js +180 -198
  5. package/bin/runners/lib/analyzers.js +223 -1669
  6. package/bin/runners/lib/cli-output.js +210 -242
  7. package/bin/runners/lib/detectors-v2.js +785 -547
  8. package/bin/runners/lib/entitlements-v2.js +458 -96
  9. package/bin/runners/lib/error-handler.js +9 -16
  10. package/bin/runners/lib/global-flags.js +0 -37
  11. package/bin/runners/lib/route-truth.js +322 -1167
  12. package/bin/runners/lib/scan-output.js +469 -448
  13. package/bin/runners/lib/ship-output.js +27 -280
  14. package/bin/runners/lib/terminal-ui.js +733 -231
  15. package/bin/runners/lib/truth.js +321 -1004
  16. package/bin/runners/lib/unified-output.js +158 -162
  17. package/bin/runners/lib/upsell.js +204 -104
  18. package/bin/runners/runAllowlist.js +324 -0
  19. package/bin/runners/runAuth.js +95 -324
  20. package/bin/runners/runCheckpoint.js +21 -39
  21. package/bin/runners/runContext.js +24 -136
  22. package/bin/runners/runDoctor.js +67 -115
  23. package/bin/runners/runEvidencePack.js +219 -0
  24. package/bin/runners/runFix.js +5 -6
  25. package/bin/runners/runGuard.js +118 -212
  26. package/bin/runners/runInit.js +2 -14
  27. package/bin/runners/runInstall.js +281 -0
  28. package/bin/runners/runLabs.js +341 -0
  29. package/bin/runners/runMcp.js +52 -130
  30. package/bin/runners/runPolish.js +20 -43
  31. package/bin/runners/runProve.js +3 -13
  32. package/bin/runners/runReality.js +0 -14
  33. package/bin/runners/runReport.js +2 -3
  34. package/bin/runners/runScan.js +44 -511
  35. package/bin/runners/runShip.js +14 -28
  36. package/bin/runners/runValidate.js +2 -19
  37. package/bin/runners/runWatch.js +54 -118
  38. package/bin/vibecheck.js +41 -148
  39. package/mcp-server/ARCHITECTURE.md +339 -0
  40. package/mcp-server/__tests__/cache.test.ts +313 -0
  41. package/mcp-server/__tests__/executor.test.ts +239 -0
  42. package/mcp-server/__tests__/fixtures/exclusion-test/.cache/webpack/cache.pack +1 -0
  43. package/mcp-server/__tests__/fixtures/exclusion-test/.next/server/chunk.js +3 -0
  44. package/mcp-server/__tests__/fixtures/exclusion-test/.turbo/cache.json +3 -0
  45. package/mcp-server/__tests__/fixtures/exclusion-test/.venv/lib/env.py +3 -0
  46. package/mcp-server/__tests__/fixtures/exclusion-test/dist/bundle.js +3 -0
  47. package/mcp-server/__tests__/fixtures/exclusion-test/package.json +5 -0
  48. package/mcp-server/__tests__/fixtures/exclusion-test/src/app.ts +5 -0
  49. package/mcp-server/__tests__/fixtures/exclusion-test/venv/lib/config.py +4 -0
  50. package/mcp-server/__tests__/ids.test.ts +345 -0
  51. package/mcp-server/__tests__/integration/tools.test.ts +410 -0
  52. package/mcp-server/__tests__/registry.test.ts +365 -0
  53. package/mcp-server/__tests__/sandbox.test.ts +323 -0
  54. package/mcp-server/__tests__/schemas.test.ts +372 -0
  55. package/mcp-server/benchmarks/run-benchmarks.ts +304 -0
  56. package/mcp-server/examples/doctor.request.json +14 -0
  57. package/mcp-server/examples/doctor.response.json +53 -0
  58. package/mcp-server/examples/error.response.json +15 -0
  59. package/mcp-server/examples/scan.request.json +14 -0
  60. package/mcp-server/examples/scan.response.json +108 -0
  61. package/mcp-server/handlers/tool-handler.ts +671 -0
  62. package/mcp-server/index-v3.ts +293 -0
  63. package/mcp-server/index.js +1072 -1573
  64. package/mcp-server/index.old.js +4137 -0
  65. package/mcp-server/lib/cache.ts +341 -0
  66. package/mcp-server/lib/errors.ts +346 -0
  67. package/mcp-server/lib/executor.ts +792 -0
  68. package/mcp-server/lib/ids.ts +238 -0
  69. package/mcp-server/lib/logger.ts +368 -0
  70. package/mcp-server/lib/metrics.ts +365 -0
  71. package/mcp-server/lib/sandbox.ts +337 -0
  72. package/mcp-server/lib/validator.ts +229 -0
  73. package/mcp-server/package-lock.json +165 -0
  74. package/mcp-server/package.json +32 -7
  75. package/mcp-server/premium-tools.js +2 -2
  76. package/mcp-server/registry/tools.json +476 -0
  77. package/mcp-server/schemas/error-envelope.schema.json +125 -0
  78. package/mcp-server/schemas/finding.schema.json +167 -0
  79. package/mcp-server/schemas/report-artifact.schema.json +88 -0
  80. package/mcp-server/schemas/run-request.schema.json +75 -0
  81. package/mcp-server/schemas/verdict.schema.json +168 -0
  82. package/mcp-server/tier-auth.d.ts +71 -0
  83. package/mcp-server/tier-auth.js +371 -183
  84. package/mcp-server/truth-context.js +90 -131
  85. package/mcp-server/truth-firewall-tools.js +1000 -1611
  86. package/mcp-server/tsconfig.json +34 -0
  87. package/mcp-server/vibecheck-tools.js +2 -2
  88. package/mcp-server/vitest.config.ts +16 -0
  89. package/package.json +3 -4
  90. package/bin/runners/lib/agent-firewall/ai/false-positive-analyzer.js +0 -474
  91. package/bin/runners/lib/agent-firewall/change-packet/builder.js +0 -488
  92. package/bin/runners/lib/agent-firewall/change-packet/schema.json +0 -228
  93. package/bin/runners/lib/agent-firewall/change-packet/store.js +0 -200
  94. package/bin/runners/lib/agent-firewall/claims/claim-types.js +0 -21
  95. package/bin/runners/lib/agent-firewall/claims/extractor.js +0 -303
  96. package/bin/runners/lib/agent-firewall/claims/patterns.js +0 -24
  97. package/bin/runners/lib/agent-firewall/critic/index.js +0 -151
  98. package/bin/runners/lib/agent-firewall/critic/judge.js +0 -432
  99. package/bin/runners/lib/agent-firewall/critic/prompts.js +0 -305
  100. package/bin/runners/lib/agent-firewall/evidence/auth-evidence.js +0 -88
  101. package/bin/runners/lib/agent-firewall/evidence/contract-evidence.js +0 -75
  102. package/bin/runners/lib/agent-firewall/evidence/env-evidence.js +0 -127
  103. package/bin/runners/lib/agent-firewall/evidence/resolver.js +0 -102
  104. package/bin/runners/lib/agent-firewall/evidence/route-evidence.js +0 -213
  105. package/bin/runners/lib/agent-firewall/evidence/side-effect-evidence.js +0 -145
  106. package/bin/runners/lib/agent-firewall/fs-hook/daemon.js +0 -19
  107. package/bin/runners/lib/agent-firewall/fs-hook/installer.js +0 -87
  108. package/bin/runners/lib/agent-firewall/fs-hook/watcher.js +0 -184
  109. package/bin/runners/lib/agent-firewall/git-hook/pre-commit.js +0 -163
  110. package/bin/runners/lib/agent-firewall/ide-extension/cursor.js +0 -107
  111. package/bin/runners/lib/agent-firewall/ide-extension/vscode.js +0 -68
  112. package/bin/runners/lib/agent-firewall/ide-extension/windsurf.js +0 -66
  113. package/bin/runners/lib/agent-firewall/interceptor/base.js +0 -304
  114. package/bin/runners/lib/agent-firewall/interceptor/cursor.js +0 -35
  115. package/bin/runners/lib/agent-firewall/interceptor/vscode.js +0 -35
  116. package/bin/runners/lib/agent-firewall/interceptor/windsurf.js +0 -34
  117. package/bin/runners/lib/agent-firewall/lawbook/distributor.js +0 -465
  118. package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +0 -604
  119. package/bin/runners/lib/agent-firewall/lawbook/index.js +0 -304
  120. package/bin/runners/lib/agent-firewall/lawbook/registry.js +0 -514
  121. package/bin/runners/lib/agent-firewall/lawbook/schema.js +0 -420
  122. package/bin/runners/lib/agent-firewall/logger.js +0 -141
  123. package/bin/runners/lib/agent-firewall/policy/default-policy.json +0 -90
  124. package/bin/runners/lib/agent-firewall/policy/engine.js +0 -103
  125. package/bin/runners/lib/agent-firewall/policy/loader.js +0 -451
  126. package/bin/runners/lib/agent-firewall/policy/rules/auth-drift.js +0 -50
  127. package/bin/runners/lib/agent-firewall/policy/rules/contract-drift.js +0 -50
  128. package/bin/runners/lib/agent-firewall/policy/rules/fake-success.js +0 -86
  129. package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +0 -162
  130. package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +0 -189
  131. package/bin/runners/lib/agent-firewall/policy/rules/scope.js +0 -93
  132. package/bin/runners/lib/agent-firewall/policy/rules/unsafe-side-effect.js +0 -57
  133. package/bin/runners/lib/agent-firewall/policy/schema.json +0 -183
  134. package/bin/runners/lib/agent-firewall/policy/verdict.js +0 -54
  135. package/bin/runners/lib/agent-firewall/proposal/extractor.js +0 -394
  136. package/bin/runners/lib/agent-firewall/proposal/index.js +0 -212
  137. package/bin/runners/lib/agent-firewall/proposal/schema.js +0 -251
  138. package/bin/runners/lib/agent-firewall/proposal/validator.js +0 -386
  139. package/bin/runners/lib/agent-firewall/reality/index.js +0 -332
  140. package/bin/runners/lib/agent-firewall/reality/state.js +0 -625
  141. package/bin/runners/lib/agent-firewall/reality/watcher.js +0 -322
  142. package/bin/runners/lib/agent-firewall/risk/index.js +0 -173
  143. package/bin/runners/lib/agent-firewall/risk/scorer.js +0 -328
  144. package/bin/runners/lib/agent-firewall/risk/thresholds.js +0 -321
  145. package/bin/runners/lib/agent-firewall/risk/vectors.js +0 -421
  146. package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +0 -472
  147. package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +0 -346
  148. package/bin/runners/lib/agent-firewall/simulator/index.js +0 -181
  149. package/bin/runners/lib/agent-firewall/simulator/route-validator.js +0 -380
  150. package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +0 -661
  151. package/bin/runners/lib/agent-firewall/time-machine/index.js +0 -267
  152. package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +0 -436
  153. package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +0 -490
  154. package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +0 -530
  155. package/bin/runners/lib/agent-firewall/truthpack/index.js +0 -67
  156. package/bin/runners/lib/agent-firewall/truthpack/loader.js +0 -137
  157. package/bin/runners/lib/agent-firewall/unblock/planner.js +0 -337
  158. package/bin/runners/lib/agent-firewall/utils/ignore-checker.js +0 -118
  159. package/bin/runners/lib/api-client.js +0 -269
  160. package/bin/runners/lib/authority-badge.js +0 -425
  161. package/bin/runners/lib/engines/accessibility-engine.js +0 -190
  162. package/bin/runners/lib/engines/api-consistency-engine.js +0 -162
  163. package/bin/runners/lib/engines/ast-cache.js +0 -99
  164. package/bin/runners/lib/engines/code-quality-engine.js +0 -255
  165. package/bin/runners/lib/engines/console-logs-engine.js +0 -115
  166. package/bin/runners/lib/engines/cross-file-analysis-engine.js +0 -268
  167. package/bin/runners/lib/engines/dead-code-engine.js +0 -198
  168. package/bin/runners/lib/engines/deprecated-api-engine.js +0 -226
  169. package/bin/runners/lib/engines/empty-catch-engine.js +0 -150
  170. package/bin/runners/lib/engines/file-filter.js +0 -131
  171. package/bin/runners/lib/engines/hardcoded-secrets-engine.js +0 -251
  172. package/bin/runners/lib/engines/mock-data-engine.js +0 -272
  173. package/bin/runners/lib/engines/parallel-processor.js +0 -71
  174. package/bin/runners/lib/engines/performance-issues-engine.js +0 -265
  175. package/bin/runners/lib/engines/security-vulnerabilities-engine.js +0 -243
  176. package/bin/runners/lib/engines/todo-fixme-engine.js +0 -115
  177. package/bin/runners/lib/engines/type-aware-engine.js +0 -152
  178. package/bin/runners/lib/engines/unsafe-regex-engine.js +0 -225
  179. package/bin/runners/lib/engines/vibecheck-engines/README.md +0 -53
  180. package/bin/runners/lib/engines/vibecheck-engines/index.js +0 -15
  181. package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +0 -164
  182. package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +0 -291
  183. package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +0 -83
  184. package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +0 -198
  185. package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +0 -275
  186. package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +0 -167
  187. package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +0 -217
  188. package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +0 -139
  189. package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +0 -140
  190. package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +0 -164
  191. package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +0 -234
  192. package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +0 -217
  193. package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +0 -78
  194. package/bin/runners/lib/engines/vibecheck-engines/package.json +0 -13
  195. package/bin/runners/lib/exit-codes.js +0 -275
  196. package/bin/runners/lib/fingerprint.js +0 -377
  197. package/bin/runners/lib/help-formatter.js +0 -413
  198. package/bin/runners/lib/logger.js +0 -38
  199. package/bin/runners/lib/ship-output-enterprise.js +0 -239
  200. package/bin/runners/lib/unified-cli-output.js +0 -604
  201. package/bin/runners/runAgent.d.ts +0 -5
  202. package/bin/runners/runAgent.js +0 -161
  203. package/bin/runners/runApprove.js +0 -1200
  204. package/bin/runners/runClassify.js +0 -859
  205. package/bin/runners/runContext.d.ts +0 -4
  206. package/bin/runners/runFirewall.d.ts +0 -5
  207. package/bin/runners/runFirewall.js +0 -134
  208. package/bin/runners/runFirewallHook.d.ts +0 -5
  209. package/bin/runners/runFirewallHook.js +0 -56
  210. package/bin/runners/runPolish.d.ts +0 -4
  211. package/bin/runners/runProof.zip +0 -0
  212. package/bin/runners/runTruth.d.ts +0 -5
  213. package/bin/runners/runTruth.js +0 -101
  214. package/mcp-server/HARDENING_SUMMARY.md +0 -299
  215. package/mcp-server/agent-firewall-interceptor.js +0 -500
  216. package/mcp-server/authority-tools.js +0 -569
  217. package/mcp-server/conductor/conflict-resolver.js +0 -588
  218. package/mcp-server/conductor/execution-planner.js +0 -544
  219. package/mcp-server/conductor/index.js +0 -377
  220. package/mcp-server/conductor/lock-manager.js +0 -615
  221. package/mcp-server/conductor/request-queue.js +0 -550
  222. package/mcp-server/conductor/session-manager.js +0 -500
  223. package/mcp-server/conductor/tools.js +0 -510
  224. package/mcp-server/lib/api-client.cjs +0 -13
  225. package/mcp-server/lib/logger.cjs +0 -30
  226. package/mcp-server/logger.js +0 -173
  227. package/mcp-server/tools-v3.js +0 -706
  228. package/mcp-server/vibecheck-mcp-server-3.2.0.tgz +0 -0
@@ -1,13 +1,8 @@
1
1
  /**
2
- * CLI Output Utilities - Enterprise Grade
3
- * * Standardizes run lifecycle, artifact management, telemetry,
4
- * * and JSON output for the Vibecheck suite.
5
- * * Features:
6
- * - 🛡️ Atomic file writes (no corruption on crash)
7
- * - 🔄 Automatic "latest" symlinking for easy debugging
8
- * - 🕵️ Deep CI/Git context extraction
9
- * - 🛑 Beautiful Crash Reporting (matches UI style)
10
- * - 🧹 Automatic Log Rotation
2
+ * CLI Output Utilities - World-Class Consistency
3
+ *
4
+ * Provides standardized JSON output, run ID generation,
5
+ * and artifact management for all CLI commands.
11
6
  */
12
7
 
13
8
  "use strict";
@@ -15,154 +10,50 @@
15
10
  const fs = require("fs");
16
11
  const path = require("path");
17
12
  const crypto = require("crypto");
18
- const os = require("os");
19
- const childProcess = require("child_process");
20
- const chalk = require("chalk"); // Added for premium error reporting
21
-
22
- // Re-export exit codes for backward compatibility
23
- const { EXIT, verdictToExitCode } = require("./exit-codes");
24
-
25
- // ═══════════════════════════════════════════════════════════════════════════════
26
- // CONFIGURATION
27
- // ═══════════════════════════════════════════════════════════════════════════════
28
-
29
- const CONFIG = {
30
- DIR_NAME: ".vibecheck",
31
- MAX_RETAINED_RUNS: 50, // Keep last 50 runs, delete older
32
- WIDTH: 76,
33
- };
34
13
 
35
14
  // ═══════════════════════════════════════════════════════════════════════════════
36
15
  // RUN ID GENERATION
37
16
  // ═══════════════════════════════════════════════════════════════════════════════
38
17
 
39
18
  /**
40
- * Generate a unique, time-sortable run ID
41
- * Format: YYYY-MM-DD-HHmm-UUID
19
+ * Generate a unique run ID for tracking
42
20
  */
43
21
  function generateRunId() {
44
- const date = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 16);
45
- const uuid = crypto.randomUUID().slice(0, 8);
46
- return `${date}-${uuid}`;
22
+ return crypto.randomUUID();
47
23
  }
48
24
 
49
25
  // ═══════════════════════════════════════════════════════════════════════════════
50
- // CONTEXT GATHERING (Telemetry)
51
- // ═══════════════════════════════════════════════════════════════════════════════
52
-
53
- function getSystemContext() {
54
- return {
55
- platform: os.platform(),
56
- arch: os.arch(),
57
- node: process.version,
58
- cpus: os.cpus().length,
59
- memory: Math.round(os.totalmem() / 1024 / 1024 / 1024) + 'GB',
60
- cwd: process.cwd(),
61
- };
62
- }
63
-
64
- function getGitContext() {
65
- try {
66
- const commit = childProcess.execSync('git rev-parse --short HEAD', { stdio: 'pipe' }).toString().trim();
67
- const branch = childProcess.execSync('git rev-parse --abbrev-ref HEAD', { stdio: 'pipe' }).toString().trim();
68
- const isDirty = childProcess.execSync('git status --porcelain', { stdio: 'pipe' }).toString().trim().length > 0;
69
- return { commit, branch, isDirty };
70
- } catch (e) {
71
- return null; // Not a git repo
72
- }
73
- }
74
-
75
- function getCiContext() {
76
- if (process.env.GITHUB_ACTIONS) return { provider: 'GitHub Actions', runId: process.env.GITHUB_RUN_ID };
77
- if (process.env.GITLAB_CI) return { provider: 'GitLab CI', jobId: process.env.CI_JOB_ID };
78
- if (process.env.JENKINS_URL) return { provider: 'Jenkins', buildUrl: process.env.BUILD_URL };
79
- if (process.env.CI) return { provider: 'Generic CI' };
80
- return { provider: null };
81
- }
82
-
83
- // ═══════════════════════════════════════════════════════════════════════════════
84
- // FILESYSTEM OPS (Atomic & Safe)
26
+ // OUTPUT DIRECTORY MANAGEMENT
85
27
  // ═══════════════════════════════════════════════════════════════════════════════
86
28
 
87
29
  /**
88
- * Atomic write to prevent file corruption if process dies mid-write
30
+ * Get run directory paths
89
31
  */
90
- function safeWriteJson(filePath, data) {
91
- const tempPath = `${filePath}.tmp.${crypto.randomUUID().slice(0, 6)}`;
92
- try {
93
- fs.writeFileSync(tempPath, JSON.stringify(data, null, 2));
94
- fs.renameSync(tempPath, filePath); // Atomic operation
95
- } catch (err) {
96
- try { fs.unlinkSync(tempPath); } catch (e) {} // Cleanup
97
- throw err;
98
- }
99
- }
100
-
101
- function updateSymlink(target, linkPath) {
102
- try {
103
- if (fs.existsSync(linkPath)) fs.unlinkSync(linkPath);
104
- // 'junction' type is required for Windows to not require Admin
105
- fs.symlinkSync(target, linkPath, 'junction');
106
- } catch (e) {
107
- // Ignore symlink errors (often permissions)
108
- }
109
- }
110
-
111
- /**
112
- * Cleanup old runs to save disk space (Log Rotation)
113
- */
114
- function rotateLogs(runsDir) {
115
- try {
116
- if (!fs.existsSync(runsDir)) return;
117
-
118
- const runs = fs.readdirSync(runsDir)
119
- .map(name => ({ name, path: path.join(runsDir, name) }))
120
- .filter(item => fs.statSync(item.path).isDirectory() && item.name !== 'latest')
121
- .sort((a, b) => b.name.localeCompare(a.name)); // Newest first
122
-
123
- if (runs.length > CONFIG.MAX_RETAINED_RUNS) {
124
- const toDelete = runs.slice(CONFIG.MAX_RETAINED_RUNS);
125
- toDelete.forEach(run => fs.rmSync(run.path, { recursive: true, force: true }));
126
- }
127
- } catch (e) {
128
- // Non-blocking cleanup failure
129
- }
130
- }
131
-
132
- // ═══════════════════════════════════════════════════════════════════════════════
133
- // OUTPUT DIRECTORY MANAGEMENT
134
- // ═══════════════════════════════════════════════════════════════════════════════
135
-
136
32
  function getRunPaths(runId, projectPath = process.cwd()) {
137
- const baseDir = path.join(projectPath, CONFIG.DIR_NAME);
138
- const runDir = path.join(baseDir, "runs", runId);
139
- const latestLink = path.join(baseDir, "runs", "latest");
33
+ const runDir = path.join(projectPath, ".vibecheck", "runs", runId);
140
34
  const artifactsDir = path.join(runDir, "artifacts");
141
35
 
142
36
  // Ensure directories exist
143
- fs.mkdirSync(artifactsDir, { recursive: true });
144
-
145
- // Update 'latest' symlink for easy debugging
146
- updateSymlink(runDir, latestLink);
37
+ if (!fs.existsSync(runDir)) fs.mkdirSync(runDir, { recursive: true });
38
+ if (!fs.existsSync(artifactsDir)) fs.mkdirSync(artifactsDir, { recursive: true });
147
39
 
148
- // Trigger cleanup async (don't block the CLI)
149
- setTimeout(() => rotateLogs(path.join(baseDir, "runs")), 100).unref();
150
-
151
40
  return {
152
41
  runDir,
153
42
  artifactsDir,
154
43
  manifestPath: path.join(runDir, "manifest.json"),
155
44
  commandPath: path.join(runDir, "command.json"),
156
- crashPath: path.join(runDir, "crash.json"),
157
45
  };
158
46
  }
159
47
 
48
+ /**
49
+ * Save artifact to run directory
50
+ */
160
51
  function saveArtifact(runId, name, data, type = "json") {
161
52
  const { artifactsDir } = getRunPaths(runId);
162
53
  const artifactPath = path.join(artifactsDir, `${name}.${type}`);
163
54
 
164
55
  if (type === "json") {
165
- safeWriteJson(artifactPath, data);
56
+ fs.writeFileSync(artifactPath, JSON.stringify(data, null, 2));
166
57
  } else {
167
58
  fs.writeFileSync(artifactPath, data);
168
59
  }
@@ -174,6 +65,9 @@ function saveArtifact(runId, name, data, type = "json") {
174
65
  // JSON OUTPUT SCHEMA
175
66
  // ═══════════════════════════════════════════════════════════════════════════════
176
67
 
68
+ /**
69
+ * Create standardized JSON output
70
+ */
177
71
  function createJsonOutput(options) {
178
72
  const {
179
73
  runId,
@@ -188,71 +82,84 @@ function createJsonOutput(options) {
188
82
  artifacts = [],
189
83
  } = options;
190
84
 
191
- return {
85
+ const output = {
86
+ runId,
87
+ command,
88
+ timestamp: new Date().toISOString(),
89
+ duration: startTime ? Date.now() - new Date(startTime).getTime() : null,
90
+ exitCode,
91
+ verdict,
92
+ result,
192
93
  meta: {
193
- schemaVersion: "2.0.0",
194
- generatedAt: new Date().toISOString(),
195
- tool: { name: "vibecheck", version, tier },
196
- system: getSystemContext(),
197
- git: getGitContext(),
198
- ci: getCiContext(),
94
+ tier,
95
+ version,
96
+ path: projectPath,
199
97
  },
200
- run: {
201
- id: runId,
202
- command,
203
- durationMs: startTime ? Date.now() - new Date(startTime).getTime() : 0,
204
- exitCode,
205
- verdict,
206
- },
207
- // The actual data payload
208
- data: result,
209
- // Links to files created
210
98
  artifacts: artifacts.map(art => ({
211
99
  type: art.type,
212
- name: path.basename(art.path),
213
- path: path.relative(projectPath, art.path), // Relative for portability
100
+ path: path.relative(projectPath, art.path),
214
101
  description: art.description,
215
102
  })),
216
103
  };
104
+
105
+ return output;
217
106
  }
218
107
 
108
+ /**
109
+ * Write JSON output to file or stdout
110
+ */
219
111
  function writeJsonOutput(output, outputPath) {
220
112
  const jsonString = JSON.stringify(output, null, 2);
221
113
 
222
114
  if (outputPath) {
223
- // If output is a file, write to it
224
- safeWriteJson(outputPath, output);
115
+ fs.writeFileSync(outputPath, jsonString);
225
116
  return outputPath;
226
117
  } else {
227
- // If stdout, we must ensure we don't break pipe consumers
228
- process.stdout.write(jsonString + '\n');
118
+ console.log(jsonString);
229
119
  return null;
230
120
  }
231
121
  }
232
122
 
233
123
  // ═══════════════════════════════════════════════════════════════════════════════
234
- // VERDICT MAPPING
124
+ // VERDCT MAPPING
235
125
  // ═══════════════════════════════════════════════════════════════════════════════
236
126
 
127
+ /**
128
+ * Map exit codes to verdict strings
129
+ */
237
130
  function exitCodeToVerdict(exitCode) {
238
- const map = {
239
- 0: "SHIP",
240
- 1: "WARN",
241
- 2: "BLOCK",
242
- 3: "FEATURE_DENIED",
243
- 4: "INVALID_INPUT",
244
- 5: "INTERNAL_ERROR"
245
- };
246
- return map[exitCode] || "UNKNOWN";
131
+ switch (exitCode) {
132
+ case 0: return "SHIP";
133
+ case 1: return "WARN";
134
+ case 2: return "BLOCK";
135
+ case 3: return "FEATURE_DENIED";
136
+ case 4: return "INVALID_INPUT";
137
+ case 5: return "INTERNAL_ERROR";
138
+ default: return "UNKNOWN";
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Map verdict to exit code
144
+ */
145
+ function verdictToExitCode(verdict) {
146
+ switch (verdict?.toUpperCase()) {
147
+ case "SHIP": return 0;
148
+ case "WARN": return 1;
149
+ case "BLOCK": return 2;
150
+ case "FEATURE_DENIED": return 3;
151
+ case "INVALID_INPUT": return 4;
152
+ case "INTERNAL_ERROR": return 5;
153
+ default: return 5;
154
+ }
247
155
  }
248
156
 
249
157
  // ═══════════════════════════════════════════════════════════════════════════════
250
- // COMMAND WRAPPER (The Safety Net)
158
+ // COMMAND WRAPPER
251
159
  // ═══════════════════════════════════════════════════════════════════════════════
252
160
 
253
161
  /**
254
- * Wrap a command runner with world-class output handling,
255
- * telemetry, and crash protection.
162
+ * Wrap a command runner with standard output handling
256
163
  */
257
164
  async function withStandardOutput(commandFn, options = {}) {
258
165
  const {
@@ -261,88 +168,104 @@ async function withStandardOutput(commandFn, options = {}) {
261
168
  runId = generateRunId(),
262
169
  json = false,
263
170
  output = null,
171
+ ci = false,
172
+ verbose = false,
264
173
  tier = "free",
265
174
  version = "1.0.0",
266
175
  } = options;
267
176
 
177
+ // Initialize paths
268
178
  const paths = getRunPaths(runId);
269
179
  const artifacts = [];
270
180
 
271
- // Artifact helper injected into the command
272
- const artifactSaver = (name, data, type = 'json') => {
273
- try {
274
- const artifactPath = saveArtifact(runId, name, data, type);
275
- artifacts.push({ type, path: artifactPath, description: name });
276
- return artifactPath;
277
- } catch (e) {
278
- console.error(chalk.yellow(`⚠️ Warning: Failed to save artifact ${name}: ${e.message}`));
279
- return null;
280
- }
281
- };
282
-
283
181
  try {
284
- // Execute Command
182
+ // Run the command
285
183
  const result = await commandFn({
286
184
  runId,
287
185
  paths,
288
- saveArtifact: artifactSaver,
186
+ saveArtifact: (name, data, type) => {
187
+ const artifactPath = saveArtifact(runId, name, data, type);
188
+ artifacts.push({
189
+ type,
190
+ path: artifactPath,
191
+ description: `${name} artifact`,
192
+ });
193
+ return artifactPath;
194
+ },
289
195
  });
290
196
 
291
- // Normalize Result
292
- const exitCode = typeof result === "number" ? result : (result.exitCode ?? 0);
197
+ // Extract exit code and verdict
198
+ const exitCode = typeof result === "number" ? result : result.exitCode || 0;
293
199
  const verdict = result.verdict || exitCodeToVerdict(exitCode);
294
- const resultData = typeof result === "object" ? result : {};
295
-
296
- const outputObj = createJsonOutput({
297
- runId, command, startTime, exitCode, verdict,
298
- result: resultData, tier, version, artifacts
299
- });
300
-
301
- // 1. Always save to internal history
302
- safeWriteJson(paths.commandPath, outputObj);
303
-
304
- // 2. If JSON requested by user, print/write it
200
+
201
+ // Create JSON output if requested
305
202
  if (json) {
306
- writeJsonOutput(outputObj, output);
203
+ const jsonOutput = createJsonOutput({
204
+ runId,
205
+ command,
206
+ startTime,
207
+ exitCode,
208
+ verdict,
209
+ result: typeof result === "object" ? result : {},
210
+ tier,
211
+ version,
212
+ artifacts,
213
+ });
214
+
215
+ writeJsonOutput(jsonOutput, output);
307
216
  }
308
-
217
+
218
+ // Save command output to run directory
219
+ const commandOutput = {
220
+ exitCode,
221
+ verdict,
222
+ result: typeof result === "object" ? result : {},
223
+ artifacts,
224
+ };
225
+ fs.writeFileSync(paths.commandPath, JSON.stringify(commandOutput, null, 2));
226
+
227
+ // Update stable pointer
228
+ const lastPath = path.join(process.cwd(), ".vibecheck", "last", `${command}.json`);
229
+ if (!fs.existsSync(path.dirname(lastPath))) {
230
+ fs.mkdirSync(path.dirname(lastPath), { recursive: true });
231
+ }
232
+ fs.writeFileSync(lastPath, JSON.stringify(commandOutput, null, 2));
233
+
309
234
  return exitCode;
310
-
311
235
  } catch (error) {
312
- // 🛑 CRITICAL ERROR HANDLING
236
+ // Handle errors consistently
313
237
  const exitCode = error.exitCode || 5;
314
238
  const verdict = "INTERNAL_ERROR";
315
239
 
316
- const errorData = {
317
- message: error.message,
318
- stack: error.stack,
319
- code: error.code || 'UNKNOWN',
320
- };
321
-
322
- const outputObj = createJsonOutput({
323
- runId, command, startTime, exitCode, verdict,
324
- result: { error: errorData }, tier, version, artifacts
325
- });
326
-
327
- // Save crash report to disk
328
- safeWriteJson(paths.crashPath, outputObj);
329
- safeWriteJson(paths.commandPath, outputObj);
330
-
331
240
  if (json) {
332
- writeJsonOutput(outputObj, output);
333
- } else {
334
- // VISUAL CRASH REPORT
335
- console.error('');
336
- console.error(chalk.bgRed.white.bold(` 🛑 SYSTEM ALERT: INTERNAL CRASH `));
337
- console.error(chalk.red('─'.repeat(CONFIG.WIDTH)));
338
- console.error(`${chalk.bold('Error:')} ${error.message}`);
339
- console.error(`${chalk.bold('Run ID:')} ${runId}`);
340
- console.error(`${chalk.bold('Log:')} ${chalk.cyan(paths.crashPath)}`);
341
- console.error(chalk.red('─'.repeat(CONFIG.WIDTH)));
342
- console.error('');
241
+ const jsonOutput = createJsonOutput({
242
+ runId,
243
+ command,
244
+ startTime,
245
+ exitCode,
246
+ verdict,
247
+ result: {
248
+ error: error.message,
249
+ stack: error.stack,
250
+ },
251
+ tier,
252
+ version,
253
+ artifacts,
254
+ });
255
+
256
+ writeJsonOutput(jsonOutput, output);
343
257
  }
344
-
345
- throw error; // Re-throw so the process actually exits with error
258
+
259
+ // Save error to run directory
260
+ const commandOutput = {
261
+ exitCode,
262
+ verdict,
263
+ error: error.message,
264
+ artifacts,
265
+ };
266
+ fs.writeFileSync(paths.commandPath, JSON.stringify(commandOutput, null, 2));
267
+
268
+ throw error;
346
269
  }
347
270
  }
348
271
 
@@ -350,10 +273,13 @@ async function withStandardOutput(commandFn, options = {}) {
350
273
  // STANDARD FLAGS PARSER
351
274
  // ═══════════════════════════════════════════════════════════════════════════════
352
275
 
276
+ /**
277
+ * Parse standard CLI flags
278
+ */
353
279
  function parseStandardFlags(args) {
354
280
  const flags = {
355
281
  json: false,
356
- ci: !!process.env.CI, // Auto-detect CI
282
+ ci: false,
357
283
  path: process.cwd(),
358
284
  output: null,
359
285
  verbose: false,
@@ -361,40 +287,82 @@ function parseStandardFlags(args) {
361
287
  help: false,
362
288
  version: false,
363
289
  debug: false,
290
+ quiet: false,
364
291
  };
365
292
 
366
- const parsed = [];
367
-
368
- for (let i = 0; i < args.length; i++) {
369
- const arg = args[i];
370
-
371
- if (arg === '--json' || arg === '-j') flags.json = true;
372
- else if (arg === '--ci') flags.ci = true;
373
- else if (arg === '--verbose' || arg === '-v') flags.verbose = true;
374
- else if (arg === '--strict') flags.strict = true;
375
- else if (arg === '--help' || arg === '-h') flags.help = true;
376
- else if (arg === '--version' || arg === '-V') flags.version = true;
377
- else if (arg === '--debug' || arg === '-d') flags.debug = true;
378
- else if (arg.startsWith('--path=')) flags.path = arg.split('=')[1];
379
- else if (arg === '-p' && args[i+1]) { flags.path = args[++i]; }
380
- else if (arg.startsWith('--output=')) flags.output = arg.split('=')[1];
381
- else if (arg === '-o' && args[i+1]) { flags.output = args[++i]; }
382
- else parsed.push(arg);
383
- }
293
+ const parsed = args.filter(arg => {
294
+ switch (arg) {
295
+ case "--json":
296
+ case "-j":
297
+ flags.json = true;
298
+ return false;
299
+ case "--ci":
300
+ flags.ci = true;
301
+ return false;
302
+ case "--verbose":
303
+ case "-v":
304
+ flags.verbose = true;
305
+ return false;
306
+ case "--strict":
307
+ flags.strict = true;
308
+ return false;
309
+ case "--help":
310
+ case "-h":
311
+ flags.help = true;
312
+ return false;
313
+ case "--version":
314
+ case "-V":
315
+ flags.version = true;
316
+ return false;
317
+ case "--debug":
318
+ case "-d":
319
+ flags.debug = true;
320
+ return false;
321
+ case "--quiet":
322
+ case "-q":
323
+ flags.quiet = true;
324
+ return false;
325
+ default:
326
+ if (arg.startsWith("--path=")) {
327
+ flags.path = arg.split("=")[1];
328
+ return false;
329
+ } else if (arg.startsWith("-p")) {
330
+ const idx = args.indexOf(arg);
331
+ if (idx < args.length - 1) {
332
+ flags.path = args[idx + 1];
333
+ args.splice(idx, 2);
334
+ return false;
335
+ }
336
+ } else if (arg.startsWith("--output=")) {
337
+ flags.output = arg.split("=")[1];
338
+ return false;
339
+ } else if (arg.startsWith("-o")) {
340
+ const idx = args.indexOf(arg);
341
+ if (idx < args.length - 1) {
342
+ flags.output = args[idx + 1];
343
+ args.splice(idx, 2);
344
+ return false;
345
+ }
346
+ }
347
+ return true;
348
+ }
349
+ });
384
350
 
385
351
  return { flags, parsed };
386
352
  }
387
353
 
354
+ // ═══════════════════════════════════════════════════════════════════════════════
355
+ // EXPORTS
356
+ // ═══════════════════════════════════════════════════════════════════════════════
357
+
388
358
  module.exports = {
389
359
  generateRunId,
390
360
  getRunPaths,
391
361
  saveArtifact,
392
362
  createJsonOutput,
393
363
  writeJsonOutput,
394
- exitCodeToVerdict, // Local function
395
- // Re-exported from exit-codes.js
364
+ exitCodeToVerdict,
396
365
  verdictToExitCode,
397
- EXIT,
398
366
  withStandardOutput,
399
367
  parseStandardFlags,
400
- };
368
+ };