@vibecheckai/cli 3.1.2 → 3.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -33
- package/bin/registry.js +319 -34
- package/bin/runners/CLI_REFACTOR_SUMMARY.md +229 -0
- package/bin/runners/REPORT_AUDIT.md +64 -0
- package/bin/runners/lib/entitlements-v2.js +97 -28
- package/bin/runners/lib/entitlements.js +3 -6
- package/bin/runners/lib/init-wizard.js +1 -1
- package/bin/runners/lib/report-engine.js +459 -280
- package/bin/runners/lib/report-html.js +1154 -1423
- package/bin/runners/lib/report-output.js +187 -0
- package/bin/runners/lib/report-templates.js +848 -850
- package/bin/runners/lib/scan-output.js +545 -0
- package/bin/runners/lib/server-usage.js +0 -12
- package/bin/runners/lib/ship-output.js +641 -0
- package/bin/runners/lib/status-output.js +253 -0
- package/bin/runners/lib/terminal-ui.js +853 -0
- package/bin/runners/runCheckpoint.js +502 -0
- package/bin/runners/runContracts.js +105 -0
- package/bin/runners/runExport.js +93 -0
- package/bin/runners/runFix.js +31 -24
- package/bin/runners/runInit.js +377 -112
- package/bin/runners/runInstall.js +1 -5
- package/bin/runners/runLabs.js +3 -3
- package/bin/runners/runPolish.js +2452 -0
- package/bin/runners/runProve.js +2 -2
- package/bin/runners/runReport.js +251 -200
- package/bin/runners/runRuntime.js +110 -0
- package/bin/runners/runScan.js +477 -379
- package/bin/runners/runSecurity.js +92 -0
- package/bin/runners/runShip.js +137 -207
- package/bin/runners/runStatus.js +16 -68
- package/bin/runners/utils.js +5 -5
- package/bin/vibecheck.js +25 -11
- package/mcp-server/index.js +150 -18
- package/mcp-server/package.json +2 -2
- package/mcp-server/premium-tools.js +13 -13
- package/mcp-server/tier-auth.js +292 -27
- package/mcp-server/vibecheck-tools.js +9 -9
- package/package.json +1 -1
- package/bin/runners/runClaimVerifier.js +0 -483
- package/bin/runners/runContextCompiler.js +0 -385
- package/bin/runners/runGate.js +0 -17
- package/bin/runners/runInitGha.js +0 -164
- package/bin/runners/runInteractive.js +0 -388
- package/bin/runners/runMdc.js +0 -204
- package/bin/runners/runMissionGenerator.js +0 -282
- package/bin/runners/runTruthpack.js +0 -636
|
@@ -1,282 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Mission Generator v1
|
|
4
|
-
*
|
|
5
|
-
* Generates Assist Mission files from ship findings.
|
|
6
|
-
* Each mission is a Markdown file with YAML frontmatter.
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* generateMissions(findings, projectPath)
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import fs from 'fs/promises';
|
|
13
|
-
import path from 'path';
|
|
14
|
-
import yaml from 'js-yaml';
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Generate mission files from findings
|
|
18
|
-
*
|
|
19
|
-
* @param {Object[]} findings - Array of findings from vibecheck ship
|
|
20
|
-
* @param {string} projectPath - Project root path
|
|
21
|
-
* @returns {Object} Generated missions info
|
|
22
|
-
*/
|
|
23
|
-
export async function generateMissions(findings, projectPath = process.cwd()) {
|
|
24
|
-
const assistDir = path.join(projectPath, '.vibecheck', 'assist');
|
|
25
|
-
const missionsDir = path.join(assistDir, 'missions');
|
|
26
|
-
|
|
27
|
-
await fs.mkdir(missionsDir, { recursive: true });
|
|
28
|
-
|
|
29
|
-
// Group findings by category
|
|
30
|
-
const grouped = groupFindings(findings);
|
|
31
|
-
|
|
32
|
-
// Generate mission files
|
|
33
|
-
const missions = [];
|
|
34
|
-
let missionNumber = 1;
|
|
35
|
-
|
|
36
|
-
for (const [category, categoryFindings] of Object.entries(grouped)) {
|
|
37
|
-
for (const finding of categoryFindings) {
|
|
38
|
-
const mission = createMission(finding, missionNumber, category);
|
|
39
|
-
const filename = `${String(missionNumber).padStart(2, '0')}_${slugify(mission.title)}.md`;
|
|
40
|
-
const filePath = path.join(missionsDir, filename);
|
|
41
|
-
|
|
42
|
-
await fs.writeFile(filePath, formatMission(mission));
|
|
43
|
-
|
|
44
|
-
missions.push({
|
|
45
|
-
id: mission.missionId,
|
|
46
|
-
title: mission.title,
|
|
47
|
-
file: filename,
|
|
48
|
-
severity: mission.severity,
|
|
49
|
-
category: mission.category,
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
missionNumber++;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Write plan.json
|
|
57
|
-
const plan = {
|
|
58
|
-
generatedAt: new Date().toISOString(),
|
|
59
|
-
totalMissions: missions.length,
|
|
60
|
-
byCategory: Object.fromEntries(
|
|
61
|
-
Object.entries(grouped).map(([cat, items]) => [cat, items.length])
|
|
62
|
-
),
|
|
63
|
-
missions,
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
await fs.writeFile(
|
|
67
|
-
path.join(assistDir, 'plan.json'),
|
|
68
|
-
JSON.stringify(plan, null, 2)
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
console.log(`\n📋 Generated ${missions.length} missions in ${missionsDir}`);
|
|
72
|
-
|
|
73
|
-
return plan;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Group findings by category
|
|
78
|
-
*/
|
|
79
|
-
function groupFindings(findings) {
|
|
80
|
-
const groups = {};
|
|
81
|
-
|
|
82
|
-
for (const finding of findings) {
|
|
83
|
-
const category = finding.category || 'general';
|
|
84
|
-
if (!groups[category]) groups[category] = [];
|
|
85
|
-
groups[category].push(finding);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Sort by severity within each category
|
|
89
|
-
const severityOrder = { BLOCK: 0, WARN: 1, INFO: 2 };
|
|
90
|
-
for (const category of Object.keys(groups)) {
|
|
91
|
-
groups[category].sort((a, b) =>
|
|
92
|
-
(severityOrder[a.severity] || 3) - (severityOrder[b.severity] || 3)
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return groups;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Create a mission object from a finding
|
|
101
|
-
*/
|
|
102
|
-
function createMission(finding, number, category) {
|
|
103
|
-
const missionId = `M${String(number).padStart(2, '0')}`;
|
|
104
|
-
|
|
105
|
-
// Determine required claims based on finding type
|
|
106
|
-
const dependsOnClaims = [];
|
|
107
|
-
if (finding.type === 'dead_ui' || finding.type === 'route_mismatch') {
|
|
108
|
-
dependsOnClaims.push({
|
|
109
|
-
type: 'route_exists',
|
|
110
|
-
subject: { path: finding.route || finding.expectedRoute },
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
if (finding.type === 'auth_gap') {
|
|
114
|
-
dependsOnClaims.push({
|
|
115
|
-
type: 'auth_enforced',
|
|
116
|
-
subject: { path: finding.route },
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Determine applicable invariants
|
|
121
|
-
const invariants = [];
|
|
122
|
-
if (category === 'DeadUI' || finding.type === 'dead_ui') {
|
|
123
|
-
invariants.push('INV_NO_FAKE_SUCCESS', 'INV_NO_ROUTE_INVENTION');
|
|
124
|
-
}
|
|
125
|
-
if (category === 'Auth' || finding.type === 'auth_gap') {
|
|
126
|
-
invariants.push('INV_NO_BYPASS_ENTITLEMENTS', 'INV_NO_SILENT_CATCH_AUTH');
|
|
127
|
-
}
|
|
128
|
-
if (category === 'Billing') {
|
|
129
|
-
invariants.push('INV_NO_BYPASS_ENTITLEMENTS');
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return {
|
|
133
|
-
missionId,
|
|
134
|
-
title: finding.title || `Fix ${category} issue`,
|
|
135
|
-
severity: finding.severity || 'WARN',
|
|
136
|
-
category,
|
|
137
|
-
scopeFiles: finding.files || [],
|
|
138
|
-
dependsOnClaims,
|
|
139
|
-
invariants,
|
|
140
|
-
assumptionBudget: 2,
|
|
141
|
-
finding,
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Format a mission as Markdown with YAML frontmatter
|
|
147
|
-
*/
|
|
148
|
-
function formatMission(mission) {
|
|
149
|
-
const frontmatter = {
|
|
150
|
-
missionId: mission.missionId,
|
|
151
|
-
title: mission.title,
|
|
152
|
-
severity: mission.severity,
|
|
153
|
-
category: mission.category,
|
|
154
|
-
scopeFiles: mission.scopeFiles,
|
|
155
|
-
dependsOnClaims: mission.dependsOnClaims,
|
|
156
|
-
invariants: mission.invariants,
|
|
157
|
-
assumptionBudget: mission.assumptionBudget,
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
const finding = mission.finding;
|
|
161
|
-
|
|
162
|
-
const content = `---
|
|
163
|
-
${yaml.dump(frontmatter, { lineWidth: -1 })}---
|
|
164
|
-
|
|
165
|
-
# Objective
|
|
166
|
-
${finding.description || finding.title || 'Fix the identified issue.'}
|
|
167
|
-
|
|
168
|
-
# Truth Pack (authoritative)
|
|
169
|
-
Use the provided context slice and do not invent endpoints, env vars, or auth assumptions.
|
|
170
|
-
|
|
171
|
-
# Evidence Pack (must reference when editing)
|
|
172
|
-
- Finding ${finding.id || mission.missionId}:
|
|
173
|
-
${mission.scopeFiles.map(f => ` - ${f}`).join('\n') || ' - (no specific files identified)'}
|
|
174
|
-
- Reason: ${finding.reason || finding.description || 'See finding details'}
|
|
175
|
-
|
|
176
|
-
# Required tool calls (before making claims)
|
|
177
|
-
${generateRequiredToolCalls(mission)}
|
|
178
|
-
|
|
179
|
-
# Steps
|
|
180
|
-
${generateSteps(mission)}
|
|
181
|
-
|
|
182
|
-
# Acceptance tests (must pass)
|
|
183
|
-
- vibecheck ship
|
|
184
|
-
- ${findTestCommand(mission)}
|
|
185
|
-
- No new blockers introduced
|
|
186
|
-
|
|
187
|
-
# Output requirements
|
|
188
|
-
- List changed files
|
|
189
|
-
- Explain each change with evidence refs
|
|
190
|
-
- Provide final ship verdict result
|
|
191
|
-
`;
|
|
192
|
-
|
|
193
|
-
return content;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Generate required tool calls for the mission
|
|
198
|
-
*/
|
|
199
|
-
function generateRequiredToolCalls(mission) {
|
|
200
|
-
const calls = [];
|
|
201
|
-
let callNum = 1;
|
|
202
|
-
|
|
203
|
-
for (const claim of mission.dependsOnClaims) {
|
|
204
|
-
calls.push(`${callNum}) validate_claim(${claim.type} ${JSON.stringify(claim.subject)})`);
|
|
205
|
-
callNum++;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (calls.length === 0) {
|
|
209
|
-
calls.push('1) vibecheck.get_truthpack() - Get current truth state');
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
calls.push(`${callNum}) search_evidence("${mission.category.toLowerCase()}", globs=["src/**","apps/**"])`);
|
|
213
|
-
|
|
214
|
-
return calls.join('\n');
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
/**
|
|
218
|
-
* Generate steps for the mission
|
|
219
|
-
*/
|
|
220
|
-
function generateSteps(mission) {
|
|
221
|
-
const steps = [];
|
|
222
|
-
const finding = mission.finding;
|
|
223
|
-
|
|
224
|
-
switch (mission.category) {
|
|
225
|
-
case 'DeadUI':
|
|
226
|
-
steps.push('1) Identify why the UI action is dead (early return / missing handler / missing await).');
|
|
227
|
-
steps.push('2) If route mismatch exists, align client call to an existing proven route (do not invent).');
|
|
228
|
-
steps.push('3) Ensure success UI happens only after response ok.');
|
|
229
|
-
steps.push('4) Ensure errors surface (no empty catch).');
|
|
230
|
-
break;
|
|
231
|
-
|
|
232
|
-
case 'Auth':
|
|
233
|
-
steps.push('1) Verify the auth gap is real by checking middleware/guard configuration.');
|
|
234
|
-
steps.push('2) Add or fix the auth middleware on the affected route.');
|
|
235
|
-
steps.push('3) Ensure auth errors are properly handled (no silent failures).');
|
|
236
|
-
steps.push('4) Test both authenticated and unauthenticated access.');
|
|
237
|
-
break;
|
|
238
|
-
|
|
239
|
-
case 'Billing':
|
|
240
|
-
steps.push('1) Verify the billing gate is missing or bypassable.');
|
|
241
|
-
steps.push('2) Add server-side tier/entitlement check.');
|
|
242
|
-
steps.push('3) Ensure client-side checks match server-side enforcement.');
|
|
243
|
-
steps.push('4) Remove any bypass flags or dev-only overrides.');
|
|
244
|
-
break;
|
|
245
|
-
|
|
246
|
-
case 'Security':
|
|
247
|
-
steps.push('1) Identify the security vulnerability.');
|
|
248
|
-
steps.push('2) Apply the appropriate fix without breaking functionality.');
|
|
249
|
-
steps.push('3) Add validation/sanitization as needed.');
|
|
250
|
-
steps.push('4) Verify the fix does not introduce new vulnerabilities.');
|
|
251
|
-
break;
|
|
252
|
-
|
|
253
|
-
default:
|
|
254
|
-
steps.push('1) Analyze the finding to understand the root cause.');
|
|
255
|
-
steps.push('2) Identify the minimal change needed to fix the issue.');
|
|
256
|
-
steps.push('3) Implement the fix with proper error handling.');
|
|
257
|
-
steps.push('4) Verify the fix resolves the finding.');
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return steps.join('\n');
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* Find the appropriate test command
|
|
265
|
-
*/
|
|
266
|
-
function findTestCommand(mission) {
|
|
267
|
-
// This would ideally come from the truth pack's project.scripts
|
|
268
|
-
return 'pnpm test OR npm test (if present)';
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Convert title to slug
|
|
273
|
-
*/
|
|
274
|
-
function slugify(text) {
|
|
275
|
-
return text
|
|
276
|
-
.toLowerCase()
|
|
277
|
-
.replace(/[^a-z0-9]+/g, '_')
|
|
278
|
-
.replace(/^_+|_+$/g, '')
|
|
279
|
-
.slice(0, 40);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
export default { generateMissions };
|