projscan 3.5.0 → 3.6.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 (60) hide show
  1. package/README.md +26 -21
  2. package/dist/cli/commands/claim.d.ts +5 -0
  3. package/dist/cli/commands/claim.js +139 -0
  4. package/dist/cli/commands/claim.js.map +1 -0
  5. package/dist/cli/commands/collision.d.ts +5 -0
  6. package/dist/cli/commands/collision.js +55 -0
  7. package/dist/cli/commands/collision.js.map +1 -0
  8. package/dist/cli/commands/coordinate.d.ts +5 -0
  9. package/dist/cli/commands/coordinate.js +43 -0
  10. package/dist/cli/commands/coordinate.js.map +1 -0
  11. package/dist/cli/commands/mergeRisk.d.ts +5 -0
  12. package/dist/cli/commands/mergeRisk.js +58 -0
  13. package/dist/cli/commands/mergeRisk.js.map +1 -0
  14. package/dist/cli/commands/route.d.ts +5 -0
  15. package/dist/cli/commands/route.js +53 -0
  16. package/dist/cli/commands/route.js.map +1 -0
  17. package/dist/cli/index.js +10 -0
  18. package/dist/cli/index.js.map +1 -1
  19. package/dist/core/claims.d.ts +60 -0
  20. package/dist/core/claims.js +139 -0
  21. package/dist/core/claims.js.map +1 -0
  22. package/dist/core/collisionDetector.d.ts +55 -0
  23. package/dist/core/collisionDetector.js +156 -0
  24. package/dist/core/collisionDetector.js.map +1 -0
  25. package/dist/core/coordination.d.ts +49 -0
  26. package/dist/core/coordination.js +71 -0
  27. package/dist/core/coordination.js.map +1 -0
  28. package/dist/core/embeddings.js +30 -17
  29. package/dist/core/embeddings.js.map +1 -1
  30. package/dist/core/intentRouter.d.ts +40 -0
  31. package/dist/core/intentRouter.js +213 -0
  32. package/dist/core/intentRouter.js.map +1 -0
  33. package/dist/core/mergeRisk.d.ts +42 -0
  34. package/dist/core/mergeRisk.js +71 -0
  35. package/dist/core/mergeRisk.js.map +1 -0
  36. package/dist/core/roadmapCatalog.js +50 -50
  37. package/dist/core/roadmapCatalog.js.map +1 -1
  38. package/dist/mcp/tools/claim.d.ts +7 -0
  39. package/dist/mcp/tools/claim.js +69 -0
  40. package/dist/mcp/tools/claim.js.map +1 -0
  41. package/dist/mcp/tools/collision.d.ts +7 -0
  42. package/dist/mcp/tools/collision.js +24 -0
  43. package/dist/mcp/tools/collision.js.map +1 -0
  44. package/dist/mcp/tools/coordinate.d.ts +7 -0
  45. package/dist/mcp/tools/coordinate.js +24 -0
  46. package/dist/mcp/tools/coordinate.js.map +1 -0
  47. package/dist/mcp/tools/mergeRisk.d.ts +7 -0
  48. package/dist/mcp/tools/mergeRisk.js +24 -0
  49. package/dist/mcp/tools/mergeRisk.js.map +1 -0
  50. package/dist/mcp/tools/route.d.ts +7 -0
  51. package/dist/mcp/tools/route.js +24 -0
  52. package/dist/mcp/tools/route.js.map +1 -0
  53. package/dist/mcp/tools.js +10 -0
  54. package/dist/mcp/tools.js.map +1 -1
  55. package/dist/projscan-sbom.cdx.json +6 -6
  56. package/dist/tool-manifest.json +94 -3
  57. package/dist/utils/formatSupport.d.ts +9 -0
  58. package/dist/utils/formatSupport.js +9 -0
  59. package/dist/utils/formatSupport.js.map +1 -1
  60. package/package.json +1 -1
