@securecode-ai/mcp 0.5.8 → 0.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 +2 -1
- package/dist/api/client.d.ts +11 -1
- package/dist/api/client.js +93 -8
- package/dist/api/client.js.map +1 -1
- package/dist/api/types.d.ts +24 -0
- package/dist/approval/policy.js +5 -0
- package/dist/approval/policy.js.map +1 -1
- package/dist/attack/agentScanBatchProtocol.d.ts +98 -0
- package/dist/attack/agentScanBatchProtocol.js +125 -0
- package/dist/attack/agentScanBatchProtocol.js.map +1 -0
- package/dist/attack/agentScanBatchSelection.d.ts +38 -0
- package/dist/attack/agentScanBatchSelection.js +167 -0
- package/dist/attack/agentScanBatchSelection.js.map +1 -0
- package/dist/attack/agentScanCoordinator.d.ts +33 -0
- package/dist/attack/agentScanCoordinator.js +116 -0
- package/dist/attack/agentScanCoordinator.js.map +1 -0
- package/dist/attack/agentScanCreditPlan.d.ts +40 -0
- package/dist/attack/agentScanCreditPlan.js +50 -0
- package/dist/attack/agentScanCreditPlan.js.map +1 -0
- package/dist/attack/agentScanLoop.js +173 -111
- package/dist/attack/agentScanLoop.js.map +1 -1
- package/dist/attack/agentScanProtocol.d.ts +2 -2
- package/dist/attack/agentScanProtocol.js.map +1 -1
- package/dist/attack/investigationState.d.ts +1 -0
- package/dist/attack/investigationState.js +20 -7
- package/dist/attack/investigationState.js.map +1 -1
- package/dist/attack/scanScheduler.d.ts +5 -0
- package/dist/attack/scanScheduler.js +37 -2
- package/dist/attack/scanScheduler.js.map +1 -1
- package/dist/attack/scanState.d.ts +6 -0
- package/dist/attack/scanState.js +5 -0
- package/dist/attack/scanState.js.map +1 -1
- package/dist/mcp/server.js +2 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.js +35 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/project-map/scanCache.d.ts +4 -1
- package/dist/project-map/scanCache.js +15 -0
- package/dist/project-map/scanCache.js.map +1 -1
- package/dist/tools/agentScan.js +10 -1
- package/dist/tools/agentScan.js.map +1 -1
- package/dist/tools/agentScanBatch.d.ts +18 -0
- package/dist/tools/agentScanBatch.js +178 -0
- package/dist/tools/agentScanBatch.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Deterministic file selection for the agent scan batch tool.
|
|
4
|
+
*
|
|
5
|
+
* Selects the top N security-relevant files from the architecture context,
|
|
6
|
+
* using either the recommended scan order or the important files list.
|
|
7
|
+
* Filters out missing, empty, binary, and oversized files before selection.
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.selectAgentScanBatchFiles = selectAgentScanBatchFiles;
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const path = __importStar(require("path"));
|
|
46
|
+
const MAX_FILE_BYTES = 1_500_000;
|
|
47
|
+
const MIN_TOP_N = 1;
|
|
48
|
+
const MAX_TOP_N = 20;
|
|
49
|
+
const DEFAULT_TOP_N = 3;
|
|
50
|
+
function normalizePath(filePath) {
|
|
51
|
+
return filePath.replace(/\\/g, '/').replace(/^\.\//, '');
|
|
52
|
+
}
|
|
53
|
+
function checkFile(workspaceRoot, filePath) {
|
|
54
|
+
const absPath = path.isAbsolute(filePath)
|
|
55
|
+
? filePath
|
|
56
|
+
: path.join(workspaceRoot, filePath);
|
|
57
|
+
if (!fs.existsSync(absPath)) {
|
|
58
|
+
return { ok: false, reason: 'file does not exist' };
|
|
59
|
+
}
|
|
60
|
+
let stat;
|
|
61
|
+
try {
|
|
62
|
+
stat = fs.statSync(absPath);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return { ok: false, reason: 'cannot stat file' };
|
|
66
|
+
}
|
|
67
|
+
if (!stat.isFile()) {
|
|
68
|
+
return { ok: false, reason: 'not a regular file' };
|
|
69
|
+
}
|
|
70
|
+
if (stat.size === 0) {
|
|
71
|
+
return { ok: false, reason: 'file is empty' };
|
|
72
|
+
}
|
|
73
|
+
if (stat.size > MAX_FILE_BYTES) {
|
|
74
|
+
return { ok: false, reason: `file too large (${(stat.size / 1_000_000).toFixed(1)}MB > 1.5MB limit)` };
|
|
75
|
+
}
|
|
76
|
+
let content;
|
|
77
|
+
try {
|
|
78
|
+
content = fs.readFileSync(absPath, 'utf8');
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return { ok: false, reason: 'cannot read file' };
|
|
82
|
+
}
|
|
83
|
+
if (content.trim().length === 0) {
|
|
84
|
+
return { ok: false, reason: 'file is empty (whitespace only)' };
|
|
85
|
+
}
|
|
86
|
+
const headBytes = Buffer.from(content.slice(0, 1000), 'utf8');
|
|
87
|
+
if (headBytes.includes(0)) {
|
|
88
|
+
return { ok: false, reason: 'binary file' };
|
|
89
|
+
}
|
|
90
|
+
return { ok: true };
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Select the top N files for sequential agent scanning.
|
|
94
|
+
*
|
|
95
|
+
* Algorithm:
|
|
96
|
+
* 1. Start with recommendedScanOrder (or importantFiles if selected).
|
|
97
|
+
* 2. Normalize paths to forward-slash workspace-relative.
|
|
98
|
+
* 3. Remove duplicates.
|
|
99
|
+
* 4. Filter out missing, empty, binary, and oversized files.
|
|
100
|
+
* 5. Fill remaining slots from the other list if needed.
|
|
101
|
+
* 6. Clamp topN to 1..20.
|
|
102
|
+
* 7. Freeze the selection before returning.
|
|
103
|
+
*/
|
|
104
|
+
function selectAgentScanBatchFiles(workspaceRoot, architecture, options) {
|
|
105
|
+
const topN = Math.max(MIN_TOP_N, Math.min(MAX_TOP_N, options.topN ?? DEFAULT_TOP_N));
|
|
106
|
+
const useImportantFirst = options.fileSelection === 'importantFiles';
|
|
107
|
+
if (!architecture) {
|
|
108
|
+
return { selected: [], skipped: [] };
|
|
109
|
+
}
|
|
110
|
+
const seen = new Set();
|
|
111
|
+
const selected = [];
|
|
112
|
+
const skipped = [];
|
|
113
|
+
const importantMap = new Map();
|
|
114
|
+
for (const f of architecture.importantFiles || []) {
|
|
115
|
+
importantMap.set(normalizePath(f.file), f);
|
|
116
|
+
}
|
|
117
|
+
const buildEntry = (filePath, rank) => {
|
|
118
|
+
const norm = normalizePath(filePath);
|
|
119
|
+
const info = importantMap.get(norm);
|
|
120
|
+
return {
|
|
121
|
+
filePath: norm,
|
|
122
|
+
rank,
|
|
123
|
+
role: info?.role,
|
|
124
|
+
importance: info?.importance,
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
const tryAdd = (filePath) => {
|
|
128
|
+
const norm = normalizePath(filePath);
|
|
129
|
+
if (seen.has(norm))
|
|
130
|
+
return;
|
|
131
|
+
seen.add(norm);
|
|
132
|
+
const check = checkFile(workspaceRoot, norm);
|
|
133
|
+
if (!check.ok) {
|
|
134
|
+
skipped.push({ filePath: norm, reason: check.reason });
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (selected.length < topN) {
|
|
138
|
+
selected.push(buildEntry(filePath, selected.length + 1));
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
const primaryList = useImportantFirst
|
|
142
|
+
? (architecture.importantFiles || [])
|
|
143
|
+
.slice()
|
|
144
|
+
.sort((a, b) => (b.importance || 0) - (a.importance || 0))
|
|
145
|
+
.map(f => f.file)
|
|
146
|
+
: (architecture.recommendedScanOrder || []);
|
|
147
|
+
for (const filePath of primaryList) {
|
|
148
|
+
if (selected.length >= topN)
|
|
149
|
+
break;
|
|
150
|
+
tryAdd(filePath);
|
|
151
|
+
}
|
|
152
|
+
if (selected.length < topN) {
|
|
153
|
+
const fallback = useImportantFirst
|
|
154
|
+
? (architecture.recommendedScanOrder || [])
|
|
155
|
+
: (architecture.importantFiles || [])
|
|
156
|
+
.slice()
|
|
157
|
+
.sort((a, b) => (b.importance || 0) - (a.importance || 0))
|
|
158
|
+
.map(f => f.file);
|
|
159
|
+
for (const filePath of fallback) {
|
|
160
|
+
if (selected.length >= topN)
|
|
161
|
+
break;
|
|
162
|
+
tryAdd(filePath);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return { selected, skipped };
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=agentScanBatchSelection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentScanBatchSelection.js","sourceRoot":"","sources":["../../src/attack/agentScanBatchSelection.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-workspace agent scan coordinator.
|
|
3
|
+
*
|
|
4
|
+
* Ensures one active agent-scan workflow per workspace per MCP process.
|
|
5
|
+
* Independent direct calls queue in FIFO order. A batch holds the lock for
|
|
6
|
+
* its full workflow (map + architecture + all scans). Different workspaces
|
|
7
|
+
* may run concurrently.
|
|
8
|
+
*
|
|
9
|
+
* Cancellation removes waiting requests. Releasing the lock occurs in finally.
|
|
10
|
+
*/
|
|
11
|
+
export declare class AgentScanCoordinator {
|
|
12
|
+
private readonly locks;
|
|
13
|
+
private getLock;
|
|
14
|
+
/**
|
|
15
|
+
* Run an operation exclusively for the given workspace.
|
|
16
|
+
* If another operation is already running for the same workspace,
|
|
17
|
+
* this waits until it completes (FIFO queue) before starting.
|
|
18
|
+
* Different workspaces run concurrently.
|
|
19
|
+
*/
|
|
20
|
+
runExclusive<T>(workspaceRoot: string, operation: () => Promise<T>, options?: {
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
maxWaitMs?: number;
|
|
23
|
+
}): Promise<T>;
|
|
24
|
+
/**
|
|
25
|
+
* Check if an operation is currently active for the given workspace.
|
|
26
|
+
*/
|
|
27
|
+
isRunning(workspaceRoot: string): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Get the number of queued operations waiting for the workspace lock.
|
|
30
|
+
*/
|
|
31
|
+
queueDepth(workspaceRoot: string): number;
|
|
32
|
+
}
|
|
33
|
+
export declare const globalScanCoordinator: AgentScanCoordinator;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Per-workspace agent scan coordinator.
|
|
4
|
+
*
|
|
5
|
+
* Ensures one active agent-scan workflow per workspace per MCP process.
|
|
6
|
+
* Independent direct calls queue in FIFO order. A batch holds the lock for
|
|
7
|
+
* its full workflow (map + architecture + all scans). Different workspaces
|
|
8
|
+
* may run concurrently.
|
|
9
|
+
*
|
|
10
|
+
* Cancellation removes waiting requests. Releasing the lock occurs in finally.
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.globalScanCoordinator = exports.AgentScanCoordinator = void 0;
|
|
14
|
+
class WorkspaceLock {
|
|
15
|
+
active = false;
|
|
16
|
+
queue = [];
|
|
17
|
+
get isActive() {
|
|
18
|
+
return this.active;
|
|
19
|
+
}
|
|
20
|
+
get queueLength() {
|
|
21
|
+
return this.queue.length;
|
|
22
|
+
}
|
|
23
|
+
async acquire(signal, maxWaitMs) {
|
|
24
|
+
if (!this.active) {
|
|
25
|
+
this.active = true;
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
if (signal?.aborted) {
|
|
29
|
+
throw new Error('Agent scan cancelled while waiting for workspace lock.');
|
|
30
|
+
}
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
const entry = { resolve, reject, signal };
|
|
33
|
+
const cleanup = () => {
|
|
34
|
+
const idx = this.queue.indexOf(entry);
|
|
35
|
+
if (idx >= 0)
|
|
36
|
+
this.queue.splice(idx, 1);
|
|
37
|
+
if (entry.abortListener && signal) {
|
|
38
|
+
signal.removeEventListener('abort', entry.abortListener);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
if (signal) {
|
|
42
|
+
entry.abortListener = () => {
|
|
43
|
+
cleanup();
|
|
44
|
+
reject(new Error('Agent scan cancelled while waiting for workspace lock.'));
|
|
45
|
+
};
|
|
46
|
+
signal.addEventListener('abort', entry.abortListener);
|
|
47
|
+
}
|
|
48
|
+
if (maxWaitMs !== undefined) {
|
|
49
|
+
const timeout = setTimeout(() => {
|
|
50
|
+
cleanup();
|
|
51
|
+
reject(new Error(`Agent scan timed out waiting for workspace lock after ${maxWaitMs}ms.`));
|
|
52
|
+
}, maxWaitMs);
|
|
53
|
+
const originalResolve = entry.resolve;
|
|
54
|
+
const originalReject = entry.reject;
|
|
55
|
+
entry.resolve = () => { clearTimeout(timeout); originalResolve(); };
|
|
56
|
+
entry.reject = (err) => { clearTimeout(timeout); originalReject(err); };
|
|
57
|
+
}
|
|
58
|
+
this.queue.push(entry);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
release() {
|
|
62
|
+
this.active = false;
|
|
63
|
+
const next = this.queue.shift();
|
|
64
|
+
if (next) {
|
|
65
|
+
this.active = true;
|
|
66
|
+
next.resolve();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
class AgentScanCoordinator {
|
|
71
|
+
locks = new Map();
|
|
72
|
+
getLock(workspaceRoot) {
|
|
73
|
+
let lock = this.locks.get(workspaceRoot);
|
|
74
|
+
if (!lock) {
|
|
75
|
+
lock = new WorkspaceLock();
|
|
76
|
+
this.locks.set(workspaceRoot, lock);
|
|
77
|
+
}
|
|
78
|
+
return lock;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Run an operation exclusively for the given workspace.
|
|
82
|
+
* If another operation is already running for the same workspace,
|
|
83
|
+
* this waits until it completes (FIFO queue) before starting.
|
|
84
|
+
* Different workspaces run concurrently.
|
|
85
|
+
*/
|
|
86
|
+
async runExclusive(workspaceRoot, operation, options) {
|
|
87
|
+
const lock = this.getLock(workspaceRoot);
|
|
88
|
+
await lock.acquire(options?.signal, options?.maxWaitMs);
|
|
89
|
+
try {
|
|
90
|
+
return await operation();
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
lock.release();
|
|
94
|
+
if (!lock.isActive && lock.queueLength === 0) {
|
|
95
|
+
this.locks.delete(workspaceRoot);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Check if an operation is currently active for the given workspace.
|
|
101
|
+
*/
|
|
102
|
+
isRunning(workspaceRoot) {
|
|
103
|
+
const lock = this.locks.get(workspaceRoot);
|
|
104
|
+
return lock?.isActive ?? false;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get the number of queued operations waiting for the workspace lock.
|
|
108
|
+
*/
|
|
109
|
+
queueDepth(workspaceRoot) {
|
|
110
|
+
const lock = this.locks.get(workspaceRoot);
|
|
111
|
+
return lock?.queueLength ?? 0;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
exports.AgentScanCoordinator = AgentScanCoordinator;
|
|
115
|
+
exports.globalScanCoordinator = new AgentScanCoordinator();
|
|
116
|
+
//# sourceMappingURL=agentScanCoordinator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentScanCoordinator.js","sourceRoot":"","sources":["../../src/attack/agentScanCoordinator.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AASH,MAAM,aAAa;IACP,MAAM,GAAG,KAAK,CAAC;IACf,KAAK,GAAiB,EAAE,CAAC;IAEjC,IAAI,QAAQ;QACR,OAAO,IAAI,CAAC,MAAM,CAAC;IACvB,CAAC;IAED,IAAI,WAAW;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAoB,EAAE,SAAkB;QAClD,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YACnB,OAAO;QACX,CAAC;QAED,IAAI,MAAM,EAAE,OAAO,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;QAC9E,CAAC;QAED,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACzC,MAAM,KAAK,GAAe,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;YAEtD,MAAM,OAAO,GAAG,GAAG,EAAE;gBACjB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBACtC,IAAI,GAAG,IAAI,CAAC;oBAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBACxC,IAAI,KAAK,CAAC,aAAa,IAAI,MAAM,EAAE,CAAC;oBAChC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;gBAC7D,CAAC;YACL,CAAC,CAAC;YAEF,IAAI,MAAM,EAAE,CAAC;gBACT,KAAK,CAAC,aAAa,GAAG,GAAG,EAAE;oBACvB,OAAO,EAAE,CAAC;oBACV,MAAM,CAAC,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC,CAAC;gBAChF,CAAC,CAAC;gBACF,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;YAC1D,CAAC;YAED,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC1B,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;oBAC5B,OAAO,EAAE,CAAC;oBACV,MAAM,CAAC,IAAI,KAAK,CAAC,yDAAyD,SAAS,KAAK,CAAC,CAAC,CAAC;gBAC/F,CAAC,EAAE,SAAS,CAAC,CAAC;gBACd,MAAM,eAAe,GAAG,KAAK,CAAC,OAAO,CAAC;gBACtC,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC;gBACpC,KAAK,CAAC,OAAO,GAAG,GAAG,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,CAAC;gBACpE,KAAK,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC5E,CAAC;YAED,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3B,CAAC,CAAC,CAAC;IACP,CAAC;IAED,OAAO;QACH,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QAEpB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,IAAI,EAAE,CAAC;YACP,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YACnB,IAAI,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC;IACL,CAAC;CACJ;AAED,MAAa,oBAAoB;IACZ,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;IAElD,OAAO,CAAC,aAAqB;QACjC,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACzC,IAAI,CAAC,IAAI,EAAE,CAAC;YACR,IAAI,GAAG,IAAI,aAAa,EAAE,CAAC;YAC3B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,YAAY,CACd,aAAqB,EACrB,SAA2B,EAC3B,OAGC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QAEzC,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;QAExD,IAAI,CAAC;YACD,OAAO,MAAM,SAAS,EAAE,CAAC;QAC7B,CAAC;gBAAS,CAAC;YACP,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,WAAW,KAAK,CAAC,EAAE,CAAC;gBAC3C,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;YACrC,CAAC;QACL,CAAC;IACL,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,aAAqB;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAC3C,OAAO,IAAI,EAAE,QAAQ,IAAI,KAAK,CAAC;IACnC,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,aAAqB;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAC3C,OAAO,IAAI,EAAE,WAAW,IAAI,CAAC,CAAC;IAClC,CAAC;CACJ;AAvDD,oDAuDC;AAEY,QAAA,qBAAqB,GAAG,IAAI,oBAAoB,EAAE,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure credit cost calculator for agent scan batch workflows.
|
|
3
|
+
*
|
|
4
|
+
* Calculates the total scan credits required for a batch run:
|
|
5
|
+
* architecture scout + N × agent scan + optional verification reserve
|
|
6
|
+
*
|
|
7
|
+
* Policies:
|
|
8
|
+
* base-only — architecture + agent scans only
|
|
9
|
+
* verification-bounded — adds a per-file verification credit reserve
|
|
10
|
+
* Batch default: verification-bounded with a 10-credit-per-file cap.
|
|
11
|
+
*
|
|
12
|
+
* Fix reserve is always zero — the batch tool disables fix generation.
|
|
13
|
+
*/
|
|
14
|
+
import type { ArchitectureDepth } from '../project-map/architectureContext';
|
|
15
|
+
export type CreditPlanPolicy = 'base-only' | 'verification-bounded';
|
|
16
|
+
export interface CreditPlanOptions {
|
|
17
|
+
depth: ArchitectureDepth;
|
|
18
|
+
architectureCacheHit: boolean;
|
|
19
|
+
uncachedFileCount: number;
|
|
20
|
+
cachedFileCount: number;
|
|
21
|
+
policy?: CreditPlanPolicy;
|
|
22
|
+
verificationCreditsPerFile?: number;
|
|
23
|
+
}
|
|
24
|
+
export interface CreditPlan {
|
|
25
|
+
architectureCredits: number;
|
|
26
|
+
agentRunCredits: number;
|
|
27
|
+
verificationCredits: number;
|
|
28
|
+
fixReserveCredits: number;
|
|
29
|
+
total: number;
|
|
30
|
+
breakdown: {
|
|
31
|
+
depth: ArchitectureDepth;
|
|
32
|
+
architectureCacheHit: boolean;
|
|
33
|
+
uncachedFiles: number;
|
|
34
|
+
cachedFiles: number;
|
|
35
|
+
policy: CreditPlanPolicy;
|
|
36
|
+
verificationCreditsPerFile: number;
|
|
37
|
+
creditsPerRun: number;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export declare function calculateBatchCredits(options: CreditPlanOptions): CreditPlan;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Pure credit cost calculator for agent scan batch workflows.
|
|
4
|
+
*
|
|
5
|
+
* Calculates the total scan credits required for a batch run:
|
|
6
|
+
* architecture scout + N × agent scan + optional verification reserve
|
|
7
|
+
*
|
|
8
|
+
* Policies:
|
|
9
|
+
* base-only — architecture + agent scans only
|
|
10
|
+
* verification-bounded — adds a per-file verification credit reserve
|
|
11
|
+
* Batch default: verification-bounded with a 10-credit-per-file cap.
|
|
12
|
+
*
|
|
13
|
+
* Fix reserve is always zero — the batch tool disables fix generation.
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.calculateBatchCredits = calculateBatchCredits;
|
|
17
|
+
const agentScanProtocol_1 = require("./agentScanProtocol");
|
|
18
|
+
const architectureScoutProtocol_1 = require("./architectureScoutProtocol");
|
|
19
|
+
const DEFAULT_VERIFICATION_CREDITS_PER_FILE = 10;
|
|
20
|
+
const MAX_VERIFICATION_CREDITS_PER_FILE = 60;
|
|
21
|
+
function calculateBatchCredits(options) {
|
|
22
|
+
const policy = options.policy ?? 'verification-bounded';
|
|
23
|
+
const verificationCreditsPerFile = Math.min(MAX_VERIFICATION_CREDITS_PER_FILE, options.verificationCreditsPerFile ?? DEFAULT_VERIFICATION_CREDITS_PER_FILE);
|
|
24
|
+
const architectureCredits = options.architectureCacheHit
|
|
25
|
+
? 0
|
|
26
|
+
: (0, architectureScoutProtocol_1.scoutDefaultsForDepth)(options.depth).creditsPerRun;
|
|
27
|
+
const agentRunCredits = options.uncachedFileCount * agentScanProtocol_1.AGENT_SCAN_DEFAULTS.creditsPerRun;
|
|
28
|
+
const verificationCredits = policy === 'verification-bounded'
|
|
29
|
+
? options.uncachedFileCount * verificationCreditsPerFile
|
|
30
|
+
: 0;
|
|
31
|
+
const fixReserveCredits = 0;
|
|
32
|
+
const total = architectureCredits + agentRunCredits + verificationCredits + fixReserveCredits;
|
|
33
|
+
return {
|
|
34
|
+
architectureCredits,
|
|
35
|
+
agentRunCredits,
|
|
36
|
+
verificationCredits,
|
|
37
|
+
fixReserveCredits,
|
|
38
|
+
total,
|
|
39
|
+
breakdown: {
|
|
40
|
+
depth: options.depth,
|
|
41
|
+
architectureCacheHit: options.architectureCacheHit,
|
|
42
|
+
uncachedFiles: options.uncachedFileCount,
|
|
43
|
+
cachedFiles: options.cachedFileCount,
|
|
44
|
+
policy,
|
|
45
|
+
verificationCreditsPerFile,
|
|
46
|
+
creditsPerRun: agentScanProtocol_1.AGENT_SCAN_DEFAULTS.creditsPerRun,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=agentScanCreditPlan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agentScanCreditPlan.js","sourceRoot":"","sources":["../../src/attack/agentScanCreditPlan.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;AAqCH,sDAqCC;AAxED,2DAA0D;AAC1D,2EAAoE;AA+BpE,MAAM,qCAAqC,GAAG,EAAE,CAAC;AACjD,MAAM,iCAAiC,GAAG,EAAE,CAAC;AAE7C,SAAgB,qBAAqB,CAAC,OAA0B;IAC5D,MAAM,MAAM,GAAqB,OAAO,CAAC,MAAM,IAAI,sBAAsB,CAAC;IAC1E,MAAM,0BAA0B,GAAG,IAAI,CAAC,GAAG,CACvC,iCAAiC,EACjC,OAAO,CAAC,0BAA0B,IAAI,qCAAqC,CAC9E,CAAC;IAEF,MAAM,mBAAmB,GAAG,OAAO,CAAC,oBAAoB;QACpD,CAAC,CAAC,CAAC;QACH,CAAC,CAAC,IAAA,iDAAqB,EAAC,OAAO,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC;IAEzD,MAAM,eAAe,GAAG,OAAO,CAAC,iBAAiB,GAAG,uCAAmB,CAAC,aAAa,CAAC;IAEtF,MAAM,mBAAmB,GAAG,MAAM,KAAK,sBAAsB;QACzD,CAAC,CAAC,OAAO,CAAC,iBAAiB,GAAG,0BAA0B;QACxD,CAAC,CAAC,CAAC,CAAC;IAER,MAAM,iBAAiB,GAAG,CAAC,CAAC;IAE5B,MAAM,KAAK,GAAG,mBAAmB,GAAG,eAAe,GAAG,mBAAmB,GAAG,iBAAiB,CAAC;IAE9F,OAAO;QACH,mBAAmB;QACnB,eAAe;QACf,mBAAmB;QACnB,iBAAiB;QACjB,KAAK;QACL,SAAS,EAAE;YACP,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,oBAAoB,EAAE,OAAO,CAAC,oBAAoB;YAClD,aAAa,EAAE,OAAO,CAAC,iBAAiB;YACxC,WAAW,EAAE,OAAO,CAAC,eAAe;YACpC,MAAM;YACN,0BAA0B;YAC1B,aAAa,EAAE,uCAAmB,CAAC,aAAa;SACnD;KACJ,CAAC;AACN,CAAC"}
|