@yagni-app/code 1.0.4 → 1.0.6
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 +30 -6
- package/dist/claudePlugins.d.ts +3 -1
- package/dist/claudePlugins.js +3 -1
- package/dist/cli.js +12 -0
- package/dist/doctor.d.ts +28 -3
- package/dist/doctor.js +117 -7
- package/dist/extension/index.d.ts +5 -5
- package/dist/extension/index.js +94 -31
- package/dist/extension/mcp/approval.d.ts +45 -0
- package/dist/extension/mcp/approval.js +164 -0
- package/dist/extension/mcp/auth.d.ts +124 -0
- package/dist/extension/mcp/auth.js +560 -0
- package/dist/extension/mcp/authStore.d.ts +61 -0
- package/dist/extension/mcp/authStore.js +105 -0
- package/dist/extension/mcp/callbackPage.d.ts +31 -0
- package/dist/extension/mcp/callbackPage.js +222 -0
- package/dist/extension/mcp/cliConfig.d.ts +12 -0
- package/dist/extension/mcp/cliConfig.js +12 -0
- package/dist/extension/mcp/config.d.ts +131 -0
- package/dist/extension/mcp/config.js +309 -0
- package/dist/extension/mcp/log.d.ts +28 -0
- package/dist/extension/mcp/log.js +82 -0
- package/dist/extension/mcp/manager.d.ts +98 -0
- package/dist/extension/mcp/manager.js +273 -0
- package/dist/extension/mcp/names.d.ts +25 -0
- package/dist/extension/mcp/names.js +40 -0
- package/dist/extension/mcp/panel.d.ts +34 -0
- package/dist/extension/mcp/panel.js +258 -0
- package/dist/extension/mcp/prompts.d.ts +23 -0
- package/dist/extension/mcp/prompts.js +93 -0
- package/dist/extension/mcp/startup.d.ts +55 -0
- package/dist/extension/mcp/startup.js +150 -0
- package/dist/extension/mcp/tools.d.ts +31 -0
- package/dist/extension/mcp/tools.js +117 -0
- package/dist/extension/mcp/transports.d.ts +17 -0
- package/dist/extension/mcp/transports.js +44 -0
- package/dist/extension/permission/execPolicy.js +17 -2
- package/dist/extension/permission/gate.d.ts +7 -0
- package/dist/extension/permission/gate.js +12 -5
- package/dist/extension/permission/guardian.d.ts +24 -5
- package/dist/extension/permission/guardian.js +162 -24
- package/dist/extension/pipeline/personas.js +5 -0
- package/dist/mcpCommand.d.ts +113 -0
- package/dist/mcpCommand.js +755 -0
- package/dist/otel.d.ts +36 -7
- package/dist/otel.js +90 -12
- package/dist/upgrade.d.ts +11 -2
- package/dist/upgrade.js +48 -8
- package/package.json +3 -2
- package/dist/extension/mcpTools.d.ts +0 -57
- package/dist/extension/mcpTools.js +0 -132
|
@@ -99,6 +99,14 @@ export interface CircuitBreakerResult {
|
|
|
99
99
|
reason?: string;
|
|
100
100
|
}
|
|
101
101
|
export declare function checkCircuitBreaker(state: GuardianState, limits: GuardianLimits): CircuitBreakerResult;
|
|
102
|
+
export interface ParsedVerdict {
|
|
103
|
+
verdict: GuardianVerdict;
|
|
104
|
+
/** True when the strict parse failed and the lenient repair ladder salvaged it. */
|
|
105
|
+
repaired: boolean;
|
|
106
|
+
}
|
|
107
|
+
export declare function parseVerdictDetailed(raw: string): ParsedVerdict | null;
|
|
108
|
+
/** Strict-shaped convenience wrapper: the verdict, or null. Callers that need
|
|
109
|
+
* the repaired signal use {@link parseVerdictDetailed}. */
|
|
102
110
|
export declare function parseVerdict(raw: string): GuardianVerdict | null;
|
|
103
111
|
export declare function formatGuardianSubtotal(state: GuardianState, limits: GuardianLimits): string;
|
|
104
112
|
export type GuardianError = "timeout" | "malformed" | "network" | "empty" | "aborted";
|
|
@@ -106,11 +114,17 @@ export interface ReviewResult {
|
|
|
106
114
|
verdict: GuardianVerdict | null;
|
|
107
115
|
error?: GuardianError;
|
|
108
116
|
cost: number;
|
|
117
|
+
/** True when the verdict came from the lenient repair ladder (strict parse
|
|
118
|
+
* failed first). The verdict is real and flows through the normal
|
|
119
|
+
* allow/ask/deny handling; this flag only marks it for telemetry. */
|
|
120
|
+
repaired?: boolean;
|
|
109
121
|
/**
|
|
110
122
|
* Scrubbed + capped copy of the model output when the verdict failed to
|
|
111
|
-
* parse (`error: "malformed"`)
|
|
112
|
-
*
|
|
113
|
-
*
|
|
123
|
+
* parse (`error: "malformed"`), or of the pre-repair extracted block when
|
|
124
|
+
* the repair ladder salvaged it (`repaired: true`). Present so the sink can
|
|
125
|
+
* capture the exact failure shape either way. Never contains the raw
|
|
126
|
+
* command unredacted: `scrubSecrets` removes secret-shaped values before
|
|
127
|
+
* this is stored.
|
|
114
128
|
*/
|
|
115
129
|
rawOutput?: string;
|
|
116
130
|
}
|
|
@@ -152,14 +166,18 @@ export interface GuardianDiagnosticEvent {
|
|
|
152
166
|
outcome: GuardianOutcome | GuardianError;
|
|
153
167
|
durationMs?: number;
|
|
154
168
|
tier?: string;
|
|
169
|
+
/** True when the lenient repair ladder salvaged a broken verdict — the
|
|
170
|
+
* outcome is still the REAL verdict (allow/ask/deny); this flag marks it
|
|
171
|
+
* for telemetry so repair hit-rate is measurable. */
|
|
172
|
+
repaired?: true;
|
|
155
173
|
/** Debug-only: command hash for correlation (never the raw command). */
|
|
156
174
|
commandHash?: string;
|
|
157
175
|
/** Debug-only: the Guardian's rationale. */
|
|
158
176
|
rationale?: string;
|
|
159
177
|
/**
|
|
160
178
|
* Scrubbed + capped copy of the unparseable model output, present only for
|
|
161
|
-
* `outcome: "malformed"`. Always-on (NOT debug-gated):
|
|
162
|
-
* `scrubSecrets`-redacted and size-capped at the source.
|
|
179
|
+
* `outcome: "malformed"` or `repaired: true`. Always-on (NOT debug-gated):
|
|
180
|
+
* it is already `scrubSecrets`-redacted and size-capped at the source.
|
|
163
181
|
*/
|
|
164
182
|
rawOutput?: string;
|
|
165
183
|
}
|
|
@@ -170,6 +188,7 @@ export interface GuardianDiagnosticEvent {
|
|
|
170
188
|
export declare function buildDiagnosticEvent(outcome: GuardianOutcome | GuardianError, opts: {
|
|
171
189
|
durationMs?: number;
|
|
172
190
|
tier?: string;
|
|
191
|
+
repaired?: boolean;
|
|
173
192
|
rationale?: string;
|
|
174
193
|
commandHash?: string;
|
|
175
194
|
rawOutput?: string;
|
|
@@ -128,33 +128,158 @@ export function checkCircuitBreaker(state, limits) {
|
|
|
128
128
|
}
|
|
129
129
|
return { tripped: false };
|
|
130
130
|
}
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
const VALID_RISK_LEVELS = ["low", "medium", "high", "critical"];
|
|
132
|
+
/** Validate an already-parsed object into a verdict. The SINGLE validation
|
|
133
|
+
* gate: strict and repaired parses both end here, so the enum checks stay
|
|
134
|
+
* exactly as strict after repair as before. */
|
|
135
|
+
function validateVerdictObject(parsed) {
|
|
136
|
+
if (!parsed)
|
|
137
|
+
return null;
|
|
138
|
+
const outcome = parsed.outcome;
|
|
139
|
+
if (outcome !== "allow" && outcome !== "ask" && outcome !== "deny")
|
|
140
|
+
return null;
|
|
141
|
+
const riskLevel = parsed.riskLevel;
|
|
142
|
+
return {
|
|
143
|
+
outcome,
|
|
144
|
+
riskLevel: typeof riskLevel === "string" && VALID_RISK_LEVELS.includes(riskLevel)
|
|
145
|
+
? riskLevel
|
|
146
|
+
: "medium",
|
|
147
|
+
rationale: typeof parsed.rationale === "string" && parsed.rationale.trim().length > 0
|
|
148
|
+
? parsed.rationale.trim()
|
|
149
|
+
: "No rationale provided.",
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/** Extract the first {...} block (efficient-tier models may wrap JSON in
|
|
153
|
+
* markdown fences despite instructions to output raw JSON). */
|
|
154
|
+
function extractJsonBlock(raw) {
|
|
155
|
+
const jsonMatch = raw.match(/\{[\s\S]*\}/);
|
|
156
|
+
return jsonMatch ? jsonMatch[0] : raw;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* The lenient repair ladder — applied ONLY after a strict `JSON.parse` of the
|
|
160
|
+
* extracted block has already thrown. Each rung fixes one observed model
|
|
161
|
+
* failure shape and immediately retries the strict parse; the ladder runs in
|
|
162
|
+
* cheapest-first order and the content-synthesizing re-quote is always LAST.
|
|
163
|
+
* Every rung is end-anchored or last-occurrence-anchored and linear-time.
|
|
164
|
+
* Returns the repaired JSON string (parsable) or null if no rung fits.
|
|
165
|
+
*
|
|
166
|
+
* Observed shapes (captured live on deepseek-v4-flash, all previously "unclear
|
|
167
|
+
* verdict"): illegal backslash escapes (\d written literally), a doubled
|
|
168
|
+
* closing quote, and unescaped quotes inside the rationale. The trailing
|
|
169
|
+
* comma is the most common LLM JSON slip in the wild, not (yet) observed here.
|
|
170
|
+
*
|
|
171
|
+
* What the ladder deliberately does NOT fix (all fail closed):
|
|
172
|
+
* single quotes as structure (ambiguous with English apostrophes), glued
|
|
173
|
+
* multi-object output (never pick one verdict of two), raw newlines inside
|
|
174
|
+
* strings (indistinguishable from legal pretty-printed whitespace without
|
|
175
|
+
* parsing), a broken prefix before the rationale anchor, and truncations.
|
|
176
|
+
*/
|
|
177
|
+
function repairVerdictJson(s) {
|
|
178
|
+
// The ladder is SEQUENTIAL: each rung transforms the previous result and
|
|
179
|
+
// immediately retries the strict parse. Composing matters — a blob can
|
|
180
|
+
// carry more than one failure shape (an illegal backslash escape AND a
|
|
181
|
+
// trailing comma, say), and each rung alone would leave the other broken.
|
|
182
|
+
let cur = s;
|
|
183
|
+
// Rung 1 — illegal backslash escapes (\d, \w, \( … become \\d). Legal JSON
|
|
184
|
+
// escapes (" \\ \/ b f n r t and \uXXXX) are left untouched by the lookahead.
|
|
185
|
+
const escapedBackslashes = cur.replace(/\\(?!["\\\/bfnrtu])/g, "\\\\");
|
|
186
|
+
if (escapedBackslashes !== cur) {
|
|
187
|
+
try {
|
|
188
|
+
JSON.parse(escapedBackslashes);
|
|
189
|
+
return escapedBackslashes;
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
cur = escapedBackslashes;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Rung 2 — doubled closing quote before }: anchored to END so a doubled
|
|
196
|
+
// quote mid-rationale is untouched (the re-quote rung handles that shape).
|
|
197
|
+
const collapsedQuote = cur.replace(/""(\s*\})$/, '"$1');
|
|
198
|
+
if (collapsedQuote !== cur) {
|
|
199
|
+
try {
|
|
200
|
+
JSON.parse(collapsedQuote);
|
|
201
|
+
return collapsedQuote;
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
cur = collapsedQuote;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// Rung 3 — trailing comma before }: anchored to END so a comma inside a
|
|
208
|
+
// rationale value ("a, b") can never be stripped.
|
|
209
|
+
const strippedComma = cur.replace(/,(\s*\})$/, '$1');
|
|
210
|
+
if (strippedComma !== cur) {
|
|
211
|
+
try {
|
|
212
|
+
JSON.parse(strippedComma);
|
|
213
|
+
return strippedComma;
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
cur = strippedComma;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Rung 4 (last resort, the only rung that synthesizes content) — re-quote
|
|
220
|
+
// the trailing rationale value. Applies only when the shape is
|
|
221
|
+
// {…"rationale":"<rest-to-end>}: the prefix before the anchor must carry no
|
|
222
|
+
// closing brace (rules out prose and glued multi-object output — an earlier
|
|
223
|
+
// sibling object always leaves a } behind), and the extracted rationale text
|
|
224
|
+
// must carry no braces either (rules out a glued TAIL). Every " and \ in the
|
|
225
|
+
// tail is escaped in ONE pass so whatever the model wrote inside the
|
|
226
|
+
// rationale becomes literal text. Anchor ambiguity resolves to the LAST
|
|
227
|
+
// "rationale":" occurrence; single pass, no loops.
|
|
228
|
+
const anchor = cur.lastIndexOf('"rationale":"');
|
|
229
|
+
if (anchor !== -1) {
|
|
230
|
+
const prefix = cur.slice(0, anchor);
|
|
231
|
+
const tail = cur.slice(anchor + '"rationale":"'.length);
|
|
232
|
+
// The tail must be the trailing value closing the object: non-empty
|
|
233
|
+
// content, an optional-whitespace + } at the very end.
|
|
234
|
+
const tailMatch = tail.match(/^(.+?)(\s*\})$/);
|
|
235
|
+
if (tailMatch && !prefix.includes("}")) {
|
|
236
|
+
const rawRationale = tailMatch[1].replace(/"+$/, "");
|
|
237
|
+
if (rawRationale.length > 0 &&
|
|
238
|
+
!rawRationale.includes("{") &&
|
|
239
|
+
!rawRationale.includes("}")) {
|
|
240
|
+
const reQuoted = prefix +
|
|
241
|
+
'"rationale":"' +
|
|
242
|
+
rawRationale.replace(/["\\]/g, "\\$&") +
|
|
243
|
+
'"}';
|
|
244
|
+
try {
|
|
245
|
+
JSON.parse(reQuoted);
|
|
246
|
+
return reQuoted;
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
/* fail closed */
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
export function parseVerdictDetailed(raw) {
|
|
257
|
+
const jsonStr = extractJsonBlock(raw);
|
|
133
258
|
try {
|
|
134
|
-
// Efficient-tier models may wrap JSON in markdown fences despite
|
|
135
|
-
// instructions to output raw JSON. Extract the first {...} block.
|
|
136
|
-
const jsonMatch = raw.match(/\{[\s\S]*\}/);
|
|
137
|
-
const jsonStr = jsonMatch ? jsonMatch[0] : raw;
|
|
138
259
|
const parsed = JSON.parse(jsonStr);
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
return null;
|
|
142
|
-
const riskLevel = parsed.riskLevel;
|
|
143
|
-
const validLevels = ["low", "medium", "high", "critical"];
|
|
144
|
-
return {
|
|
145
|
-
outcome,
|
|
146
|
-
riskLevel: typeof riskLevel === "string" && validLevels.includes(riskLevel)
|
|
147
|
-
? riskLevel
|
|
148
|
-
: "medium",
|
|
149
|
-
rationale: typeof parsed.rationale === "string" && parsed.rationale.trim().length > 0
|
|
150
|
-
? parsed.rationale.trim()
|
|
151
|
-
: "No rationale provided.",
|
|
152
|
-
};
|
|
260
|
+
const verdict = validateVerdictObject(parsed);
|
|
261
|
+
return verdict ? { verdict, repaired: false } : null;
|
|
153
262
|
}
|
|
154
263
|
catch {
|
|
155
|
-
|
|
264
|
+
// Strict parse failed — try the repair ladder on the same extracted block.
|
|
265
|
+
const repairedJson = repairVerdictJson(jsonStr);
|
|
266
|
+
if (repairedJson === null)
|
|
267
|
+
return null;
|
|
268
|
+
try {
|
|
269
|
+
const parsed = JSON.parse(repairedJson);
|
|
270
|
+
const verdict = validateVerdictObject(parsed);
|
|
271
|
+
return verdict ? { verdict, repaired: true } : null;
|
|
272
|
+
}
|
|
273
|
+
catch {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
156
276
|
}
|
|
157
277
|
}
|
|
278
|
+
/** Strict-shaped convenience wrapper: the verdict, or null. Callers that need
|
|
279
|
+
* the repaired signal use {@link parseVerdictDetailed}. */
|
|
280
|
+
export function parseVerdict(raw) {
|
|
281
|
+
return parseVerdictDetailed(raw)?.verdict ?? null;
|
|
282
|
+
}
|
|
158
283
|
// --- /cost subtotal ---
|
|
159
284
|
export function formatGuardianSubtotal(state, limits) {
|
|
160
285
|
if (state.reviews === 0)
|
|
@@ -236,8 +361,8 @@ export async function reviewCommand(command, deps) {
|
|
|
236
361
|
}
|
|
237
362
|
return { verdict: null, error: "empty", cost };
|
|
238
363
|
}
|
|
239
|
-
const
|
|
240
|
-
if (!
|
|
364
|
+
const parsed = parseVerdictDetailed(output);
|
|
365
|
+
if (!parsed) {
|
|
241
366
|
// Scrubbed + capped so the local sink and Sentry can see the exact
|
|
242
367
|
// failure shape without carrying a raw command or a secret it echoed.
|
|
243
368
|
return {
|
|
@@ -247,7 +372,19 @@ export async function reviewCommand(command, deps) {
|
|
|
247
372
|
rawOutput: scrubSecrets(output).slice(0, GUARDIAN_RAW_OUTPUT_CAP),
|
|
248
373
|
};
|
|
249
374
|
}
|
|
250
|
-
|
|
375
|
+
if (parsed.repaired) {
|
|
376
|
+
// The repair ladder salvaged a broken-but-salvageable verdict. The
|
|
377
|
+
// verdict is real (validation is exactly as strict as the happy path);
|
|
378
|
+
// capture the pre-repair shape so telemetry can keep watching what the
|
|
379
|
+
// model is still emitting wrong.
|
|
380
|
+
return {
|
|
381
|
+
verdict: parsed.verdict,
|
|
382
|
+
cost,
|
|
383
|
+
repaired: true,
|
|
384
|
+
rawOutput: scrubSecrets(output).slice(0, GUARDIAN_RAW_OUTPUT_CAP),
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
return { verdict: parsed.verdict, cost };
|
|
251
388
|
}
|
|
252
389
|
catch (err) {
|
|
253
390
|
// Distinguish the caller aborting (user hit ESC — must NOT be treated as
|
|
@@ -275,6 +412,7 @@ export function buildDiagnosticEvent(outcome, opts) {
|
|
|
275
412
|
outcome,
|
|
276
413
|
...(opts.durationMs !== undefined ? { durationMs: opts.durationMs } : {}),
|
|
277
414
|
...(opts.tier !== undefined ? { tier: opts.tier } : {}),
|
|
415
|
+
...(opts.repaired ? { repaired: true } : {}),
|
|
278
416
|
...(opts.rawOutput !== undefined ? { rawOutput: opts.rawOutput } : {}),
|
|
279
417
|
};
|
|
280
418
|
if (opts.debug) {
|
|
@@ -183,6 +183,11 @@ Rationale rules:
|
|
|
183
183
|
Output ONLY a JSON object with this exact shape:
|
|
184
184
|
{"outcome":"allow"|"ask"|"deny","riskLevel":"low"|"medium"|"high"|"critical","rationale":"see rationale rules"}
|
|
185
185
|
|
|
186
|
+
Your output must parse as strict JSON on the first try:
|
|
187
|
+
- Inside the rationale string, never write a bare double quote. Quote commands, flags, and paths with backticks instead: \`cat ~/.zshrc\`, not "cat ~/.zshrc".
|
|
188
|
+
- A backslash inside a JSON string is legal only as the two-character JSON escapes \\, \\n, \\t, or \\uXXXX, and a quote inside the rationale as \\". Never write regex-style escapes like \\d or \\w literally — write "digit" or "word character" in words instead.
|
|
189
|
+
- Output exactly one JSON object: no trailing comma, no doubled closing quote, no second object, nothing after the closing brace.
|
|
190
|
+
|
|
186
191
|
Do not output anything else after the JSON. No markdown fences, only the JSON object.`;
|
|
187
192
|
const TITLE_BODY = `You produce a session title from a user's prompt. Output ONLY a concise, sentence-case title of 3-7 words that captures the main topic or goal. Capitalize only the first word and proper nouns. Do not include a ticket code in the title text itself (the caller prepends it). No markdown, no prose, no quotes — just the title on one line.
|
|
188
193
|
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `yagni mcp …` — configure MCP servers for YAGNI Code, mirroring Claude
|
|
3
|
+
* Code's CLI surface (add / add-json / remove / get / list /
|
|
4
|
+
* reset-project-choices / add-from-claude).
|
|
5
|
+
*
|
|
6
|
+
* The config module itself lives in pi-extension-yagni (`src/mcp/config.ts`)
|
|
7
|
+
* so the extension session and this CLI read and write the exact same files
|
|
8
|
+
* through the exact same code — loaded here by file path, the same pattern as
|
|
9
|
+
* the session-worktree and headless-go entries. `list` and `get` run real
|
|
10
|
+
* health-check connections (stdio servers are spawned), so they carry the
|
|
11
|
+
* same caution Claude Code prints: only run in directories you trust.
|
|
12
|
+
*
|
|
13
|
+
* Not implemented (deliberate deviations from Claude Code):
|
|
14
|
+
* serve — the YAGNI backend already exposes an MCP endpoint
|
|
15
|
+
* login — enterprise-IdP only in Claude Code; not applicable
|
|
16
|
+
*/
|
|
17
|
+
export interface McpDeps {
|
|
18
|
+
cwd?: string;
|
|
19
|
+
home?: string;
|
|
20
|
+
env?: NodeJS.ProcessEnv;
|
|
21
|
+
stdout?: (text: string) => void;
|
|
22
|
+
stderr?: (text: string) => void;
|
|
23
|
+
/** Test seam: the extension module to import (defaults to the built copy). */
|
|
24
|
+
loadMcpModule?: () => Promise<McpCliModule>;
|
|
25
|
+
/** Test seam: health probe override (defaults to mod.probeServer). */
|
|
26
|
+
probeServer?: (name: string, config: unknown, opts?: {
|
|
27
|
+
env?: NodeJS.ProcessEnv;
|
|
28
|
+
}) => Promise<{
|
|
29
|
+
status: "connected" | "needs_auth" | "failed";
|
|
30
|
+
error?: string;
|
|
31
|
+
}>;
|
|
32
|
+
}
|
|
33
|
+
/** The structural slice of the extension's mcp config surface this file needs. */
|
|
34
|
+
export interface McpCliModule {
|
|
35
|
+
loadMcpServers(cwd: string, env: NodeJS.ProcessEnv): McpLoadResult;
|
|
36
|
+
mcpConfigPath(): string;
|
|
37
|
+
PROJECT_CONFIG_FILENAME: string;
|
|
38
|
+
writeUserMcpConfig(file: unknown): void;
|
|
39
|
+
readUserMcpConfig(): {
|
|
40
|
+
file: unknown;
|
|
41
|
+
errors: unknown[];
|
|
42
|
+
};
|
|
43
|
+
resolveProjectRoot(cwd: string): string;
|
|
44
|
+
resetProjectChoices(repoRoot: string): {
|
|
45
|
+
errors: unknown[];
|
|
46
|
+
};
|
|
47
|
+
decisionFor(state: unknown, serverName: string): "enabled" | "disabled" | "undecided";
|
|
48
|
+
readProjectApproval(repoRoot: string): {
|
|
49
|
+
state: unknown;
|
|
50
|
+
errors: unknown[];
|
|
51
|
+
};
|
|
52
|
+
updateStoredOAuthEntry(serverName: string, config: unknown, mutate: (entry: {
|
|
53
|
+
clientSecret?: string;
|
|
54
|
+
}) => void): {
|
|
55
|
+
errors: unknown[];
|
|
56
|
+
};
|
|
57
|
+
revokeTokensOnRemove(serverName: string, config: unknown, deps?: {
|
|
58
|
+
fetch?: typeof fetch;
|
|
59
|
+
}): Promise<void>;
|
|
60
|
+
getStoredOAuthEntry(serverName: string, config: unknown): {
|
|
61
|
+
clientSecret?: string;
|
|
62
|
+
} | undefined;
|
|
63
|
+
probeServer(name: string, config: unknown, opts?: {
|
|
64
|
+
connectTimeoutMs?: number;
|
|
65
|
+
env?: NodeJS.ProcessEnv;
|
|
66
|
+
}): Promise<{
|
|
67
|
+
status: "connected" | "needs_auth" | "failed";
|
|
68
|
+
error?: string;
|
|
69
|
+
}>;
|
|
70
|
+
/** ${VAR} expansion over a full server config (url, headers, command, args, env values). */
|
|
71
|
+
expandServerEnv?(config: unknown, env?: NodeJS.ProcessEnv): {
|
|
72
|
+
config: unknown;
|
|
73
|
+
missingVars: string[];
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export interface McpLoadResult {
|
|
77
|
+
servers: {
|
|
78
|
+
name: string;
|
|
79
|
+
scope: "user" | "project" | "local";
|
|
80
|
+
config: Record<string, unknown>;
|
|
81
|
+
sourcePath: string;
|
|
82
|
+
}[];
|
|
83
|
+
errors: {
|
|
84
|
+
sourcePath: string;
|
|
85
|
+
serverName?: string;
|
|
86
|
+
message: string;
|
|
87
|
+
}[];
|
|
88
|
+
}
|
|
89
|
+
export declare function resolveMcpConfigPath(): string;
|
|
90
|
+
export interface ParsedMcpArgs {
|
|
91
|
+
subcommand: string | undefined;
|
|
92
|
+
name?: string;
|
|
93
|
+
rest: string[];
|
|
94
|
+
scope: "local" | "user" | "project";
|
|
95
|
+
/** Whether -s/--scope appeared explicitly (remove without it acts across scopes). */
|
|
96
|
+
scopeExplicit: boolean;
|
|
97
|
+
transport: "stdio" | "sse" | "http";
|
|
98
|
+
/** Whether -t/--transport appeared explicitly (drives the URL-misread warning). */
|
|
99
|
+
transportExplicit: boolean;
|
|
100
|
+
env: Record<string, string>;
|
|
101
|
+
headers: Record<string, string>;
|
|
102
|
+
/** Positionals after the subcommand's own first two (stdio command args). */
|
|
103
|
+
commandArgs: string[];
|
|
104
|
+
/** OAuth client id (-only). */
|
|
105
|
+
clientId?: string;
|
|
106
|
+
/** Whether --client-secret was passed (prompt/env-read the secret). */
|
|
107
|
+
clientSecret: boolean;
|
|
108
|
+
/** Fixed loopback callback port. */
|
|
109
|
+
callbackPort?: number;
|
|
110
|
+
}
|
|
111
|
+
export declare function parseMcpArgs(argv: string[]): ParsedMcpArgs;
|
|
112
|
+
export declare function mcpCommand(args: string[], deps?: McpDeps): Promise<number>;
|
|
113
|
+
//# sourceMappingURL=mcpCommand.d.ts.map
|