projscan 4.10.0 → 4.11.1

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 (51) hide show
  1. package/README.md +72 -41
  2. package/dist/cli/commands/assess.d.ts +3 -0
  3. package/dist/cli/commands/assess.js +143 -0
  4. package/dist/cli/commands/assess.js.map +1 -0
  5. package/dist/cli/commands/simulate.d.ts +3 -0
  6. package/dist/cli/commands/simulate.js +125 -0
  7. package/dist/cli/commands/simulate.js.map +1 -0
  8. package/dist/cli/registerCommands.js +4 -0
  9. package/dist/cli/registerCommands.js.map +1 -1
  10. package/dist/core/assess.d.ts +9 -0
  11. package/dist/core/assess.js +119 -0
  12. package/dist/core/assess.js.map +1 -0
  13. package/dist/core/proofCards.d.ts +10 -0
  14. package/dist/core/proofCards.js +222 -0
  15. package/dist/core/proofCards.js.map +1 -0
  16. package/dist/core/riskDelta.d.ts +19 -0
  17. package/dist/core/riskDelta.js +77 -0
  18. package/dist/core/riskDelta.js.map +1 -0
  19. package/dist/core/simulate.d.ts +6 -0
  20. package/dist/core/simulate.js +298 -0
  21. package/dist/core/simulate.js.map +1 -0
  22. package/dist/mcp/toolCatalog.js +4 -0
  23. package/dist/mcp/toolCatalog.js.map +1 -1
  24. package/dist/mcp/tools/assess.d.ts +2 -0
  25. package/dist/mcp/tools/assess.js +42 -0
  26. package/dist/mcp/tools/assess.js.map +1 -0
  27. package/dist/mcp/tools/simulate.d.ts +2 -0
  28. package/dist/mcp/tools/simulate.js +32 -0
  29. package/dist/mcp/tools/simulate.js.map +1 -0
  30. package/dist/projscan-sbom.cdx.json +6 -6
  31. package/dist/publicCore.d.ts +2 -0
  32. package/dist/publicCore.js +2 -0
  33. package/dist/publicCore.js.map +1 -1
  34. package/dist/tool-manifest.json +52 -3
  35. package/dist/types/assess.d.ts +91 -0
  36. package/dist/types/assess.js +2 -0
  37. package/dist/types/assess.js.map +1 -0
  38. package/dist/types/simulate.d.ts +41 -0
  39. package/dist/types/simulate.js +2 -0
  40. package/dist/types/simulate.js.map +1 -0
  41. package/dist/types/workplan.d.ts +1 -0
  42. package/dist/types.d.ts +2 -0
  43. package/dist/utils/formatSupport.d.ts +2 -0
  44. package/dist/utils/formatSupport.js +2 -0
  45. package/dist/utils/formatSupport.js.map +1 -1
  46. package/docs/GUIDE.md +19 -1
  47. package/docs/demos/projscan-4-1-demo.html +214 -2
  48. package/docs/projscan-mission-control.png +0 -0
  49. package/docs/projscan-proof-cards.png +0 -0
  50. package/package.json +2 -1
  51. package/scripts/capture-readme-assets.mjs +6 -0
