projscan 3.4.1 → 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.
- package/README.md +26 -21
- package/dist/cli/commands/claim.d.ts +5 -0
- package/dist/cli/commands/claim.js +139 -0
- package/dist/cli/commands/claim.js.map +1 -0
- package/dist/cli/commands/collision.d.ts +5 -0
- package/dist/cli/commands/collision.js +55 -0
- package/dist/cli/commands/collision.js.map +1 -0
- package/dist/cli/commands/coordinate.d.ts +5 -0
- package/dist/cli/commands/coordinate.js +43 -0
- package/dist/cli/commands/coordinate.js.map +1 -0
- package/dist/cli/commands/mergeRisk.d.ts +5 -0
- package/dist/cli/commands/mergeRisk.js +58 -0
- package/dist/cli/commands/mergeRisk.js.map +1 -0
- package/dist/cli/commands/plugin.js +124 -0
- package/dist/cli/commands/plugin.js.map +1 -1
- package/dist/cli/commands/route.d.ts +5 -0
- package/dist/cli/commands/route.js +53 -0
- package/dist/cli/commands/route.js.map +1 -0
- package/dist/cli/index.js +10 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/core/claims.d.ts +60 -0
- package/dist/core/claims.js +139 -0
- package/dist/core/claims.js.map +1 -0
- package/dist/core/collisionDetector.d.ts +55 -0
- package/dist/core/collisionDetector.js +156 -0
- package/dist/core/collisionDetector.js.map +1 -0
- package/dist/core/coordination.d.ts +49 -0
- package/dist/core/coordination.js +71 -0
- package/dist/core/coordination.js.map +1 -0
- package/dist/core/embeddings.js +30 -17
- package/dist/core/embeddings.js.map +1 -1
- package/dist/core/intentRouter.d.ts +40 -0
- package/dist/core/intentRouter.js +213 -0
- package/dist/core/intentRouter.js.map +1 -0
- package/dist/core/mergeRisk.d.ts +42 -0
- package/dist/core/mergeRisk.js +71 -0
- package/dist/core/mergeRisk.js.map +1 -0
- package/dist/core/pluginTrust.d.ts +56 -0
- package/dist/core/pluginTrust.js +138 -0
- package/dist/core/pluginTrust.js.map +1 -0
- package/dist/core/plugins.d.ts +1 -1
- package/dist/core/plugins.js +33 -0
- package/dist/core/plugins.js.map +1 -1
- package/dist/core/privacy.js +2 -2
- package/dist/core/privacy.js.map +1 -1
- package/dist/core/roadmapCatalog.js +50 -50
- package/dist/core/roadmapCatalog.js.map +1 -1
- package/dist/fixes/eslintFix.js +6 -2
- package/dist/fixes/eslintFix.js.map +1 -1
- package/dist/fixes/prettierFix.js +5 -2
- package/dist/fixes/prettierFix.js.map +1 -1
- package/dist/fixes/testFix.js +8 -2
- package/dist/fixes/testFix.js.map +1 -1
- package/dist/mcp/tools/claim.d.ts +7 -0
- package/dist/mcp/tools/claim.js +69 -0
- package/dist/mcp/tools/claim.js.map +1 -0
- package/dist/mcp/tools/collision.d.ts +7 -0
- package/dist/mcp/tools/collision.js +24 -0
- package/dist/mcp/tools/collision.js.map +1 -0
- package/dist/mcp/tools/coordinate.d.ts +7 -0
- package/dist/mcp/tools/coordinate.js +24 -0
- package/dist/mcp/tools/coordinate.js.map +1 -0
- package/dist/mcp/tools/mergeRisk.d.ts +7 -0
- package/dist/mcp/tools/mergeRisk.js +24 -0
- package/dist/mcp/tools/mergeRisk.js.map +1 -0
- package/dist/mcp/tools/plugin.js +24 -16
- package/dist/mcp/tools/plugin.js.map +1 -1
- package/dist/mcp/tools/route.d.ts +7 -0
- package/dist/mcp/tools/route.js +24 -0
- package/dist/mcp/tools/route.js.map +1 -0
- package/dist/mcp/tools.js +10 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/projscan-sbom.cdx.json +6 -6
- package/dist/tool-manifest.json +95 -4
- package/dist/utils/formatSupport.d.ts +11 -0
- package/dist/utils/formatSupport.js +11 -0
- package/dist/utils/formatSupport.js.map +1 -1
- package/docs/PLUGIN-AUTHORING.md +35 -6
- package/package.json +1 -1
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { scanRepository } from './repositoryScanner.js';
|
|
4
|
+
import { buildCodeGraph, importersOf } from './codeGraph.js';
|
|
5
|
+
import { getChangedFiles } from '../utils/changedFiles.js';
|
|
6
|
+
const execFileAsync = promisify(execFile);
|
|
7
|
+
/** Parse `git worktree list --porcelain` into structured refs. Local-first. */
|
|
8
|
+
export async function listWorktrees(rootPath) {
|
|
9
|
+
let stdout;
|
|
10
|
+
try {
|
|
11
|
+
({ stdout } = await execFileAsync('git', ['worktree', 'list', '--porcelain'], {
|
|
12
|
+
cwd: rootPath,
|
|
13
|
+
maxBuffer: 8 * 1024 * 1024,
|
|
14
|
+
}));
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
const refs = [];
|
|
20
|
+
let current = null;
|
|
21
|
+
const flush = () => {
|
|
22
|
+
if (current)
|
|
23
|
+
refs.push(current);
|
|
24
|
+
current = null;
|
|
25
|
+
};
|
|
26
|
+
for (const line of stdout.split('\n')) {
|
|
27
|
+
if (line.startsWith('worktree ')) {
|
|
28
|
+
flush();
|
|
29
|
+
current = { path: line.slice('worktree '.length).trim(), branch: null, head: null };
|
|
30
|
+
}
|
|
31
|
+
else if (current && line.startsWith('HEAD ')) {
|
|
32
|
+
current.head = line.slice('HEAD '.length).trim();
|
|
33
|
+
}
|
|
34
|
+
else if (current && line.startsWith('branch ')) {
|
|
35
|
+
current.branch = line.slice('branch '.length).trim().replace(/^refs\/heads\//, '');
|
|
36
|
+
}
|
|
37
|
+
else if (current && line.trim() === 'detached') {
|
|
38
|
+
current.branch = null;
|
|
39
|
+
}
|
|
40
|
+
else if (line.trim() === '') {
|
|
41
|
+
flush();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
flush();
|
|
45
|
+
return refs;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Detect collisions across the repo's in-flight worktrees. Needs at least two
|
|
49
|
+
* worktrees (otherwise there's nothing to coordinate). The dependency edges
|
|
50
|
+
* come from the current repo's import graph (HEAD); a file added only inside a
|
|
51
|
+
* worktree simply has no edges yet and is still caught by same-file overlap.
|
|
52
|
+
*/
|
|
53
|
+
export async function detectCollisions(rootPath, options = {}) {
|
|
54
|
+
const worktrees = await listWorktrees(rootPath);
|
|
55
|
+
if (worktrees.length < 2) {
|
|
56
|
+
return {
|
|
57
|
+
schemaVersion: 1,
|
|
58
|
+
available: false,
|
|
59
|
+
reason: worktrees.length === 0
|
|
60
|
+
? 'not a git repository, or git worktrees are unavailable'
|
|
61
|
+
: 'only one worktree — collision detection needs at least two in-flight worktrees',
|
|
62
|
+
worktrees: worktrees.map((w) => ({ path: w.path, branch: w.branch, changedFileCount: 0, baseRef: null })),
|
|
63
|
+
collisions: [],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
// Changed files per worktree (repo-relative, POSIX).
|
|
67
|
+
const changes = await Promise.all(worktrees.map(async (w) => {
|
|
68
|
+
const result = await getChangedFiles(w.path, options.baseRef);
|
|
69
|
+
return {
|
|
70
|
+
ref: w,
|
|
71
|
+
files: result.available ? result.files : [],
|
|
72
|
+
baseRef: result.baseRef,
|
|
73
|
+
};
|
|
74
|
+
}));
|
|
75
|
+
// Import graph of the current repo for dependency (blast-radius) edges.
|
|
76
|
+
const scan = await scanRepository(rootPath);
|
|
77
|
+
const graph = await buildCodeGraph(rootPath, scan.files);
|
|
78
|
+
const collisions = [];
|
|
79
|
+
for (let i = 0; i < changes.length; i++) {
|
|
80
|
+
for (let j = i + 1; j < changes.length; j++) {
|
|
81
|
+
const a = changes[i];
|
|
82
|
+
const b = changes[j];
|
|
83
|
+
const aFiles = a.files;
|
|
84
|
+
const bSet = new Set(b.files);
|
|
85
|
+
const aSet = new Set(a.files);
|
|
86
|
+
// Same-file overlap — both worktrees changed the same file.
|
|
87
|
+
for (const file of aFiles) {
|
|
88
|
+
if (bSet.has(file)) {
|
|
89
|
+
collisions.push({
|
|
90
|
+
kind: 'same-file',
|
|
91
|
+
severity: 'high',
|
|
92
|
+
worktreeA: a.ref.path,
|
|
93
|
+
fileA: file,
|
|
94
|
+
worktreeB: b.ref.path,
|
|
95
|
+
fileB: file,
|
|
96
|
+
reason: `Both worktrees changed ${file}.`,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Dependency overlap — one worktree changed a file the other's change
|
|
101
|
+
// imports (1-hop import edge). Skip files already flagged same-file.
|
|
102
|
+
for (const file of aFiles) {
|
|
103
|
+
if (bSet.has(file))
|
|
104
|
+
continue;
|
|
105
|
+
const importers = new Set(importersOf(graph, file));
|
|
106
|
+
for (const other of b.files) {
|
|
107
|
+
if (other === file || aSet.has(other))
|
|
108
|
+
continue;
|
|
109
|
+
if (importers.has(other)) {
|
|
110
|
+
collisions.push({
|
|
111
|
+
kind: 'dependency',
|
|
112
|
+
severity: 'medium',
|
|
113
|
+
worktreeA: a.ref.path,
|
|
114
|
+
fileA: file,
|
|
115
|
+
worktreeB: b.ref.path,
|
|
116
|
+
fileB: other,
|
|
117
|
+
reason: `${other} (changed in the other worktree) imports ${file} (changed here).`,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
for (const file of b.files) {
|
|
123
|
+
if (aSet.has(file))
|
|
124
|
+
continue;
|
|
125
|
+
const importers = new Set(importersOf(graph, file));
|
|
126
|
+
for (const other of aFiles) {
|
|
127
|
+
if (other === file || bSet.has(other))
|
|
128
|
+
continue;
|
|
129
|
+
if (importers.has(other)) {
|
|
130
|
+
collisions.push({
|
|
131
|
+
kind: 'dependency',
|
|
132
|
+
severity: 'medium',
|
|
133
|
+
worktreeA: a.ref.path,
|
|
134
|
+
fileA: other,
|
|
135
|
+
worktreeB: b.ref.path,
|
|
136
|
+
fileB: file,
|
|
137
|
+
reason: `${other} (changed here) imports ${file} (changed in the other worktree).`,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
schemaVersion: 1,
|
|
146
|
+
available: true,
|
|
147
|
+
worktrees: changes.map((c) => ({
|
|
148
|
+
path: c.ref.path,
|
|
149
|
+
branch: c.ref.branch,
|
|
150
|
+
changedFileCount: c.files.length,
|
|
151
|
+
baseRef: c.baseRef,
|
|
152
|
+
})),
|
|
153
|
+
collisions,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=collisionDetector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collisionDetector.js","sourceRoot":"","sources":["../../src/core/collisionDetector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type CollisionReport } from './collisionDetector.js';
|
|
2
|
+
import { type Claim } from './claims.js';
|
|
3
|
+
import { type MergeRiskReport } from './mergeRisk.js';
|
|
4
|
+
/**
|
|
5
|
+
* Coordination summary (4.x arc, epic 5 — the capstone).
|
|
6
|
+
*
|
|
7
|
+
* Composes the three swarm primitives — collisions, claims, and merge-risk —
|
|
8
|
+
* into one budget-shaped read with a `readiness` verdict, so an agent gets a
|
|
9
|
+
* single coordination signal instead of three calls. It is also the arc's
|
|
10
|
+
* measurable outcome surface: the counts (collisions caught, contended claims,
|
|
11
|
+
* merge hotspots) quantify what the coordination layer surfaced. Local-first.
|
|
12
|
+
*/
|
|
13
|
+
export type CoordinationReadiness = 'clear' | 'caution' | 'conflicted';
|
|
14
|
+
export interface CoordinationSummary {
|
|
15
|
+
schemaVersion: 1;
|
|
16
|
+
available: boolean;
|
|
17
|
+
reason?: string;
|
|
18
|
+
worktreeCount: number;
|
|
19
|
+
collisions: {
|
|
20
|
+
total: number;
|
|
21
|
+
high: number;
|
|
22
|
+
medium: number;
|
|
23
|
+
};
|
|
24
|
+
claims: {
|
|
25
|
+
total: number;
|
|
26
|
+
contendedTargets: number;
|
|
27
|
+
};
|
|
28
|
+
mergeRisk: {
|
|
29
|
+
hotspotCount: number;
|
|
30
|
+
integrationOrder: Array<{
|
|
31
|
+
worktree: string;
|
|
32
|
+
branch: string | null;
|
|
33
|
+
riskScore: number;
|
|
34
|
+
}>;
|
|
35
|
+
};
|
|
36
|
+
readiness: CoordinationReadiness;
|
|
37
|
+
summary: string[];
|
|
38
|
+
}
|
|
39
|
+
export interface CoordinationInputs {
|
|
40
|
+
collisionReport: CollisionReport;
|
|
41
|
+
claims: Claim[];
|
|
42
|
+
mergeRisk: MergeRiskReport;
|
|
43
|
+
}
|
|
44
|
+
/** Pure: fold the three swarm signals into a summary + readiness verdict. */
|
|
45
|
+
export declare function summarizeCoordination(inputs: CoordinationInputs): CoordinationSummary;
|
|
46
|
+
/** Run the full coordination read for the repo's in-flight worktrees. */
|
|
47
|
+
export declare function computeCoordination(rootPath: string, options?: {
|
|
48
|
+
baseRef?: string;
|
|
49
|
+
}): Promise<CoordinationSummary>;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { detectCollisions } from './collisionDetector.js';
|
|
2
|
+
import { listClaims, findContendedClaims } from './claims.js';
|
|
3
|
+
import { computeMergeRisk } from './mergeRisk.js';
|
|
4
|
+
/** Pure: fold the three swarm signals into a summary + readiness verdict. */
|
|
5
|
+
export function summarizeCoordination(inputs) {
|
|
6
|
+
const { collisionReport, claims, mergeRisk } = inputs;
|
|
7
|
+
if (!collisionReport.available) {
|
|
8
|
+
return {
|
|
9
|
+
schemaVersion: 1,
|
|
10
|
+
available: false,
|
|
11
|
+
...(collisionReport.reason ? { reason: collisionReport.reason } : {}),
|
|
12
|
+
worktreeCount: collisionReport.worktrees.length,
|
|
13
|
+
collisions: { total: 0, high: 0, medium: 0 },
|
|
14
|
+
claims: { total: claims.length, contendedTargets: 0 },
|
|
15
|
+
mergeRisk: { hotspotCount: 0, integrationOrder: [] },
|
|
16
|
+
readiness: 'clear',
|
|
17
|
+
summary: [collisionReport.reason ?? 'Coordination unavailable.'],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const high = collisionReport.collisions.filter((c) => c.severity === 'high').length;
|
|
21
|
+
const medium = collisionReport.collisions.filter((c) => c.severity === 'medium').length;
|
|
22
|
+
const contendedTargets = new Set(findContendedClaims(claims).map((c) => c.target)).size;
|
|
23
|
+
const readiness = high > 0 || contendedTargets > 0
|
|
24
|
+
? 'conflicted'
|
|
25
|
+
: medium > 0
|
|
26
|
+
? 'caution'
|
|
27
|
+
: 'clear';
|
|
28
|
+
const summary = [];
|
|
29
|
+
summary.push(`${collisionReport.worktrees.length} in-flight worktree(s).`);
|
|
30
|
+
if (high + medium > 0) {
|
|
31
|
+
summary.push(`${high + medium} collision(s): ${high} high, ${medium} medium.`);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
summary.push('No collisions across worktrees.');
|
|
35
|
+
}
|
|
36
|
+
if (contendedTargets > 0)
|
|
37
|
+
summary.push(`${contendedTargets} claim target(s) contended by multiple agents.`);
|
|
38
|
+
if (mergeRisk.hotFiles.length > 0)
|
|
39
|
+
summary.push(`${mergeRisk.hotFiles.length} merge hotspot file(s).`);
|
|
40
|
+
if (mergeRisk.integrationOrder.length > 0) {
|
|
41
|
+
const first = mergeRisk.integrationOrder[0];
|
|
42
|
+
summary.push(`Merge ${first.branch ?? first.worktree} first (lowest risk).`);
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
schemaVersion: 1,
|
|
46
|
+
available: true,
|
|
47
|
+
worktreeCount: collisionReport.worktrees.length,
|
|
48
|
+
collisions: { total: collisionReport.collisions.length, high, medium },
|
|
49
|
+
claims: { total: claims.length, contendedTargets },
|
|
50
|
+
mergeRisk: {
|
|
51
|
+
hotspotCount: mergeRisk.hotFiles.length,
|
|
52
|
+
integrationOrder: mergeRisk.integrationOrder.map((o) => ({
|
|
53
|
+
worktree: o.worktree,
|
|
54
|
+
branch: o.branch,
|
|
55
|
+
riskScore: o.riskScore,
|
|
56
|
+
})),
|
|
57
|
+
},
|
|
58
|
+
readiness,
|
|
59
|
+
summary,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/** Run the full coordination read for the repo's in-flight worktrees. */
|
|
63
|
+
export async function computeCoordination(rootPath, options = {}) {
|
|
64
|
+
const [collisionReport, claims, mergeRisk] = await Promise.all([
|
|
65
|
+
detectCollisions(rootPath, options),
|
|
66
|
+
listClaims(rootPath),
|
|
67
|
+
computeMergeRisk(rootPath, options),
|
|
68
|
+
]);
|
|
69
|
+
return summarizeCoordination({ collisionReport, claims, mergeRisk });
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=coordination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coordination.js","sourceRoot":"","sources":["../../src/core/coordination.ts"],"names":[],"mappings":"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"}
|
package/dist/core/embeddings.js
CHANGED
|
@@ -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
|
|
71
|
-
if (
|
|
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,
|
|
76
|
-
return existing;
|
|
75
|
+
pipelines.set(model, loading);
|
|
77
76
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,MAAM,aAAa,GAAG,yBAAyB,CAAC;AACvD,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC;AAuBjC,IAAI,YAAmD,CAAC;AAExD,kEAAkE;AAClE,qEAAqE;AACrE,sEAAsE;AACtE,gEAAgE;AAChE,uEAAuE;AACvE,mEAAmE;AACnE,6CAA6C;AAC7C,EAAE;AACF,qEAAqE;AACrE,wEAAwE;AACxE,EAAE;AACF,oEAAoE;AACpE,qEAAqE;AACrE,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAC/B,MAAM,SAAS,GAAG,IAAI,GAAG,EAAqC,CAAC;AAE/D,KAAK,UAAU,mBAAmB;IAChC,IAAI,aAAa,EAAE;QAAE,OAAO,IAAI,CAAC;IACjC,IAAI,YAAY,KAAK,SAAS;QAAE,OAAO,YAAY,CAAC;IACpD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,sBAAsB,CAAC,CAAuB,CAAC;QACzE,YAAY,GAAG,GAAG,CAAC;QACnB,yEAAyE;QACzE,mDAAmD;QACnD,IAAI,GAAG,CAAC,GAAG,IAAI,OAAO,GAAG,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC1C,GAAG,CAAC,GAA+B,CAAC,gBAAgB,GAAG,KAAK,CAAC;QAChE,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,GAAwB,CAAC;QACnC,IAAI,CAAC,CAAC,IAAI,KAAK,sBAAsB,IAAI,CAAC,CAAC,IAAI,KAAK,kBAAkB,EAAE,CAAC;YACvE,YAAY,GAAG,IAAI,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,6EAA6E;QAC7E,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sCAAsC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjH,YAAY,GAAG,IAAI,CAAC;QACpB,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,MAAM,GAAG,GAAG,MAAM,mBAAmB,EAAE,CAAC;IACxC,OAAO,GAAG,KAAK,IAAI,CAAC;AACtB,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,KAAa,EAAE,WAAiC;IACzE,MAAM,GAAG,GAAG,MAAM,mBAAmB,EAAE,CAAC;IACxC,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IAEtB,IAAI,
|
|
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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"}
|