@vibecheckai/cli 3.2.4 → 3.2.6

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 (123) hide show
  1. package/bin/.generated +25 -25
  2. package/bin/dev/run-v2-torture.js +30 -30
  3. package/bin/runners/lib/__tests__/entitlements-v2.test.js +295 -295
  4. package/bin/runners/lib/api-client.js +269 -0
  5. package/bin/runners/lib/auth-truth.js +193 -193
  6. package/bin/runners/lib/backup.js +62 -62
  7. package/bin/runners/lib/billing.js +107 -107
  8. package/bin/runners/lib/claims.js +118 -118
  9. package/bin/runners/lib/cli-ui.js +540 -540
  10. package/bin/runners/lib/contracts/auth-contract.js +202 -202
  11. package/bin/runners/lib/contracts/env-contract.js +181 -181
  12. package/bin/runners/lib/contracts/external-contract.js +206 -206
  13. package/bin/runners/lib/contracts/guard.js +168 -168
  14. package/bin/runners/lib/contracts/index.js +89 -89
  15. package/bin/runners/lib/contracts/plan-validator.js +311 -311
  16. package/bin/runners/lib/contracts/route-contract.js +199 -199
  17. package/bin/runners/lib/contracts.js +804 -804
  18. package/bin/runners/lib/detect.js +89 -89
  19. package/bin/runners/lib/doctor/autofix.js +254 -254
  20. package/bin/runners/lib/doctor/index.js +37 -37
  21. package/bin/runners/lib/doctor/modules/dependencies.js +325 -325
  22. package/bin/runners/lib/doctor/modules/index.js +46 -46
  23. package/bin/runners/lib/doctor/modules/network.js +250 -250
  24. package/bin/runners/lib/doctor/modules/project.js +312 -312
  25. package/bin/runners/lib/doctor/modules/runtime.js +224 -224
  26. package/bin/runners/lib/doctor/modules/security.js +348 -348
  27. package/bin/runners/lib/doctor/modules/system.js +213 -213
  28. package/bin/runners/lib/doctor/modules/vibecheck.js +394 -394
  29. package/bin/runners/lib/doctor/reporter.js +262 -262
  30. package/bin/runners/lib/doctor/service.js +262 -262
  31. package/bin/runners/lib/doctor/types.js +113 -113
  32. package/bin/runners/lib/doctor/ui.js +263 -263
  33. package/bin/runners/lib/doctor-v2.js +608 -608
  34. package/bin/runners/lib/drift.js +425 -425
  35. package/bin/runners/lib/enforcement.js +72 -72
  36. package/bin/runners/lib/enterprise-detect.js +603 -603
  37. package/bin/runners/lib/enterprise-init.js +942 -942
  38. package/bin/runners/lib/env-resolver.js +417 -417
  39. package/bin/runners/lib/env-template.js +66 -66
  40. package/bin/runners/lib/env.js +189 -189
  41. package/bin/runners/lib/extractors/client-calls.js +990 -990
  42. package/bin/runners/lib/extractors/fastify-route-dump.js +573 -573
  43. package/bin/runners/lib/extractors/fastify-routes.js +426 -426
  44. package/bin/runners/lib/extractors/index.js +363 -363
  45. package/bin/runners/lib/extractors/next-routes.js +524 -524
  46. package/bin/runners/lib/extractors/proof-graph.js +431 -431
  47. package/bin/runners/lib/extractors/route-matcher.js +451 -451
  48. package/bin/runners/lib/extractors/truthpack-v2.js +377 -377
  49. package/bin/runners/lib/extractors/ui-bindings.js +547 -547
  50. package/bin/runners/lib/findings-schema.js +281 -281
  51. package/bin/runners/lib/firewall-prompt.js +50 -50
  52. package/bin/runners/lib/graph/graph-builder.js +265 -265
  53. package/bin/runners/lib/graph/html-renderer.js +413 -413
  54. package/bin/runners/lib/graph/index.js +32 -32
  55. package/bin/runners/lib/graph/runtime-collector.js +215 -215
  56. package/bin/runners/lib/graph/static-extractor.js +518 -518
  57. package/bin/runners/lib/html-report.js +650 -650
  58. package/bin/runners/lib/llm.js +75 -75
  59. package/bin/runners/lib/meter.js +61 -61
  60. package/bin/runners/lib/missions/evidence.js +126 -126
  61. package/bin/runners/lib/patch.js +40 -40
  62. package/bin/runners/lib/permissions/auth-model.js +213 -213
  63. package/bin/runners/lib/permissions/idor-prover.js +205 -205
  64. package/bin/runners/lib/permissions/index.js +45 -45
  65. package/bin/runners/lib/permissions/matrix-builder.js +198 -198
  66. package/bin/runners/lib/pkgjson.js +28 -28
  67. package/bin/runners/lib/policy.js +295 -295
  68. package/bin/runners/lib/preflight.js +142 -142
  69. package/bin/runners/lib/reality/correlation-detectors.js +359 -359
  70. package/bin/runners/lib/reality/index.js +318 -318
  71. package/bin/runners/lib/reality/request-hashing.js +416 -416
  72. package/bin/runners/lib/reality/request-mapper.js +453 -453
  73. package/bin/runners/lib/reality/safety-rails.js +463 -463
  74. package/bin/runners/lib/reality/semantic-snapshot.js +408 -408
  75. package/bin/runners/lib/reality/toast-detector.js +393 -393
  76. package/bin/runners/lib/reality-findings.js +84 -84
  77. package/bin/runners/lib/receipts.js +179 -179
  78. package/bin/runners/lib/redact.js +29 -29
  79. package/bin/runners/lib/replay/capsule-manager.js +154 -154
  80. package/bin/runners/lib/replay/index.js +263 -263
  81. package/bin/runners/lib/replay/player.js +348 -348
  82. package/bin/runners/lib/replay/recorder.js +331 -331
  83. package/bin/runners/lib/report.js +135 -135
  84. package/bin/runners/lib/route-detection.js +1140 -1140
  85. package/bin/runners/lib/sandbox/index.js +59 -59
  86. package/bin/runners/lib/sandbox/proof-chain.js +399 -399
  87. package/bin/runners/lib/sandbox/sandbox-runner.js +205 -205
  88. package/bin/runners/lib/sandbox/worktree.js +174 -174
  89. package/bin/runners/lib/schema-validator.js +350 -350
  90. package/bin/runners/lib/schemas/contracts.schema.json +160 -160
  91. package/bin/runners/lib/schemas/finding.schema.json +100 -100
  92. package/bin/runners/lib/schemas/mission-pack.schema.json +206 -206
  93. package/bin/runners/lib/schemas/proof-graph.schema.json +176 -176
  94. package/bin/runners/lib/schemas/reality-report.schema.json +162 -162
  95. package/bin/runners/lib/schemas/share-pack.schema.json +180 -180
  96. package/bin/runners/lib/schemas/ship-report.schema.json +117 -117
  97. package/bin/runners/lib/schemas/truthpack-v2.schema.json +303 -303
  98. package/bin/runners/lib/schemas/validator.js +438 -438
  99. package/bin/runners/lib/score-history.js +282 -282
  100. package/bin/runners/lib/share-pack.js +239 -239
  101. package/bin/runners/lib/snippets.js +67 -67
  102. package/bin/runners/lib/upsell.js +510 -510
  103. package/bin/runners/lib/usage.js +153 -153
  104. package/bin/runners/lib/validate-patch.js +156 -156
  105. package/bin/runners/lib/verdict-engine.js +628 -628
  106. package/bin/runners/reality/engine.js +917 -917
  107. package/bin/runners/reality/flows.js +122 -122
  108. package/bin/runners/reality/report.js +378 -378
  109. package/bin/runners/reality/session.js +193 -193
  110. package/bin/runners/runAgent.d.ts +5 -0
  111. package/bin/runners/runFirewall.d.ts +5 -0
  112. package/bin/runners/runFirewallHook.d.ts +5 -0
  113. package/bin/runners/runGuard.js +168 -168
  114. package/bin/runners/runScan.js +82 -0
  115. package/bin/runners/runTruth.d.ts +5 -0
  116. package/bin/vibecheck.js +45 -20
  117. package/mcp-server/index.js +85 -0
  118. package/mcp-server/lib/api-client.js +269 -0
  119. package/mcp-server/package.json +1 -1
  120. package/mcp-server/tier-auth.js +173 -113
  121. package/mcp-server/tools/index.js +72 -72
  122. package/mcp-server/vibecheck-mcp-server-3.2.0.tgz +0 -0
  123. 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
+ };