@antonbabenko/deliberation-mcp 3.6.2 → 3.7.1
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 +49 -48
- 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
280
|
const nonEmpty = lines.map((l) => l.replace(MD_EMPHASIS, "").trim()).filter((t) => t !== "");
|
|
287
281
|
for (const t of [nonEmpty[0], nonEmpty[nonEmpty.length - 1]]) {
|
|
288
|
-
if (t && TOKEN_LINE_RE.test(t)) return (
|
|
289
|
-
/** @type {any} */
|
|
290
|
-
normVerdict(t)
|
|
291
|
-
);
|
|
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
|
}
|
|
@@ -640,9 +632,14 @@ var require_orchestrate = __commonJS({
|
|
|
640
632
|
async function askOne2(provider, req, opts = {}) {
|
|
641
633
|
return callProvider(provider, req, opts.logger || NULL_LOGGER, opts.tool || "ask-one", opts.cache, opts.orientationFiles);
|
|
642
634
|
}
|
|
635
|
+
var MAX_PEER_OPINION_CHARS = 2e3;
|
|
636
|
+
function capPeerOpinion(text) {
|
|
637
|
+
if (typeof text !== "string" || text.length <= MAX_PEER_OPINION_CHARS) return text;
|
|
638
|
+
return text.slice(0, MAX_PEER_OPINION_CHARS) + "\n...[truncated]";
|
|
639
|
+
}
|
|
643
640
|
function buildArbiterPrompt(question, opinions) {
|
|
644
641
|
const blocks = opinions.map((o, i) => `### Opinion ${i + 1}
|
|
645
|
-
${o.text}`).join("\n\n");
|
|
642
|
+
${capPeerOpinion(o.text)}`).join("\n\n");
|
|
646
643
|
return [
|
|
647
644
|
"You are the arbiter. Below are independent expert opinions on the same question.",
|
|
648
645
|
"Cross-review them: note where they agree, where they disagree, and which view is best supported.",
|
|
@@ -696,7 +693,7 @@ ${blocks}`,
|
|
|
696
693
|
const peerBlocks = results.map((r) => {
|
|
697
694
|
if (r.isError) return `Peer ${r.source}: ERRORED`;
|
|
698
695
|
const issues = (r.criticalIssues || []).map((i) => ` - [${i.category}] ${i.description}`).join("\n");
|
|
699
|
-
return `Peer ${r.source}: ${r.verdict || "UNKNOWN"}${issues ? "\n" + issues : ""}
|
|
696
|
+
return capPeerOpinion(`Peer ${r.source}: ${r.verdict || "UNKNOWN"}${issues ? "\n" + issues : ""}`);
|
|
700
697
|
}).join("\n");
|
|
701
698
|
return [
|
|
702
699
|
"ADJUDICATE the peer reviews below and give ONE overall verdict.",
|
|
@@ -798,7 +795,7 @@ ${feedback || "(reviewers gave no specific issues; tighten the weakest part)"}`
|
|
|
798
795
|
opinions: lastResults
|
|
799
796
|
};
|
|
800
797
|
}
|
|
801
|
-
module2.exports = { askAll: askAll2, askOne: askOne2, consensus: consensus2, buildArbiterPrompt, runToConvergence: runToConvergence2 };
|
|
798
|
+
module2.exports = { askAll: askAll2, askOne: askOne2, consensus: consensus2, buildArbiterPrompt, buildAdjudicationPrompt, runToConvergence: runToConvergence2 };
|
|
802
799
|
}
|
|
803
800
|
});
|
|
804
801
|
|
|
@@ -1699,24 +1696,27 @@ var require_antigravity = __commonJS({
|
|
|
1699
1696
|
);
|
|
1700
1697
|
if (!bridge) throw new Error("makeAntigravityProvider requires opts.bridge (core is transport-agnostic; inject the gemini bridge)");
|
|
1701
1698
|
const model = opts.model || process.env.GEMINI_DEFAULT_MODEL || "auto-gemini-3";
|
|
1699
|
+
const allowImplement = opts.allowImplement === true;
|
|
1702
1700
|
return {
|
|
1703
1701
|
name: "gemini",
|
|
1704
|
-
|
|
1702
|
+
// canImplement reflects the construction lock so discovery (panel) is honest about THIS process.
|
|
1703
|
+
capabilities: { canImplement: allowImplement, fileUpload: false, multiTurn: true, walksFilesystem: true },
|
|
1705
1704
|
async health() {
|
|
1706
1705
|
return typeof bridge.runGemini === "function" ? { ok: true } : { ok: false, reason: "agy bridge unavailable" };
|
|
1707
1706
|
},
|
|
1708
1707
|
async ask(req) {
|
|
1709
1708
|
const started = Date.now();
|
|
1709
|
+
const implement = allowImplement && req.mode === "implement";
|
|
1710
1710
|
const includeDirs = (req.files || []).filter((f) => f.dir).map((f) => f.dir);
|
|
1711
1711
|
const args = bridge.buildAgyArgs({
|
|
1712
1712
|
prompt: req.prompt,
|
|
1713
1713
|
model,
|
|
1714
|
-
sandbox: "read-only",
|
|
1714
|
+
sandbox: implement ? "workspace-write" : "read-only",
|
|
1715
1715
|
developerInstructions: req.developerInstructions,
|
|
1716
1716
|
includeDirs
|
|
1717
1717
|
});
|
|
1718
1718
|
try {
|
|
1719
|
-
const out = await bridge.runGemini(args, req.cwd, req.timeoutMs, void 0, { readOnly:
|
|
1719
|
+
const out = await bridge.runGemini(args, req.cwd, req.timeoutMs, void 0, { readOnly: !implement, includeDirs });
|
|
1720
1720
|
return { provider: "gemini", model, text: out.response || "", threadId: out.threadId, isError: false, ms: Date.now() - started, reasoningEffort: null, ...out.workspaceMutated ? { workspaceMutated: true } : {} };
|
|
1721
1721
|
} catch (e) {
|
|
1722
1722
|
const err = (
|
|
@@ -1751,12 +1751,13 @@ var require_codex = __commonJS({
|
|
|
1751
1751
|
if (s.includes("rate")) return { errorKind: "rate-limit", retryable: true };
|
|
1752
1752
|
return { errorKind: "unknown", retryable: false };
|
|
1753
1753
|
}
|
|
1754
|
-
function codexExecArgs() {
|
|
1755
|
-
|
|
1754
|
+
function codexExecArgs(mode) {
|
|
1755
|
+
const sandbox = mode === "implement" ? "workspace-write" : "read-only";
|
|
1756
|
+
return ["exec", "--sandbox", sandbox, "--skip-git-repo-check"];
|
|
1756
1757
|
}
|
|
1757
|
-
function defaultRun({ prompt, cwd, timeoutMs }) {
|
|
1758
|
+
function defaultRun({ prompt, cwd, timeoutMs, mode }) {
|
|
1758
1759
|
return new Promise((resolve) => {
|
|
1759
|
-
const child = spawn("codex", codexExecArgs(), { cwd: cwd || process.cwd() });
|
|
1760
|
+
const child = spawn("codex", codexExecArgs(mode), { cwd: cwd || process.cwd() });
|
|
1760
1761
|
let stdout = "", stderr = "", settled = false;
|
|
1761
1762
|
const timer = timeoutMs ? setTimeout(() => child.kill("SIGKILL"), timeoutMs) : null;
|
|
1762
1763
|
if (timer) timer.unref();
|
|
@@ -1780,21 +1781,24 @@ var require_codex = __commonJS({
|
|
|
1780
1781
|
function makeCodexProvider(opts = {}) {
|
|
1781
1782
|
const run = opts.run || defaultRun;
|
|
1782
1783
|
const model = opts.model || "default";
|
|
1784
|
+
const allowImplement = opts.allowImplement === true;
|
|
1783
1785
|
return {
|
|
1784
1786
|
name: "codex",
|
|
1785
|
-
|
|
1786
|
-
// Option A: no threadId continuity
|
|
1787
|
+
// canImplement reflects the construction lock so discovery (panel) is honest about THIS
|
|
1788
|
+
// process. Option A: no threadId continuity (multiTurn:false).
|
|
1789
|
+
capabilities: { canImplement: allowImplement, fileUpload: false, multiTurn: false, walksFilesystem: true },
|
|
1787
1790
|
async health() {
|
|
1788
1791
|
return { ok: true };
|
|
1789
1792
|
},
|
|
1790
1793
|
async ask(req) {
|
|
1791
1794
|
const started = Date.now();
|
|
1795
|
+
const mode = allowImplement && req.mode === "implement" ? "implement" : "advisory";
|
|
1792
1796
|
const full = req.developerInstructions ? `${req.developerInstructions}
|
|
1793
1797
|
|
|
1794
1798
|
---
|
|
1795
1799
|
|
|
1796
1800
|
${req.prompt}` : req.prompt;
|
|
1797
|
-
const { code, stdout, stderr } = await run({ prompt: full, cwd: req.cwd, timeoutMs: req.timeoutMs });
|
|
1801
|
+
const { code, stdout, stderr } = await run({ prompt: full, cwd: req.cwd, timeoutMs: req.timeoutMs, mode });
|
|
1798
1802
|
if (code === 0) {
|
|
1799
1803
|
return { provider: "codex", model, text: stdout.trim(), isError: false, ms: Date.now() - started, reasoningEffort: null };
|
|
1800
1804
|
}
|
|
@@ -2225,7 +2229,7 @@ ${prompt}`;
|
|
|
2225
2229
|
args.push("-p", prompt);
|
|
2226
2230
|
return args;
|
|
2227
2231
|
}
|
|
2228
|
-
var ADVISORY_ENV_SCRUB = ["
|
|
2232
|
+
var ADVISORY_ENV_SCRUB = ["GIT_ASKPASS", "SSH_AUTH_SOCK"];
|
|
2229
2233
|
var CREDENTIAL_NAME_RE = /(?:^|_)(?:KEY|TOKEN|SECRET|SECRETS|PASSWORD|PASSWD|CREDENTIAL|CREDENTIALS)$|API_KEY|ACCESS_KEY|SESSION_TOKEN|PRIVATE_KEY/i;
|
|
2230
2234
|
function advisoryEnv(env) {
|
|
2231
2235
|
const out = { ...env };
|
|
@@ -2397,7 +2401,10 @@ ${prompt}`;
|
|
|
2397
2401
|
process.stderr.write("[deliberation] agy read-only run wrapped in sandbox-exec (workspace writes denied)\n");
|
|
2398
2402
|
}
|
|
2399
2403
|
const agyProcess = spawn(spawnPlan.cmd, spawnPlan.argv, {
|
|
2400
|
-
|
|
2404
|
+
// Scrub credentials in BOTH read-only and workspace-write runs. A write run
|
|
2405
|
+
// legitimately mutates the worktree but still has no need for the operator's
|
|
2406
|
+
// API keys / GIT_ASKPASS / SSH_AUTH_SOCK - the human commits and pushes, not agy.
|
|
2407
|
+
env: advisoryEnv(process.env),
|
|
2401
2408
|
shell: false,
|
|
2402
2409
|
cwd: effCwd,
|
|
2403
2410
|
// agy -p (print mode) waits for stdin EOF before returning; if the stdin
|
|
@@ -3045,6 +3052,12 @@ var require_glob = __commonJS({
|
|
|
3045
3052
|
for (const c of res) if (c.re.test(rel)) return true;
|
|
3046
3053
|
return false;
|
|
3047
3054
|
}
|
|
3055
|
+
function pushFile(rel, abs, size) {
|
|
3056
|
+
files.push({ rel, abs, size });
|
|
3057
|
+
totalBytes += size;
|
|
3058
|
+
if (files.length > maxFiles) throw new Error(`directory expansion exceeded maxFiles=${maxFiles}. Narrow include or raise the limit.`);
|
|
3059
|
+
if (totalBytes > maxBytes) throw new Error(`directory expansion exceeded maxBytes=${maxBytes} bytes. Narrow include or raise the limit.`);
|
|
3060
|
+
}
|
|
3048
3061
|
function descend(absDir, relDir) {
|
|
3049
3062
|
let entries;
|
|
3050
3063
|
try {
|
|
@@ -3076,10 +3089,7 @@ var require_glob = __commonJS({
|
|
|
3076
3089
|
if (!st.isFile()) continue;
|
|
3077
3090
|
if (matches(excludeRes, relPosix)) continue;
|
|
3078
3091
|
if (!matches(includeRes, relPosix)) continue;
|
|
3079
|
-
|
|
3080
|
-
totalBytes += st.size;
|
|
3081
|
-
if (files.length > maxFiles) throw new Error(`directory expansion exceeded maxFiles=${maxFiles}. Narrow include or raise the limit.`);
|
|
3082
|
-
if (totalBytes > maxBytes) throw new Error(`directory expansion exceeded maxBytes=${maxBytes} bytes. Narrow include or raise the limit.`);
|
|
3092
|
+
pushFile(relPosix, realTarget, st.size);
|
|
3083
3093
|
} else if (ent.isDirectory()) {
|
|
3084
3094
|
if (matches(excludeRes, relPosix) || matches(excludeRes, relPosix + "/**")) continue;
|
|
3085
3095
|
descend(absChild, relPosix);
|
|
@@ -3092,20 +3102,11 @@ var require_glob = __commonJS({
|
|
|
3092
3102
|
} catch (_) {
|
|
3093
3103
|
continue;
|
|
3094
3104
|
}
|
|
3095
|
-
|
|
3096
|
-
totalBytes += st.size;
|
|
3097
|
-
if (files.length > maxFiles) throw new Error(`directory expansion exceeded maxFiles=${maxFiles}. Narrow include or raise the limit.`);
|
|
3098
|
-
if (totalBytes > maxBytes) throw new Error(`directory expansion exceeded maxBytes=${maxBytes} bytes. Narrow include or raise the limit.`);
|
|
3105
|
+
pushFile(relPosix, absChild, st.size);
|
|
3099
3106
|
}
|
|
3100
3107
|
}
|
|
3101
3108
|
}
|
|
3102
3109
|
descend(rootAbs, "");
|
|
3103
|
-
if (files.length > maxFiles) {
|
|
3104
|
-
throw new Error(`directory expansion selected ${files.length} files; exceeds maxFiles=${maxFiles}. Narrow include or raise the limit.`);
|
|
3105
|
-
}
|
|
3106
|
-
if (totalBytes > maxBytes) {
|
|
3107
|
-
throw new Error(`directory expansion selected ${totalBytes} bytes; exceeds maxBytes=${maxBytes}. Narrow include or raise the limit.`);
|
|
3108
|
-
}
|
|
3109
3110
|
files.sort((a, b) => a.rel.localeCompare(b.rel, "en"));
|
|
3110
3111
|
return { files, totalBytes };
|
|
3111
3112
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@antonbabenko/deliberation-mcp",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.1",
|
|
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" },
|