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.
Files changed (132) hide show
  1. package/dist/{ast-rule-runner-KZJJJQAW.js → ast-rule-runner-EHBBZKQ7.js} +3 -3
  2. package/dist/{child-mcp-config-L3ZAUYGJ.js → child-mcp-config-H7Q4VHVK.js} +2 -2
  3. package/dist/{chunk-N337ROIP.js → chunk-3KA4RFGM.js} +2 -2
  4. package/dist/{chunk-W4XJF3PW.js → chunk-3QAL5UIY.js} +2 -2
  5. package/dist/{chunk-U2PGDAEV.js → chunk-4GDMHCKX.js} +41 -16
  6. package/dist/chunk-4GDMHCKX.js.map +1 -0
  7. package/dist/{chunk-MQ6CM6NH.js → chunk-6B7YJMG4.js} +2 -2
  8. package/dist/{chunk-U6BOS5XZ.js → chunk-7PN6YCEA.js} +2 -2
  9. package/dist/{chunk-WZP2FPWL.js → chunk-7S4ZLD4G.js} +8 -8
  10. package/dist/{chunk-F2JOZIHL.js → chunk-AA5OUZR6.js} +4 -4
  11. package/dist/{chunk-I3BILDI6.js → chunk-BY6NRKVI.js} +3 -3
  12. package/dist/{chunk-DYR5CK4E.js → chunk-CXXQ36SZ.js} +2 -2
  13. package/dist/{chunk-YM4627WM.js → chunk-DN47AWK3.js} +2 -2
  14. package/dist/{chunk-TBGEN6TO.js → chunk-DYSJLP7T.js} +2 -2
  15. package/dist/{chunk-5FXRCQPV.js → chunk-ETTYFUV6.js} +2 -2
  16. package/dist/{chunk-VIXGTZL4.js → chunk-FMTKKJP7.js} +4 -4
  17. package/dist/chunk-FMTKKJP7.js.map +1 -0
  18. package/dist/{chunk-EFJOWG5H.js → chunk-FTOJAN24.js} +4 -4
  19. package/dist/{chunk-RIA23PDE.js → chunk-JF74MIER.js} +2 -2
  20. package/dist/{chunk-TJMJ47DS.js → chunk-JMUITMBB.js} +2 -2
  21. package/dist/{chunk-XJN57QGS.js → chunk-JOP5NFAQ.js} +2 -2
  22. package/dist/{chunk-A7HQNXWO.js → chunk-KAGMXQMM.js} +2 -2
  23. package/dist/{chunk-V5UQBZEV.js → chunk-KNGST6PU.js} +3 -3
  24. package/dist/{chunk-OS5X43GP.js → chunk-KVWEVIPU.js} +38 -38
  25. package/dist/{chunk-OS5X43GP.js.map → chunk-KVWEVIPU.js.map} +1 -1
  26. package/dist/{chunk-JLRJ3WU7.js → chunk-LOU252L2.js} +6 -6
  27. package/dist/{chunk-2I4XNHJA.js → chunk-MWQ2UYSX.js} +2 -2
  28. package/dist/{chunk-6TYTVKWM.js → chunk-O72VDOFO.js} +2 -2
  29. package/dist/{chunk-XTNJZG2X.js → chunk-OKSGCMDV.js} +3 -3
  30. package/dist/{chunk-J4XJ2O33.js → chunk-Q7O7SACB.js} +9 -9
  31. package/dist/{chunk-WJSSC4ZQ.js → chunk-QURCW325.js} +3 -3
  32. package/dist/{chunk-67M5BPTV.js → chunk-QYPDW4PU.js} +2 -2
  33. package/dist/{chunk-4YQSX2TU.js → chunk-REEQOJUH.js} +2 -2
  34. package/dist/{chunk-BVNOK5P6.js → chunk-RVPB3BHL.js} +7 -7
  35. package/dist/{chunk-NY2DCMDD.js → chunk-RWC5WRR3.js} +5 -5
  36. package/dist/{chunk-M3P5B3RG.js → chunk-U54ZN4E6.js} +5 -5
  37. package/dist/{chunk-C5RLLXX2.js → chunk-UOYS6IQ4.js} +8 -8
  38. package/dist/{chunk-JUNUU76G.js → chunk-X3W235GA.js} +3 -3
  39. package/dist/{chunk-LJPCUYVD.js → chunk-XCKEQLRC.js} +4 -4
  40. package/dist/{chunk-LOOEJFT3.js → chunk-ZDUIEKVX.js} +2 -2
  41. package/dist/{cli-circuit-breaker-AAHKTJCY.js → cli-circuit-breaker-TWGNVVI2.js} +3 -3
  42. package/dist/cli.js +44 -44
  43. package/dist/{composite-router-OP66QH5X.js → composite-router-MKYW26IA.js} +2 -2
  44. package/dist/{consensus-vote-PXZ6P5W3.js → consensus-vote-TAZ2YBDV.js} +17 -17
  45. package/dist/{context-retriever-ZAYHL472.js → context-retriever-SNA6CRKC.js} +8 -8
  46. package/dist/{doctor-deep-T5IKW6X6.js → doctor-deep-LAWVMKF7.js} +3 -3
  47. package/dist/{doctor-live-TPYTCGOS.js → doctor-live-IMA6R5JK.js} +9 -9
  48. package/dist/{expert-bridge-QPMC75VN.js → expert-bridge-HNVJWGFN.js} +4 -4
  49. package/dist/{factory-ZU35O5V7.js → factory-HDDNT4Y4.js} +5 -5
  50. package/dist/{factory-YFFVVPNA.js → factory-I3QFIRBK.js} +9 -9
  51. package/dist/{improvement-review-CVJCZPMB.js → improvement-review-AKJN5RXY.js} +6 -6
  52. package/dist/index.d.ts +35 -2
  53. package/dist/index.js +32 -32
  54. package/dist/{init-opencode-SAZZWTN5.js → init-opencode-O6YZ22XI.js} +6 -6
  55. package/dist/issue-triage-U4WOMZSI.js +17 -0
  56. package/dist/{pr-reviewer-helpers-M2GPPYN2.js → pr-reviewer-helpers-RWNTTUMR.js} +4 -4
  57. package/dist/{registry-command-4SOG2KWX.js → registry-command-HFHNOECT.js} +2 -2
  58. package/dist/{repo-analyze-R6WFDFBV.js → repo-analyze-LNZ3Y6BR.js} +2 -2
  59. package/dist/{repo-security-plan-N4JBCHDO.js → repo-security-plan-4JKIYRQH.js} +4 -4
  60. package/dist/{research-helpers-synthesize-54VP4KYP.js → research-helpers-synthesize-4ZS432XJ.js} +4 -4
  61. package/dist/{routing-memory-UEOQNQ3G.js → routing-memory-FJFDW2BK.js} +2 -2
  62. package/dist/{session-memory-4INFFH6Q.js → session-memory-QP7J6YYG.js} +3 -3
  63. package/dist/{setup-config-BK4IWIRM.js → setup-config-4UWNJ52I.js} +3 -3
  64. package/dist/{setup-custom-api-4ROFGUFC.js → setup-custom-api-3G75IXNS.js} +4 -4
  65. package/dist/setup-data-dir-4ZJEO3GZ.js +30 -0
  66. package/dist/{tool-memory-AYT45WFG.js → tool-memory-HWESCWZI.js} +5 -5
  67. package/dist/{unified-registry-YLJGLNSD.js → unified-registry-M4MWH6HK.js} +10 -10
  68. package/dist/{weather-report-7TI7VRN7.js → weather-report-SCNDWSA4.js} +2 -2
  69. package/package.json +1 -1
  70. package/dist/chunk-U2PGDAEV.js.map +0 -1
  71. package/dist/chunk-VIXGTZL4.js.map +0 -1
  72. package/dist/issue-triage-AV7AF3R3.js +0 -17
  73. package/dist/setup-data-dir-G3EQQZL3.js +0 -30
  74. /package/dist/{ast-rule-runner-KZJJJQAW.js.map → ast-rule-runner-EHBBZKQ7.js.map} +0 -0
  75. /package/dist/{child-mcp-config-L3ZAUYGJ.js.map → child-mcp-config-H7Q4VHVK.js.map} +0 -0
  76. /package/dist/{chunk-N337ROIP.js.map → chunk-3KA4RFGM.js.map} +0 -0
  77. /package/dist/{chunk-W4XJF3PW.js.map → chunk-3QAL5UIY.js.map} +0 -0
  78. /package/dist/{chunk-MQ6CM6NH.js.map → chunk-6B7YJMG4.js.map} +0 -0
  79. /package/dist/{chunk-U6BOS5XZ.js.map → chunk-7PN6YCEA.js.map} +0 -0
  80. /package/dist/{chunk-WZP2FPWL.js.map → chunk-7S4ZLD4G.js.map} +0 -0
  81. /package/dist/{chunk-F2JOZIHL.js.map → chunk-AA5OUZR6.js.map} +0 -0
  82. /package/dist/{chunk-I3BILDI6.js.map → chunk-BY6NRKVI.js.map} +0 -0
  83. /package/dist/{chunk-DYR5CK4E.js.map → chunk-CXXQ36SZ.js.map} +0 -0
  84. /package/dist/{chunk-YM4627WM.js.map → chunk-DN47AWK3.js.map} +0 -0
  85. /package/dist/{chunk-TBGEN6TO.js.map → chunk-DYSJLP7T.js.map} +0 -0
  86. /package/dist/{chunk-5FXRCQPV.js.map → chunk-ETTYFUV6.js.map} +0 -0
  87. /package/dist/{chunk-EFJOWG5H.js.map → chunk-FTOJAN24.js.map} +0 -0
  88. /package/dist/{chunk-RIA23PDE.js.map → chunk-JF74MIER.js.map} +0 -0
  89. /package/dist/{chunk-TJMJ47DS.js.map → chunk-JMUITMBB.js.map} +0 -0
  90. /package/dist/{chunk-XJN57QGS.js.map → chunk-JOP5NFAQ.js.map} +0 -0
  91. /package/dist/{chunk-A7HQNXWO.js.map → chunk-KAGMXQMM.js.map} +0 -0
  92. /package/dist/{chunk-V5UQBZEV.js.map → chunk-KNGST6PU.js.map} +0 -0
  93. /package/dist/{chunk-JLRJ3WU7.js.map → chunk-LOU252L2.js.map} +0 -0
  94. /package/dist/{chunk-2I4XNHJA.js.map → chunk-MWQ2UYSX.js.map} +0 -0
  95. /package/dist/{chunk-6TYTVKWM.js.map → chunk-O72VDOFO.js.map} +0 -0
  96. /package/dist/{chunk-XTNJZG2X.js.map → chunk-OKSGCMDV.js.map} +0 -0
  97. /package/dist/{chunk-J4XJ2O33.js.map → chunk-Q7O7SACB.js.map} +0 -0
  98. /package/dist/{chunk-WJSSC4ZQ.js.map → chunk-QURCW325.js.map} +0 -0
  99. /package/dist/{chunk-67M5BPTV.js.map → chunk-QYPDW4PU.js.map} +0 -0
  100. /package/dist/{chunk-4YQSX2TU.js.map → chunk-REEQOJUH.js.map} +0 -0
  101. /package/dist/{chunk-BVNOK5P6.js.map → chunk-RVPB3BHL.js.map} +0 -0
  102. /package/dist/{chunk-NY2DCMDD.js.map → chunk-RWC5WRR3.js.map} +0 -0
  103. /package/dist/{chunk-M3P5B3RG.js.map → chunk-U54ZN4E6.js.map} +0 -0
  104. /package/dist/{chunk-C5RLLXX2.js.map → chunk-UOYS6IQ4.js.map} +0 -0
  105. /package/dist/{chunk-JUNUU76G.js.map → chunk-X3W235GA.js.map} +0 -0
  106. /package/dist/{chunk-LJPCUYVD.js.map → chunk-XCKEQLRC.js.map} +0 -0
  107. /package/dist/{chunk-LOOEJFT3.js.map → chunk-ZDUIEKVX.js.map} +0 -0
  108. /package/dist/{cli-circuit-breaker-AAHKTJCY.js.map → cli-circuit-breaker-TWGNVVI2.js.map} +0 -0
  109. /package/dist/{composite-router-OP66QH5X.js.map → composite-router-MKYW26IA.js.map} +0 -0
  110. /package/dist/{consensus-vote-PXZ6P5W3.js.map → consensus-vote-TAZ2YBDV.js.map} +0 -0
  111. /package/dist/{context-retriever-ZAYHL472.js.map → context-retriever-SNA6CRKC.js.map} +0 -0
  112. /package/dist/{doctor-deep-T5IKW6X6.js.map → doctor-deep-LAWVMKF7.js.map} +0 -0
  113. /package/dist/{doctor-live-TPYTCGOS.js.map → doctor-live-IMA6R5JK.js.map} +0 -0
  114. /package/dist/{expert-bridge-QPMC75VN.js.map → expert-bridge-HNVJWGFN.js.map} +0 -0
  115. /package/dist/{factory-YFFVVPNA.js.map → factory-HDDNT4Y4.js.map} +0 -0
  116. /package/dist/{factory-ZU35O5V7.js.map → factory-I3QFIRBK.js.map} +0 -0
  117. /package/dist/{improvement-review-CVJCZPMB.js.map → improvement-review-AKJN5RXY.js.map} +0 -0
  118. /package/dist/{init-opencode-SAZZWTN5.js.map → init-opencode-O6YZ22XI.js.map} +0 -0
  119. /package/dist/{issue-triage-AV7AF3R3.js.map → issue-triage-U4WOMZSI.js.map} +0 -0
  120. /package/dist/{pr-reviewer-helpers-M2GPPYN2.js.map → pr-reviewer-helpers-RWNTTUMR.js.map} +0 -0
  121. /package/dist/{registry-command-4SOG2KWX.js.map → registry-command-HFHNOECT.js.map} +0 -0
  122. /package/dist/{repo-analyze-R6WFDFBV.js.map → repo-analyze-LNZ3Y6BR.js.map} +0 -0
  123. /package/dist/{repo-security-plan-N4JBCHDO.js.map → repo-security-plan-4JKIYRQH.js.map} +0 -0
  124. /package/dist/{research-helpers-synthesize-54VP4KYP.js.map → research-helpers-synthesize-4ZS432XJ.js.map} +0 -0
  125. /package/dist/{routing-memory-UEOQNQ3G.js.map → routing-memory-FJFDW2BK.js.map} +0 -0
  126. /package/dist/{session-memory-4INFFH6Q.js.map → session-memory-QP7J6YYG.js.map} +0 -0
  127. /package/dist/{setup-config-BK4IWIRM.js.map → setup-config-4UWNJ52I.js.map} +0 -0
  128. /package/dist/{setup-custom-api-4ROFGUFC.js.map → setup-custom-api-3G75IXNS.js.map} +0 -0
  129. /package/dist/{setup-data-dir-G3EQQZL3.js.map → setup-data-dir-4ZJEO3GZ.js.map} +0 -0
  130. /package/dist/{tool-memory-AYT45WFG.js.map → tool-memory-HWESCWZI.js.map} +0 -0
  131. /package/dist/{unified-registry-YLJGLNSD.js.map → unified-registry-M4MWH6HK.js.map} +0 -0
  132. /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-6TYTVKWM.js";
13
- import "./chunk-WJSSC4ZQ.js";
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-KZJJJQAW.js.map
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-WJSSC4ZQ.js";
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-L3ZAUYGJ.js.map
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-WJSSC4ZQ.js";
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-N337ROIP.js.map
90
+ //# sourceMappingURL=chunk-3KA4RFGM.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  getRandomProvider,
3
3
  getTimeProvider
4
- } from "./chunk-WJSSC4ZQ.js";
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-W4XJF3PW.js.map
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
- function removeSastGapIfToolDetected(gaps, secTools) {
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
- const idx = gaps.indexOf(SAST_GAP_MSG);
197
- if (idx !== -1) gaps.splice(idx, 1);
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 identifyGaps(entries, ciProvider, language, securityTooling, codeowners = {}) {
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, dotGithubEntries = [], dotGithubListed = false) {
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
- listed: dotGithubListed
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
- return Array.isArray(parsed) ? parsed.filter((e) => typeof e === "string") : [];
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 workflowEntries = entries.includes(".github") ? await fetchWorkflowEntries(repoId, exec) : [];
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, workflowEntries, dotGithub.entries, dotGithub.listed);
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-U2PGDAEV.js.map
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.5" : "dev";
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-MQ6CM6NH.js.map
14
+ //# sourceMappingURL=chunk-6B7YJMG4.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getErrorMessage
3
- } from "./chunk-WJSSC4ZQ.js";
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-U6BOS5XZ.js.map
80
+ //# sourceMappingURL=chunk-7PN6YCEA.js.map
@@ -5,34 +5,34 @@ import {
5
5
  planOptionalParams,
6
6
  requireApiKey,
7
7
  validateApiKeyPresence
8
- } from "./chunk-TBGEN6TO.js";
8
+ } from "./chunk-DYSJLP7T.js";
9
9
  import {
10
10
  CUSTOM_API_DEFAULT_MODEL
11
- } from "./chunk-DYR5CK4E.js";
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-A7HQNXWO.js";
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-4YQSX2TU.js";
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-W4XJF3PW.js";
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-YM4627WM.js";
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-WJSSC4ZQ.js";
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-WZP2FPWL.js.map
4995
+ //# sourceMappingURL=chunk-7S4ZLD4G.js.map
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  GitHubProvider,
3
3
  ScmError
4
- } from "./chunk-5FXRCQPV.js";
4
+ } from "./chunk-ETTYFUV6.js";
5
5
  import {
6
6
  resolveToken
7
- } from "./chunk-N337ROIP.js";
7
+ } from "./chunk-3KA4RFGM.js";
8
8
  import {
9
9
  err,
10
10
  ok
11
- } from "./chunk-WJSSC4ZQ.js";
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-F2JOZIHL.js.map
44
+ //# sourceMappingURL=chunk-AA5OUZR6.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  analyzeGitHubRepo
3
- } from "./chunk-U2PGDAEV.js";
3
+ } from "./chunk-4GDMHCKX.js";
4
4
  import {
5
5
  createLogger,
6
6
  getTimeProvider
7
- } from "./chunk-WJSSC4ZQ.js";
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-I3BILDI6.js.map
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-WJSSC4ZQ.js";
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-DYR5CK4E.js.map
227
+ //# sourceMappingURL=chunk-CXXQ36SZ.js.map
@@ -8,7 +8,7 @@ import {
8
8
  getTimeProvider,
9
9
  isRateLimitText,
10
10
  ok
11
- } from "./chunk-WJSSC4ZQ.js";
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-YM4627WM.js.map
544
+ //# sourceMappingURL=chunk-DN47AWK3.js.map
@@ -13,7 +13,7 @@ import {
13
13
  lookupInTreeCapability,
14
14
  ok,
15
15
  resolveRetryAfterMs
16
- } from "./chunk-WJSSC4ZQ.js";
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-TBGEN6TO.js.map
837
+ //# sourceMappingURL=chunk-DYSJLP7T.js.map
@@ -4,7 +4,7 @@ import {
4
4
  err,
5
5
  getErrorMessage,
6
6
  ok
7
- } from "./chunk-WJSSC4ZQ.js";
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-5FXRCQPV.js.map
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-67M5BPTV.js";
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-W4XJF3PW.js";
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-WJSSC4ZQ.js";
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-VIXGTZL4.js.map
5828
+ //# sourceMappingURL=chunk-FMTKKJP7.js.map