aiterm-mcp 0.10.0 → 0.11.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.
- package/README.md +8 -8
- package/dist/core.js +129 -21
- package/dist/index.js +21 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -60,11 +60,11 @@ One call per model, so the tool name itself tells you which model you get:
|
|
|
60
60
|
|
|
61
61
|
| Tool | Launches | Key args |
|
|
62
62
|
| --- | --- | --- |
|
|
63
|
-
| `codex_agent` | Codex CLI (OpenAI;
|
|
64
|
-
| `grok_agent` | Grok Build, model `grok-
|
|
65
|
-
| `composer_agent` | Grok Build, model `grok-composer-2.5-fast` (xAI) |
|
|
63
|
+
| `codex_agent` | Codex CLI (OpenAI; terminal config/CLI default unless overridden) | `prompt?`, `model?`, `reasoning_effort?` (`low`/`medium`/`high`/`xhigh`/`max`/`ultra`; ultra enables proactive automatic delegation), `cwd?`, `session_name?`, `agent_done?`, `wait?`, `timeout?`, `screen?`, `lines?` |
|
|
64
|
+
| `grok_agent` | Grok Build, model `grok-4.5` by default (`model?` overrides) (xAI) | `prompt?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error; Grok CLI `--effort` is headless-only), `cwd?`, `session_name?`, `agent_done?` |
|
|
65
|
+
| `composer_agent` | Grok Build, model `grok-composer-2.5-fast` by default (`model?` overrides) (xAI) | `prompt?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error), `cwd?`, `session_name?`, `agent_done?` |
|
|
66
66
|
|
|
67
|
-
The vendor CLI must be installed and authenticated (`codex` for `codex_agent`; `grok` for both Grok tools). aiterm resolves the binary via `CODEX_BIN` / `GROK_BIN`, then `~/.local/bin/codex` / `~/.grok/bin/grok`, then `PATH`. Prerequisites are checked **before** a session exists:
|
|
67
|
+
The vendor CLI must be installed and authenticated (`codex` for `codex_agent`; `grok` for both Grok tools). aiterm resolves the binary via `CODEX_BIN` / `GROK_BIN`, then `~/.local/bin/codex` / `~/.grok/bin/grok`, then `PATH`. Prerequisites are checked **before** a session exists: empty `model` values and any `reasoning_effort` for `grok_agent` / `composer_agent` are rejected up front; a missing CLI binary or a nonexistent `cwd` fails for all three. A rejected launch leaves **zero leftover session** behind, and if the launch keystroke itself can't be delivered aiterm tears the session down. (Without an initial prompt wait, aiterm does *not* then verify the vendor CLI actually started or authenticated — read the session to confirm the agent came up.) `codex_agent` forwards `model` as `-m` and `reasoning_effort` as `-c model_reasoning_effort=…` without validating the effort value, since Codex's accepted values vary by version. Grok/Composer reject `reasoning_effort`: Grok CLI `--effort` is only for headless `grok -p`, and the interactive TUI ignores it with a warning. Pass an absolute path for `cwd` — `~` is not expanded. Codex launch responses always report the effective model/effort and where each came from (argument, terminal-config inheritance, or CLI default), with an explicit warning when the effective effort is `ultra` (max reasoning plus proactive automatic delegation). `agent_done` uses launch-local managed vendor homes and does not edit your normal hook files; Codex links only `auth.json` and copies `config.toml` into its managed `CODEX_HOME` — explicitly passed `model` / `reasoning_effort` values also rewrite the matching top-level pins in that copy, so terminal pins don't silently leak into the child — while Grok/Composer additionally isolate `GROK_HOME` and `HOME` to suppress compat hook/plugin contamination. Grok OAuth uses the normal Grok home's `auth.json` and `auth.json.lock` as a pair so refresh locking does not split across sessions. Before the first unbound `pty_send({ wait: "agent_done" })`, aiterm waits for the vendor TUI's input prompt and fails before sending if the prompt is not ready, avoiding dropped startup input. `codex_agent` launcher `wait:"agent_done"` has the same requirement and is only valid with both `prompt` and `agent_done:true`; if the TUI is not ready, the prompt is not sent and the session is left inspectable with `initial_prompt=not_sent`. While an initial prompt is still `pending`/`sent`, ordinary `pty_send` is rejected to prevent mixed input; manual takeover can still use `pty_key`, or `pty_send(..., force:true)` if you intentionally want to type into that live TUI. `agent_done` currently requires POSIX filesystem semantics (`getuid`, secure temp files, hard-link checks), so it is supported on Linux, WSL2, and macOS; native Windows can still use the core PTY tools and agent launchers without `agent_done`.
|
|
68
68
|
|
|
69
69
|
There is deliberately **no Claude launcher**, and no protocol between the agents: aiterm's job is to let your Claude (or any MCP client) reach for *other* agents and drive their terminals. Because a launched agent is just another persistent session, everything else in this README applies to it: token-reduced reads, completion detection, and a human `attach` to watch or take over.
|
|
70
70
|
|
|
@@ -219,11 +219,11 @@ Each launcher starts a specific vendor's interactive coding-agent TUI inside a f
|
|
|
219
219
|
|
|
220
220
|
| Tool | Launches | Key args |
|
|
221
221
|
| --- | --- | --- |
|
|
222
|
-
| `codex_agent` | Codex CLI (OpenAI;
|
|
223
|
-
| `grok_agent` | Grok Build, model `grok-
|
|
224
|
-
| `composer_agent` | Grok Build, model `grok-composer-2.5-fast` (xAI) |
|
|
222
|
+
| `codex_agent` | Codex CLI (OpenAI; terminal config/CLI default unless overridden) | `prompt?`, `model?`, `reasoning_effort?` (`low`/`medium`/`high`/`xhigh`/`max`/`ultra`; ultra enables proactive automatic delegation), `cwd?`, `session_name?`, `agent_done?`, `wait?`, `timeout?`, `screen?`, `lines?` |
|
|
223
|
+
| `grok_agent` | Grok Build, model `grok-4.5` by default (`model?` overrides) (xAI) | `prompt?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error; Grok CLI `--effort` is headless-only), `cwd?`, `session_name?`, `agent_done?` |
|
|
224
|
+
| `composer_agent` | Grok Build, model `grok-composer-2.5-fast` by default (`model?` overrides) (xAI) | `prompt?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error), `cwd?`, `session_name?`, `agent_done?` |
|
|
225
225
|
|
|
226
|
-
The vendor CLI must be installed and authenticated (`codex` for `codex_agent`; `grok` for both Grok tools). aiterm resolves the binary via `CODEX_BIN` / `GROK_BIN`, then `~/.local/bin/codex` / `~/.grok/bin/grok`, then `PATH`. Prerequisites are validated before a session is created
|
|
226
|
+
The vendor CLI must be installed and authenticated (`codex` for `codex_agent`; `grok` for both Grok tools). aiterm resolves the binary via `CODEX_BIN` / `GROK_BIN`, then `~/.local/bin/codex` / `~/.grok/bin/grok`, then `PATH`. Prerequisites are validated before a session is created: empty `model` and any Grok/Composer `reasoning_effort` are errors, while a missing CLI or nonexistent `cwd` fails for all three; a failed launch leaves no session behind. Codex forwards `model` as `-m` and `reasoning_effort` as `-c model_reasoning_effort=…`; Grok/Composer reject effort because interactive TUI does not support it (Grok CLI `--effort` is headless-only). Full details under [Launch other coding agents into that terminal](#2-launch-other-coding-agents-into-that-terminal--the-orchestration-flagship). Pass an absolute path for `cwd` — `~` is not expanded. `agent_done` is hook-backed for agent launchers; Codex/Grok/Composer have passing live smokes on Linux/WSL2/macOS for follow-up `pty_send(wait:"agent_done")`, and Codex has a live smoke for launcher `prompt + wait:"agent_done"`. Native Windows can launch agents but `agent_done` is not supported yet. Codex managed `CODEX_HOME` links only `auth.json`, copies `config.toml`, and owns its own `hooks.json`. Before the first unbound agent send, `pty_send({ wait:"agent_done" })` waits for the vendor TUI input prompt and fails before sending if it is not ready. `codex_agent` launcher `wait:"agent_done"` requires `prompt` plus `agent_done:true`; it sends the initial prompt only after the TUI is ready, and returns `initial_prompt=not_sent` without sending if the TUI is blocked before input. In Grok OAuth mode, aiterm keeps hook/config isolation per launch but shares both `auth.json` and `auth.json.lock` with the normal Grok home; missing OAuth auth fails without leaving a session behind.
|
|
227
227
|
|
|
228
228
|
### Completion detection (5 layers)
|
|
229
229
|
|
package/dist/core.js
CHANGED
|
@@ -1050,7 +1050,61 @@ function createEmpty0600NoFollow(p) {
|
|
|
1050
1050
|
function realCodexHome() {
|
|
1051
1051
|
return process.env.CODEX_HOME || path.join(process.env.HOME ?? os.homedir(), ".codex");
|
|
1052
1052
|
}
|
|
1053
|
-
|
|
1053
|
+
// 引数で model/effort を渡された時は managed config のピンを上書きする(端末 config の
|
|
1054
|
+
// model/model_reasoning_effort ピン——例: effort=ultra は proactive 自動委譲 ON——が対話子へ
|
|
1055
|
+
// 黙って波及するのを防ぐ)。TOML の top-level キーは最初のテーブルヘッダより前にしか置けないため、
|
|
1056
|
+
// 既存行の除去は先頭領域に限定し、上書き行はファイル先頭へ置く。
|
|
1057
|
+
function applyCodexConfigOverrides(body, overrides) {
|
|
1058
|
+
const lines = [];
|
|
1059
|
+
if (overrides.model)
|
|
1060
|
+
lines.push(`model = ${JSON.stringify(overrides.model)}`);
|
|
1061
|
+
if (overrides.effort)
|
|
1062
|
+
lines.push(`model_reasoning_effort = ${JSON.stringify(overrides.effort)}`);
|
|
1063
|
+
if (!lines.length)
|
|
1064
|
+
return body;
|
|
1065
|
+
if (body == null)
|
|
1066
|
+
return lines.join("\n") + "\n";
|
|
1067
|
+
const rows = body.split(/\r?\n/);
|
|
1068
|
+
let firstTable = rows.findIndex((l) => /^\s*\[/.test(l));
|
|
1069
|
+
if (firstTable === -1)
|
|
1070
|
+
firstTable = rows.length;
|
|
1071
|
+
const head = rows.slice(0, firstTable).filter((l) => {
|
|
1072
|
+
if (overrides.model && /^\s*model\s*=/.test(l))
|
|
1073
|
+
return false;
|
|
1074
|
+
if (overrides.effort && /^\s*model_reasoning_effort\s*=/.test(l))
|
|
1075
|
+
return false;
|
|
1076
|
+
return true;
|
|
1077
|
+
});
|
|
1078
|
+
let out = [...lines, ...head, ...rows.slice(firstTable)].join("\n");
|
|
1079
|
+
if (!out.endsWith("\n"))
|
|
1080
|
+
out += "\n";
|
|
1081
|
+
return out;
|
|
1082
|
+
}
|
|
1083
|
+
function readCodexConfigPins(configPath) {
|
|
1084
|
+
let body;
|
|
1085
|
+
try {
|
|
1086
|
+
body = fs.readFileSync(configPath, "utf8");
|
|
1087
|
+
}
|
|
1088
|
+
catch {
|
|
1089
|
+
return { model: { present: false, value: null }, effort: { present: false, value: null } };
|
|
1090
|
+
}
|
|
1091
|
+
const rows = body.split(/\r?\n/);
|
|
1092
|
+
let firstTable = rows.findIndex((l) => /^\s*\[/.test(l));
|
|
1093
|
+
if (firstTable === -1)
|
|
1094
|
+
firstTable = rows.length;
|
|
1095
|
+
const pick = (key) => {
|
|
1096
|
+
for (const l of rows.slice(0, firstTable)) {
|
|
1097
|
+
const m = l.match(new RegExp(`^\\s*${key}\\s*=\\s*(.*)$`));
|
|
1098
|
+
if (m) {
|
|
1099
|
+
const v = m[1].trim().match(/^"([^"\\]*)"\s*(?:#.*)?$/);
|
|
1100
|
+
return { present: true, value: v ? v[1] : null };
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
return { present: false, value: null };
|
|
1104
|
+
};
|
|
1105
|
+
return { model: pick("model"), effort: pick("model_reasoning_effort") };
|
|
1106
|
+
}
|
|
1107
|
+
function createManagedCodexHome(name, launchId, overrides = {}) {
|
|
1054
1108
|
const srcHome = realCodexHome();
|
|
1055
1109
|
let srcSt;
|
|
1056
1110
|
try {
|
|
@@ -1078,17 +1132,22 @@ function createManagedCodexHome(name, launchId) {
|
|
|
1078
1132
|
}
|
|
1079
1133
|
fs.symlinkSync(authSrc, path.join(managedHome, "auth.json"));
|
|
1080
1134
|
const configSrc = path.join(srcHome, "config.toml");
|
|
1135
|
+
let configBody = null;
|
|
1081
1136
|
try {
|
|
1082
1137
|
const st = fs.statSync(configSrc);
|
|
1083
|
-
if (st.isFile())
|
|
1084
|
-
fs.
|
|
1085
|
-
fs.chmodSync(path.join(managedHome, "config.toml"), 0o600);
|
|
1086
|
-
}
|
|
1138
|
+
if (st.isFile())
|
|
1139
|
+
configBody = fs.readFileSync(configSrc, "utf8");
|
|
1087
1140
|
}
|
|
1088
1141
|
catch (e) {
|
|
1089
1142
|
if (e.code !== "ENOENT")
|
|
1090
1143
|
throw e;
|
|
1091
1144
|
}
|
|
1145
|
+
const configOut = applyCodexConfigOverrides(configBody, overrides);
|
|
1146
|
+
if (configOut != null) {
|
|
1147
|
+
const configDst = path.join(managedHome, "config.toml");
|
|
1148
|
+
fs.writeFileSync(configDst, configOut, { mode: 0o600 });
|
|
1149
|
+
fs.chmodSync(configDst, 0o600);
|
|
1150
|
+
}
|
|
1092
1151
|
const hookScript = codexHookScriptPath();
|
|
1093
1152
|
if (!fs.existsSync(hookScript)) {
|
|
1094
1153
|
throw new AitermError(`Codex Stop hook wrapper が見つかりません。npm run build を実行してください: ${hookScript}`, 2);
|
|
@@ -1307,11 +1366,11 @@ function acquireAgentWaitFileLock(meta) {
|
|
|
1307
1366
|
}
|
|
1308
1367
|
};
|
|
1309
1368
|
}
|
|
1310
|
-
function createCodexAgentMetadata(name, cwd, initialPrompt) {
|
|
1369
|
+
function createCodexAgentMetadata(name, cwd, initialPrompt, overrides = {}) {
|
|
1311
1370
|
const launchId = randomBytes(16).toString("hex");
|
|
1312
1371
|
const eventFile = agentEventPath(name, launchId);
|
|
1313
1372
|
createEmpty0600NoFollow(eventFile);
|
|
1314
|
-
const codexHome = createManagedCodexHome(name, launchId);
|
|
1373
|
+
const codexHome = createManagedCodexHome(name, launchId, overrides);
|
|
1315
1374
|
const meta = {
|
|
1316
1375
|
kind: "codex",
|
|
1317
1376
|
aiterm_session: name,
|
|
@@ -1868,23 +1927,31 @@ function resolveAgentBin(kind) {
|
|
|
1868
1927
|
function shq(s) {
|
|
1869
1928
|
return `'${s.replace(/'/g, "'\\''")}'`;
|
|
1870
1929
|
}
|
|
1871
|
-
|
|
1930
|
+
// grok CLI はモデル未指定だと端末側 default に従うため、ツール契約として既定 slug を固定する。
|
|
1931
|
+
// codex は既定 slug を持たず端末 config/CLI 既定に委ねる(起動応答で実効値を報告する)。
|
|
1932
|
+
const GROK_MODEL_DEFAULTS = {
|
|
1933
|
+
grok: "grok-4.5",
|
|
1934
|
+
composer: "grok-composer-2.5-fast",
|
|
1935
|
+
};
|
|
1936
|
+
function buildAgentCmd(kind, bin, model, effort, prompt, meta = null) {
|
|
1872
1937
|
const parts = [shq(bin)];
|
|
1873
1938
|
if (kind === "codex") {
|
|
1874
1939
|
if (meta?.kind === "codex")
|
|
1875
1940
|
parts.push("--dangerously-bypass-hook-trust");
|
|
1876
|
-
//
|
|
1941
|
+
// model/effort は CLI 引数で明示(config 継承より優先)。agent_done 時は managed home 側
|
|
1942
|
+
// config.toml も同値で上書き済み(applyCodexConfigOverrides)。
|
|
1943
|
+
if (model)
|
|
1944
|
+
parts.push("-m", shq(model));
|
|
1877
1945
|
if (effort)
|
|
1878
1946
|
parts.push("-c", `model_reasoning_effort=${shq(effort)}`);
|
|
1879
1947
|
}
|
|
1880
1948
|
else {
|
|
1881
|
-
// grok / composer は同じ grok CLI
|
|
1949
|
+
// grok / composer は同じ grok CLI をモデル違いで起動。--effort は headless(grok -p)専用で
|
|
1950
|
+
// 対話 TUI では警告の上無視されるため渡さない(openAgent が指定を事前拒否する)。
|
|
1882
1951
|
parts.push("--no-auto-update");
|
|
1883
1952
|
if (meta?.kind === "grok" || meta?.kind === "composer")
|
|
1884
1953
|
parts.push("--no-alt-screen");
|
|
1885
|
-
parts.push("--model",
|
|
1886
|
-
if (effort)
|
|
1887
|
-
parts.push("--effort", shq(effort));
|
|
1954
|
+
parts.push("--model", shq(model ?? GROK_MODEL_DEFAULTS[kind]));
|
|
1888
1955
|
if ((meta?.kind === "grok" || meta?.kind === "composer") && prompt)
|
|
1889
1956
|
parts.push("--verbatim");
|
|
1890
1957
|
}
|
|
@@ -1929,15 +1996,53 @@ function agentLabel(kind) {
|
|
|
1929
1996
|
? "Grok Build(Grok)"
|
|
1930
1997
|
: "Codex";
|
|
1931
1998
|
}
|
|
1932
|
-
//
|
|
1933
|
-
|
|
1999
|
+
// 起動応答にモデル/effort の実効値と出所を明示する。codex は端末 config のピン(model /
|
|
2000
|
+
// model_reasoning_effort)が対話子へ波及する構造のため、引数・端末config継承・CLI既定の
|
|
2001
|
+
// どれで起動したかを起動時点で可視化し、実効 effort=ultra は proactive 自動委譲 ON を警告する。
|
|
2002
|
+
function buildAgentLaunchNote(kind, model, effort, meta) {
|
|
2003
|
+
if (kind !== "codex") {
|
|
2004
|
+
return (`起動設定: model=${model ?? GROK_MODEL_DEFAULTS[kind]}(${model ? "引数" : "ツール既定"})。` +
|
|
2005
|
+
"reasoning effort は対話 TUI 非対応=未指定で起動。");
|
|
2006
|
+
}
|
|
2007
|
+
const configPath = meta?.kind === "codex" && meta.codex_home
|
|
2008
|
+
? path.join(meta.codex_home, "config.toml")
|
|
2009
|
+
: path.join(realCodexHome(), "config.toml");
|
|
2010
|
+
const pins = readCodexConfigPins(configPath);
|
|
2011
|
+
const describePin = (arg, pin) => arg
|
|
2012
|
+
? `${arg}(引数)`
|
|
2013
|
+
: pin.present
|
|
2014
|
+
? pin.value
|
|
2015
|
+
? `${pin.value}(端末config継承)`
|
|
2016
|
+
: "端末config継承(値未解析)"
|
|
2017
|
+
: "CLI既定";
|
|
2018
|
+
const effectiveEffort = effort ?? (pins.effort.present ? pins.effort.value : null);
|
|
2019
|
+
return (`起動設定: model=${describePin(model, pins.model)} effort=${describePin(effort, pins.effort)}。` +
|
|
2020
|
+
(effectiveEffort === "ultra"
|
|
2021
|
+
? "⚠ effort=ultra は max 推論+proactive 自動委譲 ON(子エージェント自動生成・使用量急増に注意)。"
|
|
2022
|
+
: ""));
|
|
2023
|
+
}
|
|
1934
2024
|
export function openAgent(kind, opts = {}) {
|
|
1935
2025
|
const label = agentLabel(kind);
|
|
1936
2026
|
// 前提検証は session を作る前に全部済ませる(失敗の残骸 session を作らない)。
|
|
1937
|
-
// effort → bin → cwd の順: effort 検証は CLI 不在の端末でも同じ結果になる(テスト可能性)。
|
|
2027
|
+
// model/effort → bin → cwd の順: model/effort 検証は CLI 不在の端末でも同じ結果になる(テスト可能性)。
|
|
2028
|
+
let model = null;
|
|
2029
|
+
if (opts.model != null) {
|
|
2030
|
+
model = opts.model.trim();
|
|
2031
|
+
if (!model)
|
|
2032
|
+
throw new AitermError("model が空文字です(省略するか有効なモデル名を指定してください)", 2);
|
|
2033
|
+
}
|
|
1938
2034
|
const effort = opts.reasoning_effort ?? null;
|
|
1939
|
-
|
|
1940
|
-
|
|
2035
|
+
// grok CLI の --effort は headless(grok -p)専用で、対話 TUI では警告の上無視される。
|
|
2036
|
+
// 黙って no-op の引数を受けない=起動前に明示エラーで拒否する(codex は CLI 側の値集合が
|
|
2037
|
+
// 版で変わるため縛らず送信まで通す)。
|
|
2038
|
+
if (effort && kind === "grok") {
|
|
2039
|
+
throw new AitermError(`${label} は reasoning_effort を指定できません。grok CLI の --effort は headless(grok -p)専用で、` +
|
|
2040
|
+
"対話 TUI では警告の上無視されます(grok-4.5 の TUI 既定 effort は high)。" +
|
|
2041
|
+
"effort 制御が必要なら通常 PTY で `grok -p --effort low|medium|high ...` を使ってください", 2);
|
|
2042
|
+
}
|
|
2043
|
+
if (effort && kind === "composer") {
|
|
2044
|
+
throw new AitermError(`${label} は reasoning_effort を指定できません。grok-composer-2.5-fast は reasoning effort 非対応です` +
|
|
2045
|
+
"(モデルカタログ supports_reasoning_effort=false)", 2);
|
|
1941
2046
|
}
|
|
1942
2047
|
const agentDone = !!opts.agent_done;
|
|
1943
2048
|
const bin = resolveAgentBin(kind);
|
|
@@ -1975,13 +2080,15 @@ export function openAgent(kind, opts = {}) {
|
|
|
1975
2080
|
const binForCmd = isWin ? toWslPath(bin) : bin;
|
|
1976
2081
|
const cwdForCmd = cwd && isWin ? toWslPath(cwd) : cwd;
|
|
1977
2082
|
const [sid, hint] = openSession(opts.session_name ?? null, "bash");
|
|
2083
|
+
let launchNote = "";
|
|
1978
2084
|
try {
|
|
1979
2085
|
const meta = agentDone
|
|
1980
2086
|
? kind === "codex"
|
|
1981
|
-
? createCodexAgentMetadata(sid, cwd, opts.prompt ? "pending" : "none")
|
|
2087
|
+
? createCodexAgentMetadata(sid, cwd, opts.prompt ? "pending" : "none", { model, effort })
|
|
1982
2088
|
: createGrokAgentMetadata(kind, sid, cwd, opts.prompt ? "pending" : "none")
|
|
1983
2089
|
: null;
|
|
1984
|
-
|
|
2090
|
+
launchNote = buildAgentLaunchNote(kind, model, effort, meta);
|
|
2091
|
+
const cmd = buildAgentCmd(kind, binForCmd, model, effort, opts.prompt ?? null, meta);
|
|
1985
2092
|
const envPrefix = agentEnvPrefix(meta, sid);
|
|
1986
2093
|
const full = cwdForCmd ? `cd ${shq(cwdForCmd)} && ${envPrefix}${cmd}` : `${envPrefix}${cmd}`;
|
|
1987
2094
|
// force:true で送る。起動骨格は `bin '...'` の固定形で、prompt/cwd/effort は shq でクオート済みの
|
|
@@ -2001,7 +2108,7 @@ export function openAgent(kind, opts = {}) {
|
|
|
2001
2108
|
}
|
|
2002
2109
|
return [
|
|
2003
2110
|
sid,
|
|
2004
|
-
`${label} を session ${sid} で起動した。${agentDone ? "agent_done 待機が有効。" : ""}` +
|
|
2111
|
+
`${label} を session ${sid} で起動した。${launchNote}${agentDone ? "agent_done 待機が有効。" : ""}` +
|
|
2005
2112
|
`${agentDone && kind !== "codex" ? " hook 汚染防止のため Grok 実行中は一時 HOME を使う。" : ""}\n${hint}\n` +
|
|
2006
2113
|
`TUI の描画には数秒かかる。少し置いてから pty_read(${sid}, screen:true) で画面を読み、` +
|
|
2007
2114
|
`pty_send(${sid}, "...") で入力・pty_key(${sid}, "Enter"/"Up"/"C-c" 等) で操作する(対話)。` +
|
|
@@ -2039,6 +2146,7 @@ export async function openAgentWithInitialPrompt(kind, opts = {}) {
|
|
|
2039
2146
|
}
|
|
2040
2147
|
const [sid, hint] = openAgent(kind, {
|
|
2041
2148
|
session_name: opts.session_name ?? null,
|
|
2149
|
+
model: opts.model ?? null,
|
|
2042
2150
|
reasoning_effort: opts.reasoning_effort ?? null,
|
|
2043
2151
|
cwd: opts.cwd ?? null,
|
|
2044
2152
|
prompt: null,
|
package/dist/index.js
CHANGED
|
@@ -180,9 +180,15 @@ server.registerTool("pty_list", {
|
|
|
180
180
|
});
|
|
181
181
|
// 対話型エージェント起動ツール(モデルごとに1つ=ツール名/説明でどのモデルか一目で分かる)。
|
|
182
182
|
// いずれも永続端末に TUI を起動し session_id を返す。以後 pty_read/pty_send で対話操作する。
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
183
|
+
const agentModelDesc = (kind) => kind === "codex"
|
|
184
|
+
? "起動モデル(例: gpt-5.6-sol / gpt-5.6-terra / gpt-5.6-luna)。省略時は端末 config/CLI 既定を継承" +
|
|
185
|
+
"(端末側のピンがそのまま効く。実効値は起動応答に明示される)"
|
|
186
|
+
: `起動モデル。省略時は ${kind === "grok" ? "grok-4.5" : "grok-composer-2.5-fast"}`;
|
|
187
|
+
const agentEffortDesc = (grokLike) => grokLike
|
|
188
|
+
? "指定不可(grok CLI の --effort は headless 専用で、対話 TUI では警告の上無視される。" +
|
|
189
|
+
"composer は effort 自体非対応)。指定すると起動前にエラーを返す"
|
|
190
|
+
: "reasoning effort(思考レベル)。low/medium/high/xhigh/max/ultra(CLI 版依存)。" +
|
|
191
|
+
"ultra は max 推論+proactive 自動委譲 ON=使用量急増注意(明示要求時のみ)。省略時は端末 config/CLI 既定。";
|
|
186
192
|
function registerAgentTool(toolName, kind, desc, grokLike) {
|
|
187
193
|
const initialPromptWaitSchema = {};
|
|
188
194
|
if (kind === "codex") {
|
|
@@ -198,11 +204,10 @@ function registerAgentTool(toolName, kind, desc, grokLike) {
|
|
|
198
204
|
description: desc,
|
|
199
205
|
inputSchema: {
|
|
200
206
|
prompt: z.string().nullish().describe("起動時に渡す初手プロンプト(任意)。省略で素のTUI起動"),
|
|
201
|
-
|
|
207
|
+
model: z.string().nullish().describe(agentModelDesc(kind)),
|
|
208
|
+
// grok/composer の effort は対話 TUI で無効(headless 専用)=core 側が起動前に明示エラーで拒否。
|
|
202
209
|
// codex は CLI 側の値集合が版で変わるため縛らない(core 側も同方針)。
|
|
203
|
-
reasoning_effort:
|
|
204
|
-
.nullish()
|
|
205
|
-
.describe(agentEffortDesc(grokLike)),
|
|
210
|
+
reasoning_effort: z.string().nullish().describe(agentEffortDesc(grokLike)),
|
|
206
211
|
cwd: z.string().nullish().describe("作業ディレクトリ(対象リポのルート等・任意)"),
|
|
207
212
|
session_name: z.string().nullish().describe("セッション名(省略で自動採番)"),
|
|
208
213
|
agent_done: z
|
|
@@ -211,10 +216,11 @@ function registerAgentTool(toolName, kind, desc, grokLike) {
|
|
|
211
216
|
.describe("managed Stop hook を有効化し、pty_send(wait:'agent_done') を使えるようにする"),
|
|
212
217
|
...initialPromptWaitSchema,
|
|
213
218
|
},
|
|
214
|
-
}, async ({ prompt, reasoning_effort, cwd, session_name, agent_done, wait, timeout, screen, lines }) => {
|
|
219
|
+
}, async ({ prompt, model, reasoning_effort, cwd, session_name, agent_done, wait, timeout, screen, lines }) => {
|
|
215
220
|
try {
|
|
216
221
|
const [sid, hint] = await core.openAgentWithInitialPrompt(kind, {
|
|
217
222
|
prompt: prompt ?? undefined,
|
|
223
|
+
model: model ?? undefined,
|
|
218
224
|
reasoning_effort: reasoning_effort ?? undefined,
|
|
219
225
|
cwd: cwd ?? undefined,
|
|
220
226
|
session_name: session_name ?? undefined,
|
|
@@ -231,12 +237,13 @@ function registerAgentTool(toolName, kind, desc, grokLike) {
|
|
|
231
237
|
}
|
|
232
238
|
});
|
|
233
239
|
}
|
|
234
|
-
registerAgentTool("codex_agent", "codex", "【Codex (OpenAI
|
|
235
|
-
"起動後は pty_read で画面を読み pty_send で操作する。reasoning_effort
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
+
registerAgentTool("codex_agent", "codex", "【Codex (OpenAI)】の対話エージェント TUI を永続端末に起動する。実装・レビュー・調査を対話で回す。" +
|
|
241
|
+
"起動後は pty_read で画面を読み pty_send で操作する。model / reasoning_effort を引数で指定可" +
|
|
242
|
+
"(省略時は端末 config/CLI 既定を継承。実効値は起動応答に明示)。", false);
|
|
243
|
+
registerAgentTool("grok_agent", "grok", "【Grok Build の Grok モデル (既定 grok-4.5)】の対話エージェント TUI を永続端末に起動する。" +
|
|
244
|
+
"起動後は pty_read/pty_send で対話操作。model を引数で指定可。reasoning_effort は対話 TUI 非対応(指定はエラー)。", true);
|
|
245
|
+
registerAgentTool("composer_agent", "composer", "【Grok Build の Composer モデル (既定 grok-composer-2.5-fast)】の対話エージェント TUI を永続端末に起動する。" +
|
|
246
|
+
"起動後は pty_read/pty_send で対話操作。model を引数で指定可。reasoning_effort は非対応(指定はエラー)。", true);
|
|
240
247
|
async function main() {
|
|
241
248
|
const transport = new StdioServerTransport();
|
|
242
249
|
await server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiterm-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"mcpName": "io.github.kitepon-rgb/aiterm-mcp",
|
|
5
5
|
"description": "AI-driven persistent terminal as a local stdio MCP server (tmux-backed). Holds one local PTY; SSH and containers are just commands you send into it. Also launches interactive Codex/Grok/Composer agent TUIs in a persistent terminal. Token-reducing reads.",
|
|
6
6
|
"keywords": [
|