@@ -0,0 +1,119 @@
1
+ import { computeBugHunt } from './bugHunt.js';
2
+ import { computePreflight } from './preflight.js';
3
+ import { buildProofCards } from './proofCards.js';
4
+ import { computeQualityScorecard } from './qualityScorecard.js';
5
+ import { compareRiskDeltaSnapshots, computeRiskDelta } from './riskDelta.js';
6
+ const DEFAULT_GOAL = 'assess codebase risk and next proof-backed action';
7
+ export async function computeAssess(rootPath, options = {}) {
8
+ const mode = normalizeMode(options.mode);
9
+ const maxCards = mode === 'fix-first' ? Math.min(options.maxCards ?? 2, 2) : options.maxCards;
10
+ const goal = normalizeGoal(options.goal);
11
+ const [quality, bugHunt, preflight] = await Promise.all([
12
+ computeQualityScorecard(rootPath, { maxRisks: maxCards ?? 5 }),
13
+ computeBugHunt(rootPath, { maxFindings: maxCards ?? 5 }),
14
+ computePreflight(rootPath, { mode: 'before_commit' }),
15
+ ]);
16
+ const initialCards = buildProofCards({
17
+ goal,
18
+ qualityRisks: quality.topRisks,
19
+ bugHuntFindings: bugHunt.fixQueue.length > 0 ? bugHunt.fixQueue : bugHunt.topSuspects,
20
+ maxCards,
21
+ });
22
+ const selectedCards = mode === 'fix-first' ? initialCards.slice(0, 2) : initialCards;
23
+ const riskDelta = computeRiskDelta({
24
+ healthScore: quality.health.score,
25
+ qualityVerdict: quality.verdict,
26
+ preflightVerdict: preflight.verdict,
27
+ proofCards: selectedCards.map((card) => ({
28
+ id: card.id,
29
+ priority: card.priority,
30
+ source: card.source,
31
+ })),
32
+ selectedCardIds: selectedCards.slice(0, mode === 'fix-first' ? 2 : 1).map((card) => card.id),
33
+ });
34
+ const proofCards = selectedCards.map((card) => ({ ...card, riskDelta }));
35
+ const verdict = assessVerdict(quality.verdict, preflight.verdict);
36
+ const answers = buildAnswers({
37
+ proofCards,
38
+ riskDelta,
39
+ preflightVerdict: preflight.verdict,
40
+ });
41
+ const report = {
42
+ schemaVersion: 1,
43
+ goal,
44
+ mode,
45
+ verdict,
46
+ summary: summarize(verdict, proofCards, riskDelta),
47
+ answers,
48
+ proofCards,
49
+ ...(proofCards[0] ? { fixFirst: proofCards[0] } : {}),
50
+ riskDelta,
51
+ commands: commandsFor(mode),
52
+ feedback: proofCards.map((card) => card.feedback.command),
53
+ sourceVerdicts: {
54
+ quality: quality.verdict,
55
+ preflight: preflight.verdict,
56
+ },
57
+ ...(initialCards.length > proofCards.length ? { truncated: true } : {}),
58
+ };
59
+ if (options.baselineReport) {
60
+ report.baselineComparison = compareRiskDeltaSnapshots({
61
+ previous: options.baselineReport,
62
+ current: report,
63
+ baselinePath: options.baselinePath,
64
+ });
65
+ }
66
+ return report;
67
+ }
68
+ function buildAnswers(input) {
69
+ const first = input.proofCards[0];
70
+ const evidenceSources = first?.evidence.map((entry) => entry.source).join(', ');
71
+ const proofCommands = first?.verification.commands ?? ['projscan doctor --format json'];
72
+ return {
73
+ actuallyRisky: first
74
+ ? `${first.finding} is the top proof-backed risk.`
75
+ : 'No proof-backed risk is currently ranked above baseline verification.',
76
+ whyRisky: first
77
+ ? `Evidence comes from ${evidenceSources || 'local projscan analysis'}.`
78
+ : 'The current assessment did not find a higher-priority local signal.',
79
+ fixFirst: first ? `${first.finding}: ${first.recommendedFix.summary}` : 'Preserve the baseline.',
80
+ safestChange: first
81
+ ? `Use a small bounded change: ${first.recommendedFix.safeChangeShape}`
82
+ : 'Run the listed verification commands before taking larger changes.',
83
+ testsThatProveIt: proofCommands,
84
+ riskRemoved: `Projected risk score improves by ${input.riskDelta.delta} to ${input.riskDelta.projectedScore}.`,
85
+ shipNow: input.preflightVerdict === 'block'
86
+ ? 'Do not ship until preflight blockers are resolved.'
87
+ : `Ship only after preflight and proof commands pass; current preflight verdict is ${input.preflightVerdict}.`,
88
+ };
89
+ }
90
+ function assessVerdict(qualityVerdict, preflightVerdict) {
91
+ if (preflightVerdict === 'block' || qualityVerdict === 'blocked')
92
+ return 'blocked';
93
+ if (preflightVerdict === 'caution' || qualityVerdict === 'needs_attention')
94
+ return 'watch';
95
+ return 'ready';
96
+ }
97
+ function commandsFor(mode) {
98
+ const commands = [
99
+ 'projscan assess --mode fix-first --format json',
100
+ 'projscan preflight --mode before_commit --format json',
101
+ 'projscan quality-scorecard --format json',
102
+ ];
103
+ if (mode === 'ship-readiness')
104
+ commands.unshift('projscan preflight --mode before_merge --format json');
105
+ return [...new Set(commands)];
106
+ }
107
+ function summarize(verdict, proofCards, riskDelta) {
108
+ if (proofCards.length === 0)
109
+ return `${verdict}: no proof-backed action outranks baseline verification`;
110
+ return `${verdict}: ${proofCards.length} proof-backed action(s), projected risk delta +${riskDelta.delta}`;
111
+ }
112
+ function normalizeMode(value) {
113
+ return value ?? 'standard';
114
+ }
115
+ function normalizeGoal(value) {
116
+ const trimmed = value?.trim();
117
+ return trimmed && trimmed.length > 0 ? trimmed : DEFAULT_GOAL;
118
+ }
119
+ //# sourceMappingURL=assess.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assess.js","sourceRoot":"","sources":["../../src/core/assess.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { AssessProofCard, RiskDeltaSnapshot } from '../types/assess.js';
2
+ import type { BugHuntFinding, QualityScorecardRisk } from '../types.js';
3
+ export interface BuildProofCardsInput {
4
+ goal?: string;
5
+ qualityRisks: QualityScorecardRisk[];
6
+ bugHuntFindings: BugHuntFinding[];
7
+ maxCards?: number;
8
+ riskDelta?: RiskDeltaSnapshot;
9
+ }
10
+ export declare function buildProofCards(input: BuildProofCardsInput): AssessProofCard[];
@@ -0,0 +1,222 @@
1
+ import { computeRiskDelta } from './riskDelta.js';
2
+ const DEFAULT_MAX_CARDS = 5;
3
+ export function buildProofCards(input) {
4
+ const maxCards = normalizeMaxCards(input.maxCards);
5
+ const cards = [
6
+ ...input.bugHuntFindings.map(cardFromBugHuntFinding),
7
+ ...input.qualityRisks.map(cardFromQualityRisk),
8
+ ];
9
+ const deduped = dedupeCards(cards);
10
+ const ranked = rankCards(deduped).slice(0, maxCards);
11
+ return ranked.map((card) => ({
12
+ ...card,
13
+ riskDelta: input.riskDelta ??
14
+ computeRiskDelta({
15
+ healthScore: 100,
16
+ qualityVerdict: 'needs_attention',
17
+ preflightVerdict: 'caution',
18
+ proofCards: ranked.map((entry) => ({
19
+ id: entry.id,
20
+ priority: entry.priority,
21
+ source: entry.source,
22
+ })),
23
+ selectedCardIds: [card.id],
24
+ }),
25
+ }));
26
+ }
27
+ function cardFromBugHuntFinding(finding) {
28
+ const id = `proof-${finding.id}`;
29
+ return baseCard({
30
+ id,
31
+ priority: finding.priority,
32
+ source: finding.source,
33
+ finding: finding.title,
34
+ whyItMatters: finding.why,
35
+ files: finding.files,
36
+ evidence: finding.evidence.map((entry) => ({
37
+ source: String(entry.source),
38
+ detail: entry.message,
39
+ ...(entry.file ? { file: entry.file } : {}),
40
+ ...(entry.tool ? { command: entry.tool } : {}),
41
+ })),
42
+ commands: [...new Set([...finding.verification.commands, 'projscan bug-hunt --format json'])],
43
+ affectedAreas: affectedAreasForSource(finding.source),
44
+ fixSummary: fixSummaryForSource(finding.source, finding.title),
45
+ safeChangeShape: safeChangeShapeForSource(finding.source),
46
+ expected: finding.verification.expected,
47
+ confidence: finding.source === 'doctor' ? 'high' : 'medium',
48
+ suppressionHints: suppressionHintsForFinding(finding),
49
+ });
50
+ }
51
+ function cardFromQualityRisk(risk) {
52
+ const id = `proof-${risk.id}`;
53
+ return baseCard({
54
+ id,
55
+ priority: risk.priority,
56
+ source: risk.source,
57
+ finding: risk.title,
58
+ whyItMatters: whyQualityRiskMatters(risk),
59
+ files: risk.files,
60
+ evidence: [
61
+ {
62
+ source: 'quality-scorecard',
63
+ detail: risk.title,
64
+ ...(risk.files[0] ? { file: risk.files[0] } : {}),
65
+ command: risk.command,
66
+ },
67
+ ],
68
+ commands: [
69
+ ...new Set([
70
+ risk.command,
71
+ ...(risk.source === 'hotspot' ? [simulateCommandForRisk(risk)] : []),
72
+ 'projscan quality-scorecard --format json',
73
+ ]),
74
+ ],
75
+ affectedAreas: affectedAreasForSource(risk.source),
76
+ fixSummary: fixSummaryForSource(risk.source, risk.title),
77
+ safeChangeShape: safeChangeShapeForSource(risk.source),
78
+ expected: 'The proof card remains explainable, the relevant risk drops, and tests pass.',
79
+ confidence: risk.source === 'issue' ? 'high' : 'medium',
80
+ });
81
+ }
82
+ function baseCard(input) {
83
+ const feedbackCommand = feedbackCommandFor(input.id);
84
+ return {
85
+ id: input.id,
86
+ priority: input.priority,
87
+ source: input.source,
88
+ finding: input.finding,
89
+ whyItMatters: input.whyItMatters,
90
+ files: input.files,
91
+ evidence: input.evidence,
92
+ impact: {
93
+ commands: input.commands,
94
+ affectedAreas: input.affectedAreas,
95
+ likelyFiles: input.files,
96
+ },
97
+ recommendedFix: {
98
+ summary: input.fixSummary,
99
+ safeChangeShape: input.safeChangeShape,
100
+ },
101
+ verification: {
102
+ commands: input.commands,
103
+ expected: input.expected,
104
+ },
105
+ confidence: input.confidence,
106
+ suppression: { command: feedbackCommand, ...input.suppressionHints },
107
+ feedback: { command: feedbackCommand },
108
+ riskDelta: { baselineScore: 0, projectedScore: 0, delta: 0, basis: [] },
109
+ };
110
+ }
111
+ function suppressionHintsForFinding(finding) {
112
+ const evidence = finding.evidence.find((entry) => entry.issueId || entry.file);
113
+ const ruleId = ruleIdFromEvidence(evidence);
114
+ const file = evidence?.file ?? finding.files[0];
115
+ if (!ruleId || !file)
116
+ return undefined;
117
+ return {
118
+ ...(evidence && 'line' in evidence && typeof evidence.line === 'number'
119
+ ? { inlineHint: `// projscan-ignore-line ${ruleId} -- reason` }
120
+ : {}),
121
+ configHint: `"suppress": { "${ruleId}": ["${file}"] }`,
122
+ };
123
+ }
124
+ function ruleIdFromEvidence(evidence) {
125
+ const issueId = evidence?.issueId;
126
+ if (!issueId)
127
+ return undefined;
128
+ if (issueId === 'hardcoded-secret' || issueId.startsWith('hardcoded-secret-'))
129
+ return 'hardcoded-secret';
130
+ return issueId;
131
+ }
132
+ function dedupeCards(cards) {
133
+ const seen = new Set();
134
+ return cards.filter((card) => {
135
+ const key = `${card.files[0] ?? card.id}:${card.finding}`;
136
+ if (seen.has(key))
137
+ return false;
138
+ seen.add(key);
139
+ return true;
140
+ });
141
+ }
142
+ function rankCards(cards) {
143
+ return cards
144
+ .map((card, index) => ({ card, index }))
145
+ .sort((a, b) => priorityRank(a.card.priority) - priorityRank(b.card.priority) ||
146
+ sourceRank(a.card.source) - sourceRank(b.card.source) ||
147
+ a.index - b.index)
148
+ .map((entry) => entry.card);
149
+ }
150
+ function affectedAreasForSource(source) {
151
+ if (source === 'doctor')
152
+ return ['health'];
153
+ if (source === 'hotspot')
154
+ return ['maintainability'];
155
+ if (source === 'coordination' || source === 'session')
156
+ return ['coordination'];
157
+ if (source === 'preflight')
158
+ return ['ship-readiness'];
159
+ return ['quality'];
160
+ }
161
+ function whyQualityRiskMatters(risk) {
162
+ if (risk.source === 'hotspot') {
163
+ return 'This file concentrates churn, complexity, issue, or ownership risk and deserves a bounded review before broad changes.';
164
+ }
165
+ if (risk.source === 'coordination') {
166
+ return 'Coordination risk can cause agents or engineers to overwrite each other or validate the wrong state.';
167
+ }
168
+ return 'This issue-backed risk is visible in the project health signal and can affect confidence in daily gates.';
169
+ }
170
+ function fixSummaryForSource(source, title) {
171
+ if (source === 'hotspot')
172
+ return `Reduce the risk behind "${title}" with one focused extraction or test first.`;
173
+ if (source === 'coordination')
174
+ return 'Resolve the coordination conflict before changing shared files.';
175
+ if (source === 'session')
176
+ return 'Review touched files and clear active session conflicts before continuing.';
177
+ if (source === 'preflight')
178
+ return 'Close the preflight blocker or document the required manual sign-off.';
179
+ return `Address "${title}" with the smallest change that removes the finding.`;
180
+ }
181
+ function safeChangeShapeForSource(source) {
182
+ if (source === 'hotspot') {
183
+ return 'Inspect the file first, extract one pure helper or add one missing regression test, then rerun the listed proof commands.';
184
+ }
185
+ if (source === 'coordination' || source === 'session') {
186
+ return 'Synchronize ownership, re-run session or coordinate evidence, then continue with one owner for the file.';
187
+ }
188
+ if (source === 'preflight') {
189
+ return 'Fix concrete blockers first; for review-only scale, collect sign-off before merge or release.';
190
+ }
191
+ return 'Make one narrow code or config change, avoid unrelated cleanup, and rerun the listed proof commands.';
192
+ }
193
+ function feedbackCommandFor(id) {
194
+ return `projscan feedback intake --text "${id}: false positive because ..." --format json`;
195
+ }
196
+ function simulateCommandForRisk(risk) {
197
+ return `projscan simulate --plan "Reduce the risk behind ${risk.title.replace(/["\\]/g, '\\$&')}" --format json`;
198
+ }
199
+ function priorityRank(priority) {
200
+ if (priority === 'p0')
201
+ return 0;
202
+ if (priority === 'p1')
203
+ return 1;
204
+ return 2;
205
+ }
206
+ function sourceRank(source) {
207
+ if (source === 'doctor' || source === 'issue')
208
+ return 0;
209
+ if (source === 'preflight')
210
+ return 1;
211
+ if (source === 'hotspot')
212
+ return 2;
213
+ if (source === 'coordination' || source === 'session')
214
+ return 3;
215
+ return 4;
216
+ }
217
+ function normalizeMaxCards(value) {
218
+ if (typeof value !== 'number' || !Number.isFinite(value))
219
+ return DEFAULT_MAX_CARDS;
220
+ return Math.max(1, Math.min(25, Math.floor(value)));
221
+ }
222
+ //# sourceMappingURL=proofCards.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proofCards.js","sourceRoot":"","sources":["../../src/core/proofCards.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { PreflightVerdict, QualityScorecardVerdict, WorkplanPriority } from '../types.js';
2
+ import type { AssessBaselineComparison, AssessReport, RiskDeltaSnapshot } from '../types/assess.js';
3
+ export interface RiskDeltaInput {
4
+ healthScore: number;
5
+ qualityVerdict: QualityScorecardVerdict;
6
+ preflightVerdict: PreflightVerdict;
7
+ proofCards: Array<{
8
+ id: string;
9
+ priority: WorkplanPriority;
10
+ source: string;
11
+ }>;
12
+ selectedCardIds?: string[];
13
+ }
14
+ export declare function computeRiskDelta(input: RiskDeltaInput): RiskDeltaSnapshot;
15
+ export declare function compareRiskDeltaSnapshots(input: {
16
+ previous: Pick<AssessReport, 'riskDelta'>;
17
+ current: Pick<AssessReport, 'riskDelta'>;
18
+ baselinePath?: string;
19
+ }): AssessBaselineComparison;
@@ -0,0 +1,77 @@
1
+ export function computeRiskDelta(input) {
2
+ const basis = [`health score ${clamp(input.healthScore)}`];
3
+ const qualityPenalty = qualityVerdictPenalty(input.qualityVerdict);
4
+ const preflightPenalty = preflightVerdictPenalty(input.preflightVerdict);
5
+ const cardPenalty = input.proofCards.reduce((sum, card) => sum + priorityPenalty(card.priority), 0);
6
+ if (qualityPenalty > 0)
7
+ basis.push(`quality verdict ${input.qualityVerdict} penalty ${qualityPenalty}`);
8
+ if (preflightPenalty > 0)
9
+ basis.push(`preflight verdict ${input.preflightVerdict} penalty ${preflightPenalty}`);
10
+ if (cardPenalty > 0)
11
+ basis.push(`${input.proofCards.length} proof card risk penalty ${cardPenalty}`);
12
+ const baselineScore = clamp(input.healthScore - qualityPenalty - preflightPenalty - cardPenalty);
13
+ const selected = new Set(input.selectedCardIds ?? []);
14
+ const selectedCards = input.proofCards.filter((card) => selected.has(card.id));
15
+ const improvement = selectedCards.reduce((sum, card) => sum + expectedImprovement(card.priority), 0);
16
+ for (const card of selectedCards) {
17
+ basis.push(`${card.priority} ${card.source} improvement ${expectedImprovement(card.priority)}`);
18
+ }
19
+ const projectedScore = clamp(baselineScore + improvement);
20
+ return {
21
+ baselineScore,
22
+ projectedScore,
23
+ delta: projectedScore - baselineScore,
24
+ basis,
25
+ };
26
+ }
27
+ export function compareRiskDeltaSnapshots(input) {
28
+ const previousScore = clamp(input.previous.riskDelta.projectedScore);
29
+ const currentScore = clamp(input.current.riskDelta.projectedScore);
30
+ const delta = currentScore - previousScore;
31
+ const suffix = input.baselinePath ? ` since ${input.baselinePath}` : '';
32
+ const direction = delta > 0 ? 'improved' : delta < 0 ? 'declined' : 'is unchanged';
33
+ const amount = delta === 0 ? '' : ` by ${Math.abs(delta)}`;
34
+ return {
35
+ previousScore,
36
+ currentScore,
37
+ delta,
38
+ ...(input.baselinePath ? { baselinePath: input.baselinePath } : {}),
39
+ summary: `risk score ${direction}${amount}${suffix}`,
40
+ };
41
+ }
42
+ function qualityVerdictPenalty(verdict) {
43
+ if (verdict === 'blocked')
44
+ return 30;
45
+ if (verdict === 'needs_attention')
46
+ return 15;
47
+ if (verdict === 'healthy')
48
+ return 4;
49
+ return 0;
50
+ }
51
+ function preflightVerdictPenalty(verdict) {
52
+ if (verdict === 'block')
53
+ return 30;
54
+ if (verdict === 'caution')
55
+ return 12;
56
+ return 0;
57
+ }
58
+ function priorityPenalty(priority) {
59
+ if (priority === 'p0')
60
+ return 12;
61
+ if (priority === 'p1')
62
+ return 8;
63
+ return 3;
64
+ }
65
+ function expectedImprovement(priority) {
66
+ if (priority === 'p0')
67
+ return 18;
68
+ if (priority === 'p1')
69
+ return 12;
70
+ return 5;
71
+ }
72
+ function clamp(value) {
73
+ if (!Number.isFinite(value))
74
+ return 0;
75
+ return Math.max(0, Math.min(100, Math.round(value)));
76
+ }
77
+ //# sourceMappingURL=riskDelta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"riskDelta.js","sourceRoot":"","sources":["../../src/core/riskDelta.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { SimulateReport } from '../types/simulate.js';
2
+ export interface ComputeSimulationOptions {
3
+ plan: string;
4
+ maxFiles?: number;
5
+ }
6
+ export declare function computeSimulation(rootPath: string, options: ComputeSimulationOptions): Promise<SimulateReport>;