@antonbabenko/deliberation-mcp 3.5.4 → 3.6.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.
Files changed (2) hide show
  1. package/dist/index.js +78 -21
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -520,7 +520,14 @@ var require_orchestrate = __commonJS({
520
520
  } catch {
521
521
  }
522
522
  }
523
- async function callProvider(provider, req, logger, tool, cache) {
523
+ function withOrientation(provider, req, orientationFiles) {
524
+ if (Array.isArray(orientationFiles) && orientationFiles.length && !(Array.isArray(req.files) && req.files.length) && provider.capabilities && provider.capabilities.walksFilesystem === false) {
525
+ return { ...req, files: orientationFiles };
526
+ }
527
+ return req;
528
+ }
529
+ async function callProvider(provider, req, logger, tool, cache, orientationFiles) {
530
+ req = withOrientation(provider, req, orientationFiles);
524
531
  const useCache = cache && !(Array.isArray(req.files) && req.files.length);
525
532
  if (useCache) {
526
533
  const hit = cache.get(provider.name, req);
@@ -553,7 +560,7 @@ var require_orchestrate = __commonJS({
553
560
  const logger = opts.logger || NULL_LOGGER;
554
561
  const tool = opts.tool || "ask-all";
555
562
  const settled = await Promise.allSettled(
556
- providers.map((p) => callProvider(p, req, logger, tool, opts.cache))
563
+ providers.map((p) => callProvider(p, req, logger, tool, opts.cache, opts.orientationFiles))
557
564
  );
558
565
  return settled.map(
559
566
  (s, i) => s.status === "fulfilled" ? s.value : {
@@ -568,7 +575,7 @@ var require_orchestrate = __commonJS({
568
575
  );
569
576
  }
570
577
  async function askOne2(provider, req, opts = {}) {
571
- return callProvider(provider, req, opts.logger || NULL_LOGGER, opts.tool || "ask-one", opts.cache);
578
+ return callProvider(provider, req, opts.logger || NULL_LOGGER, opts.tool || "ask-one", opts.cache, opts.orientationFiles);
572
579
  }
573
580
  function buildArbiterPrompt(question, opinions) {
574
581
  const blocks = opinions.map((o, i) => `### Opinion ${i + 1}
@@ -593,17 +600,17 @@ ${blocks}`,
593
600
  // Promise.resolve().then(...) so even a SYNCHRONOUS throw in ask() is caught
594
601
  // by the rejection handler (a bare arbiter.ask() could throw before awaiting).
595
602
  Promise.resolve().then(
596
- () => arbiter.ask({
603
+ () => arbiter.ask(withOrientation(arbiter, {
597
604
  ...req,
598
605
  files: req.files ? req.files.map((f) => ({ ...f })) : void 0,
599
606
  developerInstructions: opts.arbiterInstructions || req.developerInstructions
600
- })
607
+ }, opts.orientationFiles))
601
608
  ).then((v) => v, () => null)
602
609
  ) : Promise.resolve(
603
610
  /** @type {DelegationResult|null} */
604
611
  null
605
612
  );
606
- const [opinions, blindVerdict] = await Promise.all([askAll2(providers, req, { logger: opts.logger, tool: "consensus" }), blindPromise]);
613
+ const [opinions, blindVerdict] = await Promise.all([askAll2(providers, req, { logger: opts.logger, tool: "consensus", orientationFiles: opts.orientationFiles }), blindPromise]);
607
614
  const ok = (
608
615
  /** @type {DelegationSuccess[]} */
609
616
  opinions.filter((o) => !o.isError)
@@ -666,8 +673,8 @@ ${feedback || "(reviewers gave no specific issues; tighten the weakest part)"}`
666
673
  const { peerPrompt, blindPrompt } = loop.prepareRound(state);
667
674
  const roundNo = state.round;
668
675
  const [blindRes, peerResults] = await Promise.all([
669
- Promise.resolve().then(() => arbiter.ask({ ...req, prompt: blindPrompt })).then((r) => r, () => null),
670
- askAll2(providers, { ...req, prompt: peerPrompt }, { logger, tool: "consensus" })
676
+ Promise.resolve().then(() => arbiter.ask(withOrientation(arbiter, { ...req, prompt: blindPrompt }, opts.orientationFiles))).then((r) => r, () => null),
677
+ askAll2(providers, { ...req, prompt: peerPrompt }, { logger, tool: "consensus", orientationFiles: opts.orientationFiles })
671
678
  ]);
672
679
  state = loop.recordBlindVerdict(state, okText(blindRes) || "(blind pass unavailable)");
673
680
  lastResults = peerResults.map(
@@ -732,6 +739,52 @@ ${feedback || "(reviewers gave no specific issues; tighten the weakest part)"}`
732
739
  }
733
740
  });
734
741
 
742
+ // ../../core/orientation.js
743
+ var require_orientation = __commonJS({
744
+ "../../core/orientation.js"(exports2, module2) {
745
+ "use strict";
746
+ var fs = require("node:fs");
747
+ var path = require("node:path");
748
+ var ORIENTATION_CANDIDATES = [
749
+ "CLAUDE.md",
750
+ "AGENTS.md",
751
+ "README.md",
752
+ "package.json",
753
+ "pyproject.toml",
754
+ "Cargo.toml",
755
+ "go.mod",
756
+ "tsconfig.json",
757
+ "main.tf"
758
+ ];
759
+ var DEFAULT_MAX_FILES = 6;
760
+ function resolveOrientationFiles(cwd, opts = {}) {
761
+ const base = cwd || process.cwd();
762
+ const max = Number.isInteger(opts.maxFiles) && /** @type {number} */
763
+ opts.maxFiles > 0 ? (
764
+ /** @type {number} */
765
+ opts.maxFiles
766
+ ) : DEFAULT_MAX_FILES;
767
+ const candidates = opts.candidates || ORIENTATION_CANDIDATES;
768
+ const out = [];
769
+ for (const name of candidates) {
770
+ if (out.length >= max) break;
771
+ const abs = path.join(base, name);
772
+ try {
773
+ if (fs.statSync(abs).isFile()) out.push({ path: abs });
774
+ } catch {
775
+ }
776
+ }
777
+ return out;
778
+ }
779
+ function orientationFilesFor2(config, cwd) {
780
+ const o = config && config.orientation;
781
+ if (!o || o.enabled !== true) return void 0;
782
+ return resolveOrientationFiles(cwd, { maxFiles: o.maxFiles });
783
+ }
784
+ module2.exports = { resolveOrientationFiles, orientationFilesFor: orientationFilesFor2, ORIENTATION_CANDIDATES, DEFAULT_MAX_FILES };
785
+ }
786
+ });
787
+
735
788
  // ../../core/prompts/index.js
736
789
  var require_prompts = __commonJS({
737
790
  "../../core/prompts/index.js"(exports2, module2) {
@@ -1443,7 +1496,7 @@ var require_openai_compatible = __commonJS({
1443
1496
  /** @type {any} */
1444
1497
  {
1445
1498
  name,
1446
- capabilities: { canImplement: false, fileUpload: false, multiTurn: true },
1499
+ capabilities: { canImplement: false, fileUpload: false, multiTurn: true, walksFilesystem: false },
1447
1500
  /** Test-only: current number of cached sessions. */
1448
1501
  get __sessionCount() {
1449
1502
  return sessions.size;
@@ -1525,7 +1578,7 @@ var require_grok = __commonJS({
1525
1578
  name: "grok",
1526
1579
  // multiTurn is not wired through Core (runGrok/runWithFiles return no threadId),
1527
1580
  // so report false to match reality.
1528
- capabilities: { canImplement: false, fileUpload: true, multiTurn: false },
1581
+ capabilities: { canImplement: false, fileUpload: true, multiTurn: false, walksFilesystem: false },
1529
1582
  async health() {
1530
1583
  return process.env.XAI_API_KEY ? { ok: true } : { ok: false, reason: "XAI_API_KEY unset" };
1531
1584
  },
@@ -1585,7 +1638,7 @@ var require_antigravity = __commonJS({
1585
1638
  const model = opts.model || process.env.GEMINI_DEFAULT_MODEL || "auto-gemini-3";
1586
1639
  return {
1587
1640
  name: "gemini",
1588
- capabilities: { canImplement: true, fileUpload: false, multiTurn: true },
1641
+ capabilities: { canImplement: true, fileUpload: false, multiTurn: true, walksFilesystem: true },
1589
1642
  async health() {
1590
1643
  return typeof bridge.runGemini === "function" ? { ok: true } : { ok: false, reason: "agy bridge unavailable" };
1591
1644
  },
@@ -1666,7 +1719,7 @@ var require_codex = __commonJS({
1666
1719
  const model = opts.model || "default";
1667
1720
  return {
1668
1721
  name: "codex",
1669
- capabilities: { canImplement: true, fileUpload: false, multiTurn: false },
1722
+ capabilities: { canImplement: true, fileUpload: false, multiTurn: false, walksFilesystem: true },
1670
1723
  // Option A: no threadId continuity
1671
1724
  async health() {
1672
1725
  return { ok: true };
@@ -4525,6 +4578,7 @@ var require_openrouter = __commonJS({
4525
4578
  // index.js
4526
4579
  var { makeRegistry, pinAlias } = require_registry();
4527
4580
  var { askAll, askOne, consensus, runToConvergence } = require_orchestrate();
4581
+ var { orientationFilesFor } = require_orientation();
4528
4582
  var { PROMPTS } = require_prompts();
4529
4583
  var analyzeCore = require_analyze();
4530
4584
  var ADVISORY = { readOnlyHint: true };
@@ -4801,6 +4855,9 @@ function buildServer({ providers, getConfig, getConfigError, sessionsDir, notify
4801
4855
  if (!persona) return request;
4802
4856
  return { ...request, developerInstructions: persona };
4803
4857
  }
4858
+ function orient(req) {
4859
+ return orientationFilesFor(getConfig(), req && req.cwd);
4860
+ }
4804
4861
  function sessionsCfg() {
4805
4862
  const c = getConfig() || {};
4806
4863
  const s = c.sessions || {};
@@ -4898,7 +4955,7 @@ function buildServer({ providers, getConfig, getConfigError, sessionsDir, notify
4898
4955
  lg.logEvent({ event: "dispatch_start", at: Date.now(), tool: "ask-all", voices: selected.length });
4899
4956
  } catch {
4900
4957
  }
4901
- const results = await askAll(selected, withPersona(req, expert), { logger: lg, tool: "ask-all", cache: opts.noCache ? void 0 : resultCache });
4958
+ const results = await askAll(selected, withPersona(req, expert), { logger: lg, tool: "ask-all", cache: opts.noCache ? void 0 : resultCache, orientationFiles: orient(req) });
4902
4959
  return {
4903
4960
  payload: { results, omitted },
4904
4961
  parts: { opinions: results, blindVerdict: null, verdict: null, arbiter: null, warnings: [] }
@@ -4916,13 +4973,13 @@ function buildServer({ providers, getConfig, getConfigError, sessionsDir, notify
4916
4973
  const resolved = await resolveArbiter(arbiterSpec, selected, registry, getConfig);
4917
4974
  if (resolved.warning) warnings.push(resolved.warning);
4918
4975
  if (resolved.mode === "host") {
4919
- const opinions = await askAll(selected, withPersona(req, expert), { logger: currentLogger(), tool: "consensus" });
4976
+ const opinions = await askAll(selected, withPersona(req, expert), { logger: currentLogger(), tool: "consensus", orientationFiles: orient(req) });
4920
4977
  const arbiter2 = { mode: "host" };
4921
4978
  const body = { opinions, blindVerdict: null, verdict: null, arbiter: arbiter2, warnings };
4922
4979
  return { payload: body, parts: body };
4923
4980
  }
4924
4981
  if (!resolved.provider) {
4925
- const out2 = await consensus(selected, withPersona(req, expert), { arbiterInstructions: PROMPTS.arbiter, logger: currentLogger() });
4982
+ const out2 = await consensus(selected, withPersona(req, expert), { arbiterInstructions: PROMPTS.arbiter, logger: currentLogger(), orientationFiles: orient(req) });
4926
4983
  const arbiter2 = { mode: "server", provider: null };
4927
4984
  return {
4928
4985
  payload: { opinions: out2.opinions, blindVerdict: out2.blindVerdict, verdict: out2.verdict, error: out2.error, arbiter: arbiter2, warnings },
@@ -4935,7 +4992,7 @@ function buildServer({ providers, getConfig, getConfigError, sessionsDir, notify
4935
4992
  peers = selected;
4936
4993
  warnings.push(`panel too small to exclude arbiter '${arbiterP.name}'; kept it in the peer panel (floor of 2)`);
4937
4994
  }
4938
- const out = await consensus(peers, withPersona(req, expert), { arbiter: arbiterP, arbiterInstructions: PROMPTS.arbiter, blindVote, logger: currentLogger() });
4995
+ const out = await consensus(peers, withPersona(req, expert), { arbiter: arbiterP, arbiterInstructions: PROMPTS.arbiter, blindVote, logger: currentLogger(), orientationFiles: orient(req) });
4939
4996
  const arbiter = { mode: "server", provider: arbiterP.name };
4940
4997
  return {
4941
4998
  payload: { opinions: out.opinions, blindVerdict: out.blindVerdict, verdict: out.verdict, error: out.error, arbiter, warnings },
@@ -4965,7 +5022,7 @@ function buildServer({ providers, getConfig, getConfigError, sessionsDir, notify
4965
5022
  }
4966
5023
  const maxRounds = Number.isInteger(maxRoundsOverride) && /** @type {number} */
4967
5024
  maxRoundsOverride > 0 ? maxRoundsOverride : Number.isInteger(cc.maxRounds) && cc.maxRounds > 0 ? cc.maxRounds : void 0;
4968
- const out = await runToConvergence(peers, withPersona(req, expert), { arbiter: arbiterP, maxRounds, logger: currentLogger() });
5025
+ const out = await runToConvergence(peers, withPersona(req, expert), { arbiter: arbiterP, maxRounds, logger: currentLogger(), orientationFiles: orient(req) });
4969
5026
  const allWarnings = out.error ? warnings.concat([`loop: ${out.error}`]) : warnings;
4970
5027
  const rounds = Array.isArray(out.rounds) ? out.rounds.length : 0;
4971
5028
  const arbiter = { mode: "server", provider: arbiterP.name };
@@ -5106,7 +5163,7 @@ function buildServer({ providers, getConfig, getConfigError, sessionsDir, notify
5106
5163
  lg.logEvent({ event: "dispatch_start", at: Date.now(), tool: "consensus", round: cur.round, voices: selected.length });
5107
5164
  } catch {
5108
5165
  }
5109
- const peerResults = await askAll(selected, withPersona(peerReq, ex), { logger: lg, tool: "consensus" });
5166
+ const peerResults = await askAll(selected, withPersona(peerReq, ex), { logger: lg, tool: "consensus", orientationFiles: orient(peerReq) });
5110
5167
  const results = peerResults.map(
5111
5168
  (r) => r.isError ? { source: r.provider, isError: true, errorKind: r.errorKind, verdict: null, criticalIssues: [], model: r.model, reasoningEffort: r.reasoningEffort ?? null, ms: r.ms } : { ...parseReview(typeof r.text === "string" ? r.text : ""), source: r.provider, isError: false, model: r.model, reasoningEffort: r.reasoningEffort ?? null, ms: r.ms }
5112
5169
  );
@@ -5230,7 +5287,7 @@ function buildServer({ providers, getConfig, getConfigError, sessionsDir, notify
5230
5287
  if (!p) {
5231
5288
  return jsonResult({ error: `provider "${want}" is not in the active panel`, panel: selected.map((x) => x.name) });
5232
5289
  }
5233
- const result = await askOne(p, withPersona(req, expert), { logger: currentLogger(), tool: "ask-one", cache: resultCache });
5290
+ const result = await askOne(p, withPersona(req, expert), { logger: currentLogger(), tool: "ask-one", cache: resultCache, orientationFiles: orient(req) });
5234
5291
  return jsonResult({ result });
5235
5292
  }
5236
5293
  if (name === "analyze") {
@@ -5299,12 +5356,12 @@ function buildServer({ providers, getConfig, getConfigError, sessionsDir, notify
5299
5356
  if (Object.prototype.hasOwnProperty.call(ASK_PROVIDER, name)) {
5300
5357
  const p = registry.get(ASK_PROVIDER[name]);
5301
5358
  if (!p) return { content: [{ type: "text", text: JSON.stringify({ error: `provider ${ASK_PROVIDER[name]} not registered` }) }] };
5302
- const result = await askOne(p, withPersona(req, expert), { logger: currentLogger(), tool: "ask-one", cache: resultCache });
5359
+ const result = await askOne(p, withPersona(req, expert), { logger: currentLogger(), tool: "ask-one", cache: resultCache, orientationFiles: orient(req) });
5303
5360
  return { content: [{ type: "text", text: JSON.stringify({ result }) }] };
5304
5361
  }
5305
5362
  if (EXPERTS.includes(name)) {
5306
5363
  const { providers: selected } = registry.selectForAskAll({ config: getConfig(), expert: name });
5307
- const results = await askAll(selected, withPersona({ ...req, expert: name }, expert), { logger: currentLogger(), tool: name, cache: resultCache });
5364
+ const results = await askAll(selected, withPersona({ ...req, expert: name }, expert), { logger: currentLogger(), tool: name, cache: resultCache, orientationFiles: orient(req) });
5308
5365
  return { content: [{ type: "text", text: JSON.stringify({ results }) }] };
5309
5366
  }
5310
5367
  throw new Error(`unknown tool: ${name}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@antonbabenko/deliberation-mcp",
3
- "version": "3.5.4",
3
+ "version": "3.6.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" },