@vibecheckai/cli 3.2.5 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (197) hide show
  1. package/bin/.generated +25 -25
  2. package/bin/dev/run-v2-torture.js +30 -30
  3. package/bin/registry.js +192 -5
  4. package/bin/runners/lib/__tests__/entitlements-v2.test.js +295 -295
  5. package/bin/runners/lib/agent-firewall/change-packet/builder.js +280 -6
  6. package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
  7. package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
  8. package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
  9. package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
  10. package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
  11. package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
  12. package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
  13. package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
  14. package/bin/runners/lib/agent-firewall/logger.js +141 -0
  15. package/bin/runners/lib/agent-firewall/policy/loader.js +312 -4
  16. package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +113 -1
  17. package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +133 -6
  18. package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
  19. package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
  20. package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
  21. package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
  22. package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
  23. package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
  24. package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
  25. package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
  26. package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
  27. package/bin/runners/lib/agent-firewall/risk/thresholds.js +321 -0
  28. package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
  29. package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
  30. package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
  31. package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
  32. package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
  33. package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
  34. package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
  35. package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
  36. package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
  37. package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
  38. package/bin/runners/lib/analyzers.js +81 -18
  39. package/bin/runners/lib/api-client.js +269 -0
  40. package/bin/runners/lib/auth-truth.js +193 -193
  41. package/bin/runners/lib/authority-badge.js +425 -0
  42. package/bin/runners/lib/backup.js +62 -62
  43. package/bin/runners/lib/billing.js +107 -107
  44. package/bin/runners/lib/claims.js +118 -118
  45. package/bin/runners/lib/cli-output.js +7 -1
  46. package/bin/runners/lib/cli-ui.js +540 -540
  47. package/bin/runners/lib/contracts/auth-contract.js +202 -202
  48. package/bin/runners/lib/contracts/env-contract.js +181 -181
  49. package/bin/runners/lib/contracts/external-contract.js +206 -206
  50. package/bin/runners/lib/contracts/guard.js +168 -168
  51. package/bin/runners/lib/contracts/index.js +89 -89
  52. package/bin/runners/lib/contracts/plan-validator.js +311 -311
  53. package/bin/runners/lib/contracts/route-contract.js +199 -199
  54. package/bin/runners/lib/contracts.js +804 -804
  55. package/bin/runners/lib/detect.js +89 -89
  56. package/bin/runners/lib/doctor/autofix.js +254 -254
  57. package/bin/runners/lib/doctor/index.js +37 -37
  58. package/bin/runners/lib/doctor/modules/dependencies.js +325 -325
  59. package/bin/runners/lib/doctor/modules/index.js +46 -46
  60. package/bin/runners/lib/doctor/modules/network.js +250 -250
  61. package/bin/runners/lib/doctor/modules/project.js +312 -312
  62. package/bin/runners/lib/doctor/modules/runtime.js +224 -224
  63. package/bin/runners/lib/doctor/modules/security.js +348 -348
  64. package/bin/runners/lib/doctor/modules/system.js +213 -213
  65. package/bin/runners/lib/doctor/modules/vibecheck.js +394 -394
  66. package/bin/runners/lib/doctor/reporter.js +262 -262
  67. package/bin/runners/lib/doctor/service.js +262 -262
  68. package/bin/runners/lib/doctor/types.js +113 -113
  69. package/bin/runners/lib/doctor/ui.js +263 -263
  70. package/bin/runners/lib/doctor-v2.js +608 -608
  71. package/bin/runners/lib/drift.js +425 -425
  72. package/bin/runners/lib/enforcement.js +72 -72
  73. package/bin/runners/lib/enterprise-detect.js +603 -603
  74. package/bin/runners/lib/enterprise-init.js +942 -942
  75. package/bin/runners/lib/env-resolver.js +417 -417
  76. package/bin/runners/lib/env-template.js +66 -66
  77. package/bin/runners/lib/env.js +189 -189
  78. package/bin/runners/lib/error-handler.js +16 -9
  79. package/bin/runners/lib/exit-codes.js +275 -0
  80. package/bin/runners/lib/extractors/client-calls.js +990 -990
  81. package/bin/runners/lib/extractors/fastify-route-dump.js +573 -573
  82. package/bin/runners/lib/extractors/fastify-routes.js +426 -426
  83. package/bin/runners/lib/extractors/index.js +363 -363
  84. package/bin/runners/lib/extractors/next-routes.js +524 -524
  85. package/bin/runners/lib/extractors/proof-graph.js +431 -431
  86. package/bin/runners/lib/extractors/route-matcher.js +451 -451
  87. package/bin/runners/lib/extractors/truthpack-v2.js +377 -377
  88. package/bin/runners/lib/extractors/ui-bindings.js +547 -547
  89. package/bin/runners/lib/findings-schema.js +281 -281
  90. package/bin/runners/lib/firewall-prompt.js +50 -50
  91. package/bin/runners/lib/global-flags.js +37 -0
  92. package/bin/runners/lib/graph/graph-builder.js +265 -265
  93. package/bin/runners/lib/graph/html-renderer.js +413 -413
  94. package/bin/runners/lib/graph/index.js +32 -32
  95. package/bin/runners/lib/graph/runtime-collector.js +215 -215
  96. package/bin/runners/lib/graph/static-extractor.js +518 -518
  97. package/bin/runners/lib/help-formatter.js +413 -0
  98. package/bin/runners/lib/html-report.js +650 -650
  99. package/bin/runners/lib/llm.js +75 -75
  100. package/bin/runners/lib/logger.js +38 -0
  101. package/bin/runners/lib/meter.js +61 -61
  102. package/bin/runners/lib/missions/evidence.js +126 -126
  103. package/bin/runners/lib/patch.js +40 -40
  104. package/bin/runners/lib/permissions/auth-model.js +213 -213
  105. package/bin/runners/lib/permissions/idor-prover.js +205 -205
  106. package/bin/runners/lib/permissions/index.js +45 -45
  107. package/bin/runners/lib/permissions/matrix-builder.js +198 -198
  108. package/bin/runners/lib/pkgjson.js +28 -28
  109. package/bin/runners/lib/policy.js +295 -295
  110. package/bin/runners/lib/preflight.js +142 -142
  111. package/bin/runners/lib/reality/correlation-detectors.js +359 -359
  112. package/bin/runners/lib/reality/index.js +318 -318
  113. package/bin/runners/lib/reality/request-hashing.js +416 -416
  114. package/bin/runners/lib/reality/request-mapper.js +453 -453
  115. package/bin/runners/lib/reality/safety-rails.js +463 -463
  116. package/bin/runners/lib/reality/semantic-snapshot.js +408 -408
  117. package/bin/runners/lib/reality/toast-detector.js +393 -393
  118. package/bin/runners/lib/reality-findings.js +84 -84
  119. package/bin/runners/lib/receipts.js +179 -179
  120. package/bin/runners/lib/redact.js +29 -29
  121. package/bin/runners/lib/replay/capsule-manager.js +154 -154
  122. package/bin/runners/lib/replay/index.js +263 -263
  123. package/bin/runners/lib/replay/player.js +348 -348
  124. package/bin/runners/lib/replay/recorder.js +331 -331
  125. package/bin/runners/lib/report.js +135 -135
  126. package/bin/runners/lib/route-detection.js +1140 -1140
  127. package/bin/runners/lib/sandbox/index.js +59 -59
  128. package/bin/runners/lib/sandbox/proof-chain.js +399 -399
  129. package/bin/runners/lib/sandbox/sandbox-runner.js +205 -205
  130. package/bin/runners/lib/sandbox/worktree.js +174 -174
  131. package/bin/runners/lib/schema-validator.js +350 -350
  132. package/bin/runners/lib/schemas/contracts.schema.json +160 -160
  133. package/bin/runners/lib/schemas/finding.schema.json +100 -100
  134. package/bin/runners/lib/schemas/mission-pack.schema.json +206 -206
  135. package/bin/runners/lib/schemas/proof-graph.schema.json +176 -176
  136. package/bin/runners/lib/schemas/reality-report.schema.json +162 -162
  137. package/bin/runners/lib/schemas/share-pack.schema.json +180 -180
  138. package/bin/runners/lib/schemas/ship-report.schema.json +117 -117
  139. package/bin/runners/lib/schemas/truthpack-v2.schema.json +303 -303
  140. package/bin/runners/lib/schemas/validator.js +438 -438
  141. package/bin/runners/lib/score-history.js +282 -282
  142. package/bin/runners/lib/share-pack.js +239 -239
  143. package/bin/runners/lib/snippets.js +67 -67
  144. package/bin/runners/lib/unified-cli-output.js +604 -0
  145. package/bin/runners/lib/upsell.js +658 -510
  146. package/bin/runners/lib/usage.js +153 -153
  147. package/bin/runners/lib/validate-patch.js +156 -156
  148. package/bin/runners/lib/verdict-engine.js +628 -628
  149. package/bin/runners/reality/engine.js +917 -917
  150. package/bin/runners/reality/flows.js +122 -122
  151. package/bin/runners/reality/report.js +378 -378
  152. package/bin/runners/reality/session.js +193 -193
  153. package/bin/runners/runAgent.d.ts +5 -0
  154. package/bin/runners/runApprove.js +1200 -0
  155. package/bin/runners/runAuth.js +324 -95
  156. package/bin/runners/runCheckpoint.js +39 -21
  157. package/bin/runners/runClassify.js +859 -0
  158. package/bin/runners/runContext.js +136 -24
  159. package/bin/runners/runDoctor.js +108 -68
  160. package/bin/runners/runFirewall.d.ts +5 -0
  161. package/bin/runners/runFirewallHook.d.ts +5 -0
  162. package/bin/runners/runFix.js +6 -5
  163. package/bin/runners/runGuard.js +262 -168
  164. package/bin/runners/runInit.js +3 -2
  165. package/bin/runners/runMcp.js +130 -52
  166. package/bin/runners/runPolish.js +43 -20
  167. package/bin/runners/runProve.js +1 -2
  168. package/bin/runners/runReport.js +3 -2
  169. package/bin/runners/runScan.js +145 -44
  170. package/bin/runners/runShip.js +3 -4
  171. package/bin/runners/runTruth.d.ts +5 -0
  172. package/bin/runners/runValidate.js +19 -2
  173. package/bin/runners/runWatch.js +104 -53
  174. package/bin/vibecheck.js +106 -19
  175. package/mcp-server/HARDENING_SUMMARY.md +299 -0
  176. package/mcp-server/agent-firewall-interceptor.js +367 -31
  177. package/mcp-server/authority-tools.js +569 -0
  178. package/mcp-server/conductor/conflict-resolver.js +588 -0
  179. package/mcp-server/conductor/execution-planner.js +544 -0
  180. package/mcp-server/conductor/index.js +377 -0
  181. package/mcp-server/conductor/lock-manager.js +615 -0
  182. package/mcp-server/conductor/request-queue.js +550 -0
  183. package/mcp-server/conductor/session-manager.js +500 -0
  184. package/mcp-server/conductor/tools.js +510 -0
  185. package/mcp-server/index.js +1199 -208
  186. package/mcp-server/lib/api-client.cjs +305 -0
  187. package/mcp-server/lib/logger.cjs +30 -0
  188. package/mcp-server/logger.js +173 -0
  189. package/mcp-server/package.json +2 -2
  190. package/mcp-server/premium-tools.js +2 -2
  191. package/mcp-server/tier-auth.js +351 -136
  192. package/mcp-server/tools/index.js +72 -72
  193. package/mcp-server/truth-firewall-tools.js +145 -15
  194. package/mcp-server/vibecheck-tools.js +2 -2
  195. package/package.json +2 -3
  196. package/mcp-server/index.old.js +0 -4137
  197. package/mcp-server/package-lock.json +0 -165
@@ -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
+ };