@vibecheckai/cli 3.2.2 → 3.2.4

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 (170) hide show
  1. package/bin/.generated +25 -25
  2. package/bin/dev/run-v2-torture.js +30 -30
  3. package/bin/runners/ENHANCEMENT_GUIDE.md +121 -121
  4. package/bin/runners/lib/__tests__/entitlements-v2.test.js +295 -295
  5. package/bin/runners/lib/agent-firewall/ai/false-positive-analyzer.js +474 -0
  6. package/bin/runners/lib/agent-firewall/claims/extractor.js +117 -28
  7. package/bin/runners/lib/agent-firewall/evidence/env-evidence.js +23 -14
  8. package/bin/runners/lib/agent-firewall/evidence/route-evidence.js +72 -1
  9. package/bin/runners/lib/agent-firewall/interceptor/base.js +2 -2
  10. package/bin/runners/lib/agent-firewall/policy/default-policy.json +6 -0
  11. package/bin/runners/lib/agent-firewall/policy/engine.js +34 -3
  12. package/bin/runners/lib/agent-firewall/policy/rules/fake-success.js +29 -4
  13. package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +12 -0
  14. package/bin/runners/lib/agent-firewall/truthpack/loader.js +21 -0
  15. package/bin/runners/lib/agent-firewall/utils/ignore-checker.js +118 -0
  16. package/bin/runners/lib/analyzers.js +606 -325
  17. package/bin/runners/lib/auth-truth.js +193 -193
  18. package/bin/runners/lib/backup.js +62 -62
  19. package/bin/runners/lib/billing.js +107 -107
  20. package/bin/runners/lib/claims.js +118 -118
  21. package/bin/runners/lib/cli-ui.js +540 -540
  22. package/bin/runners/lib/contracts/auth-contract.js +202 -202
  23. package/bin/runners/lib/contracts/env-contract.js +181 -181
  24. package/bin/runners/lib/contracts/external-contract.js +206 -206
  25. package/bin/runners/lib/contracts/guard.js +168 -168
  26. package/bin/runners/lib/contracts/index.js +89 -89
  27. package/bin/runners/lib/contracts/plan-validator.js +311 -311
  28. package/bin/runners/lib/contracts/route-contract.js +199 -199
  29. package/bin/runners/lib/contracts.js +804 -804
  30. package/bin/runners/lib/detect.js +89 -89
  31. package/bin/runners/lib/doctor/autofix.js +254 -254
  32. package/bin/runners/lib/doctor/index.js +37 -37
  33. package/bin/runners/lib/doctor/modules/dependencies.js +325 -325
  34. package/bin/runners/lib/doctor/modules/index.js +46 -46
  35. package/bin/runners/lib/doctor/modules/network.js +250 -250
  36. package/bin/runners/lib/doctor/modules/project.js +312 -312
  37. package/bin/runners/lib/doctor/modules/runtime.js +224 -224
  38. package/bin/runners/lib/doctor/modules/security.js +348 -348
  39. package/bin/runners/lib/doctor/modules/system.js +213 -213
  40. package/bin/runners/lib/doctor/modules/vibecheck.js +394 -394
  41. package/bin/runners/lib/doctor/reporter.js +262 -262
  42. package/bin/runners/lib/doctor/service.js +262 -262
  43. package/bin/runners/lib/doctor/types.js +113 -113
  44. package/bin/runners/lib/doctor/ui.js +263 -263
  45. package/bin/runners/lib/doctor-v2.js +608 -608
  46. package/bin/runners/lib/drift.js +425 -425
  47. package/bin/runners/lib/enforcement.js +72 -72
  48. package/bin/runners/lib/engines/accessibility-engine.js +190 -0
  49. package/bin/runners/lib/engines/api-consistency-engine.js +162 -0
  50. package/bin/runners/lib/engines/ast-cache.js +99 -0
  51. package/bin/runners/lib/engines/code-quality-engine.js +255 -0
  52. package/bin/runners/lib/engines/console-logs-engine.js +115 -0
  53. package/bin/runners/lib/engines/cross-file-analysis-engine.js +268 -0
  54. package/bin/runners/lib/engines/dead-code-engine.js +198 -0
  55. package/bin/runners/lib/engines/deprecated-api-engine.js +226 -0
  56. package/bin/runners/lib/engines/empty-catch-engine.js +150 -0
  57. package/bin/runners/lib/engines/file-filter.js +131 -0
  58. package/bin/runners/lib/engines/hardcoded-secrets-engine.js +251 -0
  59. package/bin/runners/lib/engines/mock-data-engine.js +272 -0
  60. package/bin/runners/lib/engines/parallel-processor.js +71 -0
  61. package/bin/runners/lib/engines/performance-issues-engine.js +265 -0
  62. package/bin/runners/lib/engines/security-vulnerabilities-engine.js +243 -0
  63. package/bin/runners/lib/engines/todo-fixme-engine.js +115 -0
  64. package/bin/runners/lib/engines/type-aware-engine.js +152 -0
  65. package/bin/runners/lib/engines/unsafe-regex-engine.js +225 -0
  66. package/bin/runners/lib/engines/vibecheck-engines/README.md +53 -0
  67. package/bin/runners/lib/engines/vibecheck-engines/index.js +15 -0
  68. package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +164 -0
  69. package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +291 -0
  70. package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +83 -0
  71. package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +198 -0
  72. package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +275 -0
  73. package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +167 -0
  74. package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +217 -0
  75. package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +139 -0
  76. package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +140 -0
  77. package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +164 -0
  78. package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +234 -0
  79. package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +217 -0
  80. package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +78 -0
  81. package/bin/runners/lib/engines/vibecheck-engines/package.json +13 -0
  82. package/bin/runners/lib/enterprise-detect.js +603 -603
  83. package/bin/runners/lib/enterprise-init.js +942 -942
  84. package/bin/runners/lib/env-resolver.js +417 -417
  85. package/bin/runners/lib/env-template.js +66 -66
  86. package/bin/runners/lib/env.js +189 -189
  87. package/bin/runners/lib/extractors/client-calls.js +990 -990
  88. package/bin/runners/lib/extractors/fastify-route-dump.js +573 -573
  89. package/bin/runners/lib/extractors/fastify-routes.js +426 -426
  90. package/bin/runners/lib/extractors/index.js +363 -363
  91. package/bin/runners/lib/extractors/next-routes.js +524 -524
  92. package/bin/runners/lib/extractors/proof-graph.js +431 -431
  93. package/bin/runners/lib/extractors/route-matcher.js +451 -451
  94. package/bin/runners/lib/extractors/truthpack-v2.js +377 -377
  95. package/bin/runners/lib/extractors/ui-bindings.js +547 -547
  96. package/bin/runners/lib/findings-schema.js +281 -281
  97. package/bin/runners/lib/firewall-prompt.js +50 -50
  98. package/bin/runners/lib/global-flags.js +213 -213
  99. package/bin/runners/lib/graph/graph-builder.js +265 -265
  100. package/bin/runners/lib/graph/html-renderer.js +413 -413
  101. package/bin/runners/lib/graph/index.js +32 -32
  102. package/bin/runners/lib/graph/runtime-collector.js +215 -215
  103. package/bin/runners/lib/graph/static-extractor.js +518 -518
  104. package/bin/runners/lib/html-report.js +650 -650
  105. package/bin/runners/lib/interactive-menu.js +1496 -1496
  106. package/bin/runners/lib/llm.js +75 -75
  107. package/bin/runners/lib/meter.js +61 -61
  108. package/bin/runners/lib/missions/evidence.js +126 -126
  109. package/bin/runners/lib/patch.js +40 -40
  110. package/bin/runners/lib/permissions/auth-model.js +213 -213
  111. package/bin/runners/lib/permissions/idor-prover.js +205 -205
  112. package/bin/runners/lib/permissions/index.js +45 -45
  113. package/bin/runners/lib/permissions/matrix-builder.js +198 -198
  114. package/bin/runners/lib/pkgjson.js +28 -28
  115. package/bin/runners/lib/policy.js +295 -295
  116. package/bin/runners/lib/preflight.js +142 -142
  117. package/bin/runners/lib/reality/correlation-detectors.js +359 -359
  118. package/bin/runners/lib/reality/index.js +318 -318
  119. package/bin/runners/lib/reality/request-hashing.js +416 -416
  120. package/bin/runners/lib/reality/request-mapper.js +453 -453
  121. package/bin/runners/lib/reality/safety-rails.js +463 -463
  122. package/bin/runners/lib/reality/semantic-snapshot.js +408 -408
  123. package/bin/runners/lib/reality/toast-detector.js +393 -393
  124. package/bin/runners/lib/reality-findings.js +84 -84
  125. package/bin/runners/lib/receipts.js +179 -179
  126. package/bin/runners/lib/redact.js +29 -29
  127. package/bin/runners/lib/replay/capsule-manager.js +154 -154
  128. package/bin/runners/lib/replay/index.js +263 -263
  129. package/bin/runners/lib/replay/player.js +348 -348
  130. package/bin/runners/lib/replay/recorder.js +331 -331
  131. package/bin/runners/lib/report-output.js +187 -187
  132. package/bin/runners/lib/report.js +135 -135
  133. package/bin/runners/lib/route-detection.js +1140 -1140
  134. package/bin/runners/lib/sandbox/index.js +59 -59
  135. package/bin/runners/lib/sandbox/proof-chain.js +399 -399
  136. package/bin/runners/lib/sandbox/sandbox-runner.js +205 -205
  137. package/bin/runners/lib/sandbox/worktree.js +174 -174
  138. package/bin/runners/lib/scan-output.js +525 -190
  139. package/bin/runners/lib/schema-validator.js +350 -350
  140. package/bin/runners/lib/schemas/contracts.schema.json +160 -160
  141. package/bin/runners/lib/schemas/finding.schema.json +100 -100
  142. package/bin/runners/lib/schemas/mission-pack.schema.json +206 -206
  143. package/bin/runners/lib/schemas/proof-graph.schema.json +176 -176
  144. package/bin/runners/lib/schemas/reality-report.schema.json +162 -162
  145. package/bin/runners/lib/schemas/share-pack.schema.json +180 -180
  146. package/bin/runners/lib/schemas/ship-report.schema.json +117 -117
  147. package/bin/runners/lib/schemas/truthpack-v2.schema.json +303 -303
  148. package/bin/runners/lib/schemas/validator.js +438 -438
  149. package/bin/runners/lib/score-history.js +282 -282
  150. package/bin/runners/lib/share-pack.js +239 -239
  151. package/bin/runners/lib/snippets.js +67 -67
  152. package/bin/runners/lib/status-output.js +253 -253
  153. package/bin/runners/lib/terminal-ui.js +351 -271
  154. package/bin/runners/lib/upsell.js +510 -510
  155. package/bin/runners/lib/usage.js +153 -153
  156. package/bin/runners/lib/validate-patch.js +156 -156
  157. package/bin/runners/lib/verdict-engine.js +628 -628
  158. package/bin/runners/reality/engine.js +917 -917
  159. package/bin/runners/reality/flows.js +122 -122
  160. package/bin/runners/reality/report.js +378 -378
  161. package/bin/runners/reality/session.js +193 -193
  162. package/bin/runners/runGuard.js +168 -168
  163. package/bin/runners/runProof.zip +0 -0
  164. package/bin/runners/runProve.js +8 -0
  165. package/bin/runners/runReality.js +14 -0
  166. package/bin/runners/runScan.js +17 -1
  167. package/bin/runners/runTruth.js +15 -3
  168. package/mcp-server/tier-auth.js +4 -4
  169. package/mcp-server/tools/index.js +72 -72
  170. package/package.json +1 -1
