@antonbabenko/deliberation-mcp 3.6.1 → 3.7.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/dist/index.js +61 -52
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -241,7 +241,10 @@ var require_provider = __commonJS({
|
|
|
241
241
|
var STRIP_TRAIL = /[*_`~\s]+$/;
|
|
242
242
|
var HEADING_RE = /^#{1,6}\s/;
|
|
243
243
|
function normVerdict(tok) {
|
|
244
|
-
return
|
|
244
|
+
return (
|
|
245
|
+
/** @type {any} */
|
|
246
|
+
tok.replace(/\s+/g, "_").toUpperCase()
|
|
247
|
+
);
|
|
245
248
|
}
|
|
246
249
|
function parseReview(text) {
|
|
247
250
|
const raw = safeString(text);
|
|
@@ -259,36 +262,24 @@ var require_provider = __commonJS({
|
|
|
259
262
|
function resolveVerdict(lines) {
|
|
260
263
|
for (const ln of lines) {
|
|
261
264
|
const m = ln.match(SENTINEL_RE);
|
|
262
|
-
if (m) return (
|
|
263
|
-
/** @type {any} */
|
|
264
|
-
normVerdict(m[1])
|
|
265
|
-
);
|
|
265
|
+
if (m) return normVerdict(m[1]);
|
|
266
266
|
}
|
|
267
267
|
for (const ln of lines) {
|
|
268
268
|
const m = ln.match(VERDICT_RE);
|
|
269
|
-
if (m) return (
|
|
270
|
-
/** @type {any} */
|
|
271
|
-
normVerdict(m[1])
|
|
272
|
-
);
|
|
269
|
+
if (m) return normVerdict(m[1]);
|
|
273
270
|
}
|
|
274
271
|
for (let i = 0; i < lines.length; i++) {
|
|
275
272
|
if (!VERDICT_WORD_RE.test(lines[i].trim())) continue;
|
|
276
273
|
for (let j = i + 1; j < lines.length && j <= i + 3; j++) {
|
|
277
274
|
const t = lines[j].replace(MD_EMPHASIS, "").trim();
|
|
278
275
|
if (!t) continue;
|
|
279
|
-
if (TOKEN_LINE_RE.test(t)) return (
|
|
280
|
-
/** @type {any} */
|
|
281
|
-
normVerdict(t)
|
|
282
|
-
);
|
|
276
|
+
if (TOKEN_LINE_RE.test(t)) return normVerdict(t);
|
|
283
277
|
break;
|
|
284
278
|
}
|
|
285
279
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
if (TOKEN_LINE_RE.test(t)) return (
|
|
289
|
-
/** @type {any} */
|
|
290
|
-
normVerdict(t)
|
|
291
|
-
);
|
|
280
|
+
const nonEmpty = lines.map((l) => l.replace(MD_EMPHASIS, "").trim()).filter((t) => t !== "");
|
|
281
|
+
for (const t of [nonEmpty[0], nonEmpty[nonEmpty.length - 1]]) {
|
|
282
|
+
if (t && TOKEN_LINE_RE.test(t)) return normVerdict(t);
|
|
292
283
|
}
|
|
293
284
|
return null;
|
|
294
285
|
}
|
|
@@ -345,6 +336,7 @@ var require_consensus_loop = __commonJS({
|
|
|
345
336
|
"use strict";
|
|
346
337
|
var MAX_ROUNDS_DEFAULT = 5;
|
|
347
338
|
var VERDICTS = Object.freeze(["APPROVE", "REQUEST_CHANGES", "REJECT"]);
|
|
339
|
+
var REVIEW_FORMAT_INSTRUCTION = "End with a line by itself in exactly this form (no markdown, token on the SAME line): VERDICT: APPROVE (or VERDICT: REQUEST_CHANGES, or VERDICT: REJECT). Then list any critical issues, one per line as: - [category] description where category is one of security, correctness, scope, ambiguity, performance, ops.";
|
|
348
340
|
function assertStatus(state, expected, op) {
|
|
349
341
|
if (state.status !== expected) {
|
|
350
342
|
throw new Error(`${op}: expected status '${expected}', got '${state.status}'`);
|
|
@@ -387,12 +379,12 @@ ${state.currentPlan}`
|
|
|
387
379
|
const peerPrompt = [
|
|
388
380
|
body,
|
|
389
381
|
"Review the plan for correctness, security, scope, ambiguity, performance, and ops gaps.",
|
|
390
|
-
|
|
382
|
+
REVIEW_FORMAT_INSTRUCTION
|
|
391
383
|
].join("\n\n");
|
|
392
384
|
const blindPrompt = [
|
|
393
385
|
body,
|
|
394
386
|
"Give your own independent verdict BEFORE seeing peer opinions.",
|
|
395
|
-
|
|
387
|
+
REVIEW_FORMAT_INSTRUCTION
|
|
396
388
|
].join("\n\n");
|
|
397
389
|
return { peerPrompt, blindPrompt };
|
|
398
390
|
}
|
|
@@ -1118,7 +1110,7 @@ var require_sessions = __commonJS({
|
|
|
1118
1110
|
var DEFAULT_MAX_AGE_DAYS = 30;
|
|
1119
1111
|
function scrubSecrets(text) {
|
|
1120
1112
|
if (typeof text !== "string" || text.length === 0) return text;
|
|
1121
|
-
return text.replace(/\bsk-or-[A-Za-z0-9_-]{20,}/g, "[REDACTED]").replace(/\bsk-[A-Za-z0-9_-]{20,}/g, "[REDACTED]").replace(/\bxai-[A-Za-z0-9_-]{20,}/g, "[REDACTED]").replace(/\bgh[pousr]_[A-Za-z0-9]{20,}/g, "[REDACTED]").replace(/\bAKIA[0-9A-Z]{16}\b/g, "[REDACTED]").replace(/\bAIza[0-9A-Za-z_-]{35,}/g, "[REDACTED]").replace(/\bBearer\s+[A-Za-z0-9._~+/-]{20,}={0,2}/g, "Bearer [REDACTED]");
|
|
1113
|
+
return text.replace(/\bsk-or-[A-Za-z0-9_-]{20,}/g, "[REDACTED]").replace(/\bsk-[A-Za-z0-9_-]{20,}/g, "[REDACTED]").replace(/\bxai-[A-Za-z0-9_-]{20,}/g, "[REDACTED]").replace(/\bgh[pousr]_[A-Za-z0-9]{20,}/g, "[REDACTED]").replace(/\bAKIA[0-9A-Z]{16}\b/g, "[REDACTED]").replace(/\bAIza[0-9A-Za-z_-]{35,}/g, "[REDACTED]").replace(/\b([a-z][a-z0-9+.-]*:\/\/[^\s:@/]+:)[^\s@/]{6,}@/gi, "$1[REDACTED]@").replace(/\bToken\s+[A-Za-z0-9._~+/-]{20,}={0,2}/g, "Token [REDACTED]").replace(/\bBearer\s+[A-Za-z0-9._~+/-]{20,}={0,2}/g, "Bearer [REDACTED]");
|
|
1122
1114
|
}
|
|
1123
1115
|
function capText(text) {
|
|
1124
1116
|
if (typeof text !== "string") return text;
|
|
@@ -1699,24 +1691,27 @@ var require_antigravity = __commonJS({
|
|
|
1699
1691
|
);
|
|
1700
1692
|
if (!bridge) throw new Error("makeAntigravityProvider requires opts.bridge (core is transport-agnostic; inject the gemini bridge)");
|
|
1701
1693
|
const model = opts.model || process.env.GEMINI_DEFAULT_MODEL || "auto-gemini-3";
|
|
1694
|
+
const allowImplement = opts.allowImplement === true;
|
|
1702
1695
|
return {
|
|
1703
1696
|
name: "gemini",
|
|
1704
|
-
|
|
1697
|
+
// canImplement reflects the construction lock so discovery (panel) is honest about THIS process.
|
|
1698
|
+
capabilities: { canImplement: allowImplement, fileUpload: false, multiTurn: true, walksFilesystem: true },
|
|
1705
1699
|
async health() {
|
|
1706
1700
|
return typeof bridge.runGemini === "function" ? { ok: true } : { ok: false, reason: "agy bridge unavailable" };
|
|
1707
1701
|
},
|
|
1708
1702
|
async ask(req) {
|
|
1709
1703
|
const started = Date.now();
|
|
1704
|
+
const implement = allowImplement && req.mode === "implement";
|
|
1710
1705
|
const includeDirs = (req.files || []).filter((f) => f.dir).map((f) => f.dir);
|
|
1711
1706
|
const args = bridge.buildAgyArgs({
|
|
1712
1707
|
prompt: req.prompt,
|
|
1713
1708
|
model,
|
|
1714
|
-
sandbox: "read-only",
|
|
1709
|
+
sandbox: implement ? "workspace-write" : "read-only",
|
|
1715
1710
|
developerInstructions: req.developerInstructions,
|
|
1716
1711
|
includeDirs
|
|
1717
1712
|
});
|
|
1718
1713
|
try {
|
|
1719
|
-
const out = await bridge.runGemini(args, req.cwd, req.timeoutMs, void 0, { readOnly:
|
|
1714
|
+
const out = await bridge.runGemini(args, req.cwd, req.timeoutMs, void 0, { readOnly: !implement, includeDirs });
|
|
1720
1715
|
return { provider: "gemini", model, text: out.response || "", threadId: out.threadId, isError: false, ms: Date.now() - started, reasoningEffort: null, ...out.workspaceMutated ? { workspaceMutated: true } : {} };
|
|
1721
1716
|
} catch (e) {
|
|
1722
1717
|
const err = (
|
|
@@ -1751,12 +1746,13 @@ var require_codex = __commonJS({
|
|
|
1751
1746
|
if (s.includes("rate")) return { errorKind: "rate-limit", retryable: true };
|
|
1752
1747
|
return { errorKind: "unknown", retryable: false };
|
|
1753
1748
|
}
|
|
1754
|
-
function codexExecArgs() {
|
|
1755
|
-
|
|
1749
|
+
function codexExecArgs(mode) {
|
|
1750
|
+
const sandbox = mode === "implement" ? "workspace-write" : "read-only";
|
|
1751
|
+
return ["exec", "--sandbox", sandbox, "--skip-git-repo-check"];
|
|
1756
1752
|
}
|
|
1757
|
-
function defaultRun({ prompt, cwd, timeoutMs }) {
|
|
1753
|
+
function defaultRun({ prompt, cwd, timeoutMs, mode }) {
|
|
1758
1754
|
return new Promise((resolve) => {
|
|
1759
|
-
const child = spawn("codex", codexExecArgs(), { cwd: cwd || process.cwd() });
|
|
1755
|
+
const child = spawn("codex", codexExecArgs(mode), { cwd: cwd || process.cwd() });
|
|
1760
1756
|
let stdout = "", stderr = "", settled = false;
|
|
1761
1757
|
const timer = timeoutMs ? setTimeout(() => child.kill("SIGKILL"), timeoutMs) : null;
|
|
1762
1758
|
if (timer) timer.unref();
|
|
@@ -1780,21 +1776,24 @@ var require_codex = __commonJS({
|
|
|
1780
1776
|
function makeCodexProvider(opts = {}) {
|
|
1781
1777
|
const run = opts.run || defaultRun;
|
|
1782
1778
|
const model = opts.model || "default";
|
|
1779
|
+
const allowImplement = opts.allowImplement === true;
|
|
1783
1780
|
return {
|
|
1784
1781
|
name: "codex",
|
|
1785
|
-
|
|
1786
|
-
// Option A: no threadId continuity
|
|
1782
|
+
// canImplement reflects the construction lock so discovery (panel) is honest about THIS
|
|
1783
|
+
// process. Option A: no threadId continuity (multiTurn:false).
|
|
1784
|
+
capabilities: { canImplement: allowImplement, fileUpload: false, multiTurn: false, walksFilesystem: true },
|
|
1787
1785
|
async health() {
|
|
1788
1786
|
return { ok: true };
|
|
1789
1787
|
},
|
|
1790
1788
|
async ask(req) {
|
|
1791
1789
|
const started = Date.now();
|
|
1790
|
+
const mode = allowImplement && req.mode === "implement" ? "implement" : "advisory";
|
|
1792
1791
|
const full = req.developerInstructions ? `${req.developerInstructions}
|
|
1793
1792
|
|
|
1794
1793
|
---
|
|
1795
1794
|
|
|
1796
1795
|
${req.prompt}` : req.prompt;
|
|
1797
|
-
const { code, stdout, stderr } = await run({ prompt: full, cwd: req.cwd, timeoutMs: req.timeoutMs });
|
|
1796
|
+
const { code, stdout, stderr } = await run({ prompt: full, cwd: req.cwd, timeoutMs: req.timeoutMs, mode });
|
|
1798
1797
|
if (code === 0) {
|
|
1799
1798
|
return { provider: "codex", model, text: stdout.trim(), isError: false, ms: Date.now() - started, reasoningEffort: null };
|
|
1800
1799
|
}
|
|
@@ -2202,6 +2201,7 @@ var require_gemini = __commonJS({
|
|
|
2202
2201
|
var DEFAULT_RECOVERY_GRACE_MS = 12e4;
|
|
2203
2202
|
var MAX_MS = 6e5;
|
|
2204
2203
|
var VALID_SANDBOX_VALUES = /* @__PURE__ */ new Set(["read-only", "workspace-write"]);
|
|
2204
|
+
var THREAD_ID_RE = /^[A-Za-z0-9_][A-Za-z0-9_-]{0,127}$/;
|
|
2205
2205
|
function goDuration(ms) {
|
|
2206
2206
|
return Math.ceil(ms / 1e3) + "s";
|
|
2207
2207
|
}
|
|
@@ -2224,11 +2224,15 @@ ${prompt}`;
|
|
|
2224
2224
|
args.push("-p", prompt);
|
|
2225
2225
|
return args;
|
|
2226
2226
|
}
|
|
2227
|
-
var ADVISORY_ENV_SCRUB = ["
|
|
2227
|
+
var ADVISORY_ENV_SCRUB = ["GIT_ASKPASS", "SSH_AUTH_SOCK"];
|
|
2228
|
+
var CREDENTIAL_NAME_RE = /(?:^|_)(?:KEY|TOKEN|SECRET|SECRETS|PASSWORD|PASSWD|CREDENTIAL|CREDENTIALS)$|API_KEY|ACCESS_KEY|SESSION_TOKEN|PRIVATE_KEY/i;
|
|
2228
2229
|
function advisoryEnv(env) {
|
|
2229
2230
|
const out = { ...env };
|
|
2230
2231
|
delete out.DELIBERATION_DISABLE_OS_SANDBOX;
|
|
2231
2232
|
for (const k of ADVISORY_ENV_SCRUB) delete out[k];
|
|
2233
|
+
for (const k of Object.keys(out)) {
|
|
2234
|
+
if (CREDENTIAL_NAME_RE.test(k)) delete out[k];
|
|
2235
|
+
}
|
|
2232
2236
|
return out;
|
|
2233
2237
|
}
|
|
2234
2238
|
function seatbeltLiteral(p) {
|
|
@@ -2349,7 +2353,8 @@ ${prompt}`;
|
|
|
2349
2353
|
real = fs.realpathSync(resolved);
|
|
2350
2354
|
} catch (_) {
|
|
2351
2355
|
}
|
|
2352
|
-
|
|
2356
|
+
const candidate = map[real] ?? map[resolved] ?? map[cwd] ?? null;
|
|
2357
|
+
return typeof candidate === "string" && THREAD_ID_RE.test(candidate) ? candidate : null;
|
|
2353
2358
|
} catch (_) {
|
|
2354
2359
|
return null;
|
|
2355
2360
|
}
|
|
@@ -2391,7 +2396,10 @@ ${prompt}`;
|
|
|
2391
2396
|
process.stderr.write("[deliberation] agy read-only run wrapped in sandbox-exec (workspace writes denied)\n");
|
|
2392
2397
|
}
|
|
2393
2398
|
const agyProcess = spawn(spawnPlan.cmd, spawnPlan.argv, {
|
|
2394
|
-
|
|
2399
|
+
// Scrub credentials in BOTH read-only and workspace-write runs. A write run
|
|
2400
|
+
// legitimately mutates the worktree but still has no need for the operator's
|
|
2401
|
+
// API keys / GIT_ASKPASS / SSH_AUTH_SOCK - the human commits and pushes, not agy.
|
|
2402
|
+
env: advisoryEnv(process.env),
|
|
2395
2403
|
shell: false,
|
|
2396
2404
|
cwd: effCwd,
|
|
2397
2405
|
// agy -p (print mode) waits for stdin EOF before returning; if the stdin
|
|
@@ -2674,8 +2682,8 @@ ${prompt}`;
|
|
|
2674
2682
|
return;
|
|
2675
2683
|
}
|
|
2676
2684
|
const threadId2 = args.threadId.trim();
|
|
2677
|
-
if (threadId2
|
|
2678
|
-
if (shouldRespond) sendError(id, -32602, "Invalid params: 'threadId' must be an explicit conversation id
|
|
2685
|
+
if (!THREAD_ID_RE.test(threadId2) || threadId2 === "latest" || threadId2 === "unknown") {
|
|
2686
|
+
if (shouldRespond) sendError(id, -32602, "Invalid params: 'threadId' must be an explicit conversation id (alphanumeric/underscore start, then [A-Za-z0-9_-], 1..128 chars)");
|
|
2679
2687
|
return;
|
|
2680
2688
|
}
|
|
2681
2689
|
if (!isNonEmptyString(args.prompt)) {
|
|
@@ -2772,6 +2780,7 @@ ${prompt}`;
|
|
|
2772
2780
|
module2.exports.READ_ONLY_GUARD = READ_ONLY_GUARD;
|
|
2773
2781
|
module2.exports.applyReadOnlyGuard = applyReadOnlyGuard;
|
|
2774
2782
|
module2.exports.advisoryEnv = advisoryEnv;
|
|
2783
|
+
module2.exports.THREAD_ID_RE = THREAD_ID_RE;
|
|
2775
2784
|
module2.exports.buildSeatbeltProfile = buildSeatbeltProfile;
|
|
2776
2785
|
module2.exports.buildSpawnCommand = buildSpawnCommand;
|
|
2777
2786
|
module2.exports.diffGitState = diffGitState;
|
|
@@ -2806,7 +2815,7 @@ var require_lock = __commonJS({
|
|
|
2806
2815
|
try {
|
|
2807
2816
|
fs.mkdirSync(lockDir);
|
|
2808
2817
|
const markerPath = path.join(lockDir, markerName);
|
|
2809
|
-
fs.writeFileSync(markerPath, JSON.stringify({ pid: process.pid, token, t: Date.now() }));
|
|
2818
|
+
fs.writeFileSync(markerPath, JSON.stringify({ pid: process.pid, token, t: Date.now() }), { mode: 384 });
|
|
2810
2819
|
return { lockDir, markerPath, token };
|
|
2811
2820
|
} catch (e) {
|
|
2812
2821
|
if (e.code !== "EEXIST") throw e;
|
|
@@ -2900,7 +2909,7 @@ var require_cache = __commonJS({
|
|
|
2900
2909
|
function writeCache(file, data) {
|
|
2901
2910
|
mkdirSync(path.dirname(file), { recursive: true });
|
|
2902
2911
|
const tmp = `${file}.tmp.${process.pid}.${Date.now()}`;
|
|
2903
|
-
writeFileSync(tmp, JSON.stringify(data));
|
|
2912
|
+
writeFileSync(tmp, JSON.stringify(data), { mode: 384 });
|
|
2904
2913
|
renameSync(tmp, file);
|
|
2905
2914
|
}
|
|
2906
2915
|
var _inflight = /* @__PURE__ */ new Map();
|
|
@@ -3038,6 +3047,12 @@ var require_glob = __commonJS({
|
|
|
3038
3047
|
for (const c of res) if (c.re.test(rel)) return true;
|
|
3039
3048
|
return false;
|
|
3040
3049
|
}
|
|
3050
|
+
function pushFile(rel, abs, size) {
|
|
3051
|
+
files.push({ rel, abs, size });
|
|
3052
|
+
totalBytes += size;
|
|
3053
|
+
if (files.length > maxFiles) throw new Error(`directory expansion exceeded maxFiles=${maxFiles}. Narrow include or raise the limit.`);
|
|
3054
|
+
if (totalBytes > maxBytes) throw new Error(`directory expansion exceeded maxBytes=${maxBytes} bytes. Narrow include or raise the limit.`);
|
|
3055
|
+
}
|
|
3041
3056
|
function descend(absDir, relDir) {
|
|
3042
3057
|
let entries;
|
|
3043
3058
|
try {
|
|
@@ -3069,8 +3084,7 @@ var require_glob = __commonJS({
|
|
|
3069
3084
|
if (!st.isFile()) continue;
|
|
3070
3085
|
if (matches(excludeRes, relPosix)) continue;
|
|
3071
3086
|
if (!matches(includeRes, relPosix)) continue;
|
|
3072
|
-
|
|
3073
|
-
totalBytes += st.size;
|
|
3087
|
+
pushFile(relPosix, realTarget, st.size);
|
|
3074
3088
|
} else if (ent.isDirectory()) {
|
|
3075
3089
|
if (matches(excludeRes, relPosix) || matches(excludeRes, relPosix + "/**")) continue;
|
|
3076
3090
|
descend(absChild, relPosix);
|
|
@@ -3083,18 +3097,11 @@ var require_glob = __commonJS({
|
|
|
3083
3097
|
} catch (_) {
|
|
3084
3098
|
continue;
|
|
3085
3099
|
}
|
|
3086
|
-
|
|
3087
|
-
totalBytes += st.size;
|
|
3100
|
+
pushFile(relPosix, absChild, st.size);
|
|
3088
3101
|
}
|
|
3089
3102
|
}
|
|
3090
3103
|
}
|
|
3091
3104
|
descend(rootAbs, "");
|
|
3092
|
-
if (files.length > maxFiles) {
|
|
3093
|
-
throw new Error(`directory expansion selected ${files.length} files; exceeds maxFiles=${maxFiles}. Narrow include or raise the limit.`);
|
|
3094
|
-
}
|
|
3095
|
-
if (totalBytes > maxBytes) {
|
|
3096
|
-
throw new Error(`directory expansion selected ${totalBytes} bytes; exceeds maxBytes=${maxBytes}. Narrow include or raise the limit.`);
|
|
3097
|
-
}
|
|
3098
3105
|
files.sort((a, b) => a.rel.localeCompare(b.rel, "en"));
|
|
3099
3106
|
return { files, totalBytes };
|
|
3100
3107
|
}
|
|
@@ -3409,7 +3416,8 @@ ${ref.inline_text}` });
|
|
|
3409
3416
|
res = await f(`${base}/files`, {
|
|
3410
3417
|
method: "POST",
|
|
3411
3418
|
headers: { "Authorization": `Bearer ${apiKey}` },
|
|
3412
|
-
body: form
|
|
3419
|
+
body: form,
|
|
3420
|
+
redirect: "error"
|
|
3413
3421
|
});
|
|
3414
3422
|
} catch (err) {
|
|
3415
3423
|
const e = new Error(`File upload network error: ${err && err.message || err}`);
|
|
@@ -3599,7 +3607,8 @@ ${ref.inline_text}` });
|
|
|
3599
3607
|
"Authorization": `Bearer ${apiKey}`
|
|
3600
3608
|
},
|
|
3601
3609
|
body: JSON.stringify(payload),
|
|
3602
|
-
signal: controller.signal
|
|
3610
|
+
signal: controller.signal,
|
|
3611
|
+
redirect: "error"
|
|
3603
3612
|
});
|
|
3604
3613
|
} catch (err) {
|
|
3605
3614
|
const name = err && err.name;
|
|
@@ -4326,7 +4335,7 @@ var require_openrouter = __commonJS({
|
|
|
4326
4335
|
const timer = setTimeout(() => controller.abort(), t);
|
|
4327
4336
|
let res;
|
|
4328
4337
|
try {
|
|
4329
|
-
res = await f(url, { method: "POST", headers, body: JSON.stringify(payload), signal: controller.signal });
|
|
4338
|
+
res = await f(url, { method: "POST", headers, body: JSON.stringify(payload), signal: controller.signal, redirect: "error" });
|
|
4330
4339
|
} catch (err) {
|
|
4331
4340
|
const msg = String(err && err.message || err);
|
|
4332
4341
|
if (err && err.name === "AbortError" || /abort/i.test(msg)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antonbabenko/deliberation-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.0",
|
|
4
4
|
"description": "Deliberation for Claude Code and any MCP host - GPT, Gemini, Grok, and OpenRouter expert subagents.",
|
|
5
5
|
"mcpName": "io.github.antonbabenko/deliberation",
|
|
6
6
|
"repository": { "type": "git", "url": "git+https://github.com/antonbabenko/deliberation.git", "directory": "server/mcp" },
|