@vibecheckai/cli 3.7.0 → 3.9.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.
- package/README.md +135 -63
- package/bin/_deprecations.js +447 -19
- package/bin/_router.js +1 -1
- package/bin/registry.js +347 -280
- package/bin/runners/context/generators/cursor-enhanced.js +2439 -0
- package/bin/runners/lib/agent-firewall/enforcement/gateway.js +1059 -0
- package/bin/runners/lib/agent-firewall/enforcement/index.js +98 -0
- package/bin/runners/lib/agent-firewall/enforcement/mode.js +318 -0
- package/bin/runners/lib/agent-firewall/enforcement/orchestrator.js +484 -0
- package/bin/runners/lib/agent-firewall/enforcement/proof-artifact.js +418 -0
- package/bin/runners/lib/agent-firewall/enforcement/schemas/change-event.schema.json +173 -0
- package/bin/runners/lib/agent-firewall/enforcement/schemas/intent.schema.json +181 -0
- package/bin/runners/lib/agent-firewall/enforcement/schemas/verdict.schema.json +222 -0
- package/bin/runners/lib/agent-firewall/enforcement/verdict-v2.js +333 -0
- package/bin/runners/lib/agent-firewall/index.js +200 -0
- package/bin/runners/lib/agent-firewall/integration/index.js +20 -0
- package/bin/runners/lib/agent-firewall/integration/ship-gate.js +437 -0
- package/bin/runners/lib/agent-firewall/intent/alignment-engine.js +634 -0
- package/bin/runners/lib/agent-firewall/intent/auto-detect.js +426 -0
- package/bin/runners/lib/agent-firewall/intent/index.js +102 -0
- package/bin/runners/lib/agent-firewall/intent/schema.js +352 -0
- package/bin/runners/lib/agent-firewall/intent/store.js +283 -0
- package/bin/runners/lib/agent-firewall/interception/fs-interceptor.js +502 -0
- package/bin/runners/lib/agent-firewall/interception/index.js +23 -0
- package/bin/runners/lib/agent-firewall/interceptor/base.js +7 -3
- package/bin/runners/lib/agent-firewall/session/collector.js +451 -0
- package/bin/runners/lib/agent-firewall/session/index.js +26 -0
- package/bin/runners/lib/artifact-envelope.js +540 -0
- package/bin/runners/lib/auth-shared.js +977 -0
- package/bin/runners/lib/checkpoint.js +941 -0
- package/bin/runners/lib/cleanup/engine.js +571 -0
- package/bin/runners/lib/cleanup/index.js +53 -0
- package/bin/runners/lib/cleanup/output.js +375 -0
- package/bin/runners/lib/cleanup/rules.js +1060 -0
- package/bin/runners/lib/doctor/diagnosis-receipt.js +454 -0
- package/bin/runners/lib/doctor/failure-signatures.js +526 -0
- package/bin/runners/lib/doctor/fix-script.js +336 -0
- package/bin/runners/lib/doctor/modules/build-tools.js +453 -0
- package/bin/runners/lib/doctor/modules/index.js +62 -3
- package/bin/runners/lib/doctor/modules/os-quirks.js +706 -0
- package/bin/runners/lib/doctor/modules/repo-integrity.js +485 -0
- package/bin/runners/lib/doctor/safe-repair.js +384 -0
- package/bin/runners/lib/engine/ast-cache.js +210 -210
- package/bin/runners/lib/engine/auth-extractor.js +211 -211
- package/bin/runners/lib/engine/billing-extractor.js +112 -112
- package/bin/runners/lib/engine/enforcement-extractor.js +100 -100
- package/bin/runners/lib/engine/env-extractor.js +207 -207
- package/bin/runners/lib/engine/express-extractor.js +208 -208
- package/bin/runners/lib/engine/extractors.js +849 -849
- package/bin/runners/lib/engine/index.js +207 -207
- package/bin/runners/lib/engine/repo-index.js +514 -514
- package/bin/runners/lib/engine/types.js +124 -124
- package/bin/runners/lib/engines/attack-detector.js +1192 -0
- package/bin/runners/lib/entitlements-v2.js +2 -2
- package/bin/runners/lib/missions/briefing.js +427 -0
- package/bin/runners/lib/missions/checkpoint.js +753 -0
- package/bin/runners/lib/missions/hardening.js +851 -0
- package/bin/runners/lib/missions/plan.js +421 -32
- package/bin/runners/lib/missions/safety-gates.js +645 -0
- package/bin/runners/lib/missions/schema.js +478 -0
- package/bin/runners/lib/packs/bundle.js +675 -0
- package/bin/runners/lib/packs/evidence-pack.js +671 -0
- package/bin/runners/lib/packs/pack-factory.js +837 -0
- package/bin/runners/lib/packs/permissions-pack.js +686 -0
- package/bin/runners/lib/packs/proof-graph-pack.js +779 -0
- package/bin/runners/lib/safelist/index.js +96 -0
- package/bin/runners/lib/safelist/integration.js +334 -0
- package/bin/runners/lib/safelist/matcher.js +696 -0
- package/bin/runners/lib/safelist/schema.js +948 -0
- package/bin/runners/lib/safelist/store.js +438 -0
- package/bin/runners/lib/schemas/ship-manifest.schema.json +251 -0
- package/bin/runners/lib/ship-gate.js +832 -0
- package/bin/runners/lib/ship-manifest.js +1153 -0
- package/bin/runners/lib/ship-output.js +1 -1
- package/bin/runners/lib/unified-cli-output.js +710 -383
- package/bin/runners/lib/upsell.js +3 -3
- package/bin/runners/lib/why-tree.js +650 -0
- package/bin/runners/runAllowlist.js +33 -4
- package/bin/runners/runApprove.js +240 -1122
- package/bin/runners/runAudit.js +692 -0
- package/bin/runners/runAuth.js +325 -29
- package/bin/runners/runCheckpoint.js +442 -494
- package/bin/runners/runCleanup.js +343 -0
- package/bin/runners/runDoctor.js +269 -19
- package/bin/runners/runFix.js +411 -32
- package/bin/runners/runForge.js +411 -0
- package/bin/runners/runIntent.js +906 -0
- package/bin/runners/runKickoff.js +878 -0
- package/bin/runners/runLaunch.js +2000 -0
- package/bin/runners/runLink.js +785 -0
- package/bin/runners/runMcp.js +1741 -837
- package/bin/runners/runPacks.js +2089 -0
- package/bin/runners/runPolish.js +41 -0
- package/bin/runners/runReality.js +178 -1
- package/bin/runners/runSafelist.js +1190 -0
- package/bin/runners/runScan.js +21 -9
- package/bin/runners/runShield.js +1282 -0
- package/bin/runners/runShip.js +395 -16
- package/bin/vibecheck.js +34 -6
- package/mcp-server/README.md +117 -158
- package/mcp-server/handlers/index.ts +2 -2
- package/mcp-server/handlers/tool-handler.ts +50 -11
- package/mcp-server/index.js +16 -0
- package/mcp-server/intent-firewall-interceptor.js +529 -0
- package/mcp-server/lib/executor.ts +5 -5
- package/mcp-server/lib/index.ts +14 -4
- package/mcp-server/lib/sandbox.test.ts +4 -4
- package/mcp-server/lib/sandbox.ts +2 -2
- package/mcp-server/manifest.json +473 -0
- package/mcp-server/package.json +1 -1
- package/mcp-server/registry/tool-registry.js +315 -523
- package/mcp-server/registry/tools.json +442 -428
- package/mcp-server/registry.test.ts +18 -12
- package/mcp-server/tier-auth.js +68 -11
- package/mcp-server/tools-v3.js +70 -16
- package/mcp-server/tsconfig.json +1 -0
- package/package.json +2 -1
- package/bin/runners/runProof.zip +0 -0
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
// bin/runners/lib/missions/schema.js
|
|
2
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
3
|
+
// MISSION SCHEMA - Formal definition for Fix Missions V2
|
|
4
|
+
// "Missions, not chaos" - Each mission is a well-defined, reversible operation
|
|
5
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
6
|
+
|
|
7
|
+
const crypto = require('crypto');
|
|
8
|
+
const {
|
|
9
|
+
ValidationError,
|
|
10
|
+
isValidFilePath,
|
|
11
|
+
isValidConfidence,
|
|
12
|
+
getAuditTrail,
|
|
13
|
+
} = require('./hardening');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {object} MissionObjective
|
|
17
|
+
* @property {string} title - Mission title
|
|
18
|
+
* @property {string} intent - What we're trying to achieve
|
|
19
|
+
* @property {string[]} successCriteria - How we know we succeeded
|
|
20
|
+
* @property {string[]} targetFindingIds - Which findings this resolves
|
|
21
|
+
* @property {number} findingCount - Number of findings targeted
|
|
22
|
+
* @property {string} category - Finding category
|
|
23
|
+
* @property {string} severity - Finding severity
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @typedef {object} MissionScope
|
|
28
|
+
* @property {string[]} allowedFiles - Files LLM may edit
|
|
29
|
+
* @property {string[]} readOnlyContext - Files for context only
|
|
30
|
+
* @property {string} blastRadius - Blast radius category
|
|
31
|
+
* @property {string|null} primaryFile - Primary file to edit
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @typedef {object} MissionVerification
|
|
36
|
+
* @property {string} proofType - What to run after (ship|lint|test|custom)
|
|
37
|
+
* @property {string} expectedOutcome - Expected result
|
|
38
|
+
* @property {number} timeout - Verification timeout in ms
|
|
39
|
+
* @property {number} retries - Number of retries attempted
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* @typedef {object} MissionSafety
|
|
44
|
+
* @property {boolean} reversible - Can be rolled back
|
|
45
|
+
* @property {boolean} requiresApproval - Needs human approval
|
|
46
|
+
* @property {number} confidence - Combined finding confidence (0-1)
|
|
47
|
+
* @property {string} riskLevel - Risk level category
|
|
48
|
+
* @property {string|null} checkpointId - Checkpoint to rollback to
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @typedef {object} MissionTemplate
|
|
53
|
+
* @property {string|null} intent - Template intent
|
|
54
|
+
* @property {string[]} do - Actions to take
|
|
55
|
+
* @property {string[]} dont - Actions to avoid
|
|
56
|
+
* @property {string[]} success - Success criteria
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @typedef {object} Mission
|
|
61
|
+
* @property {string} id - Stable mission ID (M_xxx)
|
|
62
|
+
* @property {string} type - Mission type
|
|
63
|
+
* @property {string} status - Current status
|
|
64
|
+
* @property {string} createdAt - ISO timestamp
|
|
65
|
+
* @property {string} [updatedAt] - ISO timestamp
|
|
66
|
+
* @property {MissionObjective} objective - Mission objective
|
|
67
|
+
* @property {MissionScope} scope - Files in scope
|
|
68
|
+
* @property {MissionVerification} verification - Verification config
|
|
69
|
+
* @property {MissionSafety} safety - Safety metadata
|
|
70
|
+
* @property {MissionTemplate} template - LLM prompt template
|
|
71
|
+
* @property {object[]} evidence - Evidence from findings
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Risk levels for missions
|
|
76
|
+
*/
|
|
77
|
+
const RISK_LEVEL = {
|
|
78
|
+
LOW: 'low',
|
|
79
|
+
MEDIUM: 'medium',
|
|
80
|
+
HIGH: 'high',
|
|
81
|
+
CRITICAL: 'critical',
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Blast radius categories
|
|
86
|
+
*/
|
|
87
|
+
const BLAST_RADIUS = {
|
|
88
|
+
LOW: 'low', // 1-2 files
|
|
89
|
+
MEDIUM: 'medium', // 3-5 files
|
|
90
|
+
HIGH: 'high', // 6+ files
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Proof types for verification
|
|
95
|
+
*/
|
|
96
|
+
const PROOF_TYPE = {
|
|
97
|
+
SHIP: 'ship', // Run vibecheck ship
|
|
98
|
+
LINT: 'lint', // Run linter
|
|
99
|
+
TEST: 'test', // Run tests
|
|
100
|
+
CUSTOM: 'custom', // Custom verification
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Expected outcomes for verification
|
|
105
|
+
*/
|
|
106
|
+
const EXPECTED_OUTCOME = {
|
|
107
|
+
FINDING_REMOVED: 'finding_removed',
|
|
108
|
+
TEST_PASS: 'test_pass',
|
|
109
|
+
SCORE_DECREASE: 'score_decrease',
|
|
110
|
+
NO_REGRESSION: 'no_regression',
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Mission status
|
|
115
|
+
*/
|
|
116
|
+
const MISSION_STATUS = {
|
|
117
|
+
PLANNED: 'planned',
|
|
118
|
+
PENDING: 'pending',
|
|
119
|
+
IN_PROGRESS: 'in_progress',
|
|
120
|
+
COMPLETED: 'completed',
|
|
121
|
+
FAILED: 'failed',
|
|
122
|
+
ROLLED_BACK: 'rolled_back',
|
|
123
|
+
SKIPPED: 'skipped',
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Generate a stable mission ID from finding IDs
|
|
128
|
+
* @param {string} type - Mission type
|
|
129
|
+
* @param {string[]} findingIds - Target finding IDs
|
|
130
|
+
* @returns {string} Stable mission ID
|
|
131
|
+
*/
|
|
132
|
+
function generateMissionId(type, findingIds) {
|
|
133
|
+
const sorted = [...findingIds].sort();
|
|
134
|
+
const hash = crypto
|
|
135
|
+
.createHash('sha256')
|
|
136
|
+
.update(`${type}:${sorted.join(',')}`)
|
|
137
|
+
.digest('hex')
|
|
138
|
+
.slice(0, 12);
|
|
139
|
+
return `M_${hash}`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Calculate blast radius from file count
|
|
144
|
+
* @param {number} fileCount - Number of files affected
|
|
145
|
+
* @returns {string} Blast radius category
|
|
146
|
+
*/
|
|
147
|
+
function calculateBlastRadius(fileCount) {
|
|
148
|
+
if (fileCount <= 2) return BLAST_RADIUS.LOW;
|
|
149
|
+
if (fileCount <= 5) return BLAST_RADIUS.MEDIUM;
|
|
150
|
+
return BLAST_RADIUS.HIGH;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Calculate risk level from mission properties
|
|
155
|
+
* @param {object} params - Mission parameters
|
|
156
|
+
* @returns {string} Risk level
|
|
157
|
+
*/
|
|
158
|
+
function calculateRiskLevel({ severity, confidence, blastRadius, missionType }) {
|
|
159
|
+
let score = 0;
|
|
160
|
+
|
|
161
|
+
// Severity contribution (0-40 points)
|
|
162
|
+
if (severity === 'BLOCK') score += 40;
|
|
163
|
+
else if (severity === 'WARN') score += 20;
|
|
164
|
+
else score += 5;
|
|
165
|
+
|
|
166
|
+
// Confidence inverse contribution (0-20 points)
|
|
167
|
+
// Lower confidence = higher risk
|
|
168
|
+
score += Math.round((1 - (confidence || 0.5)) * 20);
|
|
169
|
+
|
|
170
|
+
// Blast radius contribution (0-30 points)
|
|
171
|
+
if (blastRadius === BLAST_RADIUS.HIGH) score += 30;
|
|
172
|
+
else if (blastRadius === BLAST_RADIUS.MEDIUM) score += 15;
|
|
173
|
+
else score += 5;
|
|
174
|
+
|
|
175
|
+
// Mission type contribution (0-10 points)
|
|
176
|
+
const criticalTypes = [
|
|
177
|
+
'FIX_HARDCODED_SECRETS',
|
|
178
|
+
'REMOVE_OWNER_MODE',
|
|
179
|
+
'FIX_AUTH_DRIFT',
|
|
180
|
+
'FIX_STRIPE_WEBHOOKS',
|
|
181
|
+
];
|
|
182
|
+
if (criticalTypes.includes(missionType)) score += 10;
|
|
183
|
+
|
|
184
|
+
// Convert score to risk level
|
|
185
|
+
if (score >= 70) return RISK_LEVEL.CRITICAL;
|
|
186
|
+
if (score >= 50) return RISK_LEVEL.HIGH;
|
|
187
|
+
if (score >= 30) return RISK_LEVEL.MEDIUM;
|
|
188
|
+
return RISK_LEVEL.LOW;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Create a mission object from findings
|
|
193
|
+
* @param {object} params - Mission creation parameters
|
|
194
|
+
* @param {string} params.type - Mission type
|
|
195
|
+
* @param {string} params.title - Mission title
|
|
196
|
+
* @param {string} params.severity - Finding severity
|
|
197
|
+
* @param {string} params.category - Finding category
|
|
198
|
+
* @param {string[]} params.targetFindingIds - IDs of findings to fix
|
|
199
|
+
* @param {object} [params.template] - Mission template
|
|
200
|
+
* @param {string[]} [params.allowedFiles] - Files that can be edited
|
|
201
|
+
* @param {string[]} [params.readOnlyContext] - Files for context only
|
|
202
|
+
* @param {number} [params.confidence] - Confidence score (0-1)
|
|
203
|
+
* @param {object[]} [params.evidence] - Evidence from findings
|
|
204
|
+
* @param {string|null} [params.file] - Primary file
|
|
205
|
+
* @returns {Mission} Mission object
|
|
206
|
+
* @throws {ValidationError} If parameters are invalid
|
|
207
|
+
*/
|
|
208
|
+
function createMission({
|
|
209
|
+
type,
|
|
210
|
+
title,
|
|
211
|
+
severity,
|
|
212
|
+
category,
|
|
213
|
+
targetFindingIds,
|
|
214
|
+
template,
|
|
215
|
+
allowedFiles = [],
|
|
216
|
+
readOnlyContext = [],
|
|
217
|
+
confidence = 0.5,
|
|
218
|
+
evidence = [],
|
|
219
|
+
file = null,
|
|
220
|
+
}) {
|
|
221
|
+
const audit = getAuditTrail();
|
|
222
|
+
|
|
223
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
224
|
+
// INPUT VALIDATION
|
|
225
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
226
|
+
|
|
227
|
+
// Validate required fields
|
|
228
|
+
if (!type || typeof type !== 'string') {
|
|
229
|
+
throw new ValidationError('Mission type is required and must be a string', 'type', type);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (!targetFindingIds || !Array.isArray(targetFindingIds) || targetFindingIds.length === 0) {
|
|
233
|
+
throw new ValidationError('targetFindingIds must be a non-empty array', 'targetFindingIds', targetFindingIds);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Validate confidence
|
|
237
|
+
if (!isValidConfidence(confidence)) {
|
|
238
|
+
audit.warn('invalid_confidence', { confidence, default: 0.5 });
|
|
239
|
+
confidence = 0.5;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Validate and sanitize file paths
|
|
243
|
+
const sanitizedAllowedFiles = [];
|
|
244
|
+
for (const filePath of allowedFiles) {
|
|
245
|
+
if (isValidFilePath(filePath)) {
|
|
246
|
+
sanitizedAllowedFiles.push(filePath);
|
|
247
|
+
} else {
|
|
248
|
+
audit.warn('invalid_file_path_skipped', { filePath });
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const sanitizedReadOnlyContext = [];
|
|
253
|
+
for (const filePath of readOnlyContext) {
|
|
254
|
+
if (isValidFilePath(filePath)) {
|
|
255
|
+
sanitizedReadOnlyContext.push(filePath);
|
|
256
|
+
} else {
|
|
257
|
+
audit.warn('invalid_readonly_path_skipped', { filePath });
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// Validate primary file
|
|
262
|
+
let sanitizedFile = null;
|
|
263
|
+
if (file) {
|
|
264
|
+
if (isValidFilePath(file)) {
|
|
265
|
+
sanitizedFile = file;
|
|
266
|
+
} else {
|
|
267
|
+
audit.warn('invalid_primary_file', { file });
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
272
|
+
// MISSION CONSTRUCTION
|
|
273
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
274
|
+
|
|
275
|
+
const blastRadius = calculateBlastRadius(sanitizedAllowedFiles.length);
|
|
276
|
+
const riskLevel = calculateRiskLevel({
|
|
277
|
+
severity,
|
|
278
|
+
confidence,
|
|
279
|
+
blastRadius,
|
|
280
|
+
missionType: type,
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
const missionId = generateMissionId(type, targetFindingIds);
|
|
284
|
+
|
|
285
|
+
// Sanitize title
|
|
286
|
+
const sanitizedTitle = (title || `Fix ${type}`).slice(0, 200);
|
|
287
|
+
|
|
288
|
+
// Sanitize severity
|
|
289
|
+
const validSeverities = ['BLOCK', 'WARN', 'INFO', 'critical', 'high', 'medium', 'low', 'info'];
|
|
290
|
+
const sanitizedSeverity = validSeverities.includes(severity) ? severity : 'WARN';
|
|
291
|
+
|
|
292
|
+
const mission = {
|
|
293
|
+
// Identity
|
|
294
|
+
id: missionId,
|
|
295
|
+
type,
|
|
296
|
+
status: MISSION_STATUS.PLANNED,
|
|
297
|
+
createdAt: new Date().toISOString(),
|
|
298
|
+
|
|
299
|
+
// Objective (the "briefing")
|
|
300
|
+
objective: {
|
|
301
|
+
title: sanitizedTitle,
|
|
302
|
+
intent: template?.intent || `Fix ${type} issues`,
|
|
303
|
+
successCriteria: Array.isArray(template?.success) ? template.success : [`Finding ${targetFindingIds[0]} no longer appears in ship results`],
|
|
304
|
+
targetFindingIds: [...targetFindingIds], // Defensive copy
|
|
305
|
+
findingCount: targetFindingIds.length,
|
|
306
|
+
category: category || 'Unknown',
|
|
307
|
+
severity: sanitizedSeverity,
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
// Files touched (pre-calculated)
|
|
311
|
+
scope: {
|
|
312
|
+
allowedFiles: sanitizedAllowedFiles,
|
|
313
|
+
readOnlyContext: sanitizedReadOnlyContext,
|
|
314
|
+
blastRadius,
|
|
315
|
+
primaryFile: sanitizedFile || sanitizedAllowedFiles[0] || null,
|
|
316
|
+
},
|
|
317
|
+
|
|
318
|
+
// Expected proofs
|
|
319
|
+
verification: {
|
|
320
|
+
proofType: PROOF_TYPE.SHIP,
|
|
321
|
+
expectedOutcome: EXPECTED_OUTCOME.FINDING_REMOVED,
|
|
322
|
+
timeout: 30000,
|
|
323
|
+
retries: 0,
|
|
324
|
+
},
|
|
325
|
+
|
|
326
|
+
// Safety metadata
|
|
327
|
+
safety: {
|
|
328
|
+
reversible: true,
|
|
329
|
+
requiresApproval: riskLevel === RISK_LEVEL.CRITICAL,
|
|
330
|
+
confidence,
|
|
331
|
+
riskLevel,
|
|
332
|
+
checkpointId: null, // Set when checkpoint is created
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
// Template for LLM prompt
|
|
336
|
+
template: {
|
|
337
|
+
intent: template?.intent || null,
|
|
338
|
+
do: Array.isArray(template?.do) ? template.do : [],
|
|
339
|
+
dont: Array.isArray(template?.dont) ? template.dont : [],
|
|
340
|
+
success: Array.isArray(template?.success) ? template.success : [],
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
// Evidence from findings (defensive copy)
|
|
344
|
+
evidence: Array.isArray(evidence) ? [...evidence] : [],
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
audit.debug('mission_created', {
|
|
348
|
+
missionId,
|
|
349
|
+
type,
|
|
350
|
+
findingCount: targetFindingIds.length,
|
|
351
|
+
fileCount: sanitizedAllowedFiles.length,
|
|
352
|
+
riskLevel,
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
return mission;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Validate a mission object
|
|
360
|
+
* @param {object} mission - Mission to validate
|
|
361
|
+
* @returns {object} Validation result { valid: boolean, errors: string[] }
|
|
362
|
+
*/
|
|
363
|
+
function validateMission(mission) {
|
|
364
|
+
const errors = [];
|
|
365
|
+
|
|
366
|
+
if (!mission.id || !mission.id.startsWith('M_')) {
|
|
367
|
+
errors.push('Mission ID must start with "M_"');
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
if (!mission.type) {
|
|
371
|
+
errors.push('Mission type is required');
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (!mission.objective?.targetFindingIds?.length) {
|
|
375
|
+
errors.push('Mission must target at least one finding');
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (!mission.scope?.allowedFiles?.length && !mission.scope?.readOnlyContext?.length) {
|
|
379
|
+
errors.push('Mission must have at least one file in scope');
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
if (mission.safety?.confidence < 0 || mission.safety?.confidence > 1) {
|
|
383
|
+
errors.push('Confidence must be between 0 and 1');
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return {
|
|
387
|
+
valid: errors.length === 0,
|
|
388
|
+
errors,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* Serialize mission to JSON for storage
|
|
394
|
+
* @param {object} mission - Mission object
|
|
395
|
+
* @returns {string} JSON string
|
|
396
|
+
*/
|
|
397
|
+
function serializeMission(mission) {
|
|
398
|
+
return JSON.stringify(mission, null, 2);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Deserialize mission from JSON
|
|
403
|
+
* @param {string} json - JSON string
|
|
404
|
+
* @returns {object} Mission object
|
|
405
|
+
*/
|
|
406
|
+
function deserializeMission(json) {
|
|
407
|
+
const mission = JSON.parse(json);
|
|
408
|
+
// Ensure all required fields exist with defaults
|
|
409
|
+
return {
|
|
410
|
+
...mission,
|
|
411
|
+
status: mission.status || MISSION_STATUS.PLANNED,
|
|
412
|
+
safety: {
|
|
413
|
+
reversible: true,
|
|
414
|
+
requiresApproval: false,
|
|
415
|
+
confidence: 0.5,
|
|
416
|
+
riskLevel: RISK_LEVEL.MEDIUM,
|
|
417
|
+
checkpointId: null,
|
|
418
|
+
...mission.safety,
|
|
419
|
+
},
|
|
420
|
+
verification: {
|
|
421
|
+
proofType: PROOF_TYPE.SHIP,
|
|
422
|
+
expectedOutcome: EXPECTED_OUTCOME.FINDING_REMOVED,
|
|
423
|
+
timeout: 30000,
|
|
424
|
+
retries: 0,
|
|
425
|
+
...mission.verification,
|
|
426
|
+
},
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Update mission status
|
|
432
|
+
* @param {object} mission - Mission object
|
|
433
|
+
* @param {string} status - New status
|
|
434
|
+
* @param {object} metadata - Additional metadata
|
|
435
|
+
* @returns {object} Updated mission
|
|
436
|
+
*/
|
|
437
|
+
function updateMissionStatus(mission, status, metadata = {}) {
|
|
438
|
+
return {
|
|
439
|
+
...mission,
|
|
440
|
+
status,
|
|
441
|
+
updatedAt: new Date().toISOString(),
|
|
442
|
+
...metadata,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Check if mission is safe to auto-apply
|
|
448
|
+
* @param {object} mission - Mission object
|
|
449
|
+
* @returns {boolean} True if safe to auto-apply
|
|
450
|
+
*/
|
|
451
|
+
function isSafeToAutoApply(mission) {
|
|
452
|
+
return (
|
|
453
|
+
mission.safety.reversible &&
|
|
454
|
+
!mission.safety.requiresApproval &&
|
|
455
|
+
mission.safety.riskLevel !== RISK_LEVEL.CRITICAL &&
|
|
456
|
+
mission.safety.confidence >= 0.6
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
module.exports = {
|
|
461
|
+
// Constants
|
|
462
|
+
RISK_LEVEL,
|
|
463
|
+
BLAST_RADIUS,
|
|
464
|
+
PROOF_TYPE,
|
|
465
|
+
EXPECTED_OUTCOME,
|
|
466
|
+
MISSION_STATUS,
|
|
467
|
+
|
|
468
|
+
// Functions
|
|
469
|
+
generateMissionId,
|
|
470
|
+
calculateBlastRadius,
|
|
471
|
+
calculateRiskLevel,
|
|
472
|
+
createMission,
|
|
473
|
+
validateMission,
|
|
474
|
+
serializeMission,
|
|
475
|
+
deserializeMission,
|
|
476
|
+
updateMissionStatus,
|
|
477
|
+
isSafeToAutoApply,
|
|
478
|
+
};
|