@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.
- 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 +622 -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/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/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/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/tool-handler.ts +3 -3
- package/mcp-server/index.js +16 -0
- package/mcp-server/intent-firewall-interceptor.js +529 -0
- 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/tier-auth.js +68 -11
- package/mcp-server/tools-v3.js +70 -16
- package/package.json +1 -1
- package/bin/runners/runProof.zip +0 -0
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safe Repair Mode
|
|
3
|
+
*
|
|
4
|
+
* Executes only safe, non-destructive repair actions.
|
|
5
|
+
* Actions that can cause data loss or require elevated permissions are excluded.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { execSync, spawnSync } = require('child_process');
|
|
11
|
+
const { SEVERITY, FIX_TYPE } = require('./types');
|
|
12
|
+
|
|
13
|
+
const REPAIR_RESULT = {
|
|
14
|
+
SUCCESS: 'success',
|
|
15
|
+
FAILED: 'failed',
|
|
16
|
+
SKIPPED: 'skipped',
|
|
17
|
+
NOT_APPLICABLE: 'not_applicable',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Safe repair actions that can be automatically executed
|
|
22
|
+
*/
|
|
23
|
+
const SAFE_REPAIR_ACTIONS = [
|
|
24
|
+
{
|
|
25
|
+
id: 'clear-npm-cache',
|
|
26
|
+
name: 'Clear npm cache',
|
|
27
|
+
description: 'Removes npm cache to fix integrity issues',
|
|
28
|
+
applicableTo: ['npm-cache-corrupt', 'npm-permission-error'],
|
|
29
|
+
check: () => true, // Always applicable
|
|
30
|
+
execute: async (projectPath, options) => {
|
|
31
|
+
try {
|
|
32
|
+
execSync('npm cache clean --force', {
|
|
33
|
+
cwd: projectPath,
|
|
34
|
+
encoding: 'utf8',
|
|
35
|
+
timeout: 60000,
|
|
36
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
37
|
+
});
|
|
38
|
+
return { status: REPAIR_RESULT.SUCCESS, message: 'npm cache cleared' };
|
|
39
|
+
} catch (err) {
|
|
40
|
+
return { status: REPAIR_RESULT.FAILED, message: err.message };
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: 'clear-node-modules-cache',
|
|
46
|
+
name: 'Clear node_modules cache directories',
|
|
47
|
+
description: 'Removes .cache directories inside node_modules',
|
|
48
|
+
applicableTo: ['cache-large', 'build-cache-corrupt'],
|
|
49
|
+
check: (projectPath) => {
|
|
50
|
+
const cachePath = path.join(projectPath, 'node_modules', '.cache');
|
|
51
|
+
return fs.existsSync(cachePath);
|
|
52
|
+
},
|
|
53
|
+
execute: async (projectPath, options) => {
|
|
54
|
+
const cachePath = path.join(projectPath, 'node_modules', '.cache');
|
|
55
|
+
try {
|
|
56
|
+
fs.rmSync(cachePath, { recursive: true, force: true });
|
|
57
|
+
return { status: REPAIR_RESULT.SUCCESS, message: 'node_modules/.cache cleared' };
|
|
58
|
+
} catch (err) {
|
|
59
|
+
return { status: REPAIR_RESULT.FAILED, message: err.message };
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: 'remove-eslint-cache',
|
|
65
|
+
name: 'Remove ESLint cache',
|
|
66
|
+
description: 'Removes .eslintcache file',
|
|
67
|
+
applicableTo: ['eslint-error', 'cache-large'],
|
|
68
|
+
check: (projectPath) => fs.existsSync(path.join(projectPath, '.eslintcache')),
|
|
69
|
+
execute: async (projectPath, options) => {
|
|
70
|
+
try {
|
|
71
|
+
fs.unlinkSync(path.join(projectPath, '.eslintcache'));
|
|
72
|
+
return { status: REPAIR_RESULT.SUCCESS, message: '.eslintcache removed' };
|
|
73
|
+
} catch (err) {
|
|
74
|
+
return { status: REPAIR_RESULT.FAILED, message: err.message };
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 'remove-tsbuildinfo',
|
|
80
|
+
name: 'Remove TypeScript build info',
|
|
81
|
+
description: 'Removes tsconfig.tsbuildinfo for clean TypeScript rebuild',
|
|
82
|
+
applicableTo: ['typescript-error', 'build-error'],
|
|
83
|
+
check: (projectPath) => {
|
|
84
|
+
// Check for any .tsbuildinfo file
|
|
85
|
+
return fs.existsSync(path.join(projectPath, 'tsconfig.tsbuildinfo')) ||
|
|
86
|
+
fs.existsSync(path.join(projectPath, '.tsbuildinfo'));
|
|
87
|
+
},
|
|
88
|
+
execute: async (projectPath, options) => {
|
|
89
|
+
const removed = [];
|
|
90
|
+
const files = ['tsconfig.tsbuildinfo', '.tsbuildinfo'];
|
|
91
|
+
|
|
92
|
+
for (const file of files) {
|
|
93
|
+
const fullPath = path.join(projectPath, file);
|
|
94
|
+
if (fs.existsSync(fullPath)) {
|
|
95
|
+
try {
|
|
96
|
+
fs.unlinkSync(fullPath);
|
|
97
|
+
removed.push(file);
|
|
98
|
+
} catch {}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (removed.length > 0) {
|
|
103
|
+
return { status: REPAIR_RESULT.SUCCESS, message: `Removed: ${removed.join(', ')}` };
|
|
104
|
+
}
|
|
105
|
+
return { status: REPAIR_RESULT.NOT_APPLICABLE, message: 'No build info files found' };
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: 'remove-git-lock',
|
|
110
|
+
name: 'Remove git lock files',
|
|
111
|
+
description: 'Removes stale .git/*.lock files',
|
|
112
|
+
applicableTo: ['git-lock-file'],
|
|
113
|
+
check: (projectPath) => {
|
|
114
|
+
const gitDir = path.join(projectPath, '.git');
|
|
115
|
+
if (!fs.existsSync(gitDir)) return false;
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
const files = fs.readdirSync(gitDir);
|
|
119
|
+
return files.some(f => f.endsWith('.lock'));
|
|
120
|
+
} catch {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
execute: async (projectPath, options) => {
|
|
125
|
+
const gitDir = path.join(projectPath, '.git');
|
|
126
|
+
const removed = [];
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const files = fs.readdirSync(gitDir);
|
|
130
|
+
for (const file of files) {
|
|
131
|
+
if (file.endsWith('.lock')) {
|
|
132
|
+
fs.unlinkSync(path.join(gitDir, file));
|
|
133
|
+
removed.push(file);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
} catch (err) {
|
|
137
|
+
return { status: REPAIR_RESULT.FAILED, message: err.message };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (removed.length > 0) {
|
|
141
|
+
return { status: REPAIR_RESULT.SUCCESS, message: `Removed: ${removed.join(', ')}` };
|
|
142
|
+
}
|
|
143
|
+
return { status: REPAIR_RESULT.NOT_APPLICABLE, message: 'No lock files found' };
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
id: 'create-vibecheck-dir',
|
|
148
|
+
name: 'Create .vibecheck directory',
|
|
149
|
+
description: 'Creates missing .vibecheck output directory',
|
|
150
|
+
applicableTo: ['vibecheck-dir-missing'],
|
|
151
|
+
check: (projectPath) => !fs.existsSync(path.join(projectPath, '.vibecheck')),
|
|
152
|
+
execute: async (projectPath, options) => {
|
|
153
|
+
try {
|
|
154
|
+
fs.mkdirSync(path.join(projectPath, '.vibecheck'), { recursive: true });
|
|
155
|
+
return { status: REPAIR_RESULT.SUCCESS, message: '.vibecheck directory created' };
|
|
156
|
+
} catch (err) {
|
|
157
|
+
return { status: REPAIR_RESULT.FAILED, message: err.message };
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
id: 'fix-npm-registry',
|
|
163
|
+
name: 'Reset npm registry URL',
|
|
164
|
+
description: 'Sets npm registry to default npmjs.org',
|
|
165
|
+
applicableTo: ['npm-network-error'],
|
|
166
|
+
check: () => true,
|
|
167
|
+
execute: async (projectPath, options) => {
|
|
168
|
+
try {
|
|
169
|
+
execSync('npm config set registry https://registry.npmjs.org/', {
|
|
170
|
+
encoding: 'utf8',
|
|
171
|
+
timeout: 10000,
|
|
172
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
173
|
+
});
|
|
174
|
+
return { status: REPAIR_RESULT.SUCCESS, message: 'npm registry reset to default' };
|
|
175
|
+
} catch (err) {
|
|
176
|
+
return { status: REPAIR_RESULT.FAILED, message: err.message };
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
id: 'npm-dedupe',
|
|
182
|
+
name: 'Deduplicate npm packages',
|
|
183
|
+
description: 'Runs npm dedupe to reduce duplicate packages',
|
|
184
|
+
applicableTo: ['dependencies-large', 'peer-deps'],
|
|
185
|
+
check: (projectPath) => fs.existsSync(path.join(projectPath, 'node_modules')),
|
|
186
|
+
execute: async (projectPath, options) => {
|
|
187
|
+
try {
|
|
188
|
+
execSync('npm dedupe', {
|
|
189
|
+
cwd: projectPath,
|
|
190
|
+
encoding: 'utf8',
|
|
191
|
+
timeout: 120000, // 2 minutes
|
|
192
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
193
|
+
});
|
|
194
|
+
return { status: REPAIR_RESULT.SUCCESS, message: 'npm dedupe completed' };
|
|
195
|
+
} catch (err) {
|
|
196
|
+
return { status: REPAIR_RESULT.FAILED, message: err.message };
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
id: 'rebuild-native-modules',
|
|
202
|
+
name: 'Rebuild native modules',
|
|
203
|
+
description: 'Runs npm rebuild for native module issues',
|
|
204
|
+
applicableTo: ['native-module-build', 'node-version-mismatch'],
|
|
205
|
+
check: (projectPath) => fs.existsSync(path.join(projectPath, 'node_modules')),
|
|
206
|
+
execute: async (projectPath, options) => {
|
|
207
|
+
try {
|
|
208
|
+
execSync('npm rebuild', {
|
|
209
|
+
cwd: projectPath,
|
|
210
|
+
encoding: 'utf8',
|
|
211
|
+
timeout: 300000, // 5 minutes
|
|
212
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
213
|
+
});
|
|
214
|
+
return { status: REPAIR_RESULT.SUCCESS, message: 'npm rebuild completed' };
|
|
215
|
+
} catch (err) {
|
|
216
|
+
return { status: REPAIR_RESULT.FAILED, message: err.message };
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
id: 'prune-dev-dependencies',
|
|
222
|
+
name: 'Prune development dependencies',
|
|
223
|
+
description: 'Removes extraneous packages',
|
|
224
|
+
applicableTo: ['dependencies-large'],
|
|
225
|
+
check: (projectPath) => fs.existsSync(path.join(projectPath, 'node_modules')),
|
|
226
|
+
execute: async (projectPath, options) => {
|
|
227
|
+
try {
|
|
228
|
+
execSync('npm prune', {
|
|
229
|
+
cwd: projectPath,
|
|
230
|
+
encoding: 'utf8',
|
|
231
|
+
timeout: 60000,
|
|
232
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
233
|
+
});
|
|
234
|
+
return { status: REPAIR_RESULT.SUCCESS, message: 'npm prune completed' };
|
|
235
|
+
} catch (err) {
|
|
236
|
+
return { status: REPAIR_RESULT.FAILED, message: err.message };
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
];
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Run safe repair on a project
|
|
244
|
+
* @param {object[]} diagnostics - Diagnostic results
|
|
245
|
+
* @param {string} projectPath - Project path
|
|
246
|
+
* @param {object} options - Repair options
|
|
247
|
+
* @returns {object} Repair results
|
|
248
|
+
*/
|
|
249
|
+
async function runSafeRepair(diagnostics, projectPath, options = {}) {
|
|
250
|
+
const {
|
|
251
|
+
dryRun = false,
|
|
252
|
+
verbose = false,
|
|
253
|
+
maxActions = 10,
|
|
254
|
+
} = options;
|
|
255
|
+
|
|
256
|
+
const results = [];
|
|
257
|
+
let actionsRun = 0;
|
|
258
|
+
|
|
259
|
+
// Identify which repairs are applicable
|
|
260
|
+
const applicableRepairs = [];
|
|
261
|
+
|
|
262
|
+
for (const action of SAFE_REPAIR_ACTIONS) {
|
|
263
|
+
// Check if this repair applies to any diagnostics
|
|
264
|
+
const relevantDiag = diagnostics.find(d =>
|
|
265
|
+
(d.severity === SEVERITY.ERROR || d.severity === SEVERITY.WARNING) &&
|
|
266
|
+
action.applicableTo.some(pattern => d.id.includes(pattern) || d.message?.toLowerCase().includes(pattern))
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
if (relevantDiag && action.check(projectPath)) {
|
|
270
|
+
applicableRepairs.push({
|
|
271
|
+
action,
|
|
272
|
+
diagnostic: relevantDiag,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Execute repairs
|
|
278
|
+
for (const { action, diagnostic } of applicableRepairs) {
|
|
279
|
+
if (actionsRun >= maxActions) break;
|
|
280
|
+
|
|
281
|
+
const result = {
|
|
282
|
+
actionId: action.id,
|
|
283
|
+
actionName: action.name,
|
|
284
|
+
description: action.description,
|
|
285
|
+
relatedDiagnostic: diagnostic.id,
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
if (dryRun) {
|
|
289
|
+
result.status = REPAIR_RESULT.SKIPPED;
|
|
290
|
+
result.message = 'Dry run - would execute';
|
|
291
|
+
results.push(result);
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
try {
|
|
296
|
+
const execResult = await action.execute(projectPath, options);
|
|
297
|
+
result.status = execResult.status;
|
|
298
|
+
result.message = execResult.message;
|
|
299
|
+
|
|
300
|
+
if (execResult.status === REPAIR_RESULT.SUCCESS) {
|
|
301
|
+
actionsRun++;
|
|
302
|
+
}
|
|
303
|
+
} catch (err) {
|
|
304
|
+
result.status = REPAIR_RESULT.FAILED;
|
|
305
|
+
result.message = err.message;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
results.push(result);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// Summary
|
|
312
|
+
const summary = {
|
|
313
|
+
total: results.length,
|
|
314
|
+
succeeded: results.filter(r => r.status === REPAIR_RESULT.SUCCESS).length,
|
|
315
|
+
failed: results.filter(r => r.status === REPAIR_RESULT.FAILED).length,
|
|
316
|
+
skipped: results.filter(r => r.status === REPAIR_RESULT.SKIPPED).length,
|
|
317
|
+
notApplicable: results.filter(r => r.status === REPAIR_RESULT.NOT_APPLICABLE).length,
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
return {
|
|
321
|
+
projectPath,
|
|
322
|
+
timestamp: new Date().toISOString(),
|
|
323
|
+
dryRun,
|
|
324
|
+
results,
|
|
325
|
+
summary,
|
|
326
|
+
needsRecheck: summary.succeeded > 0,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Get list of all available safe repair actions
|
|
332
|
+
* @returns {object[]} Safe repair actions
|
|
333
|
+
*/
|
|
334
|
+
function listSafeRepairActions() {
|
|
335
|
+
return SAFE_REPAIR_ACTIONS.map(a => ({
|
|
336
|
+
id: a.id,
|
|
337
|
+
name: a.name,
|
|
338
|
+
description: a.description,
|
|
339
|
+
applicableTo: a.applicableTo,
|
|
340
|
+
}));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Run a specific repair action by ID
|
|
345
|
+
* @param {string} actionId - Action ID to run
|
|
346
|
+
* @param {string} projectPath - Project path
|
|
347
|
+
* @param {object} options - Options
|
|
348
|
+
* @returns {object} Result
|
|
349
|
+
*/
|
|
350
|
+
async function runRepairAction(actionId, projectPath, options = {}) {
|
|
351
|
+
const action = SAFE_REPAIR_ACTIONS.find(a => a.id === actionId);
|
|
352
|
+
|
|
353
|
+
if (!action) {
|
|
354
|
+
return {
|
|
355
|
+
status: REPAIR_RESULT.FAILED,
|
|
356
|
+
message: `Unknown repair action: ${actionId}`,
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (!action.check(projectPath)) {
|
|
361
|
+
return {
|
|
362
|
+
status: REPAIR_RESULT.NOT_APPLICABLE,
|
|
363
|
+
message: 'Repair action not applicable to current project state',
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (options.dryRun) {
|
|
368
|
+
return {
|
|
369
|
+
status: REPAIR_RESULT.SKIPPED,
|
|
370
|
+
message: 'Dry run - would execute',
|
|
371
|
+
action: action.name,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return action.execute(projectPath, options);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
module.exports = {
|
|
379
|
+
REPAIR_RESULT,
|
|
380
|
+
SAFE_REPAIR_ACTIONS,
|
|
381
|
+
runSafeRepair,
|
|
382
|
+
listSafeRepairActions,
|
|
383
|
+
runRepairAction,
|
|
384
|
+
};
|