@@ -67,28 +67,41 @@ async function getPipeline(model, onFirstLoad) {
67
67
  const mod = await tryLoadTransformers();
68
68
  if (!mod)
69
69
  return null;
70
- let existing = pipelines.get(model);
71
- if (existing) {
70
+ let loading = pipelines.get(model);
71
+ if (loading) {
72
72
  // Bump on access so the LRU cache treats the recently-used model as
73
73
  // hot. Map insertion order = recency.
74
74
  pipelines.delete(model);
75
- pipelines.set(model, existing);
76
- return existing;
75
+ pipelines.set(model, loading);
77
76
  }
78
- onFirstLoad?.(`Loading embedding model ${model} (first run downloads ~25MB)...`);
79
- existing = mod.pipeline('feature-extraction', model, {
80
- quantized: true,
81
- });
82
- pipelines.set(model, existing);
83
- // Evict the least-recently-used pipeline when over the bound. Map
84
- // iteration is in insertion order, so the first key is the oldest.
85
- while (pipelines.size > MAX_CACHED_PIPELINES) {
86
- const oldest = pipelines.keys().next().value;
87
- if (oldest === undefined)
88
- break;
89
- pipelines.delete(oldest);
77
+ else {
78
+ onFirstLoad?.(`Loading embedding model ${model} (first run downloads ~25MB)...`);
79
+ loading = mod.pipeline('feature-extraction', model, {
80
+ quantized: true,
81
+ });
82
+ pipelines.set(model, loading);
83
+ // Evict the least-recently-used pipeline when over the bound. Map
84
+ // iteration is in insertion order, so the first key is the oldest.
85
+ while (pipelines.size > MAX_CACHED_PIPELINES) {
86
+ const oldest = pipelines.keys().next().value;
87
+ if (oldest === undefined)
88
+ break;
89
+ pipelines.delete(oldest);
90
+ }
91
+ }
92
+ try {
93
+ return await loading;
94
+ }
95
+ catch (err) {
96
+ // Model download / instantiation failed — offline, an HTTP 429 from the
97
+ // model host (huggingface.co rate-limits unauthenticated CI traffic), or a
98
+ // corrupt local cache. Drop the rejected promise so it can't poison the
99
+ // cache for the rest of the process, and degrade gracefully to null so
100
+ // callers fall back to BM25 instead of throwing.
101
+ pipelines.delete(model);
102
+ process.stderr.write(`[projscan] embedding model "${model}" failed to load: ${err instanceof Error ? err.message : String(err)}. Semantic features disabled for this run.\n`);
103
+ return null;
90
104
  }
91
- return existing;
92
105
  }
93
106
  /**
94
107
  * Test-only: drop all cached pipelines. Lets unit tests verify LRU
@@ -1 +1 @@
1
- {"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../../src/core/embeddings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../../src/core/embeddings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Intent router (4.x agent-ergonomics, epic 4).
3
+ *
4
+ * projscan exposes 40+ MCP tools. An agent shouldn't have to reason over all of
5
+ * them every turn — it should be able to state a goal and get pointed at the one
6
+ * right tool. `routeIntent` does exactly that: a deterministic, curated map from
7
+ * common agent intents to the tool + exact call. No LLM (projscan never embeds
8
+ * inference); ranking is keyword overlap against a hand-curated catalog.
9
+ *
10
+ * This is the additive, non-breaking half of the epic — a discovery entry point.
11
+ * Actually shrinking the advertised tool surface (hiding the long tail behind
12
+ * this router) is a breaking change reserved for 4.0.
13
+ */
14
+ export interface RouteEntry {
15
+ /** Short intent label. */
16
+ intent: string;
17
+ category: string;
18
+ tool: string;
19
+ cli: string;
20
+ /** What the tool does, one line. */
21
+ what: string;
22
+ /** When to reach for it. */
23
+ why: string;
24
+ /** A runnable example. */
25
+ example: string;
26
+ /** Terms that signal this intent. */
27
+ keywords: string[];
28
+ }
29
+ export interface RouteResult {
30
+ intent: string | null;
31
+ matched: boolean;
32
+ matches: RouteEntry[];
33
+ }
34
+ export declare const ROUTE_CATALOG: RouteEntry[];
35
+ /**
36
+ * Map a stated intent to the best-matching projscan tool(s). With no intent,
37
+ * returns the full catalog grouped by category. Ranking is keyword overlap;
38
+ * ties keep catalog order (deterministic).
39
+ */
40
+ export declare function routeIntent(intent: string | undefined): RouteResult;
@@ -0,0 +1,213 @@
1
+ /**
2
+ * Intent router (4.x agent-ergonomics, epic 4).
3
+ *
4
+ * projscan exposes 40+ MCP tools. An agent shouldn't have to reason over all of
5
+ * them every turn — it should be able to state a goal and get pointed at the one
6
+ * right tool. `routeIntent` does exactly that: a deterministic, curated map from
7
+ * common agent intents to the tool + exact call. No LLM (projscan never embeds
8
+ * inference); ranking is keyword overlap against a hand-curated catalog.
9
+ *
10
+ * This is the additive, non-breaking half of the epic — a discovery entry point.
11
+ * Actually shrinking the advertised tool surface (hiding the long tail behind
12
+ * this router) is a breaking change reserved for 4.0.
13
+ */
14
+ export const ROUTE_CATALOG = [
15
+ {
16
+ intent: 'Understand a repo before editing',
17
+ category: 'Understand',
18
+ tool: 'projscan_understand',
19
+ cli: 'projscan understand',
20
+ what: 'Cited repo/flow/contract/change/verify maps.',
21
+ why: 'Orient in an unfamiliar codebase before making a change.',
22
+ example: 'projscan understand --view map --format json',
23
+ keywords: ['understand', 'orient', 'overview', 'map', 'comprehend', 'unfamiliar', 'learn', 'explore', 'architecture'],
24
+ },
25
+ {
26
+ intent: 'Review a PR or a set of changes',
27
+ category: 'Review',
28
+ tool: 'projscan_review',
29
+ cli: 'projscan review',
30
+ what: 'One-call structural PR review with a verdict.',
31
+ why: 'Assess risk of a diff: cycles, taint, dataflow, contracts.',
32
+ example: 'projscan review --format json',
33
+ keywords: ['review', 'pr', 'pull', 'request', 'diff', 'changes', 'verdict', 'assess'],
34
+ },
35
+ {
36
+ intent: 'See what breaks if I change something',
37
+ category: 'Impact',
38
+ tool: 'projscan_impact',
39
+ cli: 'projscan impact',
40
+ what: 'Transitive blast radius for a file or symbol.',
41
+ why: 'Before renaming or deleting, see every caller that breaks.',
42
+ example: 'projscan impact --symbol buildCodeGraph --format json',
43
+ keywords: ['impact', 'breaks', 'break', 'blast', 'radius', 'rename', 'delete', 'depends', 'affect', 'callers', 'breaking'],
44
+ },
45
+ {
46
+ intent: 'Check if it is safe to edit / commit / merge',
47
+ category: 'Safety gate',
48
+ tool: 'projscan_preflight',
49
+ cli: 'projscan preflight',
50
+ what: 'proceed / caution / block verdict with evidence.',
51
+ why: 'A safety gate before an edit, commit, or merge.',
52
+ example: 'projscan preflight --mode before_commit --format json',
53
+ keywords: ['safe', 'safety', 'gate', 'commit', 'merge', 'edit', 'proceed', 'block', 'preflight', 'allowed', 'risky'],
54
+ },
55
+ {
56
+ intent: 'Find the riskiest files / where to start',
57
+ category: 'Hotspots',
58
+ tool: 'projscan_hotspots',
59
+ cli: 'projscan hotspots',
60
+ what: 'Files ranked by churn × complexity × issues.',
61
+ why: 'Decide where to focus review or refactoring.',
62
+ example: 'projscan hotspots --format json',
63
+ keywords: ['hotspot', 'risky', 'riskiest', 'where', 'start', 'focus', 'churn', 'complexity', 'dangerous'],
64
+ },
65
+ {
66
+ intent: 'Detect conflicts between parallel agents',
67
+ category: 'Swarm coordination',
68
+ tool: 'projscan_collision',
69
+ cli: 'projscan collisions',
70
+ what: 'Same-file + dependency overlaps across worktrees.',
71
+ why: 'Two agents editing one repo: surface collisions pre-merge.',
72
+ example: 'projscan collisions --format json',
73
+ keywords: ['coordinate', 'coordination', 'parallel', 'agents', 'swarm', 'conflict', 'conflicts', 'collision', 'worktree', 'worktrees', 'overlap', 'simultaneous'],
74
+ },
75
+ {
76
+ intent: 'Claim a file so other agents know who owns it',
77
+ category: 'Swarm coordination',
78
+ tool: 'projscan_claim',
79
+ cli: 'projscan claim',
80
+ what: 'Advisory claims/leases over files, dirs, symbols.',
81
+ why: 'Tell the swarm who is working where; warn on contention.',
82
+ example: 'projscan claim add src/auth.ts --agent me',
83
+ keywords: ['claim', 'lease', 'owns', 'ownership', 'who', 'reserve', 'lock', 'coordinate', 'parallel', 'agents', 'swarm'],
84
+ },
85
+ {
86
+ intent: 'Decide the order to merge in-flight branches',
87
+ category: 'Swarm coordination',
88
+ tool: 'projscan_merge_risk',
89
+ cli: 'projscan merge-risk',
90
+ what: 'Safe integration order + conflict hotspots.',
91
+ why: 'Multiple in-flight worktrees: which to merge first.',
92
+ example: 'projscan merge-risk --format json',
93
+ keywords: ['merge', 'integrate', 'integration', 'order', 'sequence', 'first', 'conflict', 'hotspot', 'coordinate', 'parallel', 'swarm'],
94
+ },
95
+ {
96
+ intent: 'Run a project health check',
97
+ category: 'Health',
98
+ tool: 'projscan_doctor',
99
+ cli: 'projscan doctor',
100
+ what: 'Health score + detected issues.',
101
+ why: 'A quick overall health read on a repo.',
102
+ example: 'projscan doctor --format json',
103
+ keywords: ['health', 'doctor', 'score', 'issues', 'check', 'quality', 'lint'],
104
+ },
105
+ {
106
+ intent: 'Search the codebase',
107
+ category: 'Search',
108
+ tool: 'projscan_search',
109
+ cli: 'projscan search',
110
+ what: 'Symbol / file / content search (BM25 + optional semantic).',
111
+ why: 'Find where something is defined or used.',
112
+ example: 'projscan search "auth token" --format json',
113
+ keywords: ['search', 'find', 'locate', 'where', 'grep', 'lookup', 'symbol'],
114
+ },
115
+ {
116
+ intent: 'Trace dataflow / find injection risk',
117
+ category: 'Security',
118
+ tool: 'projscan_dataflow',
119
+ cli: 'projscan dataflow',
120
+ what: 'Source-to-sink dataflow risks.',
121
+ why: 'Spot request-data reaching dangerous sinks.',
122
+ example: 'projscan dataflow --format json',
123
+ keywords: ['dataflow', 'taint', 'security', 'injection', 'source', 'sink', 'vulnerability', 'sql', 'xss'],
124
+ },
125
+ {
126
+ intent: 'Get a fix for an issue',
127
+ category: 'Fix',
128
+ tool: 'projscan_fix_suggest',
129
+ cli: 'projscan fix-suggest',
130
+ what: 'Structured action prompt for an open issue.',
131
+ why: 'Turn a detected issue into a concrete fix plan.',
132
+ example: 'projscan fix-suggest <issue-id> --format json',
133
+ keywords: ['fix', 'suggest', 'resolve', 'repair', 'remediate', 'how', 'issue'],
134
+ },
135
+ {
136
+ intent: 'Orient on first use / set up projscan',
137
+ category: 'Onboarding',
138
+ tool: 'projscan_start',
139
+ cli: 'projscan start',
140
+ what: 'First-60-seconds orientation + next commands.',
141
+ why: 'New to this repo or to projscan.',
142
+ example: 'projscan start --format json',
143
+ keywords: ['start', 'begin', 'setup', 'onboard', 'first', 'getting', 'started', 'new'],
144
+ },
145
+ {
146
+ intent: 'Plan the next agent work',
147
+ category: 'Agent planning',
148
+ tool: 'projscan_workplan',
149
+ cli: 'projscan workplan',
150
+ what: 'Ordered agent execution plan with verification.',
151
+ why: 'Turn evidence into prioritized, verifiable tasks.',
152
+ example: 'projscan workplan --mode bug_hunt --format json',
153
+ keywords: ['plan', 'workplan', 'tasks', 'next', 'todo', 'prioritize', 'roadmap'],
154
+ },
155
+ {
156
+ intent: 'Find bugs to fix',
157
+ category: 'Agent planning',
158
+ tool: 'projscan_bug_hunt',
159
+ cli: 'projscan bug-hunt',
160
+ what: 'Ranked fix queue from doctor/preflight/hotspots.',
161
+ why: 'Decide which bugs to tackle first.',
162
+ example: 'projscan bug-hunt --format json',
163
+ keywords: ['bug', 'bugs', 'hunt', 'queue', 'defect', 'broken'],
164
+ },
165
+ {
166
+ intent: 'Check dependency health / outdated / audit',
167
+ category: 'Dependencies',
168
+ tool: 'projscan_outdated',
169
+ cli: 'projscan outdated',
170
+ what: 'Outdated deps, audit, and upgrade preview.',
171
+ why: 'Assess dependency freshness and vulnerabilities.',
172
+ example: 'projscan outdated --format json',
173
+ keywords: ['dependency', 'dependencies', 'outdated', 'audit', 'upgrade', 'vulnerable', 'package', 'npm'],
174
+ },
175
+ ];
176
+ const STOPWORDS = new Set([
177
+ 'the', 'a', 'an', 'i', 'to', 'my', 'is', 'it', 'of', 'in', 'on', 'and', 'or', 'for', 'this', 'that',
178
+ 'do', 'how', 'what', 'me', 'we', 'with', 'can', 'should', 'if', 'be', 'am', 'are',
179
+ ]);
180
+ function tokenize(text) {
181
+ return text
182
+ .toLowerCase()
183
+ .split(/[^a-z0-9]+/)
184
+ .filter((t) => t.length > 1 && !STOPWORDS.has(t));
185
+ }
186
+ /**
187
+ * Map a stated intent to the best-matching projscan tool(s). With no intent,
188
+ * returns the full catalog grouped by category. Ranking is keyword overlap;
189
+ * ties keep catalog order (deterministic).
190
+ */
191
+ export function routeIntent(intent) {
192
+ if (!intent || intent.trim() === '') {
193
+ const grouped = [...ROUTE_CATALOG].sort((a, b) => a.category.localeCompare(b.category));
194
+ return { intent: null, matched: grouped.length > 0, matches: grouped };
195
+ }
196
+ const tokens = new Set(tokenize(intent));
197
+ const scored = ROUTE_CATALOG.map((entry, index) => {
198
+ let score = 0;
199
+ for (const kw of entry.keywords) {
200
+ if (tokens.has(kw))
201
+ score += 1;
202
+ }
203
+ return { entry, score, index };
204
+ })
205
+ .filter((s) => s.score > 0)
206
+ .sort((a, b) => b.score - a.score || a.index - b.index);
207
+ return {
208
+ intent,
209
+ matched: scored.length > 0,
210
+ matches: scored.map((s) => s.entry),
211
+ };
212
+ }
213
+ //# sourceMappingURL=intentRouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intentRouter.js","sourceRoot":"","sources":["../../src/core/intentRouter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import { type CollisionReport, type Collision } from './collisionDetector.js';
2
+ /**
3
+ * Merge-risk preflight (4.x coordination arc, epic 3).
4
+ *
5
+ * Builds on collision detection: given the repo's in-flight worktrees and the
6
+ * collisions between them, answer the two integration questions —
7
+ * 1. In what order is it safe to merge? (integration order)
8
+ * 2. Where does conflict risk concentrate? (hotspot files)
9
+ * Local-first; reuses `detectCollisions` (no new git/graph machinery).
10
+ */
11
+ export interface IntegrationStep {
12
+ worktree: string;
13
+ branch: string | null;
14
+ /** Number of collisions this worktree is involved in. */
15
+ collisionCount: number;
16
+ changedFileCount: number;
17
+ /** Sum of collision weights (high = 2, medium = 1) — lower merges first. */
18
+ riskScore: number;
19
+ }
20
+ export interface RiskHotspot {
21
+ file: string;
22
+ /** Distinct worktrees that changed this file (>= 2 = contended). */
23
+ worktrees: string[];
24
+ severity: 'high' | 'medium';
25
+ }
26
+ export interface MergeRiskReport {
27
+ schemaVersion: 1;
28
+ available: boolean;
29
+ reason?: string;
30
+ integrationOrder: IntegrationStep[];
31
+ hotFiles: RiskHotspot[];
32
+ collisions: Collision[];
33
+ }
34
+ /** Pure derivation: turn a collision report into integration order + hotspots. */
35
+ export declare function deriveMergeRisk(report: CollisionReport): {
36
+ integrationOrder: IntegrationStep[];
37
+ hotFiles: RiskHotspot[];
38
+ };
39
+ /** Compute merge-risk for the repo's in-flight worktrees. */
40
+ export declare function computeMergeRisk(rootPath: string, options?: {
41
+ baseRef?: string;
42
+ }): Promise<MergeRiskReport>;
@@ -0,0 +1,71 @@
1
+ import { detectCollisions } from './collisionDetector.js';
2
+ const WEIGHT = { high: 2, medium: 1 };
3
+ /** Pure derivation: turn a collision report into integration order + hotspots. */
4
+ export function deriveMergeRisk(report) {
5
+ if (!report.available)
6
+ return { integrationOrder: [], hotFiles: [] };
7
+ // Per-worktree collision involvement and risk weight.
8
+ const involvement = new Map();
9
+ const bump = (worktree, weight) => {
10
+ const cur = involvement.get(worktree) ?? { count: 0, risk: 0 };
11
+ cur.count += 1;
12
+ cur.risk += weight;
13
+ involvement.set(worktree, cur);
14
+ };
15
+ for (const c of report.collisions) {
16
+ bump(c.worktreeA, WEIGHT[c.severity]);
17
+ bump(c.worktreeB, WEIGHT[c.severity]);
18
+ }
19
+ const integrationOrder = report.worktrees
20
+ .map((w) => {
21
+ const inv = involvement.get(w.path) ?? { count: 0, risk: 0 };
22
+ return {
23
+ worktree: w.path,
24
+ branch: w.branch,
25
+ collisionCount: inv.count,
26
+ changedFileCount: w.changedFileCount,
27
+ riskScore: inv.risk,
28
+ };
29
+ })
30
+ // Merge the cleanest branch first: lowest risk, then fewest changed files,
31
+ // then path for a stable, deterministic order.
32
+ .sort((a, b) => a.riskScore - b.riskScore ||
33
+ a.changedFileCount - b.changedFileCount ||
34
+ a.worktree.localeCompare(b.worktree));
35
+ // Hotspot files: a file changed by >= 2 distinct worktrees (the highest-risk
36
+ // merge-conflict signal). Tracks the worst severity seen for that file.
37
+ const fileWorktrees = new Map();
38
+ const fileSeverity = new Map();
39
+ const record = (file, worktree, severity) => {
40
+ if (!fileWorktrees.has(file))
41
+ fileWorktrees.set(file, new Set());
42
+ fileWorktrees.get(file).add(worktree);
43
+ if (severity === 'high' || !fileSeverity.has(file))
44
+ fileSeverity.set(file, severity);
45
+ };
46
+ for (const c of report.collisions) {
47
+ record(c.fileA, c.worktreeA, c.severity);
48
+ record(c.fileB, c.worktreeB, c.severity);
49
+ }
50
+ const hotFiles = [...fileWorktrees.entries()]
51
+ .filter(([, wts]) => wts.size >= 2)
52
+ .map(([file, wts]) => ({ file, worktrees: [...wts], severity: fileSeverity.get(file) ?? 'medium' }))
53
+ .sort((a, b) => b.worktrees.length - a.worktrees.length ||
54
+ (a.severity === b.severity ? 0 : a.severity === 'high' ? -1 : 1) ||
55
+ a.file.localeCompare(b.file));
56
+ return { integrationOrder, hotFiles };
57
+ }
58
+ /** Compute merge-risk for the repo's in-flight worktrees. */
59
+ export async function computeMergeRisk(rootPath, options = {}) {
60
+ const collisionReport = await detectCollisions(rootPath, options);
61
+ const { integrationOrder, hotFiles } = deriveMergeRisk(collisionReport);
62
+ return {
63
+ schemaVersion: 1,
64
+ available: collisionReport.available,
65
+ ...(collisionReport.reason ? { reason: collisionReport.reason } : {}),
66
+ integrationOrder,
67
+ hotFiles,
68
+ collisions: collisionReport.collisions,
69
+ };
70
+ }
71
+ //# sourceMappingURL=mergeRisk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mergeRisk.js","sourceRoot":"","sources":["../../src/core/mergeRisk.ts"],"names":[],"mappings":"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"}