@@ -1,942 +1,942 @@
1
- // bin/runners/lib/enterprise-init.js
2
- // Enterprise-grade initialization: security policies, compliance, CI/CD, team configs
3
- const fs = require("fs");
4
- const path = require("path");
5
- const { detectAll, CI_PROVIDERS, DEPLOY_PLATFORMS } = require("./enterprise-detect");
6
-
7
- // ANSI colors
8
- const c = {
9
- reset: "\x1b[0m",
10
- bold: "\x1b[1m",
11
- dim: "\x1b[2m",
12
- red: "\x1b[31m",
13
- green: "\x1b[32m",
14
- yellow: "\x1b[33m",
15
- blue: "\x1b[34m",
16
- cyan: "\x1b[36m",
17
- magenta: "\x1b[35m",
18
- };
19
-
20
- function ensureDir(p) {
21
- fs.mkdirSync(p, { recursive: true });
22
- }
23
-
24
- // ============================================================================
25
- // INVARIANTS CONFIGURATION
26
- // ============================================================================
27
- const INVARIANT_DEFINITIONS = {
28
- INV_NO_FAKE_SUCCESS: {
29
- id: "INV_NO_FAKE_SUCCESS",
30
- severity: "BLOCK",
31
- description: "No success UI without confirmed success (awaited network + ok check)",
32
- category: "reliability",
33
- },
34
- INV_NO_ROUTE_INVENTION: {
35
- id: "INV_NO_ROUTE_INVENTION",
36
- severity: "BLOCK",
37
- description: "No route references without matching server route",
38
- category: "integrity",
39
- },
40
- INV_NO_BYPASS_ENTITLEMENTS: {
41
- id: "INV_NO_BYPASS_ENTITLEMENTS",
42
- severity: "BLOCK",
43
- description: "No bypass flags (OWNER_MODE, skipBilling, etc)",
44
- category: "billing",
45
- },
46
- INV_NO_SILENT_CATCH_AUTH: {
47
- id: "INV_NO_SILENT_CATCH_AUTH",
48
- severity: "BLOCK",
49
- description: "No silent catch blocks in auth/billing code paths",
50
- category: "security",
51
- },
52
- INV_NO_HARDCODED_SECRETS: {
53
- id: "INV_NO_HARDCODED_SECRETS",
54
- severity: "BLOCK",
55
- description: "No hardcoded secrets, API keys, or credentials in code",
56
- category: "security",
57
- },
58
- INV_NO_GHOST_AUTH: {
59
- id: "INV_NO_GHOST_AUTH",
60
- severity: "BLOCK",
61
- description: "No sensitive endpoints without auth enforcement",
62
- category: "security",
63
- },
64
- INV_STRIPE_WEBHOOK_VERIFIED: {
65
- id: "INV_STRIPE_WEBHOOK_VERIFIED",
66
- severity: "BLOCK",
67
- description: "All Stripe webhook handlers must verify signature",
68
- category: "billing",
69
- },
70
- INV_STRIPE_IDEMPOTENT: {
71
- id: "INV_STRIPE_IDEMPOTENT",
72
- severity: "WARN",
73
- description: "Stripe webhook handlers should be idempotent",
74
- category: "billing",
75
- },
76
- INV_ENV_VARS_DECLARED: {
77
- id: "INV_ENV_VARS_DECLARED",
78
- severity: "WARN",
79
- description: "All used env vars must be declared in .env.example",
80
- category: "operations",
81
- },
82
- };
83
-
84
- // ============================================================================
85
- // COMPLIANCE TEMPLATES
86
- // ============================================================================
87
- const COMPLIANCE_TEMPLATES = {
88
- soc2: {
89
- name: "SOC 2 Type II",
90
- description: "Service Organization Control 2 compliance baseline",
91
- policies: {
92
- accessControl: true,
93
- changeManagement: true,
94
- riskAssessment: true,
95
- incidentResponse: true,
96
- vendorManagement: true,
97
- },
98
- invariants: [
99
- "INV_NO_HARDCODED_SECRETS",
100
- "INV_NO_GHOST_AUTH",
101
- "INV_NO_SILENT_CATCH_AUTH",
102
- ],
103
- },
104
- hipaa: {
105
- name: "HIPAA",
106
- description: "Health Insurance Portability and Accountability Act baseline",
107
- policies: {
108
- phi_protection: true,
109
- accessControl: true,
110
- auditLogging: true,
111
- encryption: true,
112
- },
113
- invariants: [
114
- "INV_NO_HARDCODED_SECRETS",
115
- "INV_NO_GHOST_AUTH",
116
- ],
117
- },
118
- gdpr: {
119
- name: "GDPR",
120
- description: "General Data Protection Regulation baseline",
121
- policies: {
122
- dataMinimization: true,
123
- consentManagement: true,
124
- rightToErasure: true,
125
- dataPortability: true,
126
- },
127
- invariants: [
128
- "INV_NO_HARDCODED_SECRETS",
129
- ],
130
- },
131
- pci: {
132
- name: "PCI-DSS",
133
- description: "Payment Card Industry Data Security Standard baseline",
134
- policies: {
135
- cardDataProtection: true,
136
- accessControl: true,
137
- encryption: true,
138
- monitoring: true,
139
- },
140
- invariants: [
141
- "INV_NO_HARDCODED_SECRETS",
142
- "INV_STRIPE_WEBHOOK_VERIFIED",
143
- "INV_NO_BYPASS_ENTITLEMENTS",
144
- ],
145
- },
146
- };
147
-
148
- // ============================================================================
149
- // SECURITY POLICY TEMPLATES
150
- // ============================================================================
151
- function generateSecurityPolicy(detection) {
152
- const hasPayments = Object.keys(detection.payments).length > 0;
153
- const hasAuth = Object.keys(detection.auth).length > 0;
154
-
155
- return {
156
- version: "1.0.0",
157
- headers: {
158
- strictTransportSecurity: "max-age=31536000; includeSubDomains",
159
- contentSecurityPolicy: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'",
160
- xFrameOptions: "DENY",
161
- xContentTypeOptions: "nosniff",
162
- referrerPolicy: "strict-origin-when-cross-origin",
163
- permissionsPolicy: "camera=(), microphone=(), geolocation=()",
164
- },
165
- cors: {
166
- allowedOrigins: ["${ALLOWED_ORIGINS}"],
167
- allowedMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
168
- allowCredentials: true,
169
- maxAge: 86400,
170
- },
171
- rateLimit: {
172
- enabled: true,
173
- windowMs: 60000,
174
- max: 100,
175
- message: "Too many requests, please try again later",
176
- },
177
- secrets: {
178
- scanEnabled: true,
179
- blockOnDetection: true,
180
- patterns: [
181
- "sk_live_",
182
- "pk_live_",
183
- "AKIA",
184
- "ghp_",
185
- "gho_",
186
- "eyJ",
187
- ],
188
- },
189
- auth: hasAuth ? {
190
- sessionTimeout: 3600,
191
- mfaRecommended: true,
192
- passwordMinLength: 12,
193
- } : null,
194
- payments: hasPayments ? {
195
- webhookVerification: true,
196
- idempotencyRequired: true,
197
- testModeBlockProduction: true,
198
- } : null,
199
- };
200
- }
201
-
202
- // ============================================================================
203
- // CI/CD TEMPLATES
204
- // ============================================================================
205
- function generateGitHubActionsWorkflow(detection, options = {}) {
206
- const pm = detection.packageManager;
207
- const installCmd = pm === "pnpm" ? "pnpm install --frozen-lockfile" :
208
- pm === "yarn" ? "yarn install --frozen-lockfile" :
209
- pm === "bun" ? "bun install --frozen-lockfile" : "npm ci";
210
-
211
- const runPrefix = pm === "pnpm" ? "pnpm" : pm === "yarn" ? "yarn" : pm === "bun" ? "bun" : "npx";
212
-
213
- return `name: vibecheck
214
-
215
- on:
216
- push:
217
- branches: [main, master]
218
- pull_request:
219
- branches: [main, master]
220
-
221
- permissions:
222
- contents: read
223
- pull-requests: write
224
- security-events: write
225
-
226
- env:
227
- CI: true
228
- NODE_ENV: test
229
-
230
- jobs:
231
- vibecheck:
232
- name: Ship Decision
233
- runs-on: ubuntu-latest
234
- timeout-minutes: 15
235
-
236
- steps:
237
- - name: Checkout
238
- uses: actions/checkout@v4
239
- with:
240
- fetch-depth: 0
241
-
242
- - name: Setup Node.js
243
- uses: actions/setup-node@v4
244
- with:
245
- node-version: 20
246
- cache: '${pm}'
247
-
248
- - name: Install dependencies
249
- run: ${installCmd}
250
-
251
- - name: Generate Truth Pack
252
- run: ${runPrefix} vibecheck ctx
253
- continue-on-error: true
254
-
255
- - name: Ship Decision
256
- id: ship
257
- run: |
258
- set +e
259
- mkdir -p .vibecheck
260
- ${runPrefix} vibecheck pr --out .vibecheck/pr_comment.md ${options.failOnWarn ? "--fail-on-warn" : ""}
261
- code=$?
262
- echo "exit_code=$code" >> $GITHUB_OUTPUT
263
- exit 0
264
-
265
- - name: Upload Artifacts
266
- uses: actions/upload-artifact@v4
267
- if: always()
268
- with:
269
- name: vibecheck-report
270
- path: .vibecheck/
271
- retention-days: 30
272
-
273
- - name: Comment on PR
274
- if: github.event_name == 'pull_request'
275
- uses: actions/github-script@v7
276
- with:
277
- script: |
278
- const fs = require('fs');
279
- const commentPath = '.vibecheck/pr_comment.md';
280
- if (!fs.existsSync(commentPath)) {
281
- console.log('No comment file found');
282
- return;
283
- }
284
- const body = fs.readFileSync(commentPath, 'utf8');
285
-
286
- // Find existing vibecheck comment
287
- const { data: comments } = await github.rest.issues.listComments({
288
- owner: context.repo.owner,
289
- repo: context.repo.repo,
290
- issue_number: context.issue.number,
291
- });
292
-
293
- const existingComment = comments.find(c =>
294
- c.user.type === 'Bot' && c.body.includes('vibecheck')
295
- );
296
-
297
- if (existingComment) {
298
- await github.rest.issues.updateComment({
299
- owner: context.repo.owner,
300
- repo: context.repo.repo,
301
- comment_id: existingComment.id,
302
- body
303
- });
304
- } else {
305
- await github.rest.issues.createComment({
306
- owner: context.repo.owner,
307
- repo: context.repo.repo,
308
- issue_number: context.issue.number,
309
- body
310
- });
311
- }
312
-
313
- - name: Enforce Verdict
314
- run: |
315
- code="\${{ steps.ship.outputs.exit_code }}"
316
- echo "vibecheck exit code: $code"
317
- if [ "$code" = "2" ]; then
318
- echo "::error::BLOCK verdict - deployment blocked"
319
- exit 1
320
- fi
321
- ${options.failOnWarn ? 'if [ "$code" = "1" ]; then echo "::error::WARN verdict (policy: fail-on-warn)"; exit 1; fi' : ''}
322
- echo "✅ Ship decision passed"
323
- `;
324
- }
325
-
326
- function generateGitLabCI(detection, options = {}) {
327
- const pm = detection.packageManager;
328
- const installCmd = pm === "pnpm" ? "pnpm install --frozen-lockfile" :
329
- pm === "yarn" ? "yarn install --frozen-lockfile" : "npm ci";
330
-
331
- return `stages:
332
- - test
333
- - deploy
334
-
335
- variables:
336
- CI: "true"
337
- NODE_ENV: test
338
-
339
- vibecheck:
340
- stage: test
341
- image: node:20
342
- cache:
343
- key: \${CI_COMMIT_REF_SLUG}
344
- paths:
345
- - node_modules/
346
- - .pnpm-store/
347
- before_script:
348
- - ${pm === "pnpm" ? "corepack enable && " : ""}${installCmd}
349
- script:
350
- - npx vibecheck ctx
351
- - npx vibecheck ship ${options.failOnWarn ? "--fail-on-warn" : ""}
352
- artifacts:
353
- when: always
354
- paths:
355
- - .vibecheck/
356
- expire_in: 30 days
357
- rules:
358
- - if: $CI_PIPELINE_SOURCE == "merge_request_event"
359
- - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
360
- `;
361
- }
362
-
363
- // ============================================================================
364
- // TEAM CONFIG TEMPLATES
365
- // ============================================================================
366
- function generateTeamConfig(detection, options = {}) {
367
- const environments = options.environments || ["development", "staging", "production"];
368
-
369
- return {
370
- version: "1.0.0",
371
- team: {
372
- name: options.teamName || detection.pkg?.name || "unnamed",
373
- environments,
374
- },
375
- policies: {
376
- development: {
377
- verdict: { warnAsPass: true, blockAsBlock: true },
378
- autoFix: { enabled: true, requireApproval: false },
379
- },
380
- staging: {
381
- verdict: { warnAsPass: true, blockAsBlock: true },
382
- autoFix: { enabled: true, requireApproval: true },
383
- },
384
- production: {
385
- verdict: { warnAsPass: false, blockAsBlock: true },
386
- autoFix: { enabled: false, requireApproval: true },
387
- additionalInvariants: ["INV_NO_BYPASS_ENTITLEMENTS"],
388
- },
389
- },
390
- notifications: {
391
- slack: { webhook: "${SLACK_WEBHOOK_URL}", enabled: false },
392
- email: { recipients: [], enabled: false },
393
- },
394
- reporting: {
395
- frequency: "weekly",
396
- recipients: [],
397
- includeMetrics: true,
398
- },
399
- };
400
- }
401
-
402
- // ============================================================================
403
- // MCP SERVER CONFIG
404
- // ============================================================================
405
- function generateMCPConfig(detection) {
406
- return {
407
- name: "vibecheck",
408
- version: "1.0.0",
409
- description: "Vibecheck MCP server for AI agent integration",
410
- capabilities: {
411
- tools: true,
412
- resources: true,
413
- prompts: true,
414
- },
415
- tools: [
416
- "validate_claim",
417
- "get_truthpack",
418
- "get_route_map",
419
- "verify_auth",
420
- "check_invariant",
421
- ],
422
- security: {
423
- requireAuth: false,
424
- allowedOrigins: ["*"],
425
- },
426
- };
427
- }
428
-
429
- // ============================================================================
430
- // INVARIANTS FILE
431
- // ============================================================================
432
- function generateInvariantsYml(invariants) {
433
- const lines = ["# vibecheck invariants - ship killers and warnings", ""];
434
-
435
- const blocks = invariants.filter(id => INVARIANT_DEFINITIONS[id]?.severity === "BLOCK");
436
- const warns = invariants.filter(id => INVARIANT_DEFINITIONS[id]?.severity === "WARN");
437
-
438
- if (blocks.length) {
439
- lines.push("ship_killers:");
440
- for (const id of blocks) {
441
- const def = INVARIANT_DEFINITIONS[id];
442
- lines.push(` - id: ${id}`);
443
- lines.push(` description: "${def?.description || id}"`);
444
- lines.push(` category: ${def?.category || "general"}`);
445
- lines.push("");
446
- }
447
- }
448
-
449
- if (warns.length) {
450
- lines.push("warnings:");
451
- for (const id of warns) {
452
- const def = INVARIANT_DEFINITIONS[id];
453
- lines.push(` - id: ${id}`);
454
- lines.push(` description: "${def?.description || id}"`);
455
- lines.push(` category: ${def?.category || "general"}`);
456
- lines.push("");
457
- }
458
- }
459
-
460
- return lines.join("\n");
461
- }
462
-
463
- // ============================================================================
464
- // MAIN CONFIG FILE
465
- // ============================================================================
466
- function generateVibecheckConfig(detection, options = {}) {
467
- const primaryFramework = Object.keys(detection.frameworks)[0] || "node";
468
- const primaryDb = Object.keys(detection.databases)[0];
469
- const primaryAuth = Object.keys(detection.auth)[0];
470
- const primaryPayment = Object.keys(detection.payments)[0];
471
-
472
- return {
473
- $schema: "https://vibecheck.dev/schemas/config.json",
474
- version: "2.0.0",
475
- project: {
476
- name: detection.pkg?.name || "unnamed",
477
- framework: primaryFramework,
478
- packageManager: detection.packageManager,
479
- },
480
- detection: {
481
- frameworks: Object.keys(detection.frameworks),
482
- databases: Object.keys(detection.databases),
483
- auth: Object.keys(detection.auth),
484
- payments: Object.keys(detection.payments),
485
- ci: Object.keys(detection.ci),
486
- deploy: Object.keys(detection.deploy),
487
- testing: Object.keys(detection.testing),
488
- },
489
- checks: detection.checks,
490
- invariants: detection.invariants,
491
- policy: {
492
- strict: options.strict || false,
493
- failOnWarn: options.failOnWarn || false,
494
- allowlist: {
495
- domains: [],
496
- packages: [],
497
- },
498
- ignore: {
499
- paths: [
500
- "node_modules",
501
- "__tests__",
502
- "*.test.*",
503
- "*.spec.*",
504
- "**/*.d.ts",
505
- "**/fixtures/**",
506
- "**/mocks/**",
507
- ],
508
- },
509
- },
510
- output: {
511
- dir: ".vibecheck",
512
- reports: ["json", "html"],
513
- badges: true,
514
- },
515
- integrations: {
516
- mcp: { enabled: true },
517
- ci: Object.keys(detection.ci).length > 0 ? Object.keys(detection.ci)[0] : null,
518
- },
519
- };
520
- }
521
-
522
- // ============================================================================
523
- // ENTERPRISE INIT ORCHESTRATOR
524
- // ============================================================================
525
- class EnterpriseInit {
526
- constructor(projectPath, options = {}) {
527
- this.projectPath = projectPath;
528
- this.options = options;
529
- this.detection = null;
530
- this.created = [];
531
- this.updated = [];
532
- this.skipped = [];
533
- }
534
-
535
- async run() {
536
- this.printHeader();
537
-
538
- // Step 1: Detect everything
539
- await this.detectProject();
540
-
541
- if (this.detection.error) {
542
- console.log(`\n${c.red}✗ ${this.detection.error}${c.reset}\n`);
543
- return 1;
544
- }
545
-
546
- // Step 2: Print detection results
547
- this.printDetectionResults();
548
-
549
- // Step 3: Generate configurations
550
- await this.generateConfigs();
551
-
552
- // Step 4: Setup CI/CD if requested
553
- if (this.options.ci) {
554
- await this.setupCI();
555
- }
556
-
557
- // Step 5: Setup compliance if requested
558
- if (this.options.compliance) {
559
- await this.setupCompliance();
560
- }
561
-
562
- // Step 6: Print summary
563
- this.printSummary();
564
-
565
- return 0;
566
- }
567
-
568
- printHeader() {
569
- console.log("");
570
- console.log(`${c.cyan}╔══════════════════════════════════════════════════════════════════════════╗${c.reset}`);
571
- console.log(`${c.cyan}║${c.reset} ${c.cyan}║${c.reset}`);
572
- console.log(`${c.cyan}║${c.reset} ${c.bold}🛡️ VIBECHECK ENTERPRISE INIT${c.reset} ${c.cyan}║${c.reset}`);
573
- console.log(`${c.cyan}║${c.reset} ${c.dim}Production-grade project configuration${c.reset} ${c.cyan}║${c.reset}`);
574
- console.log(`${c.cyan}║${c.reset} ${c.cyan}║${c.reset}`);
575
- console.log(`${c.cyan}╚══════════════════════════════════════════════════════════════════════════╝${c.reset}`);
576
- console.log("");
577
- }
578
-
579
- async detectProject() {
580
- process.stdout.write(`${c.dim}Analyzing project...${c.reset}`);
581
- this.detection = detectAll(this.projectPath);
582
- process.stdout.write(`\r${c.green}✓${c.reset} Project analyzed \n`);
583
- }
584
-
585
- printDetectionResults() {
586
- const d = this.detection;
587
-
588
- console.log("");
589
- console.log(`${c.cyan}┌─ Detection Results ──────────────────────────────────────────────────────┐${c.reset}`);
590
-
591
- // Project info
592
- console.log(`${c.cyan}│${c.reset}`);
593
- console.log(`${c.cyan}│${c.reset} ${c.bold}Project:${c.reset} ${d.pkg?.name || "unnamed"} ${c.dim}v${d.pkg?.version || "0.0.0"}${c.reset}`);
594
- console.log(`${c.cyan}│${c.reset} ${c.bold}Package Manager:${c.reset} ${d.packageManager}`);
595
- if (d.monorepo.isMonorepo) {
596
- console.log(`${c.cyan}│${c.reset} ${c.bold}Monorepo:${c.reset} ${c.green}Yes${c.reset}`);
597
- }
598
-
599
- // Frameworks
600
- const frameworks = Object.values(d.frameworks);
601
- if (frameworks.length) {
602
- console.log(`${c.cyan}│${c.reset}`);
603
- console.log(`${c.cyan}│${c.reset} ${c.bold}Frameworks:${c.reset}`);
604
- for (const fw of frameworks) {
605
- console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} ${fw.icon} ${fw.name}`);
606
- }
607
- }
608
-
609
- // Databases
610
- const databases = Object.values(d.databases);
611
- if (databases.length) {
612
- console.log(`${c.cyan}│${c.reset}`);
613
- console.log(`${c.cyan}│${c.reset} ${c.bold}Databases:${c.reset}`);
614
- for (const db of databases) {
615
- console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} ${db.icon} ${db.name}`);
616
- }
617
- }
618
-
619
- // Auth
620
- const auth = Object.values(d.auth);
621
- if (auth.length) {
622
- console.log(`${c.cyan}│${c.reset}`);
623
- console.log(`${c.cyan}│${c.reset} ${c.bold}Authentication:${c.reset}`);
624
- for (const a of auth) {
625
- console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} ${a.icon} ${a.name}`);
626
- }
627
- }
628
-
629
- // Payments
630
- const payments = Object.values(d.payments);
631
- if (payments.length) {
632
- console.log(`${c.cyan}│${c.reset}`);
633
- console.log(`${c.cyan}│${c.reset} ${c.bold}Payments:${c.reset}`);
634
- for (const p of payments) {
635
- console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} ${p.icon} ${p.name}`);
636
- }
637
- }
638
-
639
- // CI/CD
640
- const ci = Object.values(d.ci);
641
- if (ci.length) {
642
- console.log(`${c.cyan}│${c.reset}`);
643
- console.log(`${c.cyan}│${c.reset} ${c.bold}CI/CD:${c.reset}`);
644
- for (const c2 of ci) {
645
- console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} ${c2.icon} ${c2.name}`);
646
- }
647
- }
648
-
649
- // Deploy
650
- const deploy = Object.values(d.deploy);
651
- if (deploy.length) {
652
- console.log(`${c.cyan}│${c.reset}`);
653
- console.log(`${c.cyan}│${c.reset} ${c.bold}Deployment:${c.reset}`);
654
- for (const dp of deploy) {
655
- console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} ${dp.icon} ${dp.name}`);
656
- }
657
- }
658
-
659
- // Testing
660
- const testing = Object.values(d.testing);
661
- if (testing.length) {
662
- console.log(`${c.cyan}│${c.reset}`);
663
- console.log(`${c.cyan}│${c.reset} ${c.bold}Testing:${c.reset}`);
664
- for (const t of testing) {
665
- console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} ${t.icon} ${t.name}`);
666
- }
667
- }
668
-
669
- // Invariants
670
- console.log(`${c.cyan}│${c.reset}`);
671
- console.log(`${c.cyan}│${c.reset} ${c.bold}Ship Killers:${c.reset} ${c.magenta}${d.invariants.length} invariants${c.reset}`);
672
-
673
- console.log(`${c.cyan}│${c.reset}`);
674
- console.log(`${c.cyan}└───────────────────────────────────────────────────────────────────────────┘${c.reset}`);
675
- console.log("");
676
- }
677
-
678
- async generateConfigs() {
679
- console.log(`${c.cyan}┌─ Generating Configuration ───────────────────────────────────────────────┐${c.reset}`);
680
- console.log(`${c.cyan}│${c.reset}`);
681
-
682
- const tasks = [
683
- { name: ".vibecheck/config.json", fn: () => this.writeConfig() },
684
- { name: ".vibecheck/invariants.yml", fn: () => this.writeInvariants() },
685
- { name: ".vibecheck/security-policy.json", fn: () => this.writeSecurityPolicy() },
686
- { name: ".vibecheck/schemas/", fn: () => this.writeSchemas() },
687
- { name: ".gitignore update", fn: () => this.updateGitignore() },
688
- ];
689
-
690
- if (this.options.team) {
691
- tasks.push({ name: ".vibecheck/team.json", fn: () => this.writeTeamConfig() });
692
- }
693
-
694
- if (this.options.mcp) {
695
- tasks.push({ name: ".vibecheck/mcp.json", fn: () => this.writeMCPConfig() });
696
- }
697
-
698
- for (const task of tasks) {
699
- process.stdout.write(`${c.cyan}│${c.reset} ○ ${task.name}...`);
700
- try {
701
- const result = await task.fn();
702
- const status = result === "created" ? `${c.green}created${c.reset}` :
703
- result === "updated" ? `${c.yellow}updated${c.reset}` :
704
- `${c.dim}skipped${c.reset}`;
705
- process.stdout.write(`\r${c.cyan}│${c.reset} ${c.green}✓${c.reset} ${task.name} ${status}\n`);
706
-
707
- if (result === "created") this.created.push(task.name);
708
- else if (result === "updated") this.updated.push(task.name);
709
- else this.skipped.push(task.name);
710
- } catch (err) {
711
- process.stdout.write(`\r${c.cyan}│${c.reset} ${c.red}✗${c.reset} ${task.name} ${c.red}${err.message}${c.reset}\n`);
712
- }
713
- }
714
-
715
- console.log(`${c.cyan}│${c.reset}`);
716
- console.log(`${c.cyan}└───────────────────────────────────────────────────────────────────────────┘${c.reset}`);
717
- console.log("");
718
- }
719
-
720
- writeConfig() {
721
- const configDir = path.join(this.projectPath, ".vibecheck");
722
- ensureDir(configDir);
723
-
724
- const configPath = path.join(configDir, "config.json");
725
- const config = generateVibecheckConfig(this.detection, this.options);
726
-
727
- const exists = fs.existsSync(configPath);
728
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
729
- return exists ? "updated" : "created";
730
- }
731
-
732
- writeInvariants() {
733
- const configDir = path.join(this.projectPath, ".vibecheck");
734
- ensureDir(configDir);
735
-
736
- const invPath = path.join(configDir, "invariants.yml");
737
- const content = generateInvariantsYml(this.detection.invariants);
738
-
739
- const exists = fs.existsSync(invPath);
740
- fs.writeFileSync(invPath, content, "utf8");
741
- return exists ? "updated" : "created";
742
- }
743
-
744
- writeSecurityPolicy() {
745
- const configDir = path.join(this.projectPath, ".vibecheck");
746
- ensureDir(configDir);
747
-
748
- const policyPath = path.join(configDir, "security-policy.json");
749
- const policy = generateSecurityPolicy(this.detection);
750
-
751
- const exists = fs.existsSync(policyPath);
752
- fs.writeFileSync(policyPath, JSON.stringify(policy, null, 2), "utf8");
753
- return exists ? "updated" : "created";
754
- }
755
-
756
- writeSchemas() {
757
- const schemasDir = path.join(this.projectPath, ".vibecheck", "schemas");
758
- ensureDir(schemasDir);
759
-
760
- const schemas = {
761
- "config.schema.json": {
762
- "$schema": "https://json-schema.org/draft/2020-12/schema",
763
- "$id": "https://vibecheck.dev/schemas/config.json",
764
- "title": "Vibecheck Configuration",
765
- "type": "object",
766
- },
767
- "truthpack.schema.json": {
768
- "$schema": "https://json-schema.org/draft/2020-12/schema",
769
- "$id": "https://vibecheck.dev/schemas/truthpack.json",
770
- "title": "Vibecheck Truthpack",
771
- "type": "object",
772
- },
773
- };
774
-
775
- for (const [name, schema] of Object.entries(schemas)) {
776
- fs.writeFileSync(path.join(schemasDir, name), JSON.stringify(schema, null, 2), "utf8");
777
- }
778
-
779
- return "created";
780
- }
781
-
782
- writeTeamConfig() {
783
- const configDir = path.join(this.projectPath, ".vibecheck");
784
- ensureDir(configDir);
785
-
786
- const teamPath = path.join(configDir, "team.json");
787
- const config = generateTeamConfig(this.detection, this.options);
788
-
789
- const exists = fs.existsSync(teamPath);
790
- fs.writeFileSync(teamPath, JSON.stringify(config, null, 2), "utf8");
791
- return exists ? "updated" : "created";
792
- }
793
-
794
- writeMCPConfig() {
795
- const configDir = path.join(this.projectPath, ".vibecheck");
796
- ensureDir(configDir);
797
-
798
- const mcpPath = path.join(configDir, "mcp.json");
799
- const config = generateMCPConfig(this.detection);
800
-
801
- const exists = fs.existsSync(mcpPath);
802
- fs.writeFileSync(mcpPath, JSON.stringify(config, null, 2), "utf8");
803
- return exists ? "updated" : "created";
804
- }
805
-
806
- updateGitignore() {
807
- const gitignorePath = path.join(this.projectPath, ".gitignore");
808
- const entries = [
809
- "",
810
- "# vibecheck",
811
- ".vibecheck/truth/",
812
- ".vibecheck/reality/",
813
- ".vibecheck/missions/",
814
- ".vibecheck/prove/",
815
- ".vibecheck/cache/",
816
- "",
817
- ].join("\n");
818
-
819
- if (fs.existsSync(gitignorePath)) {
820
- const content = fs.readFileSync(gitignorePath, "utf8");
821
- if (content.includes(".vibecheck/")) {
822
- return "skipped";
823
- }
824
- fs.appendFileSync(gitignorePath, entries);
825
- return "updated";
826
- } else {
827
- fs.writeFileSync(gitignorePath, entries.trim() + "\n");
828
- return "created";
829
- }
830
- }
831
-
832
- async setupCI() {
833
- console.log(`${c.cyan}┌─ CI/CD Integration ──────────────────────────────────────────────────────┐${c.reset}`);
834
- console.log(`${c.cyan}│${c.reset}`);
835
-
836
- const ciType = this.options.ci === true ? "github" : this.options.ci;
837
-
838
- if (ciType === "github" || ciType === "github-actions") {
839
- const wfDir = path.join(this.projectPath, ".github", "workflows");
840
- ensureDir(wfDir);
841
-
842
- const wfPath = path.join(wfDir, "vibecheck.yml");
843
- const workflow = generateGitHubActionsWorkflow(this.detection, this.options);
844
-
845
- fs.writeFileSync(wfPath, workflow, "utf8");
846
- console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} Created .github/workflows/vibecheck.yml`);
847
- this.created.push(".github/workflows/vibecheck.yml");
848
- } else if (ciType === "gitlab") {
849
- const ciPath = path.join(this.projectPath, ".gitlab-ci.vibecheck.yml");
850
- const config = generateGitLabCI(this.detection, this.options);
851
-
852
- fs.writeFileSync(ciPath, config, "utf8");
853
- console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} Created .gitlab-ci.vibecheck.yml`);
854
- console.log(`${c.cyan}│${c.reset} ${c.dim}Include this in your main .gitlab-ci.yml${c.reset}`);
855
- this.created.push(".gitlab-ci.vibecheck.yml");
856
- }
857
-
858
- console.log(`${c.cyan}│${c.reset}`);
859
- console.log(`${c.cyan}└───────────────────────────────────────────────────────────────────────────┘${c.reset}`);
860
- console.log("");
861
- }
862
-
863
- async setupCompliance() {
864
- console.log(`${c.cyan}┌─ Compliance Templates ───────────────────────────────────────────────────┐${c.reset}`);
865
- console.log(`${c.cyan}│${c.reset}`);
866
-
867
- const complianceDir = path.join(this.projectPath, ".vibecheck", "compliance");
868
- ensureDir(complianceDir);
869
-
870
- const templates = typeof this.options.compliance === "string"
871
- ? [this.options.compliance]
872
- : Object.keys(COMPLIANCE_TEMPLATES);
873
-
874
- for (const key of templates) {
875
- const template = COMPLIANCE_TEMPLATES[key];
876
- if (!template) continue;
877
-
878
- const filePath = path.join(complianceDir, `${key}.json`);
879
- fs.writeFileSync(filePath, JSON.stringify({
880
- name: template.name,
881
- description: template.description,
882
- policies: template.policies,
883
- invariants: template.invariants,
884
- status: "not_started",
885
- lastAudit: null,
886
- }, null, 2), "utf8");
887
-
888
- console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} Created compliance/${key}.json (${template.name})`);
889
- this.created.push(`compliance/${key}.json`);
890
- }
891
-
892
- console.log(`${c.cyan}│${c.reset}`);
893
- console.log(`${c.cyan}└───────────────────────────────────────────────────────────────────────────┘${c.reset}`);
894
- console.log("");
895
- }
896
-
897
- printSummary() {
898
- console.log(`${c.green}${c.bold}✓ Enterprise init complete${c.reset}`);
899
- console.log("");
900
-
901
- if (this.created.length) {
902
- console.log(`${c.green}Created:${c.reset} ${this.created.length} files`);
903
- }
904
- if (this.updated.length) {
905
- console.log(`${c.yellow}Updated:${c.reset} ${this.updated.length} files`);
906
- }
907
-
908
- console.log("");
909
- console.log(`${c.cyan}╔══════════════════════════════════════════════════════════════════════════╗${c.reset}`);
910
- console.log(`${c.cyan}║${c.reset} ${c.bold}Next Steps${c.reset} ${c.cyan}║${c.reset}`);
911
- console.log(`${c.cyan}╠══════════════════════════════════════════════════════════════════════════╣${c.reset}`);
912
- console.log(`${c.cyan}║${c.reset} ${c.cyan}║${c.reset}`);
913
- console.log(`${c.cyan}║${c.reset} ${c.bold}1.${c.reset} Generate truth pack: ${c.cyan}║${c.reset}`);
914
- console.log(`${c.cyan}║${c.reset} ${c.cyan}vibecheck ctx${c.reset} ${c.cyan}║${c.reset}`);
915
- console.log(`${c.cyan}║${c.reset} ${c.cyan}║${c.reset}`);
916
- console.log(`${c.cyan}║${c.reset} ${c.bold}2.${c.reset} Run ship decision: ${c.cyan}║${c.reset}`);
917
- console.log(`${c.cyan}║${c.reset} ${c.cyan}vibecheck ship${c.reset} ${c.cyan}║${c.reset}`);
918
- console.log(`${c.cyan}║${c.reset} ${c.cyan}║${c.reset}`);
919
- console.log(`${c.cyan}║${c.reset} ${c.bold}3.${c.reset} Start MCP server for AI agents: ${c.cyan}║${c.reset}`);
920
- console.log(`${c.cyan}║${c.reset} ${c.cyan}vibecheck mcp${c.reset} ${c.cyan}║${c.reset}`);
921
- console.log(`${c.cyan}║${c.reset} ${c.cyan}║${c.reset}`);
922
- console.log(`${c.cyan}╚══════════════════════════════════════════════════════════════════════════╝${c.reset}`);
923
- console.log("");
924
- console.log(`${c.dim}Tip: Run ${c.cyan}vibecheck prove --url http://localhost:3000${c.dim} for full reality verification${c.reset}`);
925
- console.log("");
926
- }
927
- }
928
-
929
- // ============================================================================
930
- // EXPORTS
931
- // ============================================================================
932
- module.exports = {
933
- EnterpriseInit,
934
- generateGitHubActionsWorkflow,
935
- generateGitLabCI,
936
- generateSecurityPolicy,
937
- generateTeamConfig,
938
- generateVibecheckConfig,
939
- generateInvariantsYml,
940
- INVARIANT_DEFINITIONS,
941
- COMPLIANCE_TEMPLATES,
942
- };
1
+ // bin/runners/lib/enterprise-init.js
2
+ // Enterprise-grade initialization: security policies, compliance, CI/CD, team configs
3
+ const fs = require("fs");
4
+ const path = require("path");
5
+ const { detectAll, CI_PROVIDERS, DEPLOY_PLATFORMS } = require("./enterprise-detect");
6
+
7
+ // ANSI colors
8
+ const c = {
9
+ reset: "\x1b[0m",
10
+ bold: "\x1b[1m",
11
+ dim: "\x1b[2m",
12
+ red: "\x1b[31m",
13
+ green: "\x1b[32m",
14
+ yellow: "\x1b[33m",
15
+ blue: "\x1b[34m",
16
+ cyan: "\x1b[36m",
17
+ magenta: "\x1b[35m",
18
+ };
19
+
20
+ function ensureDir(p) {
21
+ fs.mkdirSync(p, { recursive: true });
22
+ }
23
+
24
+ // ============================================================================
25
+ // INVARIANTS CONFIGURATION
26
+ // ============================================================================
27
+ const INVARIANT_DEFINITIONS = {
28
+ INV_NO_FAKE_SUCCESS: {
29
+ id: "INV_NO_FAKE_SUCCESS",
30
+ severity: "BLOCK",
31
+ description: "No success UI without confirmed success (awaited network + ok check)",
32
+ category: "reliability",
33
+ },
34
+ INV_NO_ROUTE_INVENTION: {
35
+ id: "INV_NO_ROUTE_INVENTION",
36
+ severity: "BLOCK",
37
+ description: "No route references without matching server route",
38
+ category: "integrity",
39
+ },
40
+ INV_NO_BYPASS_ENTITLEMENTS: {
41
+ id: "INV_NO_BYPASS_ENTITLEMENTS",
42
+ severity: "BLOCK",
43
+ description: "No bypass flags (OWNER_MODE, skipBilling, etc)",
44
+ category: "billing",
45
+ },
46
+ INV_NO_SILENT_CATCH_AUTH: {
47
+ id: "INV_NO_SILENT_CATCH_AUTH",
48
+ severity: "BLOCK",
49
+ description: "No silent catch blocks in auth/billing code paths",
50
+ category: "security",
51
+ },
52
+ INV_NO_HARDCODED_SECRETS: {
53
+ id: "INV_NO_HARDCODED_SECRETS",
54
+ severity: "BLOCK",
55
+ description: "No hardcoded secrets, API keys, or credentials in code",
56
+ category: "security",
57
+ },
58
+ INV_NO_GHOST_AUTH: {
59
+ id: "INV_NO_GHOST_AUTH",
60
+ severity: "BLOCK",
61
+ description: "No sensitive endpoints without auth enforcement",
62
+ category: "security",
63
+ },
64
+ INV_STRIPE_WEBHOOK_VERIFIED: {
65
+ id: "INV_STRIPE_WEBHOOK_VERIFIED",
66
+ severity: "BLOCK",
67
+ description: "All Stripe webhook handlers must verify signature",
68
+ category: "billing",
69
+ },
70
+ INV_STRIPE_IDEMPOTENT: {
71
+ id: "INV_STRIPE_IDEMPOTENT",
72
+ severity: "WARN",
73
+ description: "Stripe webhook handlers should be idempotent",
74
+ category: "billing",
75
+ },
76
+ INV_ENV_VARS_DECLARED: {
77
+ id: "INV_ENV_VARS_DECLARED",
78
+ severity: "WARN",
79
+ description: "All used env vars must be declared in .env.example",
80
+ category: "operations",
81
+ },
82
+ };
83
+
84
+ // ============================================================================
85
+ // COMPLIANCE TEMPLATES
86
+ // ============================================================================
87
+ const COMPLIANCE_TEMPLATES = {
88
+ soc2: {
89
+ name: "SOC 2 Type II",
90
+ description: "Service Organization Control 2 compliance baseline",
91
+ policies: {
92
+ accessControl: true,
93
+ changeManagement: true,
94
+ riskAssessment: true,
95
+ incidentResponse: true,
96
+ vendorManagement: true,
97
+ },
98
+ invariants: [
99
+ "INV_NO_HARDCODED_SECRETS",
100
+ "INV_NO_GHOST_AUTH",
101
+ "INV_NO_SILENT_CATCH_AUTH",
102
+ ],
103
+ },
104
+ hipaa: {
105
+ name: "HIPAA",
106
+ description: "Health Insurance Portability and Accountability Act baseline",
107
+ policies: {
108
+ phi_protection: true,
109
+ accessControl: true,
110
+ auditLogging: true,
111
+ encryption: true,
112
+ },
113
+ invariants: [
114
+ "INV_NO_HARDCODED_SECRETS",
115
+ "INV_NO_GHOST_AUTH",
116
+ ],
117
+ },
118
+ gdpr: {
119
+ name: "GDPR",
120
+ description: "General Data Protection Regulation baseline",
121
+ policies: {
122
+ dataMinimization: true,
123
+ consentManagement: true,
124
+ rightToErasure: true,
125
+ dataPortability: true,
126
+ },
127
+ invariants: [
128
+ "INV_NO_HARDCODED_SECRETS",
129
+ ],
130
+ },
131
+ pci: {
132
+ name: "PCI-DSS",
133
+ description: "Payment Card Industry Data Security Standard baseline",
134
+ policies: {
135
+ cardDataProtection: true,
136
+ accessControl: true,
137
+ encryption: true,
138
+ monitoring: true,
139
+ },
140
+ invariants: [
141
+ "INV_NO_HARDCODED_SECRETS",
142
+ "INV_STRIPE_WEBHOOK_VERIFIED",
143
+ "INV_NO_BYPASS_ENTITLEMENTS",
144
+ ],
145
+ },
146
+ };
147
+
148
+ // ============================================================================
149
+ // SECURITY POLICY TEMPLATES
150
+ // ============================================================================
151
+ function generateSecurityPolicy(detection) {
152
+ const hasPayments = Object.keys(detection.payments).length > 0;
153
+ const hasAuth = Object.keys(detection.auth).length > 0;
154
+
155
+ return {
156
+ version: "1.0.0",
157
+ headers: {
158
+ strictTransportSecurity: "max-age=31536000; includeSubDomains",
159
+ contentSecurityPolicy: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'",
160
+ xFrameOptions: "DENY",
161
+ xContentTypeOptions: "nosniff",
162
+ referrerPolicy: "strict-origin-when-cross-origin",
163
+ permissionsPolicy: "camera=(), microphone=(), geolocation=()",
164
+ },
165
+ cors: {
166
+ allowedOrigins: ["${ALLOWED_ORIGINS}"],
167
+ allowedMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
168
+ allowCredentials: true,
169
+ maxAge: 86400,
170
+ },
171
+ rateLimit: {
172
+ enabled: true,
173
+ windowMs: 60000,
174
+ max: 100,
175
+ message: "Too many requests, please try again later",
176
+ },
177
+ secrets: {
178
+ scanEnabled: true,
179
+ blockOnDetection: true,
180
+ patterns: [
181
+ "sk_live_",
182
+ "pk_live_",
183
+ "AKIA",
184
+ "ghp_",
185
+ "gho_",
186
+ "eyJ",
187
+ ],
188
+ },
189
+ auth: hasAuth ? {
190
+ sessionTimeout: 3600,
191
+ mfaRecommended: true,
192
+ passwordMinLength: 12,
193
+ } : null,
194
+ payments: hasPayments ? {
195
+ webhookVerification: true,
196
+ idempotencyRequired: true,
197
+ testModeBlockProduction: true,
198
+ } : null,
199
+ };
200
+ }
201
+
202
+ // ============================================================================
203
+ // CI/CD TEMPLATES
204
+ // ============================================================================
205
+ function generateGitHubActionsWorkflow(detection, options = {}) {
206
+ const pm = detection.packageManager;
207
+ const installCmd = pm === "pnpm" ? "pnpm install --frozen-lockfile" :
208
+ pm === "yarn" ? "yarn install --frozen-lockfile" :
209
+ pm === "bun" ? "bun install --frozen-lockfile" : "npm ci";
210
+
211
+ const runPrefix = pm === "pnpm" ? "pnpm" : pm === "yarn" ? "yarn" : pm === "bun" ? "bun" : "npx";
212
+
213
+ return `name: vibecheck
214
+
215
+ on:
216
+ push:
217
+ branches: [main, master]
218
+ pull_request:
219
+ branches: [main, master]
220
+
221
+ permissions:
222
+ contents: read
223
+ pull-requests: write
224
+ security-events: write
225
+
226
+ env:
227
+ CI: true
228
+ NODE_ENV: test
229
+
230
+ jobs:
231
+ vibecheck:
232
+ name: Ship Decision
233
+ runs-on: ubuntu-latest
234
+ timeout-minutes: 15
235
+
236
+ steps:
237
+ - name: Checkout
238
+ uses: actions/checkout@v4
239
+ with:
240
+ fetch-depth: 0
241
+
242
+ - name: Setup Node.js
243
+ uses: actions/setup-node@v4
244
+ with:
245
+ node-version: 20
246
+ cache: '${pm}'
247
+
248
+ - name: Install dependencies
249
+ run: ${installCmd}
250
+
251
+ - name: Generate Truth Pack
252
+ run: ${runPrefix} vibecheck ctx
253
+ continue-on-error: true
254
+
255
+ - name: Ship Decision
256
+ id: ship
257
+ run: |
258
+ set +e
259
+ mkdir -p .vibecheck
260
+ ${runPrefix} vibecheck pr --out .vibecheck/pr_comment.md ${options.failOnWarn ? "--fail-on-warn" : ""}
261
+ code=$?
262
+ echo "exit_code=$code" >> $GITHUB_OUTPUT
263
+ exit 0
264
+
265
+ - name: Upload Artifacts
266
+ uses: actions/upload-artifact@v4
267
+ if: always()
268
+ with:
269
+ name: vibecheck-report
270
+ path: .vibecheck/
271
+ retention-days: 30
272
+
273
+ - name: Comment on PR
274
+ if: github.event_name == 'pull_request'
275
+ uses: actions/github-script@v7
276
+ with:
277
+ script: |
278
+ const fs = require('fs');
279
+ const commentPath = '.vibecheck/pr_comment.md';
280
+ if (!fs.existsSync(commentPath)) {
281
+ console.log('No comment file found');
282
+ return;
283
+ }
284
+ const body = fs.readFileSync(commentPath, 'utf8');
285
+
286
+ // Find existing vibecheck comment
287
+ const { data: comments } = await github.rest.issues.listComments({
288
+ owner: context.repo.owner,
289
+ repo: context.repo.repo,
290
+ issue_number: context.issue.number,
291
+ });
292
+
293
+ const existingComment = comments.find(c =>
294
+ c.user.type === 'Bot' && c.body.includes('vibecheck')
295
+ );
296
+
297
+ if (existingComment) {
298
+ await github.rest.issues.updateComment({
299
+ owner: context.repo.owner,
300
+ repo: context.repo.repo,
301
+ comment_id: existingComment.id,
302
+ body
303
+ });
304
+ } else {
305
+ await github.rest.issues.createComment({
306
+ owner: context.repo.owner,
307
+ repo: context.repo.repo,
308
+ issue_number: context.issue.number,
309
+ body
310
+ });
311
+ }
312
+
313
+ - name: Enforce Verdict
314
+ run: |
315
+ code="\${{ steps.ship.outputs.exit_code }}"
316
+ echo "vibecheck exit code: $code"
317
+ if [ "$code" = "2" ]; then
318
+ echo "::error::BLOCK verdict - deployment blocked"
319
+ exit 1
320
+ fi
321
+ ${options.failOnWarn ? 'if [ "$code" = "1" ]; then echo "::error::WARN verdict (policy: fail-on-warn)"; exit 1; fi' : ''}
322
+ echo "✅ Ship decision passed"
323
+ `;
324
+ }
325
+
326
+ function generateGitLabCI(detection, options = {}) {
327
+ const pm = detection.packageManager;
328
+ const installCmd = pm === "pnpm" ? "pnpm install --frozen-lockfile" :
329
+ pm === "yarn" ? "yarn install --frozen-lockfile" : "npm ci";
330
+
331
+ return `stages:
332
+ - test
333
+ - deploy
334
+
335
+ variables:
336
+ CI: "true"
337
+ NODE_ENV: test
338
+
339
+ vibecheck:
340
+ stage: test
341
+ image: node:20
342
+ cache:
343
+ key: \${CI_COMMIT_REF_SLUG}
344
+ paths:
345
+ - node_modules/
346
+ - .pnpm-store/
347
+ before_script:
348
+ - ${pm === "pnpm" ? "corepack enable && " : ""}${installCmd}
349
+ script:
350
+ - npx vibecheck ctx
351
+ - npx vibecheck ship ${options.failOnWarn ? "--fail-on-warn" : ""}
352
+ artifacts:
353
+ when: always
354
+ paths:
355
+ - .vibecheck/
356
+ expire_in: 30 days
357
+ rules:
358
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
359
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
360
+ `;
361
+ }
362
+
363
+ // ============================================================================
364
+ // TEAM CONFIG TEMPLATES
365
+ // ============================================================================
366
+ function generateTeamConfig(detection, options = {}) {
367
+ const environments = options.environments || ["development", "staging", "production"];
368
+
369
+ return {
370
+ version: "1.0.0",
371
+ team: {
372
+ name: options.teamName || detection.pkg?.name || "unnamed",
373
+ environments,
374
+ },
375
+ policies: {
376
+ development: {
377
+ verdict: { warnAsPass: true, blockAsBlock: true },
378
+ autoFix: { enabled: true, requireApproval: false },
379
+ },
380
+ staging: {
381
+ verdict: { warnAsPass: true, blockAsBlock: true },
382
+ autoFix: { enabled: true, requireApproval: true },
383
+ },
384
+ production: {
385
+ verdict: { warnAsPass: false, blockAsBlock: true },
386
+ autoFix: { enabled: false, requireApproval: true },
387
+ additionalInvariants: ["INV_NO_BYPASS_ENTITLEMENTS"],
388
+ },
389
+ },
390
+ notifications: {
391
+ slack: { webhook: "${SLACK_WEBHOOK_URL}", enabled: false },
392
+ email: { recipients: [], enabled: false },
393
+ },
394
+ reporting: {
395
+ frequency: "weekly",
396
+ recipients: [],
397
+ includeMetrics: true,
398
+ },
399
+ };
400
+ }
401
+
402
+ // ============================================================================
403
+ // MCP SERVER CONFIG
404
+ // ============================================================================
405
+ function generateMCPConfig(detection) {
406
+ return {
407
+ name: "vibecheck",
408
+ version: "1.0.0",
409
+ description: "Vibecheck MCP server for AI agent integration",
410
+ capabilities: {
411
+ tools: true,
412
+ resources: true,
413
+ prompts: true,
414
+ },
415
+ tools: [
416
+ "validate_claim",
417
+ "get_truthpack",
418
+ "get_route_map",
419
+ "verify_auth",
420
+ "check_invariant",
421
+ ],
422
+ security: {
423
+ requireAuth: false,
424
+ allowedOrigins: ["*"],
425
+ },
426
+ };
427
+ }
428
+
429
+ // ============================================================================
430
+ // INVARIANTS FILE
431
+ // ============================================================================
432
+ function generateInvariantsYml(invariants) {
433
+ const lines = ["# vibecheck invariants - ship killers and warnings", ""];
434
+
435
+ const blocks = invariants.filter(id => INVARIANT_DEFINITIONS[id]?.severity === "BLOCK");
436
+ const warns = invariants.filter(id => INVARIANT_DEFINITIONS[id]?.severity === "WARN");
437
+
438
+ if (blocks.length) {
439
+ lines.push("ship_killers:");
440
+ for (const id of blocks) {
441
+ const def = INVARIANT_DEFINITIONS[id];
442
+ lines.push(` - id: ${id}`);
443
+ lines.push(` description: "${def?.description || id}"`);
444
+ lines.push(` category: ${def?.category || "general"}`);
445
+ lines.push("");
446
+ }
447
+ }
448
+
449
+ if (warns.length) {
450
+ lines.push("warnings:");
451
+ for (const id of warns) {
452
+ const def = INVARIANT_DEFINITIONS[id];
453
+ lines.push(` - id: ${id}`);
454
+ lines.push(` description: "${def?.description || id}"`);
455
+ lines.push(` category: ${def?.category || "general"}`);
456
+ lines.push("");
457
+ }
458
+ }
459
+
460
+ return lines.join("\n");
461
+ }
462
+
463
+ // ============================================================================
464
+ // MAIN CONFIG FILE
465
+ // ============================================================================
466
+ function generateVibecheckConfig(detection, options = {}) {
467
+ const primaryFramework = Object.keys(detection.frameworks)[0] || "node";
468
+ const primaryDb = Object.keys(detection.databases)[0];
469
+ const primaryAuth = Object.keys(detection.auth)[0];
470
+ const primaryPayment = Object.keys(detection.payments)[0];
471
+
472
+ return {
473
+ $schema: "https://vibecheck.dev/schemas/config.json",
474
+ version: "2.0.0",
475
+ project: {
476
+ name: detection.pkg?.name || "unnamed",
477
+ framework: primaryFramework,
478
+ packageManager: detection.packageManager,
479
+ },
480
+ detection: {
481
+ frameworks: Object.keys(detection.frameworks),
482
+ databases: Object.keys(detection.databases),
483
+ auth: Object.keys(detection.auth),
484
+ payments: Object.keys(detection.payments),
485
+ ci: Object.keys(detection.ci),
486
+ deploy: Object.keys(detection.deploy),
487
+ testing: Object.keys(detection.testing),
488
+ },
489
+ checks: detection.checks,
490
+ invariants: detection.invariants,
491
+ policy: {
492
+ strict: options.strict || false,
493
+ failOnWarn: options.failOnWarn || false,
494
+ allowlist: {
495
+ domains: [],
496
+ packages: [],
497
+ },
498
+ ignore: {
499
+ paths: [
500
+ "node_modules",
501
+ "__tests__",
502
+ "*.test.*",
503
+ "*.spec.*",
504
+ "**/*.d.ts",
505
+ "**/fixtures/**",
506
+ "**/mocks/**",
507
+ ],
508
+ },
509
+ },
510
+ output: {
511
+ dir: ".vibecheck",
512
+ reports: ["json", "html"],
513
+ badges: true,
514
+ },
515
+ integrations: {
516
+ mcp: { enabled: true },
517
+ ci: Object.keys(detection.ci).length > 0 ? Object.keys(detection.ci)[0] : null,
518
+ },
519
+ };
520
+ }
521
+
522
+ // ============================================================================
523
+ // ENTERPRISE INIT ORCHESTRATOR
524
+ // ============================================================================
525
+ class EnterpriseInit {
526
+ constructor(projectPath, options = {}) {
527
+ this.projectPath = projectPath;
528
+ this.options = options;
529
+ this.detection = null;
530
+ this.created = [];
531
+ this.updated = [];
532
+ this.skipped = [];
533
+ }
534
+
535
+ async run() {
536
+ this.printHeader();
537
+
538
+ // Step 1: Detect everything
539
+ await this.detectProject();
540
+
541
+ if (this.detection.error) {
542
+ console.log(`\n${c.red}✗ ${this.detection.error}${c.reset}\n`);
543
+ return 1;
544
+ }
545
+
546
+ // Step 2: Print detection results
547
+ this.printDetectionResults();
548
+
549
+ // Step 3: Generate configurations
550
+ await this.generateConfigs();
551
+
552
+ // Step 4: Setup CI/CD if requested
553
+ if (this.options.ci) {
554
+ await this.setupCI();
555
+ }
556
+
557
+ // Step 5: Setup compliance if requested
558
+ if (this.options.compliance) {
559
+ await this.setupCompliance();
560
+ }
561
+
562
+ // Step 6: Print summary
563
+ this.printSummary();
564
+
565
+ return 0;
566
+ }
567
+
568
+ printHeader() {
569
+ console.log("");
570
+ console.log(`${c.cyan}╔══════════════════════════════════════════════════════════════════════════╗${c.reset}`);
571
+ console.log(`${c.cyan}║${c.reset} ${c.cyan}║${c.reset}`);
572
+ console.log(`${c.cyan}║${c.reset} ${c.bold}🛡️ VIBECHECK ENTERPRISE INIT${c.reset} ${c.cyan}║${c.reset}`);
573
+ console.log(`${c.cyan}║${c.reset} ${c.dim}Production-grade project configuration${c.reset} ${c.cyan}║${c.reset}`);
574
+ console.log(`${c.cyan}║${c.reset} ${c.cyan}║${c.reset}`);
575
+ console.log(`${c.cyan}╚══════════════════════════════════════════════════════════════════════════╝${c.reset}`);
576
+ console.log("");
577
+ }
578
+
579
+ async detectProject() {
580
+ process.stdout.write(`${c.dim}Analyzing project...${c.reset}`);
581
+ this.detection = detectAll(this.projectPath);
582
+ process.stdout.write(`\r${c.green}✓${c.reset} Project analyzed \n`);
583
+ }
584
+
585
+ printDetectionResults() {
586
+ const d = this.detection;
587
+
588
+ console.log("");
589
+ console.log(`${c.cyan}┌─ Detection Results ──────────────────────────────────────────────────────┐${c.reset}`);
590
+
591
+ // Project info
592
+ console.log(`${c.cyan}│${c.reset}`);
593
+ console.log(`${c.cyan}│${c.reset} ${c.bold}Project:${c.reset} ${d.pkg?.name || "unnamed"} ${c.dim}v${d.pkg?.version || "0.0.0"}${c.reset}`);
594
+ console.log(`${c.cyan}│${c.reset} ${c.bold}Package Manager:${c.reset} ${d.packageManager}`);
595
+ if (d.monorepo.isMonorepo) {
596
+ console.log(`${c.cyan}│${c.reset} ${c.bold}Monorepo:${c.reset} ${c.green}Yes${c.reset}`);
597
+ }
598
+
599
+ // Frameworks
600
+ const frameworks = Object.values(d.frameworks);
601
+ if (frameworks.length) {
602
+ console.log(`${c.cyan}│${c.reset}`);
603
+ console.log(`${c.cyan}│${c.reset} ${c.bold}Frameworks:${c.reset}`);
604
+ for (const fw of frameworks) {
605
+ console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} ${fw.icon} ${fw.name}`);
606
+ }
607
+ }
608
+
609
+ // Databases
610
+ const databases = Object.values(d.databases);
611
+ if (databases.length) {
612
+ console.log(`${c.cyan}│${c.reset}`);
613
+ console.log(`${c.cyan}│${c.reset} ${c.bold}Databases:${c.reset}`);
614
+ for (const db of databases) {
615
+ console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} ${db.icon} ${db.name}`);
616
+ }
617
+ }
618
+
619
+ // Auth
620
+ const auth = Object.values(d.auth);
621
+ if (auth.length) {
622
+ console.log(`${c.cyan}│${c.reset}`);
623
+ console.log(`${c.cyan}│${c.reset} ${c.bold}Authentication:${c.reset}`);
624
+ for (const a of auth) {
625
+ console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} ${a.icon} ${a.name}`);
626
+ }
627
+ }
628
+
629
+ // Payments
630
+ const payments = Object.values(d.payments);
631
+ if (payments.length) {
632
+ console.log(`${c.cyan}│${c.reset}`);
633
+ console.log(`${c.cyan}│${c.reset} ${c.bold}Payments:${c.reset}`);
634
+ for (const p of payments) {
635
+ console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} ${p.icon} ${p.name}`);
636
+ }
637
+ }
638
+
639
+ // CI/CD
640
+ const ci = Object.values(d.ci);
641
+ if (ci.length) {
642
+ console.log(`${c.cyan}│${c.reset}`);
643
+ console.log(`${c.cyan}│${c.reset} ${c.bold}CI/CD:${c.reset}`);
644
+ for (const c2 of ci) {
645
+ console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} ${c2.icon} ${c2.name}`);
646
+ }
647
+ }
648
+
649
+ // Deploy
650
+ const deploy = Object.values(d.deploy);
651
+ if (deploy.length) {
652
+ console.log(`${c.cyan}│${c.reset}`);
653
+ console.log(`${c.cyan}│${c.reset} ${c.bold}Deployment:${c.reset}`);
654
+ for (const dp of deploy) {
655
+ console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} ${dp.icon} ${dp.name}`);
656
+ }
657
+ }
658
+
659
+ // Testing
660
+ const testing = Object.values(d.testing);
661
+ if (testing.length) {
662
+ console.log(`${c.cyan}│${c.reset}`);
663
+ console.log(`${c.cyan}│${c.reset} ${c.bold}Testing:${c.reset}`);
664
+ for (const t of testing) {
665
+ console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} ${t.icon} ${t.name}`);
666
+ }
667
+ }
668
+
669
+ // Invariants
670
+ console.log(`${c.cyan}│${c.reset}`);
671
+ console.log(`${c.cyan}│${c.reset} ${c.bold}Ship Killers:${c.reset} ${c.magenta}${d.invariants.length} invariants${c.reset}`);
672
+
673
+ console.log(`${c.cyan}│${c.reset}`);
674
+ console.log(`${c.cyan}└───────────────────────────────────────────────────────────────────────────┘${c.reset}`);
675
+ console.log("");
676
+ }
677
+
678
+ async generateConfigs() {
679
+ console.log(`${c.cyan}┌─ Generating Configuration ───────────────────────────────────────────────┐${c.reset}`);
680
+ console.log(`${c.cyan}│${c.reset}`);
681
+
682
+ const tasks = [
683
+ { name: ".vibecheck/config.json", fn: () => this.writeConfig() },
684
+ { name: ".vibecheck/invariants.yml", fn: () => this.writeInvariants() },
685
+ { name: ".vibecheck/security-policy.json", fn: () => this.writeSecurityPolicy() },
686
+ { name: ".vibecheck/schemas/", fn: () => this.writeSchemas() },
687
+ { name: ".gitignore update", fn: () => this.updateGitignore() },
688
+ ];
689
+
690
+ if (this.options.team) {
691
+ tasks.push({ name: ".vibecheck/team.json", fn: () => this.writeTeamConfig() });
692
+ }
693
+
694
+ if (this.options.mcp) {
695
+ tasks.push({ name: ".vibecheck/mcp.json", fn: () => this.writeMCPConfig() });
696
+ }
697
+
698
+ for (const task of tasks) {
699
+ process.stdout.write(`${c.cyan}│${c.reset} ○ ${task.name}...`);
700
+ try {
701
+ const result = await task.fn();
702
+ const status = result === "created" ? `${c.green}created${c.reset}` :
703
+ result === "updated" ? `${c.yellow}updated${c.reset}` :
704
+ `${c.dim}skipped${c.reset}`;
705
+ process.stdout.write(`\r${c.cyan}│${c.reset} ${c.green}✓${c.reset} ${task.name} ${status}\n`);
706
+
707
+ if (result === "created") this.created.push(task.name);
708
+ else if (result === "updated") this.updated.push(task.name);
709
+ else this.skipped.push(task.name);
710
+ } catch (err) {
711
+ process.stdout.write(`\r${c.cyan}│${c.reset} ${c.red}✗${c.reset} ${task.name} ${c.red}${err.message}${c.reset}\n`);
712
+ }
713
+ }
714
+
715
+ console.log(`${c.cyan}│${c.reset}`);
716
+ console.log(`${c.cyan}└───────────────────────────────────────────────────────────────────────────┘${c.reset}`);
717
+ console.log("");
718
+ }
719
+
720
+ writeConfig() {
721
+ const configDir = path.join(this.projectPath, ".vibecheck");
722
+ ensureDir(configDir);
723
+
724
+ const configPath = path.join(configDir, "config.json");
725
+ const config = generateVibecheckConfig(this.detection, this.options);
726
+
727
+ const exists = fs.existsSync(configPath);
728
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
729
+ return exists ? "updated" : "created";
730
+ }
731
+
732
+ writeInvariants() {
733
+ const configDir = path.join(this.projectPath, ".vibecheck");
734
+ ensureDir(configDir);
735
+
736
+ const invPath = path.join(configDir, "invariants.yml");
737
+ const content = generateInvariantsYml(this.detection.invariants);
738
+
739
+ const exists = fs.existsSync(invPath);
740
+ fs.writeFileSync(invPath, content, "utf8");
741
+ return exists ? "updated" : "created";
742
+ }
743
+
744
+ writeSecurityPolicy() {
745
+ const configDir = path.join(this.projectPath, ".vibecheck");
746
+ ensureDir(configDir);
747
+
748
+ const policyPath = path.join(configDir, "security-policy.json");
749
+ const policy = generateSecurityPolicy(this.detection);
750
+
751
+ const exists = fs.existsSync(policyPath);
752
+ fs.writeFileSync(policyPath, JSON.stringify(policy, null, 2), "utf8");
753
+ return exists ? "updated" : "created";
754
+ }
755
+
756
+ writeSchemas() {
757
+ const schemasDir = path.join(this.projectPath, ".vibecheck", "schemas");
758
+ ensureDir(schemasDir);
759
+
760
+ const schemas = {
761
+ "config.schema.json": {
762
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
763
+ "$id": "https://vibecheck.dev/schemas/config.json",
764
+ "title": "Vibecheck Configuration",
765
+ "type": "object",
766
+ },
767
+ "truthpack.schema.json": {
768
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
769
+ "$id": "https://vibecheck.dev/schemas/truthpack.json",
770
+ "title": "Vibecheck Truthpack",
771
+ "type": "object",
772
+ },
773
+ };
774
+
775
+ for (const [name, schema] of Object.entries(schemas)) {
776
+ fs.writeFileSync(path.join(schemasDir, name), JSON.stringify(schema, null, 2), "utf8");
777
+ }
778
+
779
+ return "created";
780
+ }
781
+
782
+ writeTeamConfig() {
783
+ const configDir = path.join(this.projectPath, ".vibecheck");
784
+ ensureDir(configDir);
785
+
786
+ const teamPath = path.join(configDir, "team.json");
787
+ const config = generateTeamConfig(this.detection, this.options);
788
+
789
+ const exists = fs.existsSync(teamPath);
790
+ fs.writeFileSync(teamPath, JSON.stringify(config, null, 2), "utf8");
791
+ return exists ? "updated" : "created";
792
+ }
793
+
794
+ writeMCPConfig() {
795
+ const configDir = path.join(this.projectPath, ".vibecheck");
796
+ ensureDir(configDir);
797
+
798
+ const mcpPath = path.join(configDir, "mcp.json");
799
+ const config = generateMCPConfig(this.detection);
800
+
801
+ const exists = fs.existsSync(mcpPath);
802
+ fs.writeFileSync(mcpPath, JSON.stringify(config, null, 2), "utf8");
803
+ return exists ? "updated" : "created";
804
+ }
805
+
806
+ updateGitignore() {
807
+ const gitignorePath = path.join(this.projectPath, ".gitignore");
808
+ const entries = [
809
+ "",
810
+ "# vibecheck",
811
+ ".vibecheck/truth/",
812
+ ".vibecheck/reality/",
813
+ ".vibecheck/missions/",
814
+ ".vibecheck/prove/",
815
+ ".vibecheck/cache/",
816
+ "",
817
+ ].join("\n");
818
+
819
+ if (fs.existsSync(gitignorePath)) {
820
+ const content = fs.readFileSync(gitignorePath, "utf8");
821
+ if (content.includes(".vibecheck/")) {
822
+ return "skipped";
823
+ }
824
+ fs.appendFileSync(gitignorePath, entries);
825
+ return "updated";
826
+ } else {
827
+ fs.writeFileSync(gitignorePath, entries.trim() + "\n");
828
+ return "created";
829
+ }
830
+ }
831
+
832
+ async setupCI() {
833
+ console.log(`${c.cyan}┌─ CI/CD Integration ──────────────────────────────────────────────────────┐${c.reset}`);
834
+ console.log(`${c.cyan}│${c.reset}`);
835
+
836
+ const ciType = this.options.ci === true ? "github" : this.options.ci;
837
+
838
+ if (ciType === "github" || ciType === "github-actions") {
839
+ const wfDir = path.join(this.projectPath, ".github", "workflows");
840
+ ensureDir(wfDir);
841
+
842
+ const wfPath = path.join(wfDir, "vibecheck.yml");
843
+ const workflow = generateGitHubActionsWorkflow(this.detection, this.options);
844
+
845
+ fs.writeFileSync(wfPath, workflow, "utf8");
846
+ console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} Created .github/workflows/vibecheck.yml`);
847
+ this.created.push(".github/workflows/vibecheck.yml");
848
+ } else if (ciType === "gitlab") {
849
+ const ciPath = path.join(this.projectPath, ".gitlab-ci.vibecheck.yml");
850
+ const config = generateGitLabCI(this.detection, this.options);
851
+
852
+ fs.writeFileSync(ciPath, config, "utf8");
853
+ console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} Created .gitlab-ci.vibecheck.yml`);
854
+ console.log(`${c.cyan}│${c.reset} ${c.dim}Include this in your main .gitlab-ci.yml${c.reset}`);
855
+ this.created.push(".gitlab-ci.vibecheck.yml");
856
+ }
857
+
858
+ console.log(`${c.cyan}│${c.reset}`);
859
+ console.log(`${c.cyan}└───────────────────────────────────────────────────────────────────────────┘${c.reset}`);
860
+ console.log("");
861
+ }
862
+
863
+ async setupCompliance() {
864
+ console.log(`${c.cyan}┌─ Compliance Templates ───────────────────────────────────────────────────┐${c.reset}`);
865
+ console.log(`${c.cyan}│${c.reset}`);
866
+
867
+ const complianceDir = path.join(this.projectPath, ".vibecheck", "compliance");
868
+ ensureDir(complianceDir);
869
+
870
+ const templates = typeof this.options.compliance === "string"
871
+ ? [this.options.compliance]
872
+ : Object.keys(COMPLIANCE_TEMPLATES);
873
+
874
+ for (const key of templates) {
875
+ const template = COMPLIANCE_TEMPLATES[key];
876
+ if (!template) continue;
877
+
878
+ const filePath = path.join(complianceDir, `${key}.json`);
879
+ fs.writeFileSync(filePath, JSON.stringify({
880
+ name: template.name,
881
+ description: template.description,
882
+ policies: template.policies,
883
+ invariants: template.invariants,
884
+ status: "not_started",
885
+ lastAudit: null,
886
+ }, null, 2), "utf8");
887
+
888
+ console.log(`${c.cyan}│${c.reset} ${c.green}✓${c.reset} Created compliance/${key}.json (${template.name})`);
889
+ this.created.push(`compliance/${key}.json`);
890
+ }
891
+
892
+ console.log(`${c.cyan}│${c.reset}`);
893
+ console.log(`${c.cyan}└───────────────────────────────────────────────────────────────────────────┘${c.reset}`);
894
+ console.log("");
895
+ }
896
+
897
+ printSummary() {
898
+ console.log(`${c.green}${c.bold}✓ Enterprise init complete${c.reset}`);
899
+ console.log("");
900
+
901
+ if (this.created.length) {
902
+ console.log(`${c.green}Created:${c.reset} ${this.created.length} files`);
903
+ }
904
+ if (this.updated.length) {
905
+ console.log(`${c.yellow}Updated:${c.reset} ${this.updated.length} files`);
906
+ }
907
+
908
+ console.log("");
909
+ console.log(`${c.cyan}╔══════════════════════════════════════════════════════════════════════════╗${c.reset}`);
910
+ console.log(`${c.cyan}║${c.reset} ${c.bold}Next Steps${c.reset} ${c.cyan}║${c.reset}`);
911
+ console.log(`${c.cyan}╠══════════════════════════════════════════════════════════════════════════╣${c.reset}`);
912
+ console.log(`${c.cyan}║${c.reset} ${c.cyan}║${c.reset}`);
913
+ console.log(`${c.cyan}║${c.reset} ${c.bold}1.${c.reset} Generate truth pack: ${c.cyan}║${c.reset}`);
914
+ console.log(`${c.cyan}║${c.reset} ${c.cyan}vibecheck ctx${c.reset} ${c.cyan}║${c.reset}`);
915
+ console.log(`${c.cyan}║${c.reset} ${c.cyan}║${c.reset}`);
916
+ console.log(`${c.cyan}║${c.reset} ${c.bold}2.${c.reset} Run ship decision: ${c.cyan}║${c.reset}`);
917
+ console.log(`${c.cyan}║${c.reset} ${c.cyan}vibecheck ship${c.reset} ${c.cyan}║${c.reset}`);
918
+ console.log(`${c.cyan}║${c.reset} ${c.cyan}║${c.reset}`);
919
+ console.log(`${c.cyan}║${c.reset} ${c.bold}3.${c.reset} Start MCP server for AI agents: ${c.cyan}║${c.reset}`);
920
+ console.log(`${c.cyan}║${c.reset} ${c.cyan}vibecheck mcp${c.reset} ${c.cyan}║${c.reset}`);
921
+ console.log(`${c.cyan}║${c.reset} ${c.cyan}║${c.reset}`);
922
+ console.log(`${c.cyan}╚══════════════════════════════════════════════════════════════════════════╝${c.reset}`);
923
+ console.log("");
924
+ console.log(`${c.dim}Tip: Run ${c.cyan}vibecheck prove --url http://localhost:3000${c.dim} for full reality verification${c.reset}`);
925
+ console.log("");
926
+ }
927
+ }
928
+
929
+ // ============================================================================
930
+ // EXPORTS
931
+ // ============================================================================
932
+ module.exports = {
933
+ EnterpriseInit,
934
+ generateGitHubActionsWorkflow,
935
+ generateGitLabCI,
936
+ generateSecurityPolicy,
937
+ generateTeamConfig,
938
+ generateVibecheckConfig,
939
+ generateInvariantsYml,
940
+ INVARIANT_DEFINITIONS,
941
+ COMPLIANCE_TEMPLATES,
942
+ };