@antonbabenko/deliberation-mcp 3.6.0 → 3.6.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.
- package/dist/index.js +99 -23
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -231,18 +231,71 @@ var require_provider = __commonJS({
|
|
|
231
231
|
var VERDICT_RE = /\bverdict\b[^A-Za-z0-9]*\b(APPROVE|REJECT|REQUEST[_\s]CHANGES)\b/i;
|
|
232
232
|
var BULLET_RE = /^([-*+•]|`?\[)/;
|
|
233
233
|
var BRACKET_CAT_RE = /\[\s*([A-Za-z_]+)\s*\]/g;
|
|
234
|
+
var SENTINEL_RE = /^[#>*_`\s]*verdict\s*[:=]\s*[*_`\s]*(APPROVE|REJECT|REQUEST[_\s]CHANGES)\b/i;
|
|
235
|
+
var VERDICT_WORD_RE = /^[#>*_`\s]*verdict[*_`:\s]*$/i;
|
|
236
|
+
var TOKEN_LINE_RE = /^(APPROVE|REJECT|REQUEST[_\s]CHANGES)$/i;
|
|
237
|
+
var MD_EMPHASIS = /[*_`~]/g;
|
|
238
|
+
var FENCE_RE = /^\s*(```|~~~)/;
|
|
239
|
+
var ARTIFACT_RE = /^[*_`~\s:.\-]*$/;
|
|
240
|
+
var STRIP_LEAD = /^[*_`~\s:.\-]+/;
|
|
241
|
+
var STRIP_TRAIL = /[*_`~\s]+$/;
|
|
242
|
+
var HEADING_RE = /^#{1,6}\s/;
|
|
243
|
+
function normVerdict(tok) {
|
|
244
|
+
return tok.replace(/\s+/g, "_").toUpperCase();
|
|
245
|
+
}
|
|
234
246
|
function parseReview(text) {
|
|
235
247
|
const raw = safeString(text);
|
|
236
|
-
const lines =
|
|
237
|
-
let
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
if (vm) verdict = /** @type {ParsedReview["verdict"]} */
|
|
243
|
-
vm[1].replace(/\s+/g, "_").toUpperCase();
|
|
248
|
+
const lines = [];
|
|
249
|
+
let inFence = false;
|
|
250
|
+
for (const ln of raw.split(/\r?\n/)) {
|
|
251
|
+
if (FENCE_RE.test(ln)) {
|
|
252
|
+
inFence = !inFence;
|
|
253
|
+
continue;
|
|
244
254
|
}
|
|
245
|
-
|
|
255
|
+
if (!inFence) lines.push(ln);
|
|
256
|
+
}
|
|
257
|
+
return { verdict: resolveVerdict(lines), criticalIssues: resolveIssues(lines) };
|
|
258
|
+
}
|
|
259
|
+
function resolveVerdict(lines) {
|
|
260
|
+
for (const ln of lines) {
|
|
261
|
+
const m = ln.match(SENTINEL_RE);
|
|
262
|
+
if (m) return (
|
|
263
|
+
/** @type {any} */
|
|
264
|
+
normVerdict(m[1])
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
for (const ln of lines) {
|
|
268
|
+
const m = ln.match(VERDICT_RE);
|
|
269
|
+
if (m) return (
|
|
270
|
+
/** @type {any} */
|
|
271
|
+
normVerdict(m[1])
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
for (let i = 0; i < lines.length; i++) {
|
|
275
|
+
if (!VERDICT_WORD_RE.test(lines[i].trim())) continue;
|
|
276
|
+
for (let j = i + 1; j < lines.length && j <= i + 3; j++) {
|
|
277
|
+
const t = lines[j].replace(MD_EMPHASIS, "").trim();
|
|
278
|
+
if (!t) continue;
|
|
279
|
+
if (TOKEN_LINE_RE.test(t)) return (
|
|
280
|
+
/** @type {any} */
|
|
281
|
+
normVerdict(t)
|
|
282
|
+
);
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
const nonEmpty = lines.map((l) => l.replace(MD_EMPHASIS, "").trim()).filter((t) => t !== "");
|
|
287
|
+
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
|
+
);
|
|
292
|
+
}
|
|
293
|
+
return null;
|
|
294
|
+
}
|
|
295
|
+
function resolveIssues(lines) {
|
|
296
|
+
const out = [];
|
|
297
|
+
for (let i = 0; i < lines.length; i++) {
|
|
298
|
+
const trimmed = lines[i].trim();
|
|
246
299
|
if (!BULLET_RE.test(trimmed)) continue;
|
|
247
300
|
let chosen = null;
|
|
248
301
|
for (const mm of trimmed.matchAll(BRACKET_CAT_RE)) {
|
|
@@ -258,10 +311,20 @@ var require_provider = __commonJS({
|
|
|
258
311
|
/** @type {ReviewCriticalIssue["category"]} */
|
|
259
312
|
REVIEW_CATEGORIES.includes(cat) ? cat : REVIEW_FALLBACK_CATEGORY
|
|
260
313
|
);
|
|
261
|
-
|
|
262
|
-
if (description
|
|
314
|
+
let description = trimmed.slice(chosen.index + chosen[0].length).replace(STRIP_LEAD, "").replace(STRIP_TRAIL, "").trim();
|
|
315
|
+
if (!description || ARTIFACT_RE.test(description)) {
|
|
316
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
317
|
+
const nt = lines[j].trim();
|
|
318
|
+
if (!nt) break;
|
|
319
|
+
if (BULLET_RE.test(nt) || HEADING_RE.test(nt)) break;
|
|
320
|
+
if (SENTINEL_RE.test(nt) || VERDICT_WORD_RE.test(nt) || VERDICT_RE.test(nt)) break;
|
|
321
|
+
description = nt.replace(STRIP_LEAD, "").replace(STRIP_TRAIL, "").trim();
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (description && !ARTIFACT_RE.test(description)) out.push({ category, description });
|
|
263
326
|
}
|
|
264
|
-
return
|
|
327
|
+
return out;
|
|
265
328
|
}
|
|
266
329
|
module2.exports = {
|
|
267
330
|
toErrorResult,
|
|
@@ -324,12 +387,12 @@ ${state.currentPlan}`
|
|
|
324
387
|
const peerPrompt = [
|
|
325
388
|
body,
|
|
326
389
|
"Review the plan for correctness, security, scope, ambiguity, performance, and ops gaps.",
|
|
327
|
-
"End with:
|
|
390
|
+
"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."
|
|
328
391
|
].join("\n\n");
|
|
329
392
|
const blindPrompt = [
|
|
330
393
|
body,
|
|
331
394
|
"Give your own independent verdict BEFORE seeing peer opinions.",
|
|
332
|
-
"End with:
|
|
395
|
+
"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."
|
|
333
396
|
].join("\n\n");
|
|
334
397
|
return { peerPrompt, blindPrompt };
|
|
335
398
|
}
|
|
@@ -1055,7 +1118,7 @@ var require_sessions = __commonJS({
|
|
|
1055
1118
|
var DEFAULT_MAX_AGE_DAYS = 30;
|
|
1056
1119
|
function scrubSecrets(text) {
|
|
1057
1120
|
if (typeof text !== "string" || text.length === 0) return text;
|
|
1058
|
-
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]");
|
|
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(/\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]");
|
|
1059
1122
|
}
|
|
1060
1123
|
function capText(text) {
|
|
1061
1124
|
if (typeof text !== "string") return text;
|
|
@@ -2139,6 +2202,7 @@ var require_gemini = __commonJS({
|
|
|
2139
2202
|
var DEFAULT_RECOVERY_GRACE_MS = 12e4;
|
|
2140
2203
|
var MAX_MS = 6e5;
|
|
2141
2204
|
var VALID_SANDBOX_VALUES = /* @__PURE__ */ new Set(["read-only", "workspace-write"]);
|
|
2205
|
+
var THREAD_ID_RE = /^[A-Za-z0-9_][A-Za-z0-9_-]{0,127}$/;
|
|
2142
2206
|
function goDuration(ms) {
|
|
2143
2207
|
return Math.ceil(ms / 1e3) + "s";
|
|
2144
2208
|
}
|
|
@@ -2162,10 +2226,14 @@ ${prompt}`;
|
|
|
2162
2226
|
return args;
|
|
2163
2227
|
}
|
|
2164
2228
|
var ADVISORY_ENV_SCRUB = ["GITHUB_TOKEN", "GH_TOKEN", "GIT_ASKPASS", "SSH_AUTH_SOCK"];
|
|
2229
|
+
var CREDENTIAL_NAME_RE = /(?:^|_)(?:KEY|TOKEN|SECRET|SECRETS|PASSWORD|PASSWD|CREDENTIAL|CREDENTIALS)$|API_KEY|ACCESS_KEY|SESSION_TOKEN|PRIVATE_KEY/i;
|
|
2165
2230
|
function advisoryEnv(env) {
|
|
2166
2231
|
const out = { ...env };
|
|
2167
2232
|
delete out.DELIBERATION_DISABLE_OS_SANDBOX;
|
|
2168
2233
|
for (const k of ADVISORY_ENV_SCRUB) delete out[k];
|
|
2234
|
+
for (const k of Object.keys(out)) {
|
|
2235
|
+
if (CREDENTIAL_NAME_RE.test(k)) delete out[k];
|
|
2236
|
+
}
|
|
2169
2237
|
return out;
|
|
2170
2238
|
}
|
|
2171
2239
|
function seatbeltLiteral(p) {
|
|
@@ -2286,7 +2354,8 @@ ${prompt}`;
|
|
|
2286
2354
|
real = fs.realpathSync(resolved);
|
|
2287
2355
|
} catch (_) {
|
|
2288
2356
|
}
|
|
2289
|
-
|
|
2357
|
+
const candidate = map[real] ?? map[resolved] ?? map[cwd] ?? null;
|
|
2358
|
+
return typeof candidate === "string" && THREAD_ID_RE.test(candidate) ? candidate : null;
|
|
2290
2359
|
} catch (_) {
|
|
2291
2360
|
return null;
|
|
2292
2361
|
}
|
|
@@ -2611,8 +2680,8 @@ ${prompt}`;
|
|
|
2611
2680
|
return;
|
|
2612
2681
|
}
|
|
2613
2682
|
const threadId2 = args.threadId.trim();
|
|
2614
|
-
if (threadId2
|
|
2615
|
-
if (shouldRespond) sendError(id, -32602, "Invalid params: 'threadId' must be an explicit conversation id
|
|
2683
|
+
if (!THREAD_ID_RE.test(threadId2) || threadId2 === "latest" || threadId2 === "unknown") {
|
|
2684
|
+
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)");
|
|
2616
2685
|
return;
|
|
2617
2686
|
}
|
|
2618
2687
|
if (!isNonEmptyString(args.prompt)) {
|
|
@@ -2709,6 +2778,7 @@ ${prompt}`;
|
|
|
2709
2778
|
module2.exports.READ_ONLY_GUARD = READ_ONLY_GUARD;
|
|
2710
2779
|
module2.exports.applyReadOnlyGuard = applyReadOnlyGuard;
|
|
2711
2780
|
module2.exports.advisoryEnv = advisoryEnv;
|
|
2781
|
+
module2.exports.THREAD_ID_RE = THREAD_ID_RE;
|
|
2712
2782
|
module2.exports.buildSeatbeltProfile = buildSeatbeltProfile;
|
|
2713
2783
|
module2.exports.buildSpawnCommand = buildSpawnCommand;
|
|
2714
2784
|
module2.exports.diffGitState = diffGitState;
|
|
@@ -2743,7 +2813,7 @@ var require_lock = __commonJS({
|
|
|
2743
2813
|
try {
|
|
2744
2814
|
fs.mkdirSync(lockDir);
|
|
2745
2815
|
const markerPath = path.join(lockDir, markerName);
|
|
2746
|
-
fs.writeFileSync(markerPath, JSON.stringify({ pid: process.pid, token, t: Date.now() }));
|
|
2816
|
+
fs.writeFileSync(markerPath, JSON.stringify({ pid: process.pid, token, t: Date.now() }), { mode: 384 });
|
|
2747
2817
|
return { lockDir, markerPath, token };
|
|
2748
2818
|
} catch (e) {
|
|
2749
2819
|
if (e.code !== "EEXIST") throw e;
|
|
@@ -2837,7 +2907,7 @@ var require_cache = __commonJS({
|
|
|
2837
2907
|
function writeCache(file, data) {
|
|
2838
2908
|
mkdirSync(path.dirname(file), { recursive: true });
|
|
2839
2909
|
const tmp = `${file}.tmp.${process.pid}.${Date.now()}`;
|
|
2840
|
-
writeFileSync(tmp, JSON.stringify(data));
|
|
2910
|
+
writeFileSync(tmp, JSON.stringify(data), { mode: 384 });
|
|
2841
2911
|
renameSync(tmp, file);
|
|
2842
2912
|
}
|
|
2843
2913
|
var _inflight = /* @__PURE__ */ new Map();
|
|
@@ -3008,6 +3078,8 @@ var require_glob = __commonJS({
|
|
|
3008
3078
|
if (!matches(includeRes, relPosix)) continue;
|
|
3009
3079
|
files.push({ rel: relPosix, abs: realTarget, size: st.size });
|
|
3010
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.`);
|
|
3011
3083
|
} else if (ent.isDirectory()) {
|
|
3012
3084
|
if (matches(excludeRes, relPosix) || matches(excludeRes, relPosix + "/**")) continue;
|
|
3013
3085
|
descend(absChild, relPosix);
|
|
@@ -3022,6 +3094,8 @@ var require_glob = __commonJS({
|
|
|
3022
3094
|
}
|
|
3023
3095
|
files.push({ rel: relPosix, abs: absChild, size: st.size });
|
|
3024
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.`);
|
|
3025
3099
|
}
|
|
3026
3100
|
}
|
|
3027
3101
|
}
|
|
@@ -3346,7 +3420,8 @@ ${ref.inline_text}` });
|
|
|
3346
3420
|
res = await f(`${base}/files`, {
|
|
3347
3421
|
method: "POST",
|
|
3348
3422
|
headers: { "Authorization": `Bearer ${apiKey}` },
|
|
3349
|
-
body: form
|
|
3423
|
+
body: form,
|
|
3424
|
+
redirect: "error"
|
|
3350
3425
|
});
|
|
3351
3426
|
} catch (err) {
|
|
3352
3427
|
const e = new Error(`File upload network error: ${err && err.message || err}`);
|
|
@@ -3536,7 +3611,8 @@ ${ref.inline_text}` });
|
|
|
3536
3611
|
"Authorization": `Bearer ${apiKey}`
|
|
3537
3612
|
},
|
|
3538
3613
|
body: JSON.stringify(payload),
|
|
3539
|
-
signal: controller.signal
|
|
3614
|
+
signal: controller.signal,
|
|
3615
|
+
redirect: "error"
|
|
3540
3616
|
});
|
|
3541
3617
|
} catch (err) {
|
|
3542
3618
|
const name = err && err.name;
|
|
@@ -4263,7 +4339,7 @@ var require_openrouter = __commonJS({
|
|
|
4263
4339
|
const timer = setTimeout(() => controller.abort(), t);
|
|
4264
4340
|
let res;
|
|
4265
4341
|
try {
|
|
4266
|
-
res = await f(url, { method: "POST", headers, body: JSON.stringify(payload), signal: controller.signal });
|
|
4342
|
+
res = await f(url, { method: "POST", headers, body: JSON.stringify(payload), signal: controller.signal, redirect: "error" });
|
|
4267
4343
|
} catch (err) {
|
|
4268
4344
|
const msg = String(err && err.message || err);
|
|
4269
4345
|
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.6.
|
|
3
|
+
"version": "3.6.2",
|
|
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" },
|