consult-mcp 0.6.1 → 1.0.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.
@@ -1,6 +1,6 @@
1
1
  import { messagesOn } from "../settings.js";
2
2
  import { AdvisorError } from "../types.js";
3
- import { frameMessages } from "./inbox.js";
3
+ import { createMessage, frameMessages } from "./inbox.js";
4
4
  import { inScope } from "./scope.js";
5
5
  /** Bounds two agents that keep answering each other. */
6
6
  export const MAX_SENDS_PER_HOUR = 10;
@@ -53,7 +53,7 @@ export function createSessions(deps) {
53
53
  }
54
54
  }
55
55
  let sends = new Map();
56
- function send(sessionId, text) {
56
+ async function send(sessionId, text) {
57
57
  assertMessagesOn();
58
58
  const self = deps.self();
59
59
  const target = findTarget(self, sessionId);
@@ -66,9 +66,15 @@ export function createSessions(deps) {
66
66
  throw new AdvisorError(`you have sent session ${sessionId} ${MAX_SENDS_PER_HOUR} messages in the last hour; wait before sending more`);
67
67
  }
68
68
  const from = { agent: me.agent, sessionId: me.sessionId, cwd: me.cwd, ...(me.branch ? { branch: me.branch.slice(0, MAX_BRANCH) } : {}) };
69
- const message = deps.enqueue(target.sessionId, from, text);
69
+ // Counted before sending, so a failed attempt still uses up one of the hour's sends.
70
70
  sends = new Map([...sends, [sessionId, [...recent, now]]]);
71
- return { messageId: message.id, agent: target.agent, sessionId: target.sessionId };
71
+ const sent = { agent: target.agent, sessionId: target.sessionId };
72
+ if (target.agent === "codex" && deps.promptCodex) {
73
+ const message = createMessage(from, text, new Date(now));
74
+ if (await deps.promptCodex(target, frameMessages([message])))
75
+ return { ...sent, messageId: message.id, delivery: "prompt" };
76
+ }
77
+ return { ...sent, messageId: deps.enqueue(target.sessionId, from, text).id, delivery: "inbox" };
72
78
  }
73
79
  /** Messages waiting for this session, framed for the agent. They are delivered once. */
74
80
  function receive() {
@@ -1,4 +1,5 @@
1
1
  import { loadSettings, settingsPath } from "../settings.js";
2
+ import { sessionsSupported, SESSIONS_UNSUPPORTED } from "../platform.js";
2
3
  import { codexIndexPath, describeSession } from "./describe.js";
3
4
  import { systemIdentityDeps } from "./identity.js";
4
5
  import { claim, enqueue, inboxDir } from "./inbox.js";
@@ -6,6 +7,7 @@ import { startLiveSession } from "./live.js";
6
7
  import { listLive, registryDir } from "./registry.js";
7
8
  import { createSessions } from "./service.js";
8
9
  const REFRESH_MS = 15_000;
10
+ const CODEX_QUEUE_TIMEOUT_MS = 30_000;
9
11
  /**
10
12
  * For `consult serve`: registers this session and returns the session tools when live sessions are on.
11
13
  * Without valid settings it returns nothing, so the rest of consult works as before.
@@ -22,6 +24,10 @@ export async function sessionTools(opts) {
22
24
  }
23
25
  if (!settings.sessions.enabled)
24
26
  return undefined;
27
+ if (!sessionsSupported()) {
28
+ opts.warn(SESSIONS_UNSUPPORTED);
29
+ return undefined;
30
+ }
25
31
  try {
26
32
  const dir = registryDir(opts.env);
27
33
  const codexIndex = codexIndexPath(opts.env);
@@ -44,6 +50,12 @@ export async function sessionTools(opts) {
44
50
  askFork: opts.askFork,
45
51
  enqueue: (recipient, from, text) => enqueue(inbox, recipient, from, text),
46
52
  claim: (sessionId) => claim(inbox, sessionId),
53
+ promptCodex: async (target, framed) => {
54
+ const res = await opts
55
+ .run("codex", ["queue", "--thread", target.sessionId, "--message", framed], { cwd: target.cwd, timeoutMs: CODEX_QUEUE_TIMEOUT_MS })
56
+ .catch(() => undefined);
57
+ return res?.code === 0;
58
+ },
47
59
  });
48
60
  return { list, ask, ...(settings.messages.enabled ? { messages: { send, receive } } : {}) };
49
61
  }
package/dist/tui.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { cancel, confirm, intro, isCancel, log, multiselect, outro, select } from "@clack/prompts";
2
+ import { SESSIONS_UNSUPPORTED } from "./platform.js";
2
3
  import { DEFAULT_SETTINGS, SESSIONS_MODES, messagesOn, sessionsMode, withMessagesEnabled, withSessionsMode, withTasksEnabled, } from "./settings.js";
3
4
  const MODE_OPTIONS = [
4
5
  { value: "off", label: "Off", hint: "default: agents can't see each other's sessions" },
@@ -68,11 +69,14 @@ export async function runSettings(io) {
68
69
  if (!current)
69
70
  return cancel("Left settings unchanged.");
70
71
  const registered = (await Promise.all(io.installed.map(async (agent) => ((await io.isRegistered(agent)) ? [agent] : [])))).flat();
71
- const mode = await promptSessionsMode(sessionsMode(current));
72
+ const supported = io.sessionsSupported ?? true;
73
+ if (!supported)
74
+ log.info(`Note: ${SESSIONS_UNSUPPORTED}.`);
75
+ const mode = supported ? await promptSessionsMode(sessionsMode(current)) : sessionsMode(current);
72
76
  if (mode === undefined)
73
77
  return cancel("No changes made.");
74
78
  // Messages go between live sessions, so there is nothing to ask while those are off.
75
- const messages = mode === "off" ? current.messages.enabled : await promptMessages(current.messages.enabled);
79
+ const messages = mode === "off" || !supported ? current.messages.enabled : await promptMessages(current.messages.enabled);
76
80
  if (messages === undefined)
77
81
  return cancel("No changes made.");
78
82
  const tasks = await confirm({
@@ -98,9 +102,10 @@ export async function runSettings(io) {
98
102
  ...(plan.register.length > 0 ? await io.register(plan.register) : []),
99
103
  ...(plan.unregister.length > 0 ? await io.unregister(plan.unregister) : []),
100
104
  ].filter((r) => changed.includes(r.agent));
101
- const hooks = io.setMessageHooks(messagesOn(plan.settings) ? hosts : []);
105
+ const hooks = io.setMessageHooks(messagesOn(plan.settings) && supported ? hosts : []);
102
106
  for (const r of [...results, ...hooks])
103
107
  (r.ok ? log.success : log.error)(r.message);
104
108
  const messagesState = messagesOn(plan.settings) ? "on" : "off";
105
- outro(`Live sessions: ${mode}. Session messages: ${messagesState}. Task dispatch: ${tasks ? "on" : "off"}. Restart running agent sessions to apply.`);
109
+ const sessionsState = supported ? `Live sessions: ${mode}. Session messages: ${messagesState}. ` : "";
110
+ outro(`${sessionsState}Task dispatch: ${tasks ? "on" : "off"}. Restart running agent sessions to apply.`);
106
111
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "consult-mcp",
3
- "version": "0.6.1",
3
+ "version": "1.0.0",
4
4
  "description": "MCP server that lets Claude Code, Codex and Grok ask each other for a second opinion through the CLIs already signed in on your machine",
5
5
  "keywords": [
6
6
  "mcp",
@@ -43,7 +43,8 @@
43
43
  },
44
44
  "os": [
45
45
  "darwin",
46
- "linux"
46
+ "linux",
47
+ "win32"
47
48
  ],
48
49
  "dependencies": {
49
50
  "@clack/prompts": "^1.8.1",