nexus-agents 8.47.5 → 8.47.7
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/dist/{ast-rule-runner-KZJJJQAW.js → ast-rule-runner-EHBBZKQ7.js} +3 -3
- package/dist/{child-mcp-config-L3ZAUYGJ.js → child-mcp-config-H7Q4VHVK.js} +2 -2
- package/dist/{chunk-N337ROIP.js → chunk-3KA4RFGM.js} +2 -2
- package/dist/{chunk-W4XJF3PW.js → chunk-3QAL5UIY.js} +2 -2
- package/dist/{chunk-U2PGDAEV.js → chunk-4GDMHCKX.js} +41 -16
- package/dist/chunk-4GDMHCKX.js.map +1 -0
- package/dist/{chunk-MQ6CM6NH.js → chunk-6B7YJMG4.js} +2 -2
- package/dist/{chunk-U6BOS5XZ.js → chunk-7PN6YCEA.js} +2 -2
- package/dist/{chunk-WZP2FPWL.js → chunk-7S4ZLD4G.js} +8 -8
- package/dist/{chunk-F2JOZIHL.js → chunk-AA5OUZR6.js} +4 -4
- package/dist/{chunk-I3BILDI6.js → chunk-BY6NRKVI.js} +3 -3
- package/dist/{chunk-DYR5CK4E.js → chunk-CXXQ36SZ.js} +2 -2
- package/dist/{chunk-YM4627WM.js → chunk-DN47AWK3.js} +2 -2
- package/dist/{chunk-TBGEN6TO.js → chunk-DYSJLP7T.js} +2 -2
- package/dist/{chunk-5FXRCQPV.js → chunk-ETTYFUV6.js} +2 -2
- package/dist/{chunk-VIXGTZL4.js → chunk-FMTKKJP7.js} +4 -4
- package/dist/chunk-FMTKKJP7.js.map +1 -0
- package/dist/{chunk-EFJOWG5H.js → chunk-FTOJAN24.js} +4 -4
- package/dist/{chunk-RIA23PDE.js → chunk-JF74MIER.js} +2 -2
- package/dist/{chunk-TJMJ47DS.js → chunk-JMUITMBB.js} +2 -2
- package/dist/{chunk-XJN57QGS.js → chunk-JOP5NFAQ.js} +2 -2
- package/dist/{chunk-A7HQNXWO.js → chunk-KAGMXQMM.js} +2 -2
- package/dist/{chunk-V5UQBZEV.js → chunk-KNGST6PU.js} +3 -3
- package/dist/{chunk-OS5X43GP.js → chunk-KVWEVIPU.js} +38 -38
- package/dist/{chunk-OS5X43GP.js.map → chunk-KVWEVIPU.js.map} +1 -1
- package/dist/{chunk-JLRJ3WU7.js → chunk-LOU252L2.js} +6 -6
- package/dist/{chunk-2I4XNHJA.js → chunk-MWQ2UYSX.js} +2 -2
- package/dist/{chunk-6TYTVKWM.js → chunk-O72VDOFO.js} +2 -2
- package/dist/{chunk-XTNJZG2X.js → chunk-OKSGCMDV.js} +3 -3
- package/dist/{chunk-J4XJ2O33.js → chunk-Q7O7SACB.js} +9 -9
- package/dist/{chunk-WJSSC4ZQ.js → chunk-QURCW325.js} +3 -3
- package/dist/{chunk-67M5BPTV.js → chunk-QYPDW4PU.js} +2 -2
- package/dist/{chunk-4YQSX2TU.js → chunk-REEQOJUH.js} +2 -2
- package/dist/{chunk-BVNOK5P6.js → chunk-RVPB3BHL.js} +7 -7
- package/dist/{chunk-NY2DCMDD.js → chunk-RWC5WRR3.js} +5 -5
- package/dist/{chunk-M3P5B3RG.js → chunk-U54ZN4E6.js} +5 -5
- package/dist/{chunk-C5RLLXX2.js → chunk-UOYS6IQ4.js} +8 -8
- package/dist/{chunk-JUNUU76G.js → chunk-X3W235GA.js} +3 -3
- package/dist/{chunk-LJPCUYVD.js → chunk-XCKEQLRC.js} +4 -4
- package/dist/{chunk-LOOEJFT3.js → chunk-ZDUIEKVX.js} +2 -2
- package/dist/{cli-circuit-breaker-AAHKTJCY.js → cli-circuit-breaker-TWGNVVI2.js} +3 -3
- package/dist/cli.js +44 -44
- package/dist/{composite-router-OP66QH5X.js → composite-router-MKYW26IA.js} +2 -2
- package/dist/{consensus-vote-PXZ6P5W3.js → consensus-vote-TAZ2YBDV.js} +17 -17
- package/dist/{context-retriever-ZAYHL472.js → context-retriever-SNA6CRKC.js} +8 -8
- package/dist/{doctor-deep-T5IKW6X6.js → doctor-deep-LAWVMKF7.js} +3 -3
- package/dist/{doctor-live-TPYTCGOS.js → doctor-live-IMA6R5JK.js} +9 -9
- package/dist/{expert-bridge-QPMC75VN.js → expert-bridge-HNVJWGFN.js} +4 -4
- package/dist/{factory-ZU35O5V7.js → factory-HDDNT4Y4.js} +5 -5
- package/dist/{factory-YFFVVPNA.js → factory-I3QFIRBK.js} +9 -9
- package/dist/{improvement-review-CVJCZPMB.js → improvement-review-AKJN5RXY.js} +6 -6
- package/dist/index.d.ts +35 -2
- package/dist/index.js +32 -32
- package/dist/{init-opencode-SAZZWTN5.js → init-opencode-O6YZ22XI.js} +6 -6
- package/dist/issue-triage-U4WOMZSI.js +17 -0
- package/dist/{pr-reviewer-helpers-M2GPPYN2.js → pr-reviewer-helpers-RWNTTUMR.js} +4 -4
- package/dist/{registry-command-4SOG2KWX.js → registry-command-HFHNOECT.js} +2 -2
- package/dist/{repo-analyze-R6WFDFBV.js → repo-analyze-LNZ3Y6BR.js} +2 -2
- package/dist/{repo-security-plan-N4JBCHDO.js → repo-security-plan-4JKIYRQH.js} +4 -4
- package/dist/{research-helpers-synthesize-54VP4KYP.js → research-helpers-synthesize-4ZS432XJ.js} +4 -4
- package/dist/{routing-memory-UEOQNQ3G.js → routing-memory-FJFDW2BK.js} +2 -2
- package/dist/{session-memory-4INFFH6Q.js → session-memory-QP7J6YYG.js} +3 -3
- package/dist/{setup-config-BK4IWIRM.js → setup-config-4UWNJ52I.js} +3 -3
- package/dist/{setup-custom-api-4ROFGUFC.js → setup-custom-api-3G75IXNS.js} +4 -4
- package/dist/setup-data-dir-4ZJEO3GZ.js +30 -0
- package/dist/{tool-memory-AYT45WFG.js → tool-memory-HWESCWZI.js} +5 -5
- package/dist/{unified-registry-YLJGLNSD.js → unified-registry-M4MWH6HK.js} +10 -10
- package/dist/{weather-report-7TI7VRN7.js → weather-report-SCNDWSA4.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-U2PGDAEV.js.map +0 -1
- package/dist/chunk-VIXGTZL4.js.map +0 -1
- package/dist/issue-triage-AV7AF3R3.js +0 -17
- package/dist/setup-data-dir-G3EQQZL3.js +0 -30
- /package/dist/{ast-rule-runner-KZJJJQAW.js.map → ast-rule-runner-EHBBZKQ7.js.map} +0 -0
- /package/dist/{child-mcp-config-L3ZAUYGJ.js.map → child-mcp-config-H7Q4VHVK.js.map} +0 -0
- /package/dist/{chunk-N337ROIP.js.map → chunk-3KA4RFGM.js.map} +0 -0
- /package/dist/{chunk-W4XJF3PW.js.map → chunk-3QAL5UIY.js.map} +0 -0
- /package/dist/{chunk-MQ6CM6NH.js.map → chunk-6B7YJMG4.js.map} +0 -0
- /package/dist/{chunk-U6BOS5XZ.js.map → chunk-7PN6YCEA.js.map} +0 -0
- /package/dist/{chunk-WZP2FPWL.js.map → chunk-7S4ZLD4G.js.map} +0 -0
- /package/dist/{chunk-F2JOZIHL.js.map → chunk-AA5OUZR6.js.map} +0 -0
- /package/dist/{chunk-I3BILDI6.js.map → chunk-BY6NRKVI.js.map} +0 -0
- /package/dist/{chunk-DYR5CK4E.js.map → chunk-CXXQ36SZ.js.map} +0 -0
- /package/dist/{chunk-YM4627WM.js.map → chunk-DN47AWK3.js.map} +0 -0
- /package/dist/{chunk-TBGEN6TO.js.map → chunk-DYSJLP7T.js.map} +0 -0
- /package/dist/{chunk-5FXRCQPV.js.map → chunk-ETTYFUV6.js.map} +0 -0
- /package/dist/{chunk-EFJOWG5H.js.map → chunk-FTOJAN24.js.map} +0 -0
- /package/dist/{chunk-RIA23PDE.js.map → chunk-JF74MIER.js.map} +0 -0
- /package/dist/{chunk-TJMJ47DS.js.map → chunk-JMUITMBB.js.map} +0 -0
- /package/dist/{chunk-XJN57QGS.js.map → chunk-JOP5NFAQ.js.map} +0 -0
- /package/dist/{chunk-A7HQNXWO.js.map → chunk-KAGMXQMM.js.map} +0 -0
- /package/dist/{chunk-V5UQBZEV.js.map → chunk-KNGST6PU.js.map} +0 -0
- /package/dist/{chunk-JLRJ3WU7.js.map → chunk-LOU252L2.js.map} +0 -0
- /package/dist/{chunk-2I4XNHJA.js.map → chunk-MWQ2UYSX.js.map} +0 -0
- /package/dist/{chunk-6TYTVKWM.js.map → chunk-O72VDOFO.js.map} +0 -0
- /package/dist/{chunk-XTNJZG2X.js.map → chunk-OKSGCMDV.js.map} +0 -0
- /package/dist/{chunk-J4XJ2O33.js.map → chunk-Q7O7SACB.js.map} +0 -0
- /package/dist/{chunk-WJSSC4ZQ.js.map → chunk-QURCW325.js.map} +0 -0
- /package/dist/{chunk-67M5BPTV.js.map → chunk-QYPDW4PU.js.map} +0 -0
- /package/dist/{chunk-4YQSX2TU.js.map → chunk-REEQOJUH.js.map} +0 -0
- /package/dist/{chunk-BVNOK5P6.js.map → chunk-RVPB3BHL.js.map} +0 -0
- /package/dist/{chunk-NY2DCMDD.js.map → chunk-RWC5WRR3.js.map} +0 -0
- /package/dist/{chunk-M3P5B3RG.js.map → chunk-U54ZN4E6.js.map} +0 -0
- /package/dist/{chunk-C5RLLXX2.js.map → chunk-UOYS6IQ4.js.map} +0 -0
- /package/dist/{chunk-JUNUU76G.js.map → chunk-X3W235GA.js.map} +0 -0
- /package/dist/{chunk-LJPCUYVD.js.map → chunk-XCKEQLRC.js.map} +0 -0
- /package/dist/{chunk-LOOEJFT3.js.map → chunk-ZDUIEKVX.js.map} +0 -0
- /package/dist/{cli-circuit-breaker-AAHKTJCY.js.map → cli-circuit-breaker-TWGNVVI2.js.map} +0 -0
- /package/dist/{composite-router-OP66QH5X.js.map → composite-router-MKYW26IA.js.map} +0 -0
- /package/dist/{consensus-vote-PXZ6P5W3.js.map → consensus-vote-TAZ2YBDV.js.map} +0 -0
- /package/dist/{context-retriever-ZAYHL472.js.map → context-retriever-SNA6CRKC.js.map} +0 -0
- /package/dist/{doctor-deep-T5IKW6X6.js.map → doctor-deep-LAWVMKF7.js.map} +0 -0
- /package/dist/{doctor-live-TPYTCGOS.js.map → doctor-live-IMA6R5JK.js.map} +0 -0
- /package/dist/{expert-bridge-QPMC75VN.js.map → expert-bridge-HNVJWGFN.js.map} +0 -0
- /package/dist/{factory-YFFVVPNA.js.map → factory-HDDNT4Y4.js.map} +0 -0
- /package/dist/{factory-ZU35O5V7.js.map → factory-I3QFIRBK.js.map} +0 -0
- /package/dist/{improvement-review-CVJCZPMB.js.map → improvement-review-AKJN5RXY.js.map} +0 -0
- /package/dist/{init-opencode-SAZZWTN5.js.map → init-opencode-O6YZ22XI.js.map} +0 -0
- /package/dist/{issue-triage-AV7AF3R3.js.map → issue-triage-U4WOMZSI.js.map} +0 -0
- /package/dist/{pr-reviewer-helpers-M2GPPYN2.js.map → pr-reviewer-helpers-RWNTTUMR.js.map} +0 -0
- /package/dist/{registry-command-4SOG2KWX.js.map → registry-command-HFHNOECT.js.map} +0 -0
- /package/dist/{repo-analyze-R6WFDFBV.js.map → repo-analyze-LNZ3Y6BR.js.map} +0 -0
- /package/dist/{repo-security-plan-N4JBCHDO.js.map → repo-security-plan-4JKIYRQH.js.map} +0 -0
- /package/dist/{research-helpers-synthesize-54VP4KYP.js.map → research-helpers-synthesize-4ZS432XJ.js.map} +0 -0
- /package/dist/{routing-memory-UEOQNQ3G.js.map → routing-memory-FJFDW2BK.js.map} +0 -0
- /package/dist/{session-memory-4INFFH6Q.js.map → session-memory-QP7J6YYG.js.map} +0 -0
- /package/dist/{setup-config-BK4IWIRM.js.map → setup-config-4UWNJ52I.js.map} +0 -0
- /package/dist/{setup-custom-api-4ROFGUFC.js.map → setup-custom-api-3G75IXNS.js.map} +0 -0
- /package/dist/{setup-data-dir-G3EQQZL3.js.map → setup-data-dir-4ZJEO3GZ.js.map} +0 -0
- /package/dist/{tool-memory-AYT45WFG.js.map → tool-memory-HWESCWZI.js.map} +0 -0
- /package/dist/{unified-registry-YLJGLNSD.js.map → unified-registry-M4MWH6HK.js.map} +0 -0
- /package/dist/{weather-report-7TI7VRN7.js.map → weather-report-SCNDWSA4.js.map} +0 -0
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
getBuiltInAstRulesPath,
|
|
10
10
|
loadRules,
|
|
11
11
|
runAstQaRules
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-O72VDOFO.js";
|
|
13
|
+
import "./chunk-QURCW325.js";
|
|
14
14
|
import "./chunk-MTYJPPIG.js";
|
|
15
15
|
import "./chunk-BTYRPZON.js";
|
|
16
16
|
import "./chunk-ZPWHCABL.js";
|
|
@@ -26,4 +26,4 @@ export {
|
|
|
26
26
|
loadRules,
|
|
27
27
|
runAstQaRules
|
|
28
28
|
};
|
|
29
|
-
//# sourceMappingURL=ast-rule-runner-
|
|
29
|
+
//# sourceMappingURL=ast-rule-runner-EHBBZKQ7.js.map
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-T46RV7Y7.js";
|
|
4
4
|
import {
|
|
5
5
|
createLogger
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-QURCW325.js";
|
|
7
7
|
import "./chunk-MTYJPPIG.js";
|
|
8
8
|
import "./chunk-BTYRPZON.js";
|
|
9
9
|
import "./chunk-ZPWHCABL.js";
|
|
@@ -60,4 +60,4 @@ export {
|
|
|
60
60
|
generateMcpConfig,
|
|
61
61
|
getDefaultAllowedTools
|
|
62
62
|
};
|
|
63
|
-
//# sourceMappingURL=child-mcp-config-
|
|
63
|
+
//# sourceMappingURL=child-mcp-config-H7Q4VHVK.js.map
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
createLogger,
|
|
3
3
|
err,
|
|
4
4
|
ok
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-QURCW325.js";
|
|
6
6
|
|
|
7
7
|
// src/scm/token-resolver.ts
|
|
8
8
|
import { execFile } from "node:child_process";
|
|
@@ -87,4 +87,4 @@ export {
|
|
|
87
87
|
hasToken,
|
|
88
88
|
getTokenEnvVars
|
|
89
89
|
};
|
|
90
|
-
//# sourceMappingURL=chunk-
|
|
90
|
+
//# sourceMappingURL=chunk-3KA4RFGM.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getRandomProvider,
|
|
3
3
|
getTimeProvider
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QURCW325.js";
|
|
5
5
|
|
|
6
6
|
// src/utils/id-utils.ts
|
|
7
7
|
import { randomUUID } from "node:crypto";
|
|
@@ -24,4 +24,4 @@ export {
|
|
|
24
24
|
generateHyphenId,
|
|
25
25
|
generateUUID
|
|
26
26
|
};
|
|
27
|
-
//# sourceMappingURL=chunk-
|
|
27
|
+
//# sourceMappingURL=chunk-3QAL5UIY.js.map
|
|
@@ -191,11 +191,15 @@ function getLanguageRecommendations(language, securityTooling) {
|
|
|
191
191
|
}
|
|
192
192
|
var SAST_TOOLS = /* @__PURE__ */ new Set(["semgrep", "codeql", "snyk"]);
|
|
193
193
|
var SAST_GAP_MSG = "No SAST/SCA security scanning configured";
|
|
194
|
-
|
|
194
|
+
var SAST_UNVERIFIED_MSG = "SAST/SCA scanning unverified \u2014 .github/workflows could not be listed";
|
|
195
|
+
function removeSastGapIfToolDetected(gaps, secTools, workflowsMeasured) {
|
|
196
|
+
const idx = gaps.indexOf(SAST_GAP_MSG);
|
|
197
|
+
if (idx === -1) return;
|
|
195
198
|
if (secTools.some((t) => SAST_TOOLS.has(t))) {
|
|
196
|
-
|
|
197
|
-
|
|
199
|
+
gaps.splice(idx, 1);
|
|
200
|
+
return;
|
|
198
201
|
}
|
|
202
|
+
if (!workflowsMeasured) gaps[idx] = SAST_UNVERIFIED_MSG;
|
|
199
203
|
}
|
|
200
204
|
function judgedGaps(entries, language, codeowners) {
|
|
201
205
|
const gaps = [];
|
|
@@ -205,14 +209,28 @@ function judgedGaps(entries, language, codeowners) {
|
|
|
205
209
|
if (tests.measured && !tests.hasTests) gaps.push("No test directory detected");
|
|
206
210
|
return gaps;
|
|
207
211
|
}
|
|
208
|
-
function
|
|
212
|
+
function resolveListings(listings) {
|
|
213
|
+
return {
|
|
214
|
+
dotGithubEntries: listings.dotGithubEntries ?? [],
|
|
215
|
+
dotGithubListed: listings.dotGithubListed ?? false,
|
|
216
|
+
workflowsMeasured: listings.workflowsMeasured ?? true
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function resolveObserved(observed) {
|
|
220
|
+
return {
|
|
221
|
+
codeowners: observed.codeowners ?? {},
|
|
222
|
+
workflowsMeasured: observed.workflowsMeasured ?? true
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function identifyGaps(entries, ciProvider, language, securityTooling, observed = {}) {
|
|
226
|
+
const { codeowners, workflowsMeasured } = resolveObserved(observed);
|
|
209
227
|
const gaps = [];
|
|
210
228
|
if (ciProvider === null) gaps.push("No CI/CD configuration detected");
|
|
211
229
|
for (const [files, message] of GAP_RULES) {
|
|
212
230
|
if (!files.some((f) => entries.includes(f))) gaps.push(message);
|
|
213
231
|
}
|
|
214
232
|
gaps.push(...judgedGaps(entries, language, codeowners));
|
|
215
|
-
removeSastGapIfToolDetected(gaps, securityTooling ?? []);
|
|
233
|
+
removeSastGapIfToolDetected(gaps, securityTooling ?? [], workflowsMeasured);
|
|
216
234
|
const hasGenericSecGap = gaps.includes("No SAST/SCA security scanning configured");
|
|
217
235
|
if (hasGenericSecGap && language !== null && language !== void 0 && securityTooling !== void 0) {
|
|
218
236
|
const langRecs = getLanguageRecommendations(language, securityTooling);
|
|
@@ -220,7 +238,8 @@ function identifyGaps(entries, ciProvider, language, securityTooling, codeowners
|
|
|
220
238
|
}
|
|
221
239
|
return gaps;
|
|
222
240
|
}
|
|
223
|
-
function analyzeRepo(metadata, topLevelEntries, workflowEntries,
|
|
241
|
+
function analyzeRepo(metadata, topLevelEntries, workflowEntries, listings = {}) {
|
|
242
|
+
const { dotGithubEntries, dotGithubListed, workflowsMeasured } = resolveListings(listings);
|
|
224
243
|
const ciProvider = detectCiProvider(topLevelEntries);
|
|
225
244
|
const secTooling = detectSecurityTooling(topLevelEntries, workflowEntries);
|
|
226
245
|
const tests = detectTestInfraMeasured(topLevelEntries, metadata.language);
|
|
@@ -245,9 +264,10 @@ function analyzeRepo(metadata, topLevelEntries, workflowEntries, dotGithubEntrie
|
|
|
245
264
|
stars: metadata.stargazers_count,
|
|
246
265
|
topLevelEntries: [...topLevelEntries],
|
|
247
266
|
gaps: identifyGaps(topLevelEntries, ciProvider, metadata.language, secTooling, {
|
|
248
|
-
entries: dotGithubEntries,
|
|
249
|
-
|
|
250
|
-
})
|
|
267
|
+
codeowners: { entries: dotGithubEntries, listed: dotGithubListed },
|
|
268
|
+
workflowsMeasured
|
|
269
|
+
}),
|
|
270
|
+
workflowsMeasured
|
|
251
271
|
};
|
|
252
272
|
}
|
|
253
273
|
var MARKUP_LANGUAGES = /* @__PURE__ */ new Set([
|
|
@@ -392,9 +412,10 @@ async function fetchWorkflowEntries(repoId, exec) {
|
|
|
392
412
|
{ timeout: 15e3 }
|
|
393
413
|
);
|
|
394
414
|
const parsed = JSON.parse(stdout.trim());
|
|
395
|
-
|
|
415
|
+
const entries = Array.isArray(parsed) ? parsed.filter((e) => typeof e === "string") : [];
|
|
416
|
+
return { entries, listed: true };
|
|
396
417
|
} catch {
|
|
397
|
-
return [];
|
|
418
|
+
return { entries: [], listed: false };
|
|
398
419
|
}
|
|
399
420
|
}
|
|
400
421
|
async function fetchDotGithubEntries(repoId, exec) {
|
|
@@ -410,9 +431,9 @@ async function fetchDotGithubEntries(repoId, exec) {
|
|
|
410
431
|
return { entries: [], listed: false };
|
|
411
432
|
}
|
|
412
433
|
}
|
|
413
|
-
async function analyzeGitHubRepo(input) {
|
|
434
|
+
async function analyzeGitHubRepo(input, execOverride) {
|
|
414
435
|
const repoId = normalizeRepoId(input.repo);
|
|
415
|
-
const exec = await getExecFile();
|
|
436
|
+
const exec = execOverride ?? await getExecFile();
|
|
416
437
|
const { metadata, entries } = await fetchRepoData(repoId, exec);
|
|
417
438
|
const primaryLang = await resolveLanguage(repoId, entries, metadata, exec);
|
|
418
439
|
const enhanced = { ...metadata, language: primaryLang };
|
|
@@ -422,9 +443,13 @@ async function analyzeGitHubRepo(input) {
|
|
|
422
443
|
const resolved = await resolveLicense(repoId, exec);
|
|
423
444
|
if (resolved !== null) enhanced.license = { spdx_id: resolved };
|
|
424
445
|
}
|
|
425
|
-
const
|
|
446
|
+
const workflows = entries.includes(".github") ? await fetchWorkflowEntries(repoId, exec) : { entries: [], listed: true };
|
|
426
447
|
const dotGithub = entries.includes(".github") ? await fetchDotGithubEntries(repoId, exec) : { entries: [], listed: true };
|
|
427
|
-
return analyzeRepo(enhanced, entries,
|
|
448
|
+
return analyzeRepo(enhanced, entries, workflows.entries, {
|
|
449
|
+
dotGithubEntries: dotGithub.entries,
|
|
450
|
+
dotGithubListed: dotGithub.listed,
|
|
451
|
+
workflowsMeasured: workflows.listed
|
|
452
|
+
});
|
|
428
453
|
}
|
|
429
454
|
|
|
430
455
|
export {
|
|
@@ -438,4 +463,4 @@ export {
|
|
|
438
463
|
analyzeRepo,
|
|
439
464
|
analyzeGitHubRepo
|
|
440
465
|
};
|
|
441
|
-
//# sourceMappingURL=chunk-
|
|
466
|
+
//# sourceMappingURL=chunk-4GDMHCKX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp/tools/repo-analyze.ts"],"sourcesContent":["/* eslint-disable max-lines -- cohesive module, governance allows 400-600 */\n/**\n * nexus-agents/mcp - Repository Analyze Logic\n *\n * Inspects a GitHub repository and returns structured analysis\n * including language, tooling, CI, security, and gap identification.\n *\n * @module mcp/tools/repo-analyze\n * (Source: Issue #1074)\n */\n\nimport { z } from 'zod';\nimport type {\n RepoAnalyzeInput,\n RepoAnalysis,\n CodeownersLookup,\n ExecFileFn,\n GapObservations,\n RepoListings,\n} from './repo-analyze-types.js';\n\n/**\n * Zod schema for the `gh api repos/{repoId}` payload (#2962). Pre-fix the\n * stdout was cast directly via `JSON.parse(...) as GhRepoMetadata`, so any\n * GitHub-side schema drift went unflagged until `analyzeRepo` dereferenced\n * a missing field. Now `safeParse` + a structured error surface the drift\n * with a stdout preview.\n */\nconst GhRepoMetadataSchema = z.object({\n name: z.string(),\n full_name: z.string(),\n description: z.string().nullable(),\n language: z.string().nullable(),\n default_branch: z.string(),\n stargazers_count: z.number(),\n license: z.object({ spdx_id: z.string() }).nullable(),\n});\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\n/** Normalize \"owner/repo\" from either \"owner/repo\" or full GitHub URL. */\nexport function normalizeRepoId(input: string): string {\n const urlMatch = /github\\.com\\/([^/]+\\/[^/]+?)(?:\\.git)?(?:\\/|$)/.exec(input);\n const matched = urlMatch?.[1] ?? '';\n if (matched.length > 0) return matched;\n if (/^[^/]+\\/[^/]+$/.test(input)) return input;\n throw new Error(`Invalid repo format: \"${input}\". Use \"owner/name\" or a GitHub URL.`);\n}\n\n/** Package manager detection rules: [files, manager]. First match wins. */\nconst PACKAGE_MANAGER_RULES: ReadonlyArray<readonly [readonly string[], string]> = [\n [['pnpm-lock.yaml'], 'pnpm'],\n [['yarn.lock'], 'yarn'],\n [['package-lock.json', 'package.json'], 'npm'],\n [['Cargo.toml'], 'cargo'],\n [['go.mod'], 'go'],\n [['requirements.txt', 'pyproject.toml'], 'pip'],\n [['Gemfile'], 'bundler'],\n [['pom.xml'], 'maven'],\n [['build.gradle', 'build.gradle.kts'], 'gradle'],\n];\n\n/** Detect package manager from top-level files. */\nexport function detectPackageManager(entries: readonly string[]): string | null {\n for (const [files, manager] of PACKAGE_MANAGER_RULES) {\n if (files.some((f) => entries.includes(f))) return manager;\n }\n return null;\n}\n\n/** Detect CI provider from directory structure. */\nexport function detectCiProvider(entries: readonly string[]): string | null {\n if (entries.includes('.github')) return 'github-actions';\n if (entries.includes('.gitlab-ci.yml')) return 'gitlab-ci';\n if (entries.includes('Jenkinsfile')) return 'jenkins';\n if (entries.includes('.circleci')) return 'circleci';\n if (entries.includes('.travis.yml')) return 'travis';\n if (entries.includes('azure-pipelines.yml')) return 'azure-devops';\n if (entries.includes('concourse')) return 'concourse';\n return null;\n}\n\n/** Tool names detectable from CI workflow filenames (#1674). */\nconst WORKFLOW_SECURITY_PATTERNS: ReadonlyArray<readonly [string, string]> = [\n ['semgrep', 'semgrep'],\n ['codeql', 'codeql'],\n ['grype', 'grype'],\n ['snyk', 'snyk'],\n];\n\n/** Detect security tools from .github/workflows/ filenames. */\nfunction detectWorkflowSecurity(\n workflowEntries: readonly string[],\n existing: readonly string[]\n): readonly string[] {\n const wfLower = workflowEntries.map((w) => w.toLowerCase());\n const found: string[] = [];\n for (const [pattern, tool] of WORKFLOW_SECURITY_PATTERNS) {\n if (!existing.includes(tool) && wfLower.some((w) => w.includes(pattern))) {\n found.push(tool);\n }\n }\n return found;\n}\n\n/** Root-level config files that imply a security tool is in use. */\nconst ROOT_SECURITY_FILES: ReadonlyArray<readonly [readonly string[], string]> = [\n [['.semgrep.yml', '.semgrep'], 'semgrep'],\n [['.snyk'], 'snyk'],\n [['SECURITY.md'], 'security-policy'],\n [['.grype.yaml'], 'grype'],\n [['CODEOWNERS'], 'codeowners'],\n // gitleaks (#2732). Catches `.gitleaks.toml` (canonical) plus legacy\n // `gitleaks.toml` / `.gitleaksignore` variants. Without this, a repo\n // carrying `.gitleaks.toml` reported `existingTooling` without gitleaks,\n // and `repo_security_plan` then showed `secrets: covered: true,\n // scanners: []` (covered by existing-but-undetected tooling).\n [['.gitleaks.toml', 'gitleaks.toml', '.gitleaksignore'], 'gitleaks'],\n];\n\n/** Detect security tooling from root files and CI workflow filenames (#1674). */\nexport function detectSecurityTooling(\n entries: readonly string[],\n workflowEntries?: readonly string[]\n): readonly string[] {\n const tools: string[] = [];\n for (const [files, tool] of ROOT_SECURITY_FILES) {\n if (files.some((f) => entries.includes(f))) tools.push(tool);\n }\n if (workflowEntries !== undefined) {\n tools.push(...detectWorkflowSecurity(workflowEntries, tools));\n }\n return tools;\n}\n\n/** Detect framework from package manager config. */\nexport function detectFramework(entries: readonly string[]): string | null {\n if (entries.includes('helmfile.yaml') || entries.includes('helmfile.yaml.gotmpl'))\n return 'helmfile';\n if (entries.includes('next.config.js') || entries.includes('next.config.ts')) return 'nextjs';\n if (entries.includes('angular.json')) return 'angular';\n if (entries.includes('vite.config.ts') || entries.includes('vite.config.js')) return 'vite';\n if (entries.includes('tsconfig.json') && entries.includes('package.json')) return 'typescript';\n return null;\n}\n\n/**\n * A LICENSE file under any conventional name (#6018).\n *\n * The previous check was `entries.includes('LICENSE') || includes('LICENSE.md')`,\n * which misses the Rust/Go convention of dual-licensing as `LICENSE-APACHE` +\n * `LICENSE-MIT`. `repo_analyze` therefore reported \"No LICENSE file\" for a repo\n * whose own `topLevelEntries` — in the same response — listed both.\n */\nfunction hasLicenseFileIn(entries: readonly string[]): boolean {\n return entries.some((e) => /^licen[cs]e/i.test(e));\n}\n\n/**\n * CODEOWNERS in any location GitHub honours (#6018).\n *\n * GitHub reads it from the repo root, `.github/`, or `docs/`. Checking only the\n * root reported \"No CODEOWNERS file\" against a repo carrying a 31-line\n * `.github/CODEOWNERS`, which is where most projects put it.\n *\n * `dotGithubEntries` is the listing of `.github/` when it could be fetched;\n * pass an empty array when it could not, in which case a root-only miss is\n * UNMEASURED rather than a gap — see {@link identifyGaps}.\n */\nfunction hasCodeownersFile(\n entries: readonly string[],\n dotGithubEntries: readonly string[],\n docsEntries: readonly string[] = []\n): boolean {\n return (\n entries.includes('CODEOWNERS') ||\n dotGithubEntries.includes('CODEOWNERS') ||\n docsEntries.includes('CODEOWNERS')\n );\n}\n\n/**\n * Whether CODEOWNERS is genuinely absent, as opposed to merely unlooked-at.\n *\n * Returns false — no gap — when `.github/` exists but could not be listed. An\n * absence nobody checked is not a finding, and reporting it as one is the\n * defect this whole change is about (#6018).\n */\nfunction codeownersIsMissing(entries: readonly string[], lookup: CodeownersLookup): boolean {\n if (hasCodeownersFile(entries, lookup.entries ?? [])) return false;\n const unlooked = entries.includes('.github') && lookup.listed !== true;\n return !unlooked;\n}\n\n/** Gap detection rules: [files-any-present, gap message]. */\nconst GAP_RULES: ReadonlyArray<readonly [readonly string[], string]> = [\n [['SECURITY.md'], 'No SECURITY.md policy'],\n // CODEOWNERS and LICENSE are matched by predicate, not exact name — see\n // hasCodeownersFile / hasLicenseFile. GitHub honours CODEOWNERS in three\n // locations and Rust/Go dual-license as LICENSE-APACHE + LICENSE-MIT (#6018).\n [\n ['.semgrep.yml', '.semgrep', '.grype.yaml', '.snyk'],\n 'No SAST/SCA security scanning configured',\n ],\n // Test detection handled separately via detectTestInfra (supports monorepo + co-located patterns)\n [['.gitignore'], 'No .gitignore file'],\n];\n\n/** Scanner recommendation per language. Canonical source: secure-language-stacks. */\ninterface LanguageScanners {\n readonly sast: readonly string[];\n readonly sca: readonly string[];\n}\n\nconst LANGUAGE_SCANNER_MATRIX: Readonly<Record<string, LanguageScanners>> = {\n TypeScript: {\n sast: ['semgrep (p/typescript, p/nodejs)', 'eslint-plugin-security'],\n sca: ['osv-scanner', 'npm audit'],\n },\n JavaScript: {\n sast: ['semgrep (p/javascript, p/nodejs)', 'eslint-plugin-security'],\n sca: ['osv-scanner', 'npm audit'],\n },\n Python: {\n sast: ['semgrep (p/python)', 'bandit'],\n sca: ['osv-scanner', 'pip-audit'],\n },\n Java: {\n sast: ['semgrep (p/java)', 'spotbugs + find-sec-bugs'],\n sca: ['osv-scanner', 'OWASP dependency-check'],\n },\n Go: {\n sast: ['semgrep (p/golang)', 'gosec'],\n sca: ['osv-scanner', 'govulncheck'],\n },\n Rust: {\n sast: ['semgrep (p/rust)'],\n sca: ['osv-scanner', 'cargo-audit'],\n },\n 'C++': {\n sast: ['semgrep (p/c)', 'cppcheck'],\n sca: ['osv-scanner'],\n },\n C: {\n sast: ['semgrep (p/c)', 'cppcheck'],\n sca: ['osv-scanner'],\n },\n Kotlin: {\n sast: ['semgrep (p/kotlin)', 'detekt'],\n sca: ['osv-scanner', 'OWASP dependency-check'],\n },\n Swift: {\n sast: ['semgrep (p/swift)'],\n sca: ['osv-scanner'],\n },\n Ruby: {\n sast: ['semgrep (p/ruby)', 'brakeman'],\n sca: ['osv-scanner', 'bundler-audit'],\n },\n PHP: {\n sast: ['semgrep (p/php)', 'phpstan'],\n sca: ['osv-scanner', 'composer audit'],\n },\n Shell: {\n sast: ['semgrep (p/bash)', 'shellcheck'],\n sca: [],\n },\n HCL: {\n sast: ['semgrep (p/terraform)', 'tfsec'],\n sca: ['osv-scanner'],\n },\n};\n\n/** Generate language-specific scanner recommendations when SAST/SCA is missing. */\nexport function getLanguageRecommendations(\n language: string | null,\n securityTooling: readonly string[]\n): readonly string[] {\n if (language === null) return [];\n const scanners = LANGUAGE_SCANNER_MATRIX[language];\n if (scanners === undefined) return [];\n\n const hasSast = securityTooling.includes('semgrep') || securityTooling.includes('snyk');\n const hasSca =\n securityTooling.includes('osv-scanner') ||\n securityTooling.includes('grype') ||\n securityTooling.includes('snyk');\n\n const recs: string[] = [];\n if (!hasSast && scanners.sast.length > 0) {\n const tools = scanners.sast.join(', ');\n recs.push(`${language} project missing SAST: ${tools}`);\n }\n if (!hasSca && scanners.sca.length > 0) {\n const tools = scanners.sca.join(', ');\n recs.push(`${language} project missing SCA: ${tools}`);\n }\n return recs;\n}\n\n/** SAST tool names that suppress the generic gap message. */\nconst SAST_TOOLS = new Set(['semgrep', 'codeql', 'snyk']);\nconst SAST_GAP_MSG = 'No SAST/SCA security scanning configured';\n\n/** What the SAST gap says when the workflows listing failed (#6035). */\nconst SAST_UNVERIFIED_MSG = 'SAST/SCA scanning unverified — .github/workflows could not be listed';\n\n/**\n * Resolve the SAST/SCA gap against what was actually observed (#1674, #6035).\n *\n * Three outcomes, not two. A detected tool removes the gap. An unmeasured\n * workflows listing REPLACES the assertion with an unverified statement,\n * because CI-level SAST detection is exactly what that listing provides — with\n * it absent, \"no scanning is configured\" is a claim the analysis cannot make.\n * Only a successful listing that found nothing leaves the gap asserted.\n */\nfunction removeSastGapIfToolDetected(\n gaps: string[],\n secTools: readonly string[],\n workflowsMeasured: boolean\n): void {\n const idx = gaps.indexOf(SAST_GAP_MSG);\n if (idx === -1) return;\n if (secTools.some((t) => SAST_TOOLS.has(t))) {\n gaps.splice(idx, 1);\n return;\n }\n if (!workflowsMeasured) gaps[idx] = SAST_UNVERIFIED_MSG;\n}\n\n/**\n * The three gaps that cannot be judged from an exact-filename table (#6018).\n *\n * Each needs either a glob (LICENSE-APACHE), a second directory listing\n * (.github/CODEOWNERS), or the repo's language (Rust keeps tests where a\n * top-level listing cannot see them). Extracted from {@link identifyGaps} to\n * keep that function under the complexity cap, and because these three share a\n * property the table-driven rules do not: each can be UNMEASURABLE, and must\n * stay silent rather than assert an absence nobody checked.\n */\nfunction judgedGaps(\n entries: readonly string[],\n language: string | null | undefined,\n codeowners: CodeownersLookup\n): string[] {\n const gaps: string[] = [];\n if (!hasLicenseFileIn(entries)) gaps.push('No LICENSE file');\n if (codeownersIsMissing(entries, codeowners)) gaps.push('No CODEOWNERS file');\n const tests = detectTestInfraMeasured(entries, language ?? null);\n if (tests.measured && !tests.hasTests) gaps.push('No test directory detected');\n return gaps;\n}\n\n/**\n * Apply the listing defaults in ONE place.\n *\n * Inline `??` chains at each use site put the defaults inside the functions\n * that consume them, which tipped both past the complexity cap and — more to\n * the point — scattered the decision about what an omitted listing means.\n * `workflowsMeasured` defaults TRUE because an omitted flag comes from a caller\n * that did no listing at all (the unit-test callers), not from a failed one;\n * a failed listing passes false explicitly.\n */\nfunction resolveListings(listings: RepoListings): Required<RepoListings> {\n return {\n dotGithubEntries: listings.dotGithubEntries ?? [],\n dotGithubListed: listings.dotGithubListed ?? false,\n workflowsMeasured: listings.workflowsMeasured ?? true,\n };\n}\n\n/**\n * Apply the observation defaults in one place, for the same reason\n * {@link resolveListings} exists: inline `??`/destructuring defaults inside\n * `identifyGaps` pushed it past the complexity cap, and scattered the decision\n * about what an omitted observation means.\n */\nfunction resolveObserved(observed: GapObservations): Required<GapObservations> {\n return {\n codeowners: observed.codeowners ?? {},\n workflowsMeasured: observed.workflowsMeasured ?? true,\n };\n}\n\n/** Identify gaps in repository best practices. */\nexport function identifyGaps(\n entries: readonly string[],\n ciProvider: string | null,\n language?: string | null,\n securityTooling?: readonly string[],\n /**\n * What the listings actually observed. Bundled rather than two more\n * positional params: they travel together, they are both \"what did we manage\n * to measure\" rather than \"what did we find\", and two more defaults tipped\n * this function past the complexity cap.\n */\n observed: GapObservations = {}\n): readonly string[] {\n const { codeowners, workflowsMeasured } = resolveObserved(observed);\n const gaps: string[] = [];\n if (ciProvider === null) gaps.push('No CI/CD configuration detected');\n for (const [files, message] of GAP_RULES) {\n if (!files.some((f) => entries.includes(f))) gaps.push(message);\n }\n\n gaps.push(...judgedGaps(entries, language, codeowners));\n\n // Resolve the SAST/SCA gap against what was observed (#1674, #6035)\n removeSastGapIfToolDetected(gaps, securityTooling ?? [], workflowsMeasured);\n\n // Language-specific recommendations when generic SAST/SCA gap detected\n const hasGenericSecGap = gaps.includes('No SAST/SCA security scanning configured');\n if (\n hasGenericSecGap &&\n language !== null &&\n language !== undefined &&\n securityTooling !== undefined\n ) {\n const langRecs = getLanguageRecommendations(language, securityTooling);\n gaps.push(...langRecs);\n }\n\n return gaps;\n}\n\n// ============================================================================\n// Core\n// ============================================================================\n\n/** GitHub repo metadata from the API. */\nexport interface GhRepoMetadata {\n readonly name: string;\n readonly full_name: string;\n readonly description: string | null;\n readonly language: string | null;\n readonly default_branch: string;\n readonly stargazers_count: number;\n readonly license: { readonly spdx_id: string } | null;\n}\n\n/** Analyze a GitHub repository given its metadata and file tree. */\nexport function analyzeRepo(\n metadata: GhRepoMetadata,\n topLevelEntries: readonly string[],\n workflowEntries?: readonly string[],\n /** What each secondary listing observed — grouped, not four positional flags. */\n listings: RepoListings = {}\n): RepoAnalysis {\n const { dotGithubEntries, dotGithubListed, workflowsMeasured } = resolveListings(listings);\n const ciProvider = detectCiProvider(topLevelEntries);\n const secTooling = detectSecurityTooling(topLevelEntries, workflowEntries);\n const tests = detectTestInfraMeasured(topLevelEntries, metadata.language);\n\n return {\n name: metadata.full_name,\n language: metadata.language,\n framework: detectFramework(topLevelEntries),\n packageManager: detectPackageManager(topLevelEntries),\n ciProvider,\n securityTooling: secTooling,\n // Match `Dockerfile`, `Dockerfile.<purpose>` (e.g. `Dockerfile.sandbox`),\n // and docker-compose variants. Pre-#2730 the check was exact-match only,\n // so a repo with three legitimate `Dockerfile.*` files reported false.\n hasDockerfile:\n topLevelEntries.some((e) => e === 'Dockerfile' || e.startsWith('Dockerfile.')) ||\n topLevelEntries.includes('docker-compose.yml') ||\n topLevelEntries.includes('docker-compose.yaml'),\n hasHelmCharts:\n topLevelEntries.includes('Chart.yaml') ||\n topLevelEntries.includes('charts') ||\n topLevelEntries.includes('helm'),\n hasMakefile: topLevelEntries.includes('Makefile'),\n hasTests: tests.hasTests,\n testsMeasured: tests.measured,\n license: metadata.license?.spdx_id ?? null,\n description: metadata.description,\n defaultBranch: metadata.default_branch,\n stars: metadata.stargazers_count,\n topLevelEntries: [...topLevelEntries],\n gaps: identifyGaps(topLevelEntries, ciProvider, metadata.language, secTooling, {\n codeowners: { entries: dotGithubEntries, listed: dotGithubListed },\n workflowsMeasured,\n }),\n workflowsMeasured,\n };\n}\n\n/** Non-code languages to exclude when detecting primary language. */\nconst MARKUP_LANGUAGES = new Set([\n 'HTML',\n 'CSS',\n 'SCSS',\n 'Less',\n 'Markdown',\n 'Roff',\n 'SVG',\n 'XML',\n 'XSLT',\n 'Mustache',\n 'Handlebars',\n 'EJS',\n]);\n\n/** Detect primary language from GitHub languages API (byte counts). */\nfunction detectPrimaryLanguage(\n languages: Record<string, number>,\n fallback: string | null\n): string | null {\n const sorted = Object.entries(languages)\n .filter(([lang]) => !MARKUP_LANGUAGES.has(lang))\n .sort((a, b) => b[1] - a[1]);\n const top = sorted[0];\n return top !== undefined ? top[0] : fallback;\n}\n\n/** Check for test infrastructure beyond top-level directories. */\nfunction detectTestInfra(entries: readonly string[]): boolean {\n const testDirs = ['tests', 'test', '__tests__', 'spec'];\n if (testDirs.some((d) => entries.includes(d))) return true;\n // Check for test config files (co-located test pattern, monorepos)\n const testConfigs = [\n 'vitest.config.ts',\n 'vitest.config.js',\n 'vitest.config.mts',\n 'vitest.workspace.ts',\n 'vitest.workspace.js',\n 'jest.config.ts',\n 'jest.config.js',\n 'jest.config.mjs',\n 'cypress.config.ts',\n 'cypress.config.js',\n 'playwright.config.ts',\n '.mocharc.yml',\n '.mocharc.json',\n ];\n if (testConfigs.some((c) => entries.includes(c))) return true;\n // Monorepo: packages/ dir + package.json implies co-located tests\n return entries.includes('packages') && entries.includes('package.json');\n}\n\n/**\n * Languages whose test layout the probes above actually understand.\n *\n * The list is the honest boundary of {@link detectTestInfra}: every rule in it\n * looks for a JS/TS-shaped root `tests/` directory or a JS test-runner config.\n * A language absent from this list is not \"a repo without tests\" — it is a repo\n * this function cannot measure, and #6018 is what happens when the two are\n * conflated (a 9-crate Rust workspace with 1385 `#[test]` functions reported\n * `hasTests: false` and \"No test directory detected\").\n *\n * Adding a language here is a promise that the probes below recognise its\n * conventions. Rust is deliberately ABSENT: its tests live in `#[cfg(test)]`\n * modules inside source files and in per-crate `tests/` directories, neither of\n * which a top-level listing can see.\n */\nconst TEST_DETECTABLE_LANGUAGES: ReadonlySet<string> = new Set([\n 'TypeScript',\n 'JavaScript',\n 'Python',\n 'Ruby',\n 'PHP',\n]);\n\n/** Test detection plus whether it was measurable at all (#6018). */\ninterface TestInfraVerdict {\n readonly hasTests: boolean;\n readonly measured: boolean;\n}\n\n/**\n * Detect tests, reporting `measured: false` when the repo's language has no\n * probe rather than reporting a JS-shaped absence as a finding (#6018).\n *\n * A positive detection is trusted regardless of language: a root `tests/`\n * directory means tests whoever wrote it. Only the NEGATIVE needs the\n * language guard, because that is the direction that fabricates a gap.\n */\nfunction detectTestInfraMeasured(\n entries: readonly string[],\n language: string | null\n): TestInfraVerdict {\n const detected = detectTestInfra(entries);\n if (detected) return { hasTests: true, measured: true };\n const measured = language !== null && TEST_DETECTABLE_LANGUAGES.has(language);\n return { hasTests: false, measured };\n}\n\n/** Infer code language from project files when GitHub reports markup. */\nfunction inferLanguageFromEntries(\n entries: readonly string[],\n fallback: string | null\n): string | null {\n if (entries.includes('tsconfig.json')) return 'TypeScript';\n if (entries.includes('Cargo.toml')) return 'Rust';\n if (entries.includes('go.mod')) return 'Go';\n if (entries.includes('pyproject.toml') || entries.includes('setup.py')) return 'Python';\n if (entries.includes('pom.xml') || entries.includes('build.gradle')) return 'Java';\n if (entries.includes('Gemfile')) return 'Ruby';\n if (entries.includes('package.json')) return 'JavaScript';\n return fallback;\n}\n\n/** Lazy-load promisified execFile. */\nasync function getExecFile(): Promise<ExecFileFn> {\n const { execFile } = await import('node:child_process');\n const { promisify } = await import('node:util');\n return promisify(execFile);\n}\n\n/** Fetch repo metadata and languages via GitHub API. */\nasync function fetchRepoData(\n repoId: string,\n exec: ExecFileFn\n): Promise<{ metadata: GhRepoMetadata; entries: string[] }> {\n const { stdout: metaJson } = await exec(\n 'gh',\n [\n 'api',\n `repos/${repoId}`,\n '--jq',\n '{name: .name, full_name: .full_name, description: .description, language: .language, default_branch: .default_branch, stargazers_count: .stargazers_count, license: .license}',\n ],\n { timeout: 30_000 }\n );\n let parsed: unknown;\n try {\n parsed = JSON.parse(metaJson.trim());\n } catch {\n throw new Error(`Failed to parse repo metadata for ${repoId}: ${metaJson.slice(0, 200)}`);\n }\n // Closes #2962 (P1): Zod-validate the parsed JSON instead of casting\n // blindly. Pre-fix, a GitHub-side schema drift produced a typed-but-\n // mismatched object that crashed deep in `analyzeRepo` or silently\n // surfaced a wrong field (e.g., enhanced.license.spdx_id null →\n // \"no license\" — same shape as #2943).\n const validated = GhRepoMetadataSchema.safeParse(parsed);\n if (!validated.success) {\n throw new Error(\n `Repo metadata schema mismatch for ${repoId}: ${validated.error.message} ` +\n `(payload preview: ${metaJson.slice(0, 200)})`\n );\n }\n const metadata: GhRepoMetadata = validated.data;\n const { stdout: contentsJson } = await exec(\n 'gh',\n ['api', `repos/${repoId}/contents`, '--jq', '[.[].name]'],\n { timeout: 30_000 }\n );\n let entries: string[];\n try {\n const parsed: unknown = JSON.parse(contentsJson.trim());\n entries = Array.isArray(parsed) ? parsed.filter((e): e is string => typeof e === 'string') : [];\n } catch {\n throw new Error(`Failed to parse repo contents for ${repoId}: ${contentsJson.slice(0, 200)}`);\n }\n return { metadata, entries };\n}\n\n/** Resolve NOASSERTION license via the GitHub license API. */\nasync function resolveLicense(repoId: string, exec: ExecFileFn): Promise<string | null> {\n try {\n const { stdout } = await exec(\n 'gh',\n ['api', `repos/${repoId}/license`, '--jq', '.license.spdx_id'],\n { timeout: 15_000 }\n );\n const spdxId = stdout.trim();\n if (spdxId !== '' && spdxId !== 'null' && spdxId !== 'NOASSERTION') {\n return spdxId;\n }\n } catch {\n // Keep NOASSERTION if license API also fails\n }\n return null;\n}\n\n/** Resolve primary language, falling back to entry inference for markup repos. */\nasync function resolveLanguage(\n repoId: string,\n entries: readonly string[],\n metadata: GhRepoMetadata,\n exec: ExecFileFn\n): Promise<string | null> {\n let languages: Record<string, number> = {};\n try {\n const { stdout } = await exec('gh', ['api', `repos/${repoId}/languages`], { timeout: 15_000 });\n languages = JSON.parse(stdout.trim()) as Record<string, number>;\n } catch {\n /* fall back to metadata.language */\n }\n const primary = detectPrimaryLanguage(languages, metadata.language);\n if (primary === null || MARKUP_LANGUAGES.has(primary)) {\n return inferLanguageFromEntries(entries, primary);\n }\n return primary;\n}\n\n/**\n * Fetch workflow filenames from `.github/workflows/` (#1674).\n *\n * Returns `listed: false` when the directory could not be read (#6035), so a\n * miss stays unmeasured instead of becoming a false gap — the same discipline\n * {@link fetchDotGithubEntries} got in #6018. This one returned a bare `[]` on\n * any error, which is indistinguishable from a repo with no workflows, and\n * `removeSastGapIfToolDetected` then left \"No SAST/SCA security scanning\n * configured\" standing for a repo running CodeQL. A 403 from a secondary rate\n * limit or a token without `contents` scope was enough.\n */\nasync function fetchWorkflowEntries(\n repoId: string,\n exec: ExecFileFn\n): Promise<{ entries: readonly string[]; listed: boolean }> {\n try {\n const { stdout } = await exec(\n 'gh',\n ['api', `repos/${repoId}/contents/.github/workflows`, '--jq', '[.[].name]'],\n { timeout: 15_000 }\n );\n const parsed: unknown = JSON.parse(stdout.trim());\n const entries = Array.isArray(parsed)\n ? parsed.filter((e): e is string => typeof e === 'string')\n : [];\n return { entries, listed: true };\n } catch {\n // Cannot distinguish \"no workflows directory\" from \"the API call failed\",\n // so report the weaker claim. A 404 for a repo with no workflows is\n // therefore also unmeasured here; the SAST gap is then stated as unverified\n // rather than asserted, which is the honest reading of both.\n return { entries: [], listed: false };\n }\n}\n\n/**\n * Fetch the `.github/` listing so CODEOWNERS can be found where GitHub actually\n * honours it (#6018). Returns `listed: false` when the directory could not be\n * read, so a miss stays unmeasured instead of becoming a false gap.\n */\nasync function fetchDotGithubEntries(\n repoId: string,\n exec: ExecFileFn\n): Promise<{ entries: readonly string[]; listed: boolean }> {\n try {\n const { stdout } = await exec(\n 'gh',\n ['api', `repos/${repoId}/contents/.github`, '--jq', '[.[].name]'],\n { timeout: 15_000 }\n );\n const parsed: unknown = JSON.parse(stdout.trim());\n return Array.isArray(parsed)\n ? { entries: parsed.filter((e): e is string => typeof e === 'string'), listed: true }\n : { entries: [], listed: false };\n } catch {\n return { entries: [], listed: false };\n }\n}\n\n/** Fetch repo data from GitHub and produce analysis. */\nexport async function analyzeGitHubRepo(\n input: RepoAnalyzeInput,\n /**\n * Injected `gh` runner, so the FETCH path is testable and not only the\n * pure functions downstream of it (#6035).\n *\n * Without this, reverting `fetchWorkflowEntries` to report `listed: true`\n * on error broke no test: the flag was exercised by injecting it into\n * `identifyGaps` directly, while the producer that derives it had no\n * coverage at all. Every other fetch in this module already takes an\n * `ExecFileFn`; the entry point was the one place that did not.\n */\n execOverride?: ExecFileFn\n): Promise<RepoAnalysis> {\n const repoId = normalizeRepoId(input.repo);\n const exec = execOverride ?? (await getExecFile());\n const { metadata, entries } = await fetchRepoData(repoId, exec);\n\n const primaryLang = await resolveLanguage(repoId, entries, metadata, exec);\n const enhanced = { ...metadata, language: primaryLang };\n\n // Resolve null or NOASSERTION license when LICENSE file exists\n const hasLicenseFile = hasLicenseFileIn(entries);\n const licenseUnresolved = enhanced.license === null || enhanced.license.spdx_id === 'NOASSERTION';\n if (licenseUnresolved && hasLicenseFile) {\n const resolved = await resolveLicense(repoId, exec);\n if (resolved !== null) enhanced.license = { spdx_id: resolved };\n }\n\n // Fetch workflow filenames for CI-level security detection (#1674)\n const workflows = entries.includes('.github')\n ? await fetchWorkflowEntries(repoId, exec)\n : { entries: [] as readonly string[], listed: true }; // no .github/ at all = measured absence\n const dotGithub = entries.includes('.github')\n ? await fetchDotGithubEntries(repoId, exec)\n : { entries: [] as readonly string[], listed: true }; // no .github/ at all = measured absence\n\n return analyzeRepo(enhanced, entries, workflows.entries, {\n dotGithubEntries: dotGithub.entries,\n dotGithubListed: dotGithub.listed,\n workflowsMeasured: workflows.listed,\n });\n}\n"],"mappings":"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","names":["parsed"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/version.ts
|
|
2
2
|
import semver from "semver";
|
|
3
|
-
var VERSION = true ? "8.47.
|
|
3
|
+
var VERSION = true ? "8.47.7" : "dev";
|
|
4
4
|
var NODE_ENGINE_RANGE = ">=22.5.0";
|
|
5
5
|
function isNodeVersionSupported(version) {
|
|
6
6
|
return semver.satisfies(version, NODE_ENGINE_RANGE);
|
|
@@ -11,4 +11,4 @@ export {
|
|
|
11
11
|
NODE_ENGINE_RANGE,
|
|
12
12
|
isNodeVersionSupported
|
|
13
13
|
};
|
|
14
|
-
//# sourceMappingURL=chunk-
|
|
14
|
+
//# sourceMappingURL=chunk-6B7YJMG4.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getErrorMessage
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-QURCW325.js";
|
|
4
4
|
|
|
5
5
|
// src/cli/setup-config.ts
|
|
6
6
|
import { copyFileSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
@@ -77,4 +77,4 @@ function ensureBackup(outputPath) {
|
|
|
77
77
|
export {
|
|
78
78
|
runConfigInitSync
|
|
79
79
|
};
|
|
80
|
-
//# sourceMappingURL=chunk-
|
|
80
|
+
//# sourceMappingURL=chunk-7PN6YCEA.js.map
|
|
@@ -5,34 +5,34 @@ import {
|
|
|
5
5
|
planOptionalParams,
|
|
6
6
|
requireApiKey,
|
|
7
7
|
validateApiKeyPresence
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-DYSJLP7T.js";
|
|
9
9
|
import {
|
|
10
10
|
CUSTOM_API_DEFAULT_MODEL
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-CXXQ36SZ.js";
|
|
12
12
|
import {
|
|
13
13
|
CUSTOM_API_BASE_URL_ENV,
|
|
14
14
|
PROVIDER_ENV_KEYS,
|
|
15
15
|
assertCustomApiHostResolvesPublic,
|
|
16
16
|
validateCustomApiBaseUrl
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-KAGMXQMM.js";
|
|
18
18
|
import {
|
|
19
19
|
nexusMkdtempSync
|
|
20
20
|
} from "./chunk-T46RV7Y7.js";
|
|
21
21
|
import {
|
|
22
22
|
getAvailabilityCache
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-REEQOJUH.js";
|
|
24
24
|
import {
|
|
25
25
|
extractSystemPrompt
|
|
26
26
|
} from "./chunk-QZUG667L.js";
|
|
27
27
|
import {
|
|
28
28
|
generateHyphenId
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-3QAL5UIY.js";
|
|
30
30
|
import {
|
|
31
31
|
CliCircuitBreaker,
|
|
32
32
|
DEFAULT_CIRCUIT_BREAKER_CONFIG,
|
|
33
33
|
getCliCircuitBreakerSnapshot,
|
|
34
34
|
getDefaultCliCircuitBreakerRegistry
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-DN47AWK3.js";
|
|
36
36
|
import {
|
|
37
37
|
CLI_SUBPROCESS_TIMEOUTS,
|
|
38
38
|
CLI_TIMEOUTS,
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
resolveCliModelName,
|
|
74
74
|
resolveRetryAfterMs,
|
|
75
75
|
retryAfterMsFromContext
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-QURCW325.js";
|
|
77
77
|
import {
|
|
78
78
|
parseBoolValue
|
|
79
79
|
} from "./chunk-BTYRPZON.js";
|
|
@@ -4992,4 +4992,4 @@ export {
|
|
|
4992
4992
|
SdkAdapter,
|
|
4993
4993
|
createAutoAdapter
|
|
4994
4994
|
};
|
|
4995
|
-
//# sourceMappingURL=chunk-
|
|
4995
|
+
//# sourceMappingURL=chunk-7S4ZLD4G.js.map
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
GitHubProvider,
|
|
3
3
|
ScmError
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ETTYFUV6.js";
|
|
5
5
|
import {
|
|
6
6
|
resolveToken
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-3KA4RFGM.js";
|
|
8
8
|
import {
|
|
9
9
|
err,
|
|
10
10
|
ok
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-QURCW325.js";
|
|
12
12
|
|
|
13
13
|
// src/scm/factory.ts
|
|
14
14
|
async function createScmProvider(config) {
|
|
@@ -41,4 +41,4 @@ export {
|
|
|
41
41
|
createScmProvider,
|
|
42
42
|
createGitHubProvider
|
|
43
43
|
};
|
|
44
|
-
//# sourceMappingURL=chunk-
|
|
44
|
+
//# sourceMappingURL=chunk-AA5OUZR6.js.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
analyzeGitHubRepo
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-4GDMHCKX.js";
|
|
4
4
|
import {
|
|
5
5
|
createLogger,
|
|
6
6
|
getTimeProvider
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QURCW325.js";
|
|
8
8
|
|
|
9
9
|
// src/mcp/tools/scanner-registry-fetcher.ts
|
|
10
10
|
import { z } from "zod";
|
|
@@ -721,4 +721,4 @@ export {
|
|
|
721
721
|
generateSecurityPlan,
|
|
722
722
|
buildPlanFromAnalysis
|
|
723
723
|
};
|
|
724
|
-
//# sourceMappingURL=chunk-
|
|
724
|
+
//# sourceMappingURL=chunk-BY6NRKVI.js.map
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
MCP_TIMEOUTS,
|
|
6
6
|
TEST_TIMEOUTS,
|
|
7
7
|
WORKFLOW_TIMEOUTS
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-QURCW325.js";
|
|
9
9
|
import {
|
|
10
10
|
createGetEnvVarDocumentation,
|
|
11
11
|
createGetTimeout,
|
|
@@ -224,4 +224,4 @@ export {
|
|
|
224
224
|
CUSTOM_API_DEFAULT_MODEL,
|
|
225
225
|
DEFAULTS
|
|
226
226
|
};
|
|
227
|
-
//# sourceMappingURL=chunk-
|
|
227
|
+
//# sourceMappingURL=chunk-CXXQ36SZ.js.map
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
getTimeProvider,
|
|
9
9
|
isRateLimitText,
|
|
10
10
|
ok
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-QURCW325.js";
|
|
12
12
|
|
|
13
13
|
// src/cli-adapters/circuit-breaker-types.ts
|
|
14
14
|
var CircuitErrorCode = {
|
|
@@ -541,4 +541,4 @@ export {
|
|
|
541
541
|
CliCircuitBreakerIntegration,
|
|
542
542
|
createCliCircuitBreakerIntegration
|
|
543
543
|
};
|
|
544
|
-
//# sourceMappingURL=chunk-
|
|
544
|
+
//# sourceMappingURL=chunk-DN47AWK3.js.map
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
lookupInTreeCapability,
|
|
14
14
|
ok,
|
|
15
15
|
resolveRetryAfterMs
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-QURCW325.js";
|
|
17
17
|
|
|
18
18
|
// src/config/model-parameter-support.ts
|
|
19
19
|
function parseClaudeMajorMinor(bareId) {
|
|
@@ -834,4 +834,4 @@ export {
|
|
|
834
834
|
DEFAULT_COLLECT_STREAM_MAX_CHUNKS,
|
|
835
835
|
collectStream
|
|
836
836
|
};
|
|
837
|
-
//# sourceMappingURL=chunk-
|
|
837
|
+
//# sourceMappingURL=chunk-DYSJLP7T.js.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
err,
|
|
5
5
|
getErrorMessage,
|
|
6
6
|
ok
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-QURCW325.js";
|
|
8
8
|
|
|
9
9
|
// src/scm/types.ts
|
|
10
10
|
var ScmError = class extends Error {
|
|
@@ -281,4 +281,4 @@ export {
|
|
|
281
281
|
ScmError,
|
|
282
282
|
GitHubProvider
|
|
283
283
|
};
|
|
284
|
-
//# sourceMappingURL=chunk-
|
|
284
|
+
//# sourceMappingURL=chunk-ETTYFUV6.js.map
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./chunk-7LP6VJRP.js";
|
|
6
6
|
import {
|
|
7
7
|
SessionMemory
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-QYPDW4PU.js";
|
|
9
9
|
import {
|
|
10
10
|
StatsOnlyAdapter,
|
|
11
11
|
ensureSharedMemoryRegistry
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "./chunk-MUJCGBZW.js";
|
|
16
16
|
import {
|
|
17
17
|
generateId
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-3QAL5UIY.js";
|
|
19
19
|
import {
|
|
20
20
|
ErrorCode,
|
|
21
21
|
NexusError,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
ok,
|
|
30
30
|
openSqliteDatabase,
|
|
31
31
|
setSharedMobiMemDbPathResolver
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-QURCW325.js";
|
|
33
33
|
import {
|
|
34
34
|
nexusDataPath
|
|
35
35
|
} from "./chunk-BTYRPZON.js";
|
|
@@ -5825,4 +5825,4 @@ export {
|
|
|
5825
5825
|
reinitializeMemoryBackends,
|
|
5826
5826
|
ToolMemoryManager
|
|
5827
5827
|
};
|
|
5828
|
-
//# sourceMappingURL=chunk-
|
|
5828
|
+
//# sourceMappingURL=chunk-FMTKKJP7.js.map
|