nexus-agents 8.51.1 → 8.51.2

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.
@@ -7,7 +7,7 @@ import {
7
7
  toolStructuredError,
8
8
  toolSuccessStructured,
9
9
  wrapToolWithTimeout
10
- } from "./chunk-R32HCVJN.js";
10
+ } from "./chunk-U6R6EULS.js";
11
11
  import {
12
12
  JsonlStore,
13
13
  SECURITY_KEYWORDS,
@@ -1597,6 +1597,7 @@ function classifySignalPriority(signal) {
1597
1597
 
1598
1598
  // src/mcp/tools/improvement-review.ts
1599
1599
  var execFileAsync2 = promisify2(execFile2);
1600
+ var TARGET_REPO_PATTERN = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
1600
1601
  var ImprovementReviewInputSchema = z3.object({
1601
1602
  lookbackDays: z3.number().int().min(1).max(90).optional().default(7).describe("Lookback window for outcome data, in days. Default 7."),
1602
1603
  fileIssues: z3.boolean().optional().default(false).describe(
@@ -1606,6 +1607,9 @@ var ImprovementReviewInputSchema = z3.object({
1606
1607
  fitnessFloor: z3.number().int().min(0).max(100).optional().default(90).describe("Fitness score below this threshold triggers a tech-debt signal."),
1607
1608
  selfEvalReportPath: z3.string().optional().describe(
1608
1609
  "Optional path to a self-eval JSON report (from `self-eval --json`). When set, high-confidence unanimous deprecate/refactor findings are surfaced as tech-debt signals through the same deduped/rate-limited issue path (#3224). Unreadable/malformed reports are skipped (no signal). Absent \u2192 no self-eval signals."
1610
+ ),
1611
+ targetRepo: z3.string().regex(TARGET_REPO_PATTERN, "targetRepo must be `owner/repo`").optional().describe(
1612
+ "Repository (`owner/repo`) to file issues against when fileIssues=true. Absent \u2192 the cwd remote (via `gh repo view`); the resolved target is reported as `issueTarget` (#6112)."
1609
1613
  )
1610
1614
  });
1611
1615
  var MAX_ISSUES_PER_RUN = 5;
@@ -1940,10 +1944,70 @@ async function loadSelfEvalSignals(reportPath, windowLabel, logger) {
1940
1944
  return [];
1941
1945
  }
1942
1946
  }
1943
- async function existingIssueForSignal(signalKey) {
1947
+ var defaultGhExec = async (args) => execFileAsync2("gh", [...args]);
1948
+ var LABEL_LIST_LIMIT = 1e3;
1949
+ var NOT_FILING = { repo: null, source: "not-filing" };
1950
+ async function maybeFileIssues(signals, opts) {
1951
+ if (!opts.fileIssues) return { issuesFiled: [], issuesSkipped: [], issueTarget: NOT_FILING };
1952
+ return fileSignalsAsIssues(signals, {
1953
+ logger: opts.logger,
1954
+ ghExec: opts.ghExec,
1955
+ ...opts.targetRepo === void 0 ? {} : { targetRepo: opts.targetRepo }
1956
+ });
1957
+ }
1958
+ function repoArgs(target) {
1959
+ return target.repo === null ? [] : ["--repo", target.repo];
1960
+ }
1961
+ async function resolveIssueTarget(deps) {
1962
+ if (deps.targetRepo !== void 0) return { repo: deps.targetRepo, source: "input" };
1963
+ try {
1964
+ const { stdout } = await deps.ghExec(["repo", "view", "--json", "nameWithOwner"]);
1965
+ const parsed = JSON.parse(stdout);
1966
+ if (typeof parsed.nameWithOwner === "string" && parsed.nameWithOwner.length > 0) {
1967
+ return { repo: parsed.nameWithOwner, source: "cwd-remote" };
1968
+ }
1969
+ return { repo: null, source: "unresolved" };
1970
+ } catch (caught) {
1971
+ deps.logger.warn("improvement_review: target repo lookup failed; gh will resolve from cwd", {
1972
+ error: getErrorMessage(caught)
1973
+ });
1974
+ return { repo: null, source: "unresolved" };
1975
+ }
1976
+ }
1977
+ async function fetchRepoLabels(deps, target) {
1978
+ try {
1979
+ const { stdout } = await deps.ghExec([
1980
+ "label",
1981
+ "list",
1982
+ "--json",
1983
+ "name",
1984
+ "--limit",
1985
+ String(LABEL_LIST_LIMIT),
1986
+ ...repoArgs(target)
1987
+ ]);
1988
+ const parsed = JSON.parse(stdout);
1989
+ if (parsed.length >= LABEL_LIST_LIMIT) {
1990
+ deps.logger.warn("improvement_review: gh label list filled its page; filing unfiltered", {
1991
+ returned: parsed.length,
1992
+ limit: LABEL_LIST_LIMIT
1993
+ });
1994
+ return { status: "truncated" };
1995
+ }
1996
+ return {
1997
+ status: "ok",
1998
+ names: new Set(parsed.flatMap((l) => typeof l.name === "string" ? [l.name] : []))
1999
+ };
2000
+ } catch (caught) {
2001
+ deps.logger.warn("improvement_review: gh label list failed; filing without labels", {
2002
+ error: getErrorMessage(caught)
2003
+ });
2004
+ return { status: "unavailable" };
2005
+ }
2006
+ }
2007
+ async function existingIssueForSignal(signalKey, ghExec, target) {
1944
2008
  try {
1945
2009
  const searchTerm = signalKey.replace(/"/g, "");
1946
- const { stdout } = await execFileAsync2("gh", [
2010
+ const { stdout } = await ghExec([
1947
2011
  "issue",
1948
2012
  "list",
1949
2013
  "--state",
@@ -1953,7 +2017,8 @@ async function existingIssueForSignal(signalKey) {
1953
2017
  "--json",
1954
2018
  "number,url",
1955
2019
  "--limit",
1956
- "5"
2020
+ "5",
2021
+ ...repoArgs(target)
1957
2022
  ]);
1958
2023
  const parsed = JSON.parse(stdout);
1959
2024
  if (parsed.length > 0 && typeof parsed[0]?.url === "string") {
@@ -1967,22 +2032,36 @@ async function existingIssueForSignal(signalKey) {
1967
2032
  function issueLabelsForSignal(signal) {
1968
2033
  return [priorityLabel(classifySignalPriority(signal)), signal.category];
1969
2034
  }
1970
- async function fileIssueForSignal(signal) {
2035
+ function partitionLabels(requested, labels) {
2036
+ switch (labels.status) {
2037
+ case "unavailable":
2038
+ return { kept: [], labelsDropped: [...requested], labelCheck: "unavailable" };
2039
+ case "truncated":
2040
+ return { kept: [...requested], labelsDropped: [], labelCheck: "truncated" };
2041
+ case "ok":
2042
+ return {
2043
+ kept: requested.filter((l) => labels.names.has(l)),
2044
+ labelsDropped: requested.filter((l) => !labels.names.has(l)),
2045
+ labelCheck: "ok"
2046
+ };
2047
+ }
2048
+ }
2049
+ async function fileIssueForSignal(signal, kept, ghExec, target) {
1971
2050
  const body = `${signal.body}
1972
2051
 
1973
2052
  ---
1974
2053
 
1975
2054
  _Signal key (do not edit): \`${signal.signalKey}\` \xB7 Generated by \`improvement_review\` (#2402) \xB7 Severity: ${signal.severity}_`;
1976
2055
  try {
1977
- const { stdout } = await execFileAsync2("gh", [
2056
+ const { stdout } = await ghExec([
1978
2057
  "issue",
1979
2058
  "create",
1980
2059
  "--title",
1981
2060
  signal.title,
1982
2061
  "--body",
1983
2062
  body,
1984
- "--label",
1985
- issueLabelsForSignal(signal).join(",")
2063
+ ...kept.length > 0 ? ["--label", kept.join(",")] : [],
2064
+ ...repoArgs(target)
1986
2065
  ]);
1987
2066
  const url = stdout.trim();
1988
2067
  if (!url.startsWith("https://")) {
@@ -2015,31 +2094,45 @@ var SEVERITY_ORDER = {
2015
2094
  warning: 1,
2016
2095
  info: 2
2017
2096
  };
2018
- async function fileSignalsAsIssues(signals, ctx) {
2097
+ async function fileSignalsAsIssues(signals, deps) {
2019
2098
  const issuesFiled = [];
2020
2099
  const issuesSkipped = [];
2100
+ const target = await resolveIssueTarget(deps);
2101
+ let labelsOnce;
2102
+ const repoLabels = () => labelsOnce ??= fetchRepoLabels(deps, target);
2021
2103
  for (const signal of signals) {
2022
2104
  if (issuesFiled.length >= MAX_ISSUES_PER_RUN) {
2023
2105
  issuesSkipped.push({ signalKey: signal.signalKey, reason: "rate-limit" });
2024
2106
  continue;
2025
2107
  }
2026
- const existing = await existingIssueForSignal(signal.signalKey);
2108
+ const existing = await existingIssueForSignal(signal.signalKey, deps.ghExec, target);
2027
2109
  if (existing !== null) {
2028
2110
  issuesSkipped.push({ signalKey: signal.signalKey, reason: `dup:${existing}` });
2029
2111
  continue;
2030
2112
  }
2031
- const result = await fileIssueForSignal(signal);
2113
+ const { kept, labelsDropped, labelCheck } = partitionLabels(
2114
+ issueLabelsForSignal(signal),
2115
+ await repoLabels()
2116
+ );
2117
+ const result = await fileIssueForSignal(signal, kept, deps.ghExec, target);
2032
2118
  if (result.ok) {
2033
- issuesFiled.push({ signalKey: signal.signalKey, issueUrl: result.url });
2034
- ctx.logger.info("improvement signal filed", {
2119
+ issuesFiled.push({
2035
2120
  signalKey: signal.signalKey,
2036
- url: result.url
2121
+ issueUrl: result.url,
2122
+ labelsDropped,
2123
+ labelCheck
2124
+ });
2125
+ deps.logger.info("improvement signal filed", {
2126
+ signalKey: signal.signalKey,
2127
+ url: result.url,
2128
+ labelsDropped,
2129
+ labelCheck
2037
2130
  });
2038
2131
  } else {
2039
2132
  issuesSkipped.push({ signalKey: signal.signalKey, reason: `error:${result.error}` });
2040
2133
  }
2041
2134
  }
2042
- return { issuesFiled, issuesSkipped };
2135
+ return { issuesFiled, issuesSkipped, issueTarget: target };
2043
2136
  }
2044
2137
  function readBufferedVoteRejections(now, lookbackDays) {
2045
2138
  const cutoff = now - lookbackDays * DAY_MS;
@@ -2073,7 +2166,12 @@ async function runImprovementReview(input, deps = {}) {
2073
2166
  signals.sort((a, b) => SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity]);
2074
2167
  emitFitnessDeclinedSignal(audit, fitnessFloor, getPipelineEventBus(), logger);
2075
2168
  shadowRecordRemediations(signals, logger);
2076
- const { issuesFiled, issuesSkipped } = fileIssues ? await fileSignalsAsIssues(signals, { logger }) : { issuesFiled: [], issuesSkipped: [] };
2169
+ const { issuesFiled, issuesSkipped, issueTarget } = await maybeFileIssues(signals, {
2170
+ fileIssues,
2171
+ logger,
2172
+ ghExec: deps.ghExec ?? defaultGhExec,
2173
+ targetRepo: input.targetRepo
2174
+ });
2077
2175
  return {
2078
2176
  window: windowLabel,
2079
2177
  totalOutcomes: windowed.length,
@@ -2082,7 +2180,8 @@ async function runImprovementReview(input, deps = {}) {
2082
2180
  // (suggest-only — composes existing detection, no auto-invocation).
2083
2181
  remediationTasks: improvementSignalsToTasks(signals),
2084
2182
  issuesFiled,
2085
- issuesSkipped
2183
+ issuesSkipped,
2184
+ issueTarget
2086
2185
  };
2087
2186
  }
2088
2187
  function shadowRecordRemediations(signals, logger) {
@@ -2122,6 +2221,9 @@ var TOOL_INPUT_SCHEMA = {
2122
2221
  fitnessFloor: z3.number().int().min(0).max(100).optional().describe("Fitness score below this threshold triggers a tech-debt signal (default 90)."),
2123
2222
  selfEvalReportPath: z3.string().optional().describe(
2124
2223
  "Optional path to a self-eval JSON report. High-confidence unanimous deprecate/refactor findings surface as tech-debt signals (#3224)."
2224
+ ),
2225
+ targetRepo: z3.string().regex(TARGET_REPO_PATTERN, "targetRepo must be `owner/repo`").optional().describe(
2226
+ "Repository (`owner/repo`) to file issues against. Absent \u2192 the cwd remote; the resolved target is reported as `issueTarget` (#6112)."
2125
2227
  )
2126
2228
  };
2127
2229
  function registerImprovementReviewTool(server, deps) {
@@ -2173,4 +2275,4 @@ export {
2173
2275
  runImprovementReview,
2174
2276
  registerImprovementReviewTool
2175
2277
  };
2176
- //# sourceMappingURL=chunk-T2LVUHW4.js.map
2278
+ //# sourceMappingURL=chunk-6PRVSB5B.js.map