openvibers/openvibe.codes Commits

Codes: local adapters for MiniMax Code and Claude Code on another provider (#176)

OP OpenVibers committed 14 days ago · 4a8a00025f · 8 files, +353 −7

The router could select two harnesses the local adapters did not know (Codes #172):
MiniMax Code (mcode) and Claude Code pointed at another provider's Anthropic-compatible
endpoint. On a person's own machine they answered "no adapter for this harness yet".

harness/adapters/cli.js gains both, with their siblings' contract:

- detection: the binary on PATH and the version it reports about itself. Claude Code on
  another provider also needs its connection (the endpoint and the token), and says so
  when it is not there.
- argv: the portal's own (mm-run.sh's mcode exec --input - --output-format stream-json,
  cm-run.sh's claude -p --output-format stream-json), the brief on stdin.
- environment: the person's own key and endpoint, from the C3 connection's run token, in
  the environment and never in argv. No provider is named: the endpoint and the model id
  come from the connection.
- the run's output becomes one result, and a failure says why.
- resume: mcode's --session and claude's --resume.

The /start page names both. The next patch of the CLI is 0.5.1.

Changes

ddiff --git a/README.md b/README.md
iindex b15bae7..99a1a3d 100644
---- a/README.md
++++ b/README.md
@@@ -54,6 +54,8 @@ More: [docs/cli.md](docs/cli.md).
| Agent | Adapter | Needs |
|---|---|---|
| Claude Code | `claude -p --output-format stream-json` | `claude` on PATH |
++| Claude Code (another provider) | the same `claude -p --output-format stream-json`, on your own Anthropic-compatible endpoint | `claude` on PATH, `ANTHROPIC_BASE_URL` (the endpoint of your connection) and `ANTHROPIC_AUTH_TOKEN` (its run token); the model id in `ANTHROPIC_MODEL` |
++| MiniMax Code | `mcode exec --input - --output-format stream-json` | `mcode` on PATH (your own MiniMax sign-in on this machine) |
| Codex | `codex exec --json` | `codex` on PATH |
| OpenCode | `opencode run --format json` | `opencode` on PATH |
| Command Code | `cmd --print --output-format json` | `cmd` on PATH |
ddiff --git a/bin/openvibe-codes.js b/bin/openvibe-codes.js
iindex 25beb26..5f6b468 100755
---- a/bin/openvibe-codes.js
++++ b/bin/openvibe-codes.js
@@@ -21,8 +21,8 @@ const USAGE = `openvibe-codes ${VERSION} — code with any agent, from your term
openvibe-codes route [--task edit] [--need harness:resume,…] which agent a task would go to, and why
openvibe-codes run [options] "what to do" run a task ("-" reads it from stdin)
--task edit|review|long|resume what kind of task (default edit)
-- --agent <id> skip routing: claude-code, codex, opencode, command-code, aider,
-- deepseek, openai-compatible
++ --agent <id> skip routing: claude-code, claude-other, codex, opencode, command-code,
++ aider, minimax-code, deepseek, openai-compatible
--model <name> the first agent's model
--permission read|edit|full read: look and answer; edit: change files (default);
full: anything, unattended
@@@ -105,7 +105,7 @@ async function main() {
if (cmd === 'agents') {
const list = harness.agents();
if (o.json) { out(JSON.stringify(list, null, 2)); return 0; }
-- for (const a of list) out(`${a.available ? '✔' : '·'} ${a.id.padEnd(18)} ${a.name.padEnd(16)} ${a.available ? dim(a.where || '') : dim(a.reason)}`);
++ for (const a of list) out(`${a.available ? '✔' : '·'} ${a.id.padEnd(18)} ${a.name.padEnd(16)} ${a.available ? dim([a.where, a.version].filter(Boolean).join(' · ')) : dim(a.reason)}`);
return 0;
}
if (cmd === 'logins') {
ddiff --git a/harness/adapters/cli.js b/harness/adapters/cli.js
iindex 9032c71..9a0589d 100644
---- a/harness/adapters/cli.js
++++ b/harness/adapters/cli.js
@@@ -13,8 +13,10 @@
* full anything the agent can do, unattended (its own guardrails only) — for a sandbox or a throwaway checkout
* Nothing here pushes, commits or opens a pull request: that is the person's (or a later Improve OpenVibe step's) call.
*/
++const { execFileSync } = require('child_process');
const ev = require('../events');
const { spawnAgent, exitReason } = require('../process');
++const { effortFor } = require('../../engine/adapters/base');
/** A parser that reads JSON lines, hands each object to onEvent, and ends the run with exactly one result. */
function jsonLines(agent, onEvent, onEnd) {
@@@ -33,6 +35,23 @@ function jsonLines(agent, onEvent, onEnd) {
};
}
++/**
++ * What a CLI says about itself: its version, asked of the binary itself (never read from a file of ours, and never
++ * a key). A CLI that cannot answer says nothing: the run says why instead.
++ *
++ * @param {string} bin the executable
++ * @param {object} [env] the environment it runs in (PATH)
++ * @param {string[]} [args] the arguments that ask
++ * @returns {string|null} the version, one line, cut short
++ */
++function versionOf(bin, env = process.env, args = ['--version']) {
++ try {
++ const out = execFileSync(bin, args, { env: { ...process.env, ...env }, encoding: 'utf8', timeout: 5000, stdio: ['ignore', 'pipe', 'ignore'] });
++ const line = String(out || '').split('\n').map((s) => s.trim()).find(Boolean) || '';
++ return line ? line.slice(0, 120) : null;
++ } catch { return null; }
++}
++
// ── Claude Code: `claude -p --output-format stream-json` already prints the shared events ──
const claudeCode = {
id: 'claude-code', name: 'Claude Code', kind: 'cli', bin: 'claude',
@@@ -215,4 +234,121 @@ const aider = {
},
};
--module.exports = { claudeCode, codex, opencode, commandCode, aider, jsonLines };
++
++// ── MiniMax Code: `mcode exec --input - --output-format stream-json` (the portal's mm-run.sh) ──
++// The argv is the portal's own: the brief rides in on stdin (--input -), the rules would ride in the appended system
++// prompt, and the permission is one of mcode's own policies (smart, full, off: "ask" needs the TUI, which a job has
++// not). The key is the person's own MiniMax sign-in on this machine; nothing of ours is read, and nothing is written.
++const MM_PERMISSION = { read: 'off', edit: 'smart', full: 'full' };
++
++const minimaxCode = {
++ id: 'minimax-code', name: 'MiniMax Code', kind: 'cli', bin: 'mcode',
++ /** The version this machine has (asked of the binary itself, never read from a file of ours). */
++ version: (env) => versionOf('mcode', env),
++ start(t, ctx = {}) {
++ const args = ['exec', '--input', '-', '--output-format', 'stream-json', '--prompt-mode', 'coding',
++ '--permission', MM_PERMISSION[t.permission] || 'smart', '--cwd', t.cwd || process.cwd(),
++ '--timeout', `${Math.max(1, Math.ceil((t.timeoutMs || 45 * 60_000) / 60_000))}m`,
++ '--max-steps', String(t.maxTurns || 150)];
++ if (t.model) args.push('--model', t.model);
++ const effort = effortFor('minimax-code', t.effort);
++ if (effort) args.push('--effort', effort);
++ if (t.resume) args.push('--session', String(t.resume));
++ // Programmatic Tool Calling: the model batches its tool calls in one round trip (the portal's default).
++ args.push('--ptc');
++ const startedAt = Date.now();
++ const parser = jsonLines(minimaxCode, (o, emit, st) => {
++ st.startedAt = startedAt;
++ if (o.sessionId) st.sessionId = o.sessionId;
++ const it = o.item || {};
++ const initOnce = () => { if (!st.inited) { st.inited = true; emit(ev.init(st.sessionId, 'minimax-code', t.model)); } };
++ if (o.type === 'item.started' && (it.type === 'agent_message' || it.type === 'reasoning')) initOnce();
++ else if (o.type === 'item.completed' && it.type === 'agent_message') {
++ initOnce();
++ const text = String(it.content || it.contentDelta || it.text || '');
++ if (text.trim()) { st.lastText = text; emit(ev.text(text, t.model)); }
++ } else if (o.type === 'item.completed' && (it.type === 'tool_use' || it.type === 'tool_call')) {
++ initOnce();
++ emit(ev.toolUse(it.id || it.toolCallId || it.callId || '', it.name || it.toolName || 'tool', it.input || it.arguments || {}, t.model));
++ } else if (o.type === 'item.completed' && it.type === 'tool_result') {
++ emit(ev.toolResult(it.toolCallId || it.callId || it.id || '', String(it.output || it.content || it.result || ''), !!(it.isError || it.status === 'failed')));
++ } else if (o.type === 'turn.failed') {
++ st.failed = String((o.error && (o.error.message || o.error)) || 'turn failed');
++ emit(ev.error(st.failed));
++ } else if (o.type === 'exec.completed') {
++ initOnce();
++ const r = o.result || {};
++ const answer = String(r.answer || r.output || '');
++ if (answer) { st.answer = answer; st.lastText = answer; }
++ if (r.status) st.status = String(r.status);
++ } else if (o.type === 'result') {
++ initOnce();
++ st.answer = String(o.result || '') || st.answer;
++ }
++ }, (info, emit, st) => {
++ if (!st.sessionId && !st.lastText && !st.answer) return; // nothing ran: the generic exit reason says why
++ const text = String(st.answer || st.lastText || '');
++ const bad = st.status && st.status !== 'succeeded';
++ const ok = !st.failed && !bad && info.code === 0 && !!text;
++ const why = st.failed || (bad ? `MiniMax Code stopped with the status ${st.status}` : null) || exitReason(info, 'MiniMax Code');
++ emit(ev.result({ ok, text: ok ? text : why, sessionId: st.sessionId, model: t.model, startedAt }));
++ });
++ return spawnAgent({ cmd: this.bin, args, cwd: t.cwd, env: ctx.env, timeoutMs: t.timeoutMs, signal: t.signal, parser, stdin: t.prompt });
++ },
++};
++
++// ── Claude Code on another provider: the same CLI, the cm-style environment (the portal's cm-run.sh) ──
++// The endpoint and the model come from the person's own connection (Codes C3): the base URL and the run token travel
++// in the environment, and the model id rides in ANTHROPIC_MODEL. No provider is named here: this harness is whatever
++// Anthropic-compatible endpoint the person connected, not one of ours.
++const ANTHROPIC_ENV = ['ANTHROPIC_BASE_URL', 'ANTHROPIC_AUTH_TOKEN', 'ANTHROPIC_API_KEY', 'ANTHROPIC_CUSTOM_HEADERS'];
++
++const claudeOther = {
++ id: 'claude-other', name: 'Claude Code (another provider)', kind: 'cli', bin: 'claude',
++ /** The version this machine has (asked of the binary itself). */
++ version: (env) => versionOf('claude', env),
++ /** What this harness needs before it can run: the connection's endpoint and its token. */
++ check(env) {
++ if (!env.ANTHROPIC_BASE_URL) return { available: false, reason: 'set ANTHROPIC_BASE_URL (the endpoint of your connection)' };
++ if (!env.ANTHROPIC_AUTH_TOKEN && !env.ANTHROPIC_API_KEY) return { available: false, reason: 'set ANTHROPIC_AUTH_TOKEN (the run token of your connection)' };
++ return { available: true };
++ },
++ start(t, ctx = {}) {
++ const env = ctx.env || {};
++ const mode = { read: 'plan', edit: 'acceptEdits', full: 'bypassPermissions' }[t.permission] || 'plan';
++ const args = ['-p', '--output-format', 'stream-json', '--verbose', '--include-partial-messages',
++ '--permission-mode', mode, '--exclude-dynamic-system-prompt-sections'];
++ if (t.maxTurns) args.push('--max-turns', String(t.maxTurns));
++ if (t.resume) args.push('--resume', String(t.resume));
++ // Even unattended, a run never pushes: publishing is the person's step.
++ args.push('--disallowedTools', 'Bash(git push:*)');
++ // The harness's environment (PATH finds the CLI), with the connection's own names on top: the endpoint, the
++ // token and the model id. The key travels in the environment, never in argv: the process list of this machine
++ // is readable.
++ const childEnv = { ...env };
++ for (const name of ANTHROPIC_ENV) if (env[name]) childEnv[name] = env[name];
++ const model = t.model || env.ANTHROPIC_MODEL || null;
++ if (model) childEnv.ANTHROPIC_MODEL = model;
++ const effort = effortFor('claude-other', t.effort);
++ if (effort) childEnv.CLAUDE_CODE_EFFORT_LEVEL = effort;
++ const startedAt = Date.now();
++ const parser = jsonLines(claudeOther, (o, emit, st) => {
++ if (o.type === 'system' && o.subtype === 'init') {
++ st.sessionId = o.session_id; st.model = o.model || model;
++ emit(ev.init(o.session_id, 'claude-other', st.model));
++ return;
++ }
++ if (o.type === 'result') { st.sawResult = true; st.answer = String(o.result || ''); emit({ ...o, result: ev.scrub(o.result || '') }); return; }
++ if (o.type === 'assistant' || o.type === 'user') emit(o);
++ }, (info, emit, st) => {
++ if (st.sawResult) return; // Claude Code's own result line already ended the run
++ if (!st.sessionId && !st.answer) return; // nothing ran: the generic exit reason says why
++ const text = String(st.answer || '');
++ const ok = info.code === 0 && !!text;
++ emit(ev.result({ ok, text: ok ? text : exitReason(info, 'Claude Code'), sessionId: st.sessionId, model: st.model || model, startedAt }));
++ });
++ return spawnAgent({ cmd: this.bin, args, cwd: t.cwd, env: childEnv, timeoutMs: t.timeoutMs, signal: t.signal, parser, stdin: t.prompt });
++ },
++};
++
++module.exports = { claudeCode, claudeOther, codex, opencode, commandCode, aider, minimaxCode, jsonLines, versionOf };
ddiff --git a/harness/index.js b/harness/index.js
iindex 25860dc..ace77d0 100644
---- a/harness/index.js
++++ b/harness/index.js
@@@ -57,6 +57,10 @@ function projectProvider(env) {
function adaptersFor(env) {
return {
'claude-code': cli.claudeCode,
++ // Claude Code on the person's own endpoint: the same CLI, the connection's environment (Codes C3).
++ 'claude-other': cli.claudeOther,
++ // MiniMax Code: the person's own MiniMax sign-in on this machine.
++ 'minimax-code': cli.minimaxCode,
codex: cli.codex,
opencode: cli.opencode,
'command-code': cli.commandCode,
@@@ -82,7 +86,17 @@ function availability(adapter, env) {
if (!adapter) return { available: false, reason: 'no adapter for this harness yet' };
if (adapter.kind === 'cli') {
const where = onPath(adapter.bin, env);
-- return where ? { available: true, where } : { available: false, reason: `\`${adapter.bin}\` is not on PATH (install ${adapter.name})` };
++ if (!where) return { available: false, reason: `\`${adapter.bin}\` is not on PATH (install ${adapter.name})` };
++ // A harness that needs something else besides the binary (Claude Code on another provider needs its endpoint
++ // and its token) says so in its own words.
++ if (adapter.check) {
++ const c = adapter.check(env) || {};
++ if (!c.available) return { available: false, reason: c.reason || `${adapter.name} is not set up here` };
++ }
++ const out = { available: true, where };
++ // The version the binary reports about itself, when it answers.
++ if (adapter.version) { const v = adapter.version(env); if (v) out.version = v; }
++ return out;
}
if (adapter.id === 'openvibe-ai') return env.OPENVIBE_AI_TOKEN || (env.OPENVIBE_APP_ID && env.OPENVIBE_APP_SECRET) ? { available: true, where: adapter.baseUrl } : { available: false, reason: 'set OPENVIBE_APP_ID and OPENVIBE_APP_SECRET (an app of your project on openvibe.services with ai.app.run)' };
if (adapter.id === 'openai-compatible') return env.OPENVIBE_CODES_BASE_URL ? { available: true, where: env.OPENVIBE_CODES_BASE_URL } : { available: false, reason: 'set OPENVIBE_CODES_BASE_URL (and OPENVIBE_CODES_MODEL) to your server' };
ddiff --git a/harness/job.js b/harness/job.js
iindex 0da2d6f..b9f3e18 100644
---- a/harness/job.js
++++ b/harness/job.js
@@@ -70,7 +70,7 @@ function scrub(s) {
* the job's input: everything else in it is ignored.
*/
const ENV_NAMES = new Set([
-- 'ANTHROPIC_BASE_URL', 'ANTHROPIC_AUTH_TOKEN', 'ANTHROPIC_CUSTOM_HEADERS',
++ 'ANTHROPIC_BASE_URL', 'ANTHROPIC_AUTH_TOKEN', 'ANTHROPIC_API_KEY', 'ANTHROPIC_CUSTOM_HEADERS', 'ANTHROPIC_MODEL',
'OPENAI_BASE_URL', 'OPENAI_API_KEY', 'OPENAI_CUSTOM_HEADERS',
'DEEPSEEK_BASE_URL', 'DEEPSEEK_API_KEY',
'OPENVIBE_AI_URL', 'OPENVIBE_AI_TOKEN', 'OPENVIBE_CODES_BASE_URL', 'OPENVIBE_CODES_API_KEY',
ddiff --git a/package.json b/package.json
iindex 40a4323..8cab16c 100644
---- a/package.json
++++ b/package.json
@@@ -1,6 +1,6 @@
{
"name": "openvibe-codes",
-- "version": "0.5.0",
++ "version": "0.5.1",
"private": true,
"description": "OpenVibe.Codes: the open coding-agent harness. Run a coding task on Claude Code, Codex, OpenCode, Command Code, Aider, the DeepSeek API or your own model, with routing by capability and cost and hand-offs between agents; plus the site with the agent catalog, a public routing API and the way to improve OpenVibe itself.",
"main": "harness/index.js",
ddiff --git a/server/http/pages.js b/server/http/pages.js
iindex e81b6bc..276b97e 100644
---- a/server/http/pages.js
++++ b/server/http/pages.js
@@@ -188,6 +188,8 @@ for await (const event of harness.run({ prompt: 'fix the failing test', cwd: '.'
<p>Install any of them; the harness uses what is there and says why the rest are not.</p>
${table(['Agent', 'What it needs'], [
[html`<a href="/harnesses#claude-code">Claude Code</a>`, html`<code>claude</code> on PATH, signed in`],
++ [html`<a href="/harnesses#claude-other">Claude Code (another provider)</a>`, html`<code>claude</code> on PATH, plus your own Anthropic-compatible endpoint in <code>ANTHROPIC_BASE_URL</code>, its token in <code>ANTHROPIC_AUTH_TOKEN</code> and the model id in <code>ANTHROPIC_MODEL</code>`],
++ [html`<a href="/harnesses#minimax-code">MiniMax Code</a>`, html`<code>mcode</code> on PATH, signed in to your own MiniMax account`],
[html`<a href="/harnesses#codex">Codex</a>`, html`<code>codex</code> on PATH, signed in`],
[html`<a href="/harnesses#opencode">OpenCode</a>`, html`<code>opencode</code> on PATH`],
[html`<a href="/harnesses#command-code">Command Code</a>`, html`<code>cmd</code> on PATH`],
ddiff --git a/test/harness-cli-mm.test.js b/test/harness-cli-mm.test.js
nnew file mode 100644
iindex 0000000..858fc4b
---- /dev/null
++++ b/test/harness-cli-mm.test.js
@@@ -0,0 +1,192 @@
++'use strict';
++/**
++ * The two harnesses the router can select and the local adapters did not know: MiniMax Code (mcode) and Claude Code on
++ * another provider (claude-other).
++ *
++ * What each is given to run with: the argv (the portal's own, from mm-run.sh and cm-run.sh), the environment (the
++ * person's own key and endpoint, and never a key in argv), what it says when the binary is not installed, and how a
++ * run's output becomes one result.
++ *
++ * The stand-in CLIs are written here, at run time, and the key-shaped values are built at run time too (a test that
++ * spells out a key is a file with a key in it).
++ */
++const assert = require('assert');
++const fs = require('fs');
++const os = require('os');
++const path = require('path');
++const { check, done } = require('./helpers/boot');
++const cli = require('../harness/adapters/cli');
++const { availability, createHarness } = require('../harness');
++const fake = require('./helpers/fakesecrets');
++
++/** What the stand-in CLIs record: the argv, the stdin and the few environment names that matter here. */
++const RECORD_ENV = ['ANTHROPIC_BASE_URL', 'ANTHROPIC_AUTH_TOKEN', 'ANTHROPIC_API_KEY', 'ANTHROPIC_MODEL',
++ 'ANTHROPIC_CUSTOM_HEADERS', 'CLAUDE_CODE_EFFORT_LEVEL', 'MINIMAX_API_KEY'];
++
++const FAKE_MCODE = `
++const fs = require('fs');
++if (process.argv.includes('--version')) { console.log('mcode 9.9.9'); process.exit(0); }
++const stdin = fs.readFileSync(0, 'utf8');
++const rec = { argv: process.argv.slice(2), stdin, env: {} };
++for (const k of ${JSON.stringify(RECORD_ENV)}) rec.env[k] = process.env[k] == null ? null : process.env[k];
++fs.writeFileSync(process.env.FAKE_RECORD, JSON.stringify(rec));
++const out = (o) => console.log(JSON.stringify(o));
++out({ schemaVersion: 1, type: 'item.started', sessionId: 'mm-1', item: { type: 'agent_message' } });
++if (process.env.FAKE_MMODE === 'fail') {
++ out({ schemaVersion: 1, type: 'turn.failed', sessionId: 'mm-1', error: { message: 'the plan ran out' } });
++ process.exit(1);
++}
++out({ schemaVersion: 1, type: 'item.completed', sessionId: 'mm-1', item: { type: 'agent_message', content: 'minimax did it' } });
++out({ schemaVersion: 1, type: 'exec.completed', sessionId: 'mm-1', result: { status: 'succeeded', answer: 'minimax did it' } });
++`;
++
++const FAKE_CLAUDE = `
++const fs = require('fs');
++if (process.argv.includes('--version')) { console.log('2.1.314 (Claude Code)'); process.exit(0); }
++const stdin = fs.readFileSync(0, 'utf8');
++const rec = { argv: process.argv.slice(2), stdin, env: {} };
++for (const k of ${JSON.stringify(RECORD_ENV)}) rec.env[k] = process.env[k] == null ? null : process.env[k];
++fs.writeFileSync(process.env.FAKE_RECORD, JSON.stringify(rec));
++const out = (o) => console.log(JSON.stringify(o));
++out({ type: 'system', subtype: 'init', session_id: 'cl-9', model: 'other-model' });
++out({ type: 'assistant', message: { model: 'other-model', content: [{ type: 'text', text: 'claude did it' }] } });
++out({ type: 'result', subtype: 'success', is_error: false, result: 'claude did it', session_id: 'cl-9', duration_ms: 5, num_turns: 1, total_cost_usd: 0.01 });
++`;
++
++/** A directory with the stand-in CLIs in it, and the record file they write. */
++function fakes(names) {
++ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'codes-mm-'));
++ const bin = path.join(dir, 'bin');
++ fs.mkdirSync(bin);
++ const scripts = { mcode: FAKE_MCODE, claude: FAKE_CLAUDE };
++ for (const n of names) fs.writeFileSync(path.join(bin, n), `#!${process.execPath}\n'use strict';\n${scripts[n]}\n`, { mode: 0o755 });
++ const record = path.join(dir, 'record.json');
++ return { dir, bin, record, cleanup: () => fs.rmSync(dir, { recursive: true, force: true }) };
++}
++
++/** Every event one adapter's run produces. */
++async function run(adapter, task, env) {
++ const events = [];
++ for await (const e of adapter.start(task, { env })) events.push(e);
++ return events;
++}
++
++/** The value of an argument in an argv. */
++const argOf = (argv, name) => { const i = argv.indexOf(name); return i < 0 ? null : argv[i + 1]; };
++
++(async () => {
++ const f = fakes(['mcode', 'claude']);
++
++ await check('MiniMax Code: the argv the portal\'s mm-run.sh uses, and the brief on stdin', async () => {
++ const events = await run(cli.minimaxCode, { prompt: 'rename the variable', cwd: f.dir, permission: 'edit' },
++ { PATH: f.bin, FAKE_RECORD: f.record });
++ const rec = JSON.parse(fs.readFileSync(f.record, 'utf8'));
++ assert.ok(rec.argv.includes('exec'), rec.argv.join(' '));
++ assert.strictEqual(argOf(rec.argv, '--input'), '-');
++ assert.strictEqual(argOf(rec.argv, '--output-format'), 'stream-json');
++ assert.strictEqual(argOf(rec.argv, '--prompt-mode'), 'coding');
++ assert.strictEqual(argOf(rec.argv, '--permission'), 'smart');
++ assert.strictEqual(argOf(rec.argv, '--cwd'), f.dir);
++ assert.strictEqual(argOf(rec.argv, '--max-steps'), '150');
++ assert.ok(rec.argv.includes('--ptc'), 'the portal batches its tool calls');
++ assert.strictEqual(rec.stdin, 'rename the variable', 'the brief rides in on stdin');
++ assert.ok(!rec.argv.join(' ').includes('rename the variable'), 'not in argv');
++ assert.strictEqual(events.filter((e) => e.type === 'result').length, 1, 'one result');
++ });
++
++ await check('MiniMax Code: the permission level is one of mcode\'s own policies', async () => {
++ for (const [level, policy] of [['read', 'off'], ['edit', 'smart'], ['full', 'full']]) {
++ await run(cli.minimaxCode, { prompt: 'x', cwd: f.dir, permission: level }, { PATH: f.bin, FAKE_RECORD: f.record });
++ const rec = JSON.parse(fs.readFileSync(f.record, 'utf8'));
++ assert.strictEqual(argOf(rec.argv, '--permission'), policy, level);
++ }
++ });
++
++ await check('MiniMax Code: a resume continues the session, and no key sits in argv', async () => {
++ const key = fake.providerKey();
++ await run(cli.minimaxCode, { prompt: 'x', cwd: f.dir, permission: 'edit', resume: 'mm-9', model: 'MiniMax-M2' },
++ { PATH: f.bin, FAKE_RECORD: f.record, MINIMAX_API_KEY: key });
++ const rec = JSON.parse(fs.readFileSync(f.record, 'utf8'));
++ assert.strictEqual(argOf(rec.argv, '--session'), 'mm-9');
++ assert.strictEqual(argOf(rec.argv, '--model'), 'MiniMax-M2');
++ assert.ok(!rec.argv.join(' ').includes(key), 'the key is not in argv');
++ assert.strictEqual(rec.env.MINIMAX_API_KEY, key, 'the key is in the environment');
++ });
++
++ await check('MiniMax Code: the run\'s answer is one result, and a failure says why', async () => {
++ const ok = await run(cli.minimaxCode, { prompt: 'x', cwd: f.dir, permission: 'edit' }, { PATH: f.bin, FAKE_RECORD: f.record });
++ const result = ok[ok.length - 1];
++ assert.strictEqual(result.type, 'result');
++ assert.strictEqual(result.is_error, false, result.result);
++ assert.strictEqual(result.result, 'minimax did it');
++ assert.strictEqual(result.session_id, 'mm-1');
++ const bad = await run(cli.minimaxCode, { prompt: 'x', cwd: f.dir, permission: 'edit' }, { PATH: f.bin, FAKE_RECORD: f.record, FAKE_MMODE: 'fail' });
++ const failed = bad[bad.length - 1];
++ assert.strictEqual(failed.type, 'result');
++ assert.strictEqual(failed.is_error, true);
++ assert.match(failed.result, /the plan ran out/);
++ });
++
++ await check('Claude Code on another provider: the endpoint and the model come from the connection', async () => {
++ const key = fake.providerKey();
++ const endpoint = 'https://provider.example/anthropic';
++ const events = await run(cli.claudeOther, { prompt: 'fix the test', cwd: f.dir, permission: 'edit' },
++ { PATH: f.bin, FAKE_RECORD: f.record, ANTHROPIC_BASE_URL: endpoint, ANTHROPIC_AUTH_TOKEN: key, ANTHROPIC_MODEL: 'provider-model-x' });
++ const rec = JSON.parse(fs.readFileSync(f.record, 'utf8'));
++ assert.strictEqual(rec.env.ANTHROPIC_BASE_URL, endpoint, 'the endpoint of the connection');
++ assert.strictEqual(rec.env.ANTHROPIC_AUTH_TOKEN, key, 'the key of the connection');
++ assert.strictEqual(rec.env.ANTHROPIC_MODEL, 'provider-model-x', 'the model id of the connection');
++ assert.ok(!rec.argv.join(' ').includes(key), 'the key is never in argv');
++ assert.ok(!rec.argv.join(' ').toLowerCase().includes('minimax'), 'no provider is hard-coded');
++ assert.strictEqual(argOf(rec.argv, '--output-format'), 'stream-json');
++ assert.strictEqual(argOf(rec.argv, '--permission-mode'), 'acceptEdits');
++ assert.strictEqual(rec.stdin, 'fix the test', 'the brief rides in on stdin');
++ const result = events[events.length - 1];
++ assert.strictEqual(result.type, 'result');
++ assert.strictEqual(result.is_error, false, result.result);
++ assert.strictEqual(result.result, 'claude did it');
++ });
++
++ await check('Claude Code on another provider: a resume continues the session', async () => {
++ await run(cli.claudeOther, { prompt: 'x', cwd: f.dir, permission: 'edit', resume: 'cl-9' },
++ { PATH: f.bin, FAKE_RECORD: f.record, ANTHROPIC_BASE_URL: 'https://provider.example/anthropic', ANTHROPIC_AUTH_TOKEN: fake.providerKey() });
++ const rec = JSON.parse(fs.readFileSync(f.record, 'utf8'));
++ assert.strictEqual(argOf(rec.argv, '--resume'), 'cl-9');
++ });
++
++ await check('detection: the binary that is not there, and the one that is', () => {
++ const missing = availability(cli.minimaxCode, { PATH: '/nonexistent' });
++ assert.strictEqual(missing.available, false);
++ assert.match(missing.reason, /not on PATH/);
++ const there = availability(cli.minimaxCode, { PATH: f.bin });
++ assert.strictEqual(there.available, true, there.reason);
++ assert.match(there.version, /mcode/, 'the version it reports about itself');
++ });
++
++ await check('detection: Claude Code on another provider needs its connection', () => {
++ const bare = availability(cli.claudeOther, { PATH: f.bin });
++ assert.strictEqual(bare.available, false);
++ assert.match(bare.reason, /ANTHROPIC_BASE_URL/);
++ const noToken = availability(cli.claudeOther, { PATH: f.bin, ANTHROPIC_BASE_URL: 'https://provider.example/anthropic' });
++ assert.strictEqual(noToken.available, false);
++ assert.match(noToken.reason, /ANTHROPIC_AUTH_TOKEN/);
++ const ready = availability(cli.claudeOther, { PATH: f.bin, ANTHROPIC_BASE_URL: 'https://provider.example/anthropic', ANTHROPIC_AUTH_TOKEN: fake.providerKey() });
++ assert.strictEqual(ready.available, true, ready.reason);
++ assert.match(ready.version, /Claude Code/);
++ });
++
++ await check('the harness knows both harnesses, and says why they are down', () => {
++ const harness = createHarness({ env: { PATH: f.bin } });
++ const rows = harness.agents();
++ const mm = rows.find((r) => r.id === 'minimax-code');
++ const other = rows.find((r) => r.id === 'claude-other');
++ assert.ok(mm && other, 'both are in the catalogue');
++ assert.strictEqual(mm.adapter, 'cli');
++ assert.strictEqual(mm.available, true, mm.reason);
++ assert.strictEqual(other.available, false);
++ assert.match(other.reason, /ANTHROPIC_BASE_URL/);
++ });
++
++ f.cleanup();
++ done();
++})().catch((e) => { console.error(e); process.exit(1); });