renovate-mcp 0.9.3 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/data/presets.generated.d.ts +1 -1
- package/dist/data/presets.generated.js +33 -2
- package/dist/lib/renovateCli.d.ts +8 -0
- package/dist/lib/renovateCli.js +7 -1
- package/dist/lib/runtimeWarnings.d.ts +25 -0
- package/dist/lib/runtimeWarnings.js +106 -0
- package/dist/lib/setupCheck.d.ts +16 -1
- package/dist/lib/setupCheck.js +44 -12
- package/dist/lib/version.d.ts +1 -1
- package/dist/lib/version.js +1 -1
- package/dist/tools/dryRun.js +3 -0
- package/dist/tools/validateConfig.js +5 -1
- package/dist/tools/writeConfig.js +23 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -274,3 +274,4 @@ Scope and non-goals are summarized in [What this is NOT](#what-this-is-not); thi
|
|
|
274
274
|
- `dry_run` emits MCP progress notifications only when the caller's `tools/call` includes `_meta.progressToken` — no-op otherwise, so legacy clients see zero overhead. A 5-second heartbeat ticks while the child runs; each tick's message is best-effort enriched with the latest Renovate JSON-log `msg` seen on stdout. Notifications are also emitted at start and completion. We deliberately don't couple to Renovate's log schema beyond reading `msg`, since that schema isn't a stable API.
|
|
275
275
|
- `dry_run_diff` is stateless on purpose: both reports are passed as inputs, no per-repo state is kept on the server. Updates are keyed by `(manager, packageFile, depName)` so a version bump on the same dep shows up once under `changed` rather than twice as `removed + added`. Compared per identity: `newValue`, `newVersion`, `updateType`, `branchName`, `groupName`, `schedule`. Either input can be the raw Renovate report or the full `dry_run` summary (with the `report` key) — the tool unwraps `report` automatically.
|
|
276
276
|
- `write_config` writes to a temp file, validates, then atomically renames — so a failed validation never leaves a broken config on disk. The `force: true` escape hatch is gated behind a separate `confirmForce: "YES_OVERRIDE_VALIDATION"` literal: a single boolean is too easy for a prompt-injected agent to flip, but emitting an unusual sentinel string is a deliberate step that's harder to navigate accidentally.
|
|
277
|
+
- `check_setup` and the shell-out tools (`validate_config`, `write_config`, `dry_run`) detect Renovate runtime conditions that degrade the tool silently — currently the bundled `re2` native module failing to load (typically after a Node major-version upgrade leaves a prebuilt `re2.node` compiled against the old ABI). When the WARN appears in Renovate's stderr, the tool response carries a `warnings: [{ kind: "re2-unusable", … }]` entry alongside its normal output and `check_setup` aggregates the same warning into `SetupStatus.warnings` plus the startup `instructions` banner. Renovate keeps running on JavaScript `RegExp` so calls don't fail, but regex-heavy operations (custom managers, validation, lookups) are noticeably slower; the fix hint is `cd $(npm root -g)/renovate && npm rebuild re2` (or reinstall Renovate). This is passive detection only — the server doesn't rebuild anything itself.
|
|
@@ -3,6 +3,6 @@ export interface GeneratedPreset {
|
|
|
3
3
|
description: string | null;
|
|
4
4
|
body: Record<string, unknown>;
|
|
5
5
|
}
|
|
6
|
-
export declare const RENOVATE_VERSION = "43.
|
|
6
|
+
export declare const RENOVATE_VERSION = "43.150.0";
|
|
7
7
|
export declare const PRESETS: Record<string, GeneratedPreset>;
|
|
8
8
|
export declare const PRESET_NAMES: readonly string[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// AUTO-GENERATED by scripts/generate-presets.mjs from renovate@43.
|
|
1
|
+
// AUTO-GENERATED by scripts/generate-presets.mjs from renovate@43.150.0.
|
|
2
2
|
// Do not edit by hand. Run `npm run generate:presets` to refresh.
|
|
3
|
-
export const RENOVATE_VERSION = "43.
|
|
3
|
+
export const RENOVATE_VERSION = "43.150.0";
|
|
4
4
|
export const PRESETS = {
|
|
5
5
|
"abandonments:recommended": {
|
|
6
6
|
"namespace": "abandonments",
|
|
@@ -3455,6 +3455,27 @@ export const PRESETS = {
|
|
|
3455
3455
|
]
|
|
3456
3456
|
}
|
|
3457
3457
|
},
|
|
3458
|
+
"group:conformMonorepo": {
|
|
3459
|
+
"namespace": "group",
|
|
3460
|
+
"description": null,
|
|
3461
|
+
"body": {
|
|
3462
|
+
"packageRules": [
|
|
3463
|
+
{
|
|
3464
|
+
"description": "Group packages from conform monorepo together.",
|
|
3465
|
+
"extends": [
|
|
3466
|
+
"monorepo:conform"
|
|
3467
|
+
],
|
|
3468
|
+
"groupName": "conform monorepo",
|
|
3469
|
+
"matchUpdateTypes": [
|
|
3470
|
+
"digest",
|
|
3471
|
+
"patch",
|
|
3472
|
+
"minor",
|
|
3473
|
+
"major"
|
|
3474
|
+
]
|
|
3475
|
+
}
|
|
3476
|
+
]
|
|
3477
|
+
}
|
|
3478
|
+
},
|
|
3458
3479
|
"group:contentful-rich-textMonorepo": {
|
|
3459
3480
|
"namespace": "group",
|
|
3460
3481
|
"description": null,
|
|
@@ -7192,6 +7213,7 @@ export const PRESETS = {
|
|
|
7192
7213
|
"group:clarityMonorepo",
|
|
7193
7214
|
"group:clearscriptMonorepo",
|
|
7194
7215
|
"group:commitlintMonorepo",
|
|
7216
|
+
"group:conformMonorepo",
|
|
7195
7217
|
"group:contentful-rich-textMonorepo",
|
|
7196
7218
|
"group:cspellMonorepo",
|
|
7197
7219
|
"group:datadog-browser-sdkMonorepo",
|
|
@@ -13714,6 +13736,15 @@ export const PRESETS = {
|
|
|
13714
13736
|
]
|
|
13715
13737
|
}
|
|
13716
13738
|
},
|
|
13739
|
+
"monorepo:conform": {
|
|
13740
|
+
"namespace": "monorepo",
|
|
13741
|
+
"description": "conform monorepo",
|
|
13742
|
+
"body": {
|
|
13743
|
+
"matchSourceUrls": [
|
|
13744
|
+
"https://github.com/edmundhung/conform"
|
|
13745
|
+
]
|
|
13746
|
+
}
|
|
13747
|
+
},
|
|
13717
13748
|
"monorepo:contentful-rich-text": {
|
|
13718
13749
|
"namespace": "monorepo",
|
|
13719
13750
|
"description": "contentful-rich-text monorepo",
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import { type RuntimeWarning } from "./runtimeWarnings.js";
|
|
1
2
|
export interface RunResult {
|
|
2
3
|
stdout: string;
|
|
3
4
|
stderr: string;
|
|
4
5
|
exitCode: number;
|
|
6
|
+
/**
|
|
7
|
+
* Renovate runtime conditions detected from stderr that the caller benefits
|
|
8
|
+
* from knowing about even though the run itself may have succeeded (e.g. RE2
|
|
9
|
+
* native-module dlopen failure causing a silent slow-path fallback). Always
|
|
10
|
+
* present — empty array when nothing was detected.
|
|
11
|
+
*/
|
|
12
|
+
runtimeWarnings: RuntimeWarning[];
|
|
5
13
|
}
|
|
6
14
|
export interface RunOptions {
|
|
7
15
|
cwd?: string;
|
package/dist/lib/renovateCli.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
+
import { detectRuntimeWarnings } from "./runtimeWarnings.js";
|
|
2
3
|
/**
|
|
3
4
|
* Spawn a command and capture stdout/stderr. Never throws on non-zero exit —
|
|
4
5
|
* caller inspects exitCode. Throws only for spawn errors (ENOENT etc.) and
|
|
@@ -78,7 +79,12 @@ export function run(cmd, args, opts = {}) {
|
|
|
78
79
|
reject(new Error(`Command timed out after ${opts.timeoutMs}ms: ${cmd} ${args.join(" ")}`));
|
|
79
80
|
return;
|
|
80
81
|
}
|
|
81
|
-
resolve({
|
|
82
|
+
resolve({
|
|
83
|
+
stdout,
|
|
84
|
+
stderr,
|
|
85
|
+
exitCode: code ?? -1,
|
|
86
|
+
runtimeWarnings: detectRuntimeWarnings(stderr),
|
|
87
|
+
});
|
|
82
88
|
});
|
|
83
89
|
if (opts.stdin != null) {
|
|
84
90
|
child.stdin.end(opts.stdin);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect Renovate runtime warnings emitted to stderr that callers benefit from
|
|
3
|
+
* knowing about even though Renovate itself keeps running. Currently the only
|
|
4
|
+
* detected condition is the RE2 native-module dlopen failure: when the bundled
|
|
5
|
+
* `re2.node` was compiled against a different Node ABI than the one currently
|
|
6
|
+
* running, Renovate logs a single WARN and silently falls back to JavaScript
|
|
7
|
+
* `RegExp`. The fallback is functional but significantly slower for
|
|
8
|
+
* regex-heavy operations (custom managers, validation, lookups), and the
|
|
9
|
+
* degradation is otherwise invisible to MCP callers.
|
|
10
|
+
*
|
|
11
|
+
* Mirrors the parsing pattern in `lookupProblems.ts`: line-by-line scan,
|
|
12
|
+
* try-JSON-then-plain-text per line, dedupe, and cap the output. We also keep
|
|
13
|
+
* the parser narrow on purpose — Renovate emits many benign WARNs during
|
|
14
|
+
* normal runs (preset deprecations, etc.) and a generic capture would leak
|
|
15
|
+
* them into our responses.
|
|
16
|
+
*/
|
|
17
|
+
export type RuntimeWarningKind = "re2-unusable";
|
|
18
|
+
export interface RuntimeWarning {
|
|
19
|
+
kind: RuntimeWarningKind;
|
|
20
|
+
message: string;
|
|
21
|
+
detail?: string;
|
|
22
|
+
fix: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function detectRuntimeWarnings(stderr: string): RuntimeWarning[];
|
|
25
|
+
export declare function dedupeRuntimeWarnings(warnings: RuntimeWarning[]): RuntimeWarning[];
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect Renovate runtime warnings emitted to stderr that callers benefit from
|
|
3
|
+
* knowing about even though Renovate itself keeps running. Currently the only
|
|
4
|
+
* detected condition is the RE2 native-module dlopen failure: when the bundled
|
|
5
|
+
* `re2.node` was compiled against a different Node ABI than the one currently
|
|
6
|
+
* running, Renovate logs a single WARN and silently falls back to JavaScript
|
|
7
|
+
* `RegExp`. The fallback is functional but significantly slower for
|
|
8
|
+
* regex-heavy operations (custom managers, validation, lookups), and the
|
|
9
|
+
* degradation is otherwise invisible to MCP callers.
|
|
10
|
+
*
|
|
11
|
+
* Mirrors the parsing pattern in `lookupProblems.ts`: line-by-line scan,
|
|
12
|
+
* try-JSON-then-plain-text per line, dedupe, and cap the output. We also keep
|
|
13
|
+
* the parser narrow on purpose — Renovate emits many benign WARNs during
|
|
14
|
+
* normal runs (preset deprecations, etc.) and a generic capture would leak
|
|
15
|
+
* them into our responses.
|
|
16
|
+
*/
|
|
17
|
+
const MAX_DETAIL_LENGTH = 300;
|
|
18
|
+
const MAX_WARNINGS = 10;
|
|
19
|
+
const RE2_FIX_HINT = "The RE2 native module bundled with Renovate failed to load (likely after a Node version upgrade). Renovate is falling back to JavaScript `RegExp`, which is significantly slower for regex-heavy operations. To restore vectorized regex: `cd $(npm root -g)/renovate && npm rebuild re2`, or reinstall Renovate (`npm i -g renovate`). If `RENOVATE_BIN` points at a project-local install, run `npm rebuild re2` in that project instead.";
|
|
20
|
+
const RE2_MESSAGE = "Renovate's RE2 native module is unusable; falling back to JavaScript `RegExp` (slower).";
|
|
21
|
+
function truncate(s) {
|
|
22
|
+
if (s.length <= MAX_DETAIL_LENGTH)
|
|
23
|
+
return s;
|
|
24
|
+
return `${s.slice(0, MAX_DETAIL_LENGTH - 1)}…`;
|
|
25
|
+
}
|
|
26
|
+
function isRe2DlopenFailure(err) {
|
|
27
|
+
if (!err || typeof err !== "object")
|
|
28
|
+
return null;
|
|
29
|
+
const obj = err;
|
|
30
|
+
const code = typeof obj.code === "string" ? obj.code : undefined;
|
|
31
|
+
const message = typeof obj.message === "string" ? obj.message : undefined;
|
|
32
|
+
if (code !== "ERR_DLOPEN_FAILED")
|
|
33
|
+
return null;
|
|
34
|
+
if (!message || !/re2\.node/.test(message))
|
|
35
|
+
return null;
|
|
36
|
+
return { detail: truncate(message) };
|
|
37
|
+
}
|
|
38
|
+
export function detectRuntimeWarnings(stderr) {
|
|
39
|
+
if (!stderr)
|
|
40
|
+
return [];
|
|
41
|
+
const warnings = [];
|
|
42
|
+
const seen = new Set();
|
|
43
|
+
const pushRe2 = (detail) => {
|
|
44
|
+
if (seen.has("re2-unusable"))
|
|
45
|
+
return;
|
|
46
|
+
if (warnings.length >= MAX_WARNINGS)
|
|
47
|
+
return;
|
|
48
|
+
seen.add("re2-unusable");
|
|
49
|
+
const w = { kind: "re2-unusable", message: RE2_MESSAGE, fix: RE2_FIX_HINT };
|
|
50
|
+
if (detail)
|
|
51
|
+
w.detail = detail;
|
|
52
|
+
warnings.push(w);
|
|
53
|
+
};
|
|
54
|
+
for (const rawLine of stderr.split(/\r?\n/)) {
|
|
55
|
+
const line = rawLine.trim();
|
|
56
|
+
if (!line)
|
|
57
|
+
continue;
|
|
58
|
+
if (warnings.length >= MAX_WARNINGS)
|
|
59
|
+
break;
|
|
60
|
+
if (line.startsWith("{")) {
|
|
61
|
+
try {
|
|
62
|
+
const parsed = JSON.parse(line);
|
|
63
|
+
if (parsed && typeof parsed === "object") {
|
|
64
|
+
const msg = typeof parsed.msg === "string" ? parsed.msg : "";
|
|
65
|
+
if (msg.includes("RE2 not usable")) {
|
|
66
|
+
const detail = parsed.err && typeof parsed.err === "object" && parsed.err !== null
|
|
67
|
+
? typeof parsed.err.message === "string"
|
|
68
|
+
? truncate(parsed.err.message)
|
|
69
|
+
: undefined
|
|
70
|
+
: undefined;
|
|
71
|
+
pushRe2(detail);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const re2Err = isRe2DlopenFailure(parsed.err);
|
|
75
|
+
if (re2Err) {
|
|
76
|
+
pushRe2(re2Err.detail);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// fall through to plain-text matching below
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (/\bRE2 not usable\b/.test(line)) {
|
|
86
|
+
pushRe2();
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (/\bERR_DLOPEN_FAILED\b/.test(line) && /re2\.node/.test(line)) {
|
|
90
|
+
pushRe2(truncate(line));
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return warnings;
|
|
95
|
+
}
|
|
96
|
+
export function dedupeRuntimeWarnings(warnings) {
|
|
97
|
+
const seen = new Set();
|
|
98
|
+
const out = [];
|
|
99
|
+
for (const w of warnings) {
|
|
100
|
+
if (seen.has(w.kind))
|
|
101
|
+
continue;
|
|
102
|
+
seen.add(w.kind);
|
|
103
|
+
out.push(w);
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
package/dist/lib/setupCheck.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type RuntimeWarning } from "./runtimeWarnings.js";
|
|
1
2
|
export type RenovateBinary = "renovate" | "renovate-config-validator";
|
|
2
3
|
export interface BinaryStatus {
|
|
3
4
|
tool: RenovateBinary;
|
|
@@ -5,6 +6,11 @@ export interface BinaryStatus {
|
|
|
5
6
|
found: boolean;
|
|
6
7
|
version?: string;
|
|
7
8
|
error?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Runtime warnings parsed from this binary's `--version` stderr (e.g. RE2
|
|
11
|
+
* dlopen failure). Present only when at least one warning was detected.
|
|
12
|
+
*/
|
|
13
|
+
runtimeWarnings?: RuntimeWarning[];
|
|
8
14
|
}
|
|
9
15
|
export type DryRunPlatform = "local" | "github" | "gitlab";
|
|
10
16
|
export interface PlatformContext {
|
|
@@ -36,6 +42,13 @@ export interface SetupStatus {
|
|
|
36
42
|
platformContext: PlatformContext;
|
|
37
43
|
ok: boolean;
|
|
38
44
|
hints: string[];
|
|
45
|
+
/**
|
|
46
|
+
* Deduped union of `runtimeWarnings` from every binary's `--version` probe.
|
|
47
|
+
* Distinct from `hints`: hints are "things you need to install / fix to use
|
|
48
|
+
* this server"; warnings are "Renovate is running but degraded." Empty array
|
|
49
|
+
* when nothing was detected.
|
|
50
|
+
*/
|
|
51
|
+
warnings: RuntimeWarning[];
|
|
39
52
|
}
|
|
40
53
|
export declare function checkSetup(): Promise<SetupStatus>;
|
|
41
54
|
/**
|
|
@@ -56,7 +69,9 @@ export declare function unavailableTools(status: SetupStatus): string[];
|
|
|
56
69
|
/**
|
|
57
70
|
* Concise startup banner appended to the server's MCP `instructions` so the
|
|
58
71
|
* LLM is primed to treat CLI-missing as a partial-availability signal rather
|
|
59
|
-
* than a setup error.
|
|
72
|
+
* than a setup error. Also emits a banner — independent of binary availability
|
|
73
|
+
* — when Renovate runtime warnings are detected (e.g. RE2 dlopen failure
|
|
74
|
+
* causing a slow-path fallback). Returns `null` when nothing needs surfacing.
|
|
60
75
|
*/
|
|
61
76
|
export declare function startupBanner(status: SetupStatus): string | null;
|
|
62
77
|
export declare function describeSetup(status: SetupStatus): string;
|
package/dist/lib/setupCheck.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { run, resolveRenovateTool } from "./renovateCli.js";
|
|
2
|
+
import { dedupeRuntimeWarnings } from "./runtimeWarnings.js";
|
|
2
3
|
const DRY_RUN_PLATFORMS = ["local", "github", "gitlab"];
|
|
3
4
|
const VERSION_TIMEOUT_MS = 10_000;
|
|
4
5
|
const INSTALL_HINT = "Install Renovate globally with `npm i -g renovate`, or set RENOVATE_BIN / RENOVATE_CONFIG_VALIDATOR_BIN to existing binaries.";
|
|
@@ -6,12 +7,14 @@ async function checkBinary(tool) {
|
|
|
6
7
|
const command = resolveRenovateTool(tool);
|
|
7
8
|
try {
|
|
8
9
|
const result = await run(command, ["--version"], { timeoutMs: VERSION_TIMEOUT_MS });
|
|
10
|
+
const runtimeWarnings = result.runtimeWarnings.length ? result.runtimeWarnings : undefined;
|
|
9
11
|
if (result.exitCode !== 0) {
|
|
10
12
|
return {
|
|
11
13
|
tool,
|
|
12
14
|
command,
|
|
13
15
|
found: false,
|
|
14
16
|
error: (result.stderr || result.stdout).trim() || `exit code ${result.exitCode}`,
|
|
17
|
+
runtimeWarnings,
|
|
15
18
|
};
|
|
16
19
|
}
|
|
17
20
|
return {
|
|
@@ -19,6 +22,7 @@ async function checkBinary(tool) {
|
|
|
19
22
|
command,
|
|
20
23
|
found: true,
|
|
21
24
|
version: result.stdout.trim() || undefined,
|
|
25
|
+
runtimeWarnings,
|
|
22
26
|
};
|
|
23
27
|
}
|
|
24
28
|
catch (err) {
|
|
@@ -48,6 +52,10 @@ export async function checkSetup() {
|
|
|
48
52
|
if (!renovateConfigValidator.found) {
|
|
49
53
|
hints.push(`renovate-config-validator not reachable at \`${renovateConfigValidator.command}\`. ${INSTALL_HINT}`);
|
|
50
54
|
}
|
|
55
|
+
const warnings = dedupeRuntimeWarnings([
|
|
56
|
+
...(renovate.runtimeWarnings ?? []),
|
|
57
|
+
...(renovateConfigValidator.runtimeWarnings ?? []),
|
|
58
|
+
]);
|
|
51
59
|
return {
|
|
52
60
|
node: process.version,
|
|
53
61
|
renovate,
|
|
@@ -56,6 +64,7 @@ export async function checkSetup() {
|
|
|
56
64
|
platformContext: inspectPlatformContext(process.env),
|
|
57
65
|
ok: renovate.found && renovateConfigValidator.found,
|
|
58
66
|
hints,
|
|
67
|
+
warnings,
|
|
59
68
|
};
|
|
60
69
|
}
|
|
61
70
|
/**
|
|
@@ -139,21 +148,34 @@ export function unavailableTools(status) {
|
|
|
139
148
|
/**
|
|
140
149
|
* Concise startup banner appended to the server's MCP `instructions` so the
|
|
141
150
|
* LLM is primed to treat CLI-missing as a partial-availability signal rather
|
|
142
|
-
* than a setup error.
|
|
151
|
+
* than a setup error. Also emits a banner — independent of binary availability
|
|
152
|
+
* — when Renovate runtime warnings are detected (e.g. RE2 dlopen failure
|
|
153
|
+
* causing a slow-path fallback). Returns `null` when nothing needs surfacing.
|
|
143
154
|
*/
|
|
144
155
|
export function startupBanner(status) {
|
|
145
156
|
const unavailable = unavailableTools(status);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
+
const sections = [];
|
|
158
|
+
if (unavailable.length > 0) {
|
|
159
|
+
const unavailList = unavailable.map((n) => `\`${n}\``).join(", ");
|
|
160
|
+
const offlineList = OFFLINE_TOOLS.map((n) => `\`${n}\``).join(", ");
|
|
161
|
+
sections.push([
|
|
162
|
+
"Partial availability:",
|
|
163
|
+
` Renovate CLI not found — only blocks: ${unavailList}.`,
|
|
164
|
+
` Offline tools (${offlineList}) still work; do not flag this as a setup problem when the task only needs those.`,
|
|
165
|
+
" Install Renovate (`npm i -g renovate`) before calling the blocked tools, or call `check_setup` for a full diagnostic.",
|
|
166
|
+
" Set `RENOVATE_MCP_REQUIRE_CLI=false` to suppress this notice if you have consciously chosen the offline subset.",
|
|
167
|
+
].join("\n"));
|
|
168
|
+
}
|
|
169
|
+
if (status.warnings.length > 0) {
|
|
170
|
+
const lines = ["Renovate runtime warnings:"];
|
|
171
|
+
for (const w of status.warnings) {
|
|
172
|
+
lines.push(` - ${w.message}`);
|
|
173
|
+
lines.push(` Fix: ${w.fix}`);
|
|
174
|
+
}
|
|
175
|
+
lines.push(" These do not block tool calls. Surface this if a user reports unexpectedly slow runs.");
|
|
176
|
+
sections.push(lines.join("\n"));
|
|
177
|
+
}
|
|
178
|
+
return sections.length === 0 ? null : sections.join("\n\n");
|
|
157
179
|
}
|
|
158
180
|
export function describeSetup(status) {
|
|
159
181
|
const lines = [];
|
|
@@ -187,6 +209,16 @@ export function describeSetup(status) {
|
|
|
187
209
|
for (const h of status.hints)
|
|
188
210
|
lines.push(` - ${h}`);
|
|
189
211
|
}
|
|
212
|
+
if (status.warnings.length > 0) {
|
|
213
|
+
lines.push("");
|
|
214
|
+
lines.push("Warnings:");
|
|
215
|
+
for (const w of status.warnings) {
|
|
216
|
+
lines.push(` - ${w.message}`);
|
|
217
|
+
if (w.detail)
|
|
218
|
+
lines.push(` Detail: ${w.detail}`);
|
|
219
|
+
lines.push(` Fix: ${w.fix}`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
190
222
|
return lines.join("\n");
|
|
191
223
|
}
|
|
192
224
|
function formatBinary(s) {
|
package/dist/lib/version.d.ts
CHANGED
package/dist/lib/version.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { fileURLToPath } from "node:url";
|
|
2
|
-
export const SERVER_VERSION = "0.
|
|
2
|
+
export const SERVER_VERSION = "0.10.0"; // x-release-please-version
|
|
3
3
|
// "released" = the server is running from a `node_modules/` install (global
|
|
4
4
|
// `npm i -g`, project-local `npm i`, or `npx renovate-mcp`). Anything else —
|
|
5
5
|
// most commonly an MCP config of `{"command": "node", "args": [".../dist/index.js"]}`
|
package/dist/tools/dryRun.js
CHANGED
|
@@ -337,6 +337,9 @@ export function registerDryRun(server) {
|
|
|
337
337
|
if (reportErrors.length > 0) {
|
|
338
338
|
summary.reportErrors = reportErrors;
|
|
339
339
|
}
|
|
340
|
+
if (result.runtimeWarnings.length > 0) {
|
|
341
|
+
summary.warnings = result.runtimeWarnings;
|
|
342
|
+
}
|
|
340
343
|
// If no structured report, surface the last bit of stderr so Claude can
|
|
341
344
|
// debug without blowing up the context with Renovate's verbose logs.
|
|
342
345
|
if (!report) {
|
|
@@ -45,11 +45,15 @@ export function registerValidateConfig(server) {
|
|
|
45
45
|
const result = await run(bin, args, { timeoutMs: 30_000 });
|
|
46
46
|
const valid = result.exitCode === 0;
|
|
47
47
|
const output = (result.stdout + result.stderr).trim();
|
|
48
|
+
const payload = { valid, output };
|
|
49
|
+
if (result.runtimeWarnings.length > 0) {
|
|
50
|
+
payload.warnings = result.runtimeWarnings;
|
|
51
|
+
}
|
|
48
52
|
return {
|
|
49
53
|
content: [
|
|
50
54
|
{
|
|
51
55
|
type: "text",
|
|
52
|
-
text: JSON.stringify(
|
|
56
|
+
text: JSON.stringify(payload, null, 2),
|
|
53
57
|
},
|
|
54
58
|
],
|
|
55
59
|
isError: !valid,
|
|
@@ -84,46 +84,54 @@ export function registerWriteConfig(server) {
|
|
|
84
84
|
let valid = false;
|
|
85
85
|
let validationOutput = "";
|
|
86
86
|
let validatorMissing = false;
|
|
87
|
+
let runtimeWarnings = [];
|
|
87
88
|
try {
|
|
88
89
|
const bin = resolveRenovateTool("renovate-config-validator");
|
|
89
90
|
const v = await run(bin, [tmp], { timeoutMs: 30_000 });
|
|
90
91
|
validationOutput = (v.stdout + v.stderr).trim();
|
|
91
92
|
valid = v.exitCode === 0;
|
|
93
|
+
runtimeWarnings = v.runtimeWarnings;
|
|
92
94
|
}
|
|
93
95
|
catch (err) {
|
|
94
96
|
validatorMissing = true;
|
|
95
97
|
validationOutput = formatMissingBinaryError("renovate-config-validator", err);
|
|
96
98
|
}
|
|
97
99
|
if (!valid && !force) {
|
|
100
|
+
const failPayload = {
|
|
101
|
+
wrote: false,
|
|
102
|
+
reason: validatorMissing ? "validator-unavailable" : "validation-failed",
|
|
103
|
+
validationOutput,
|
|
104
|
+
hint: validatorMissing
|
|
105
|
+
? "Install renovate-config-validator (or set RENOVATE_CONFIG_VALIDATOR_BIN), then retry. Pass force=true to skip validation entirely."
|
|
106
|
+
: "Pass force=true to write anyway.",
|
|
107
|
+
};
|
|
108
|
+
if (runtimeWarnings.length > 0)
|
|
109
|
+
failPayload.warnings = runtimeWarnings;
|
|
98
110
|
return {
|
|
99
111
|
isError: true,
|
|
100
112
|
content: [
|
|
101
113
|
{
|
|
102
114
|
type: "text",
|
|
103
|
-
text: JSON.stringify(
|
|
104
|
-
wrote: false,
|
|
105
|
-
reason: validatorMissing ? "validator-unavailable" : "validation-failed",
|
|
106
|
-
validationOutput,
|
|
107
|
-
hint: validatorMissing
|
|
108
|
-
? "Install renovate-config-validator (or set RENOVATE_CONFIG_VALIDATOR_BIN), then retry. Pass force=true to skip validation entirely."
|
|
109
|
-
: "Pass force=true to write anyway.",
|
|
110
|
-
}, null, 2),
|
|
115
|
+
text: JSON.stringify(failPayload, null, 2),
|
|
111
116
|
},
|
|
112
117
|
],
|
|
113
118
|
};
|
|
114
119
|
}
|
|
115
120
|
await fs.rename(tmp, target);
|
|
121
|
+
const okPayload = {
|
|
122
|
+
wrote: true,
|
|
123
|
+
path: rel,
|
|
124
|
+
bytes: payload.length,
|
|
125
|
+
valid,
|
|
126
|
+
validationOutput: valid ? undefined : validationOutput,
|
|
127
|
+
};
|
|
128
|
+
if (runtimeWarnings.length > 0)
|
|
129
|
+
okPayload.warnings = runtimeWarnings;
|
|
116
130
|
return {
|
|
117
131
|
content: [
|
|
118
132
|
{
|
|
119
133
|
type: "text",
|
|
120
|
-
text: JSON.stringify(
|
|
121
|
-
wrote: true,
|
|
122
|
-
path: rel,
|
|
123
|
-
bytes: payload.length,
|
|
124
|
-
valid,
|
|
125
|
-
validationOutput: valid ? undefined : validationOutput,
|
|
126
|
-
}, null, 2),
|
|
134
|
+
text: JSON.stringify(okPayload, null, 2),
|
|
127
135
|
},
|
|
128
136
|
],
|
|
129
137
|
};
|