@vibecheckai/cli 3.7.0 → 3.8.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 (99) hide show
  1. package/README.md +135 -63
  2. package/bin/_deprecations.js +447 -19
  3. package/bin/_router.js +1 -1
  4. package/bin/registry.js +347 -280
  5. package/bin/runners/context/generators/cursor-enhanced.js +2439 -0
  6. package/bin/runners/lib/agent-firewall/enforcement/gateway.js +1059 -0
  7. package/bin/runners/lib/agent-firewall/enforcement/index.js +98 -0
  8. package/bin/runners/lib/agent-firewall/enforcement/mode.js +318 -0
  9. package/bin/runners/lib/agent-firewall/enforcement/orchestrator.js +484 -0
  10. package/bin/runners/lib/agent-firewall/enforcement/proof-artifact.js +418 -0
  11. package/bin/runners/lib/agent-firewall/enforcement/schemas/change-event.schema.json +173 -0
  12. package/bin/runners/lib/agent-firewall/enforcement/schemas/intent.schema.json +181 -0
  13. package/bin/runners/lib/agent-firewall/enforcement/schemas/verdict.schema.json +222 -0
  14. package/bin/runners/lib/agent-firewall/enforcement/verdict-v2.js +333 -0
  15. package/bin/runners/lib/agent-firewall/index.js +200 -0
  16. package/bin/runners/lib/agent-firewall/integration/index.js +20 -0
  17. package/bin/runners/lib/agent-firewall/integration/ship-gate.js +437 -0
  18. package/bin/runners/lib/agent-firewall/intent/alignment-engine.js +622 -0
  19. package/bin/runners/lib/agent-firewall/intent/auto-detect.js +426 -0
  20. package/bin/runners/lib/agent-firewall/intent/index.js +102 -0
  21. package/bin/runners/lib/agent-firewall/intent/schema.js +352 -0
  22. package/bin/runners/lib/agent-firewall/intent/store.js +283 -0
  23. package/bin/runners/lib/agent-firewall/interception/fs-interceptor.js +502 -0
  24. package/bin/runners/lib/agent-firewall/interception/index.js +23 -0
  25. package/bin/runners/lib/agent-firewall/session/collector.js +451 -0
  26. package/bin/runners/lib/agent-firewall/session/index.js +26 -0
  27. package/bin/runners/lib/artifact-envelope.js +540 -0
  28. package/bin/runners/lib/auth-shared.js +977 -0
  29. package/bin/runners/lib/checkpoint.js +941 -0
  30. package/bin/runners/lib/cleanup/engine.js +571 -0
  31. package/bin/runners/lib/cleanup/index.js +53 -0
  32. package/bin/runners/lib/cleanup/output.js +375 -0
  33. package/bin/runners/lib/cleanup/rules.js +1060 -0
  34. package/bin/runners/lib/doctor/diagnosis-receipt.js +454 -0
  35. package/bin/runners/lib/doctor/failure-signatures.js +526 -0
  36. package/bin/runners/lib/doctor/fix-script.js +336 -0
  37. package/bin/runners/lib/doctor/modules/build-tools.js +453 -0
  38. package/bin/runners/lib/doctor/modules/index.js +62 -3
  39. package/bin/runners/lib/doctor/modules/os-quirks.js +706 -0
  40. package/bin/runners/lib/doctor/modules/repo-integrity.js +485 -0
  41. package/bin/runners/lib/doctor/safe-repair.js +384 -0
  42. package/bin/runners/lib/engines/attack-detector.js +1192 -0
  43. package/bin/runners/lib/entitlements-v2.js +2 -2
  44. package/bin/runners/lib/missions/briefing.js +427 -0
  45. package/bin/runners/lib/missions/checkpoint.js +753 -0
  46. package/bin/runners/lib/missions/hardening.js +851 -0
  47. package/bin/runners/lib/missions/plan.js +421 -32
  48. package/bin/runners/lib/missions/safety-gates.js +645 -0
  49. package/bin/runners/lib/missions/schema.js +478 -0
  50. package/bin/runners/lib/packs/bundle.js +675 -0
  51. package/bin/runners/lib/packs/evidence-pack.js +671 -0
  52. package/bin/runners/lib/packs/pack-factory.js +837 -0
  53. package/bin/runners/lib/packs/permissions-pack.js +686 -0
  54. package/bin/runners/lib/packs/proof-graph-pack.js +779 -0
  55. package/bin/runners/lib/safelist/index.js +96 -0
  56. package/bin/runners/lib/safelist/integration.js +334 -0
  57. package/bin/runners/lib/safelist/matcher.js +696 -0
  58. package/bin/runners/lib/safelist/schema.js +948 -0
  59. package/bin/runners/lib/safelist/store.js +438 -0
  60. package/bin/runners/lib/schemas/ship-manifest.schema.json +251 -0
  61. package/bin/runners/lib/ship-gate.js +832 -0
  62. package/bin/runners/lib/ship-manifest.js +1153 -0
  63. package/bin/runners/lib/ship-output.js +1 -1
  64. package/bin/runners/lib/unified-cli-output.js +710 -383
  65. package/bin/runners/lib/upsell.js +3 -3
  66. package/bin/runners/lib/why-tree.js +650 -0
  67. package/bin/runners/runAllowlist.js +33 -4
  68. package/bin/runners/runApprove.js +240 -1122
  69. package/bin/runners/runAudit.js +692 -0
  70. package/bin/runners/runAuth.js +325 -29
  71. package/bin/runners/runCheckpoint.js +442 -494
  72. package/bin/runners/runCleanup.js +343 -0
  73. package/bin/runners/runDoctor.js +269 -19
  74. package/bin/runners/runFix.js +411 -32
  75. package/bin/runners/runForge.js +411 -0
  76. package/bin/runners/runIntent.js +906 -0
  77. package/bin/runners/runKickoff.js +878 -0
  78. package/bin/runners/runLaunch.js +2000 -0
  79. package/bin/runners/runLink.js +785 -0
  80. package/bin/runners/runMcp.js +1741 -837
  81. package/bin/runners/runPacks.js +2089 -0
  82. package/bin/runners/runPolish.js +41 -0
  83. package/bin/runners/runSafelist.js +1190 -0
  84. package/bin/runners/runScan.js +21 -9
  85. package/bin/runners/runShield.js +1282 -0
  86. package/bin/runners/runShip.js +395 -16
  87. package/bin/vibecheck.js +34 -6
  88. package/mcp-server/README.md +117 -158
  89. package/mcp-server/handlers/tool-handler.ts +3 -3
  90. package/mcp-server/index.js +16 -0
  91. package/mcp-server/intent-firewall-interceptor.js +529 -0
  92. package/mcp-server/manifest.json +473 -0
  93. package/mcp-server/package.json +1 -1
  94. package/mcp-server/registry/tool-registry.js +315 -523
  95. package/mcp-server/registry/tools.json +442 -428
  96. package/mcp-server/tier-auth.js +68 -11
  97. package/mcp-server/tools-v3.js +70 -16
  98. package/package.json +1 -1
  99. package/bin/runners/runProof.zip +0 -0
@@ -0,0 +1,437 @@
1
+ /**
2
+ * Ship Gate - Enforcement integration for ship/packs/seal/CI
3
+ *
4
+ * ═══════════════════════════════════════════════════════════════════════════════
5
+ * AGENT FIREWALL™ - SHIP GATE
6
+ * ═══════════════════════════════════════════════════════════════════════════════
7
+ *
8
+ * This module provides the integration layer between the Agent Firewall
9
+ * enforcement system and shipping commands (ship, packs, seal, CI).
10
+ *
11
+ * SHIP CANNOT PROCEED unless:
12
+ * 1. A valid PASS verdict exists
13
+ * 2. The verdict is recent (not stale)
14
+ * 3. The verdict hash is verified
15
+ * 4. Reality proofs are satisfied (if required)
16
+ *
17
+ * @module integration/ship-gate
18
+ * @version 1.0.0
19
+ */
20
+
21
+ "use strict";
22
+
23
+ const path = require("path");
24
+ const fs = require("fs");
25
+ const crypto = require("crypto");
26
+
27
+ const { createGateway, MODE, VERDICT } = require("../enforcement/gateway");
28
+ const { IntentStore } = require("../intent/store");
29
+
30
+ // ═══════════════════════════════════════════════════════════════════════════════
31
+ // CONSTANTS
32
+ // ═══════════════════════════════════════════════════════════════════════════════
33
+
34
+ const SHIP_GATE_STATUS = {
35
+ CLEAR: "CLEAR", // Can ship
36
+ BLOCKED: "BLOCKED", // Cannot ship - violations
37
+ NO_VERDICT: "NO_VERDICT", // Cannot ship - no enforcement run
38
+ STALE_VERDICT: "STALE_VERDICT", // Cannot ship - verdict too old
39
+ TAMPERED: "TAMPERED", // Cannot ship - verdict integrity failed
40
+ NO_INTENT: "NO_INTENT", // Cannot ship - no intent declared
41
+ PROOFS_PENDING: "PROOFS_PENDING", // Cannot ship - reality proofs needed
42
+ };
43
+
44
+ const DEFAULT_VERDICT_MAX_AGE_MS = 30 * 60 * 1000; // 30 minutes
45
+ const STRICT_VERDICT_MAX_AGE_MS = 5 * 60 * 1000; // 5 minutes for CI
46
+
47
+ // ═══════════════════════════════════════════════════════════════════════════════
48
+ // SHIP GATE
49
+ // ═══════════════════════════════════════════════════════════════════════════════
50
+
51
+ class ShipGate {
52
+ constructor(projectRoot, options = {}) {
53
+ this.projectRoot = projectRoot;
54
+ this.options = options;
55
+ this.gateway = createGateway(projectRoot, options);
56
+ this.intentStore = new IntentStore(projectRoot);
57
+ }
58
+
59
+ /**
60
+ * Check if ship is allowed
61
+ *
62
+ * @param {Object} options
63
+ * @param {boolean} options.strict - Require recent verdict and proofs
64
+ * @param {boolean} options.requireIntent - Require declared intent
65
+ * @param {boolean} options.requireProofs - Require reality proofs
66
+ * @param {number} options.maxVerdictAge - Max age of verdict in ms
67
+ * @returns {Object} Ship gate result
68
+ */
69
+ async checkShipStatus(options = {}) {
70
+ const strict = options.strict || process.env.CI || false;
71
+ const requireIntent = options.requireIntent !== false;
72
+ const requireProofs = options.requireProofs || strict;
73
+ const maxAge = options.maxVerdictAge || (strict ? STRICT_VERDICT_MAX_AGE_MS : DEFAULT_VERDICT_MAX_AGE_MS);
74
+
75
+ const result = {
76
+ status: SHIP_GATE_STATUS.CLEAR,
77
+ canShip: false,
78
+ message: "",
79
+ details: {},
80
+ verdict: null,
81
+ intent: null,
82
+ proofs: [],
83
+ recommendations: [],
84
+ };
85
+
86
+ // Step 1: Check for declared intent
87
+ if (requireIntent) {
88
+ const hasIntent = this.intentStore.hasIntent();
89
+ const intent = this.intentStore.getCurrent({ allowMissing: true });
90
+
91
+ if (!hasIntent || intent?.summary?.includes("NO INTENT")) {
92
+ result.status = SHIP_GATE_STATUS.NO_INTENT;
93
+ result.message = "No intent declared - cannot ship without declared intent";
94
+ result.recommendations.push("Run: vibecheck intent set -s 'your intent'");
95
+ return result;
96
+ }
97
+
98
+ result.intent = intent;
99
+ }
100
+
101
+ // Step 2: Check for valid verdict
102
+ const latestVerdict = this._getLatestVerdict();
103
+
104
+ if (!latestVerdict) {
105
+ result.status = SHIP_GATE_STATUS.NO_VERDICT;
106
+ result.message = "No enforcement verdict found - run vibecheck shield first";
107
+ result.recommendations.push("Run: vibecheck shield");
108
+ return result;
109
+ }
110
+
111
+ result.verdict = latestVerdict;
112
+
113
+ // Step 3: Verify verdict integrity
114
+ const integrityCheck = this._verifyVerdictIntegrity(latestVerdict);
115
+
116
+ if (!integrityCheck.valid) {
117
+ result.status = SHIP_GATE_STATUS.TAMPERED;
118
+ result.message = `Verdict integrity check failed: ${integrityCheck.reason}`;
119
+ result.details.integrityCheck = integrityCheck;
120
+ result.recommendations.push("Re-run: vibecheck shield");
121
+ return result;
122
+ }
123
+
124
+ // Step 4: Check verdict age
125
+ const verdictAge = Date.now() - new Date(latestVerdict.timestamp).getTime();
126
+
127
+ if (verdictAge > maxAge) {
128
+ result.status = SHIP_GATE_STATUS.STALE_VERDICT;
129
+ result.message = `Verdict is ${Math.round(verdictAge / 60000)} minutes old (max: ${Math.round(maxAge / 60000)})`;
130
+ result.details.verdictAge = verdictAge;
131
+ result.details.maxAge = maxAge;
132
+ result.recommendations.push("Re-run: vibecheck shield");
133
+ return result;
134
+ }
135
+
136
+ // Step 5: Check verdict decision
137
+ if (latestVerdict.decision === VERDICT.BLOCK) {
138
+ result.status = SHIP_GATE_STATUS.BLOCKED;
139
+ result.message = latestVerdict.summary || "Enforcement violations found";
140
+ result.details.violations = latestVerdict.violations;
141
+ result.details.fixGuidance = latestVerdict.fix_guidance;
142
+
143
+ // Add fix recommendations
144
+ for (const fix of latestVerdict.fix_guidance || []) {
145
+ if (fix.command) {
146
+ result.recommendations.push(fix.command);
147
+ }
148
+ }
149
+
150
+ return result;
151
+ }
152
+
153
+ // Step 6: Check reality proofs (if required)
154
+ if (requireProofs && latestVerdict.proofs) {
155
+ const pendingProofs = latestVerdict.proofs.filter(p => p.status === "pending");
156
+ const failedProofs = latestVerdict.proofs.filter(p => p.status === "failed");
157
+
158
+ if (failedProofs.length > 0) {
159
+ result.status = SHIP_GATE_STATUS.BLOCKED;
160
+ result.message = `${failedProofs.length} reality proof(s) failed`;
161
+ result.details.failedProofs = failedProofs;
162
+ result.recommendations.push("Run: vibecheck prove");
163
+ return result;
164
+ }
165
+
166
+ if (pendingProofs.length > 0) {
167
+ result.status = SHIP_GATE_STATUS.PROOFS_PENDING;
168
+ result.message = `${pendingProofs.length} reality proof(s) pending`;
169
+ result.details.pendingProofs = pendingProofs;
170
+ result.recommendations.push("Run: vibecheck prove --all");
171
+ return result;
172
+ }
173
+
174
+ result.proofs = latestVerdict.proofs;
175
+ }
176
+
177
+ // All checks passed
178
+ result.status = SHIP_GATE_STATUS.CLEAR;
179
+ result.canShip = true;
180
+ result.message = "All enforcement checks passed - clear to ship";
181
+
182
+ return result;
183
+ }
184
+
185
+ /**
186
+ * Get ship manifest for embedding in releases
187
+ *
188
+ * Creates a signed manifest that proves the code passed enforcement
189
+ * at ship time. Can be verified later.
190
+ */
191
+ async getShipManifest() {
192
+ const status = await this.checkShipStatus({ strict: true });
193
+
194
+ if (!status.canShip) {
195
+ return {
196
+ success: false,
197
+ error: status.message,
198
+ status: status.status,
199
+ };
200
+ }
201
+
202
+ const manifest = {
203
+ schema_version: "3.0.0",
204
+ shipped_at: new Date().toISOString(),
205
+ project_root: this.projectRoot,
206
+ intent: {
207
+ hash: status.intent?.hash,
208
+ summary: status.intent?.summary,
209
+ },
210
+ verdict: {
211
+ id: status.verdict.id,
212
+ decision: status.verdict.decision,
213
+ hash: status.verdict.verdict_hash,
214
+ timestamp: status.verdict.timestamp,
215
+ violations_count: status.verdict.violations?.length || 0,
216
+ proofs_count: status.verdict.proofs?.length || 0,
217
+ },
218
+ proofs_verified: status.proofs.filter(p => p.status === "verified").length,
219
+ chain: status.verdict.chain,
220
+ };
221
+
222
+ // Sign the manifest
223
+ manifest.signature = this._signManifest(manifest);
224
+
225
+ return {
226
+ success: true,
227
+ manifest,
228
+ };
229
+ }
230
+
231
+ /**
232
+ * Verify a ship manifest
233
+ */
234
+ verifyShipManifest(manifest) {
235
+ if (!manifest || !manifest.signature) {
236
+ return { valid: false, reason: "MISSING_SIGNATURE" };
237
+ }
238
+
239
+ // Verify signature
240
+ const secret = process.env.VIBECHECK_SIGN_KEY || "vibecheck-local-signing-key";
241
+ const content = JSON.stringify({
242
+ shipped_at: manifest.shipped_at,
243
+ intent: manifest.intent,
244
+ verdict: manifest.verdict,
245
+ proofs_verified: manifest.proofs_verified,
246
+ chain: manifest.chain,
247
+ });
248
+
249
+ const expected = crypto.createHmac("sha256", secret)
250
+ .update(content)
251
+ .digest("hex");
252
+
253
+ if (expected !== manifest.signature.value) {
254
+ return { valid: false, reason: "SIGNATURE_MISMATCH" };
255
+ }
256
+
257
+ return { valid: true, reason: "VERIFIED" };
258
+ }
259
+
260
+ /**
261
+ * Format ship gate status for CLI output
262
+ */
263
+ formatStatus(status, options = {}) {
264
+ const lines = [];
265
+ const ansi = options.ansi || {};
266
+ const r = ansi.reset || "";
267
+ const b = ansi.bold || "";
268
+ const g = ansi.green || "";
269
+ const y = ansi.yellow || "";
270
+ const red = ansi.red || "";
271
+ const d = ansi.dim || "";
272
+
273
+ // Header
274
+ lines.push("═══════════════════════════════════════════════════════════════════════════════");
275
+ lines.push(`${b}AGENT FIREWALL - SHIP GATE${r}`);
276
+ lines.push("═══════════════════════════════════════════════════════════════════════════════");
277
+ lines.push("");
278
+
279
+ // Status
280
+ const statusColor = status.canShip ? g : red;
281
+ const statusIcon = status.canShip ? "✓" : "✗";
282
+
283
+ lines.push(`${b}Status:${r} ${statusColor}${statusIcon} ${status.status}${r}`);
284
+ lines.push(`${b}Message:${r} ${status.message}`);
285
+ lines.push("");
286
+
287
+ // Details
288
+ if (status.verdict) {
289
+ lines.push(`${d}Verdict ID:${r} ${status.verdict.id}`);
290
+ lines.push(`${d}Decision:${r} ${status.verdict.decision}`);
291
+ lines.push(`${d}Verdict Hash:${r} ${status.verdict.verdict_hash?.substring(0, 16)}...`);
292
+ lines.push("");
293
+ }
294
+
295
+ if (status.intent) {
296
+ lines.push(`${d}Intent:${r} "${status.intent.summary}"`);
297
+ lines.push(`${d}Intent Hash:${r} ${status.intent.hash?.substring(0, 16)}...`);
298
+ lines.push("");
299
+ }
300
+
301
+ // Violations
302
+ if (status.details?.violations?.length > 0) {
303
+ lines.push(`${b}Violations (${status.details.violations.length}):${r}`);
304
+ for (const v of status.details.violations.slice(0, 5)) {
305
+ lines.push(` ${red}•${r} [${v.code}] ${v.message}`);
306
+ if (v.fix_hint) {
307
+ lines.push(` ${g}→${r} ${v.fix_hint}`);
308
+ }
309
+ }
310
+ if (status.details.violations.length > 5) {
311
+ lines.push(` ${d}... and ${status.details.violations.length - 5} more${r}`);
312
+ }
313
+ lines.push("");
314
+ }
315
+
316
+ // Recommendations
317
+ if (status.recommendations?.length > 0) {
318
+ lines.push(`${b}To proceed:${r}`);
319
+ for (const rec of status.recommendations) {
320
+ lines.push(` ${y}→${r} ${rec}`);
321
+ }
322
+ lines.push("");
323
+ }
324
+
325
+ lines.push("═══════════════════════════════════════════════════════════════════════════════");
326
+
327
+ return lines.join("\n");
328
+ }
329
+
330
+ // ═══════════════════════════════════════════════════════════════════════════
331
+ // PRIVATE METHODS
332
+ // ═══════════════════════════════════════════════════════════════════════════
333
+
334
+ _getLatestVerdict() {
335
+ const latestPath = path.join(this.projectRoot, ".vibecheck", "verdicts", "latest.json");
336
+
337
+ if (fs.existsSync(latestPath)) {
338
+ try {
339
+ return JSON.parse(fs.readFileSync(latestPath, "utf-8"));
340
+ } catch {
341
+ return null;
342
+ }
343
+ }
344
+
345
+ return null;
346
+ }
347
+
348
+ _verifyVerdictIntegrity(verdict) {
349
+ if (!verdict || !verdict.verdict_hash) {
350
+ return { valid: false, reason: "MISSING_HASH" };
351
+ }
352
+
353
+ const content = JSON.stringify({
354
+ decision: verdict.decision,
355
+ mode: verdict.mode,
356
+ violations: verdict.violations.map(v => ({ code: v.code, resource: v.resource })),
357
+ proofs: verdict.proofs.map(p => ({ id: p.id, status: p.status })),
358
+ intent_hash: verdict.intent_hash,
359
+ timestamp: verdict.timestamp,
360
+ chain: verdict.chain,
361
+ });
362
+
363
+ const computed = crypto.createHash("sha256").update(content).digest("hex");
364
+
365
+ if (computed !== verdict.verdict_hash) {
366
+ return { valid: false, reason: "HASH_MISMATCH", computed, stored: verdict.verdict_hash };
367
+ }
368
+
369
+ return { valid: true, reason: "VERIFIED" };
370
+ }
371
+
372
+ _signManifest(manifest) {
373
+ const secret = process.env.VIBECHECK_SIGN_KEY || "vibecheck-local-signing-key";
374
+ const content = JSON.stringify({
375
+ shipped_at: manifest.shipped_at,
376
+ intent: manifest.intent,
377
+ verdict: manifest.verdict,
378
+ proofs_verified: manifest.proofs_verified,
379
+ chain: manifest.chain,
380
+ });
381
+
382
+ return {
383
+ algorithm: "sha256-hmac",
384
+ value: crypto.createHmac("sha256", secret).update(content).digest("hex"),
385
+ signed_at: new Date().toISOString(),
386
+ };
387
+ }
388
+ }
389
+
390
+ // ═══════════════════════════════════════════════════════════════════════════════
391
+ // FACTORY FUNCTIONS
392
+ // ═══════════════════════════════════════════════════════════════════════════════
393
+
394
+ /**
395
+ * Create a ship gate instance
396
+ */
397
+ function createShipGate(projectRoot, options = {}) {
398
+ return new ShipGate(projectRoot, options);
399
+ }
400
+
401
+ /**
402
+ * Quick check if ship is allowed
403
+ */
404
+ async function canShip(projectRoot, options = {}) {
405
+ const gate = createShipGate(projectRoot, options);
406
+ const status = await gate.checkShipStatus(options);
407
+ return status.canShip;
408
+ }
409
+
410
+ /**
411
+ * Get ship status for CI
412
+ */
413
+ async function getCIStatus(projectRoot) {
414
+ const gate = createShipGate(projectRoot, { mode: MODE.CI });
415
+ const status = await gate.checkShipStatus({ strict: true });
416
+
417
+ return {
418
+ canShip: status.canShip,
419
+ exitCode: status.canShip ? 0 : 2,
420
+ status: status.status,
421
+ message: status.message,
422
+ verdictId: status.verdict?.id,
423
+ violationsCount: status.details?.violations?.length || 0,
424
+ };
425
+ }
426
+
427
+ // ═══════════════════════════════════════════════════════════════════════════════
428
+ // EXPORTS
429
+ // ═══════════════════════════════════════════════════════════════════════════════
430
+
431
+ module.exports = {
432
+ ShipGate,
433
+ createShipGate,
434
+ canShip,
435
+ getCIStatus,
436
+ SHIP_GATE_STATUS,
437
+ };