aiterm-mcp 0.21.3 → 0.21.4
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.ja.md +9 -4
- package/README.md +11 -4
- package/dist/core.js +62 -0
- package/dist/runtime-error-store.js +8 -4
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
> **Claude Code から Codex CLI の対話 TUI を操作する——スラッシュコマンドや [`$imagegen`](https://learn.chatgpt.com/docs/image-generation#generate-or-edit-an-image) のようなスキルまで、MCP越しに使える。**
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
<img src=".github/og.
|
|
4
|
+
<img src=".github/og.png" alt="Aiterm — 異なる知性が一つの持続する実行現場を共有する森の観測拠点" width="100%">
|
|
5
|
+
<br>
|
|
6
|
+
<sub><em>この画像は、異なる知性がひとつの持続する実行現場を共有し、それぞれの視点から同じ仕事を前へ進める姿を表しています。</em></sub>
|
|
5
7
|
</p>
|
|
6
8
|
|
|
7
|
-
#
|
|
9
|
+
# Aiterm
|
|
8
10
|
|
|
9
11
|
[](https://github.com/kitepon-rgb/aiterm-mcp/actions/workflows/ci.yml)
|
|
10
12
|
[](https://www.npmjs.com/package/aiterm-mcp)
|
|
11
13
|
[](https://www.npmjs.com/package/aiterm-mcp)
|
|
12
14
|
[](https://nodejs.org)
|
|
13
15
|
[](LICENSE)
|
|
14
|
-
[](https://packagephobia.com/result?p=aiterm-mcp)
|
|
15
16
|
|
|
16
17
|
> *(English: [README.md](README.md))*
|
|
17
18
|
|
|
@@ -95,6 +96,10 @@ host統合は、kitepon.devの製品開発を支える内部基盤
|
|
|
95
96
|
|
|
96
97
|
13 ツール: 6 つの **PTY ツール**(`pty_open` / `pty_send` / `pty_read` / `pty_key` / `pty_close` / `pty_list`)で 1 本の永続端末を開き・操作し・読む。加えて 4 つの **エージェント起動ツール**(`claude_agent` / `codex_agent` / `grok_agent` / `composer_agent`)が別のコーディングエージェントの TUI を新しい端末の中に起動し、`claude_turn`がdurable caller向けの構造化issue/recoveryを、`claude_approval`がmanaged Claudeの相関済み承認UI中継を、`diagnostics`が安全なfactory readinessを返す。バックエンドは **tmux** なので、MCP サーバや AI クライアントが再起動してもセッションは生き残る。
|
|
97
98
|
|
|
99
|
+
**v0.21.4ではfresh managed Claudeからuser scope MCPを復元。** 通常hook、plugin、permission、
|
|
100
|
+
project/local MCPの隔離は維持し、`~/.claude.json`で既にuser scope登録された`mcpServers`だけを
|
|
101
|
+
owner-onlyのlaunch設定へsnapshotする。破損したuser MCP設定は、toolなしで黙って起動せずsession作成前に失敗する。
|
|
102
|
+
|
|
98
103
|
**v0.21.3ではCodexの完了経路からStop hookを撤去。** Codexの完了通知と最終回答の帰属は、
|
|
99
104
|
root rollout transcriptへ永続化される`task_complete.turn_id`をdispatch byte境界以後から観測する。
|
|
100
105
|
hookの実行ファイルが壊れたり消えたりしても`aiterm-wait`は座礁しない。v0.21.0では外部agent launcherへ
|
|
@@ -162,7 +167,7 @@ $ aiterm-wait --session codex1 --cursor <event_cursor> # exit 0=done / 3=timeo
|
|
|
162
167
|
| `grok_agent` | Grok Build(xAI、既定`grok-4.5`、`model?`で上書き) | `prompt?`, `model?`, `reasoning_effort?`は非対応(指定時は明示エラー), `cwd?`, `session_name?`, `write_scope?` |
|
|
163
168
|
| `composer_agent` | Grok Build(xAI、既定`grok-composer-2.5-fast`、`model?`で上書き) | `prompt?`, `model?`, `reasoning_effort?`は非対応(指定時は明示エラー), `cwd?`, `session_name?`, `write_scope?` |
|
|
164
169
|
|
|
165
|
-
各ベンダーの CLI が導入・認証済みであること(`claude_agent` は `claude`、`codex_agent` は `codex`、Grok 系は `grok`)。バイナリは `CLAUDE_BIN` / `CODEX_BIN` / `GROK_BIN`、各既定path、`PATH` の順で解決する。CLI不在・不正なmodel/effort・実在しない`cwd`はsession作成前に失敗し、残骸を残さない。Claudeはさらに、PTY作成前に同じCLIの`auth status --json`が`loggedIn:true`を返すことを要求する。未認証・malformed・失敗exit・timeoutは残骸ゼロで失敗し、正常なvendor所有の共有認証は複数sessionから利用する。managed Claudeへのexact `/login`・`/logout`は通常dispatchとforce送信の双方で副作用前に拒否するため、認証は通常端末で一度だけ修理する。Claudeは通常settingsを継承しないlaunch専用settingsとStop hook
|
|
170
|
+
各ベンダーの CLI が導入・認証済みであること(`claude_agent` は `claude`、`codex_agent` は `codex`、Grok 系は `grok`)。バイナリは `CLAUDE_BIN` / `CODEX_BIN` / `GROK_BIN`、各既定path、`PATH` の順で解決する。CLI不在・不正なmodel/effort・実在しない`cwd`はsession作成前に失敗し、残骸を残さない。Claudeはさらに、PTY作成前に同じCLIの`auth status --json`が`loggedIn:true`を返すことを要求する。未認証・malformed・失敗exit・timeoutは残骸ゼロで失敗し、正常なvendor所有の共有認証は複数sessionから利用する。managed Claudeへのexact `/login`・`/logout`は通常dispatchとforce送信の双方で副作用前に拒否するため、認証は通常端末で一度だけ修理する。Claudeは通常settingsを継承しないlaunch専用settingsとStop hookを使う一方、user scopeの`mcpServers`だけは`~/.claude.json`から別のowner-only launch configへsnapshotし`--mcp-config`で渡す。project/local MCPは継承しない。本文なしeventとowner-only bounded resultを分離し、`pty_read({ agent_transcript:true })`はdigestとbyte数を検証したresultだけを返してClaude private transcriptを読まない。後着resultは同じsessionからprompt再送なしで回収できる。managed Claudeのactive turn中はC-c以外の`pty_key`と素送信を拒否する。Claudeが`Do you want to proceed?`を表示したら、`claude_approval(action:"inspect", ...)`で画面digestを取得し、表示内容を判断してから、そのdigestと`approve_once`または`deny`を`respond`へ渡す。同じoperation・同じ画面が維持されている時だけ入力し、任意文字列や恒久許可選択肢は中継しない。中断は`C-c`、解除は`pty_close`。
|
|
166
171
|
|
|
167
172
|
エージェント間の隠れたプロトコルは無い。起動したClaude/Codex/Grok/Composerは利用者がattachできるもう1本の永続sessionであり、MCPクライアントが通常のPTY操作で駆動する。
|
|
168
173
|
|
package/README.md
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
> **Drive Codex CLI's interactive TUI from Claude Code — including slash commands and skills such as [`$imagegen`](https://learn.chatgpt.com/docs/image-generation#generate-or-edit-an-image) — through MCP.**
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
<img src=".github/og.
|
|
4
|
+
<img src=".github/og.png" alt="Aiterm — a shared forest observatory where different intelligences work in one persistent execution space" width="100%">
|
|
5
|
+
<br>
|
|
6
|
+
<sub><em>This image represents different intelligences sharing one persistent workspace and advancing the same work from their own perspectives.</em></sub>
|
|
5
7
|
</p>
|
|
6
8
|
|
|
7
|
-
#
|
|
9
|
+
# Aiterm
|
|
8
10
|
|
|
9
11
|
[](https://github.com/kitepon-rgb/aiterm-mcp/actions/workflows/ci.yml)
|
|
10
12
|
[](https://www.npmjs.com/package/aiterm-mcp)
|
|
11
13
|
[](https://www.npmjs.com/package/aiterm-mcp)
|
|
12
14
|
[](https://nodejs.org)
|
|
13
15
|
[](LICENSE)
|
|
14
|
-
[](https://packagephobia.com/result?p=aiterm-mcp)
|
|
15
16
|
|
|
16
17
|
> *(日本語: [README.ja.md](README.ja.md))*
|
|
17
18
|
|
|
@@ -95,6 +96,12 @@ toolchain behind kitepon.dev's products.
|
|
|
95
96
|
|
|
96
97
|
Thirteen tools: six **PTY tools** — `pty_open` / `pty_send` / `pty_read` / `pty_key` / `pty_close` / `pty_list` — to open, drive, and read one persistent terminal, four **agent launchers** — `claude_agent` / `codex_agent` / `grok_agent` / `composer_agent` — that each start another coding agent's TUI inside a fresh one, `claude_turn` for durable structured issue/recovery, `claude_approval` for correlated managed-Claude approval prompts, and `diagnostics` for safe factory readiness. The backend is **tmux**, so sessions survive even if the MCP server or the AI client restarts.
|
|
97
98
|
|
|
99
|
+
**v0.21.4 restores user-scoped MCPs in fresh managed Claude sessions.** Aiterm keeps
|
|
100
|
+
normal hooks, plugins, permissions, and project/local MCPs isolated, while snapshotting only
|
|
101
|
+
the already user-scoped `mcpServers` from `~/.claude.json` into an owner-only launch config.
|
|
102
|
+
Malformed user MCP config fails before a session is created instead of silently launching
|
|
103
|
+
Claude without its tools.
|
|
104
|
+
|
|
98
105
|
**v0.21.3 removes Codex Stop hooks from the completion path.** Codex completion and
|
|
99
106
|
final-message attribution now come from the root rollout transcript's durable
|
|
100
107
|
`task_complete.turn_id`, observed after the dispatch byte boundary. A broken or stale
|
|
@@ -178,7 +185,7 @@ One call per model, so the tool name itself tells you which model you get:
|
|
|
178
185
|
| `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?`, `write_scope?` |
|
|
179
186
|
| `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?`, `write_scope?` |
|
|
180
187
|
|
|
181
|
-
The vendor CLI must be installed and authenticated (`claude` for `claude_agent`; `codex` for `codex_agent`; `grok` for both Grok tools). aiterm resolves the binary via `CLAUDE_BIN` / `CODEX_BIN` / `GROK_BIN`, then `~/.local/bin/claude` / `~/.local/bin/codex` / `~/.grok/bin/grok`, then `PATH`. Prerequisites are checked **before** a session exists: empty `model` values and unsupported effort values are rejected up front; a missing CLI binary or a nonexistent `cwd` fails for all four. Before creating a Claude session, aiterm also requires a successful structured `claude auth status --json` result with `loggedIn: true`; unavailable, malformed, or failed authentication leaves **zero leftover session**. Claude sessions share the vendor-owned credential store rather than copying credentials per launch, so multiple sessions can reuse one healthy login. Managed Claude rejects exact `/login` and `/logout` dispatches, including forced sends: repair authentication once in a normal terminal, then relaunch any stale unauthenticated sessions. Claude and Codex launchers forward `model` and `reasoning_effort` through their vendor CLI's public flags; Grok/Composer reject `reasoning_effort` because it is headless-only. Pass an absolute path for `cwd` — `~` is not expanded. Durable callers can make a promptless Claude launch exactly replayable by passing an explicit `session_name` and a `launch_operation_id` formatted as `sha256:<64 lowercase hex>`. Repeating the identical launch returns the same structured session receipt without starting the CLI twice; a different correlation ID or launch argument for that session fails explicitly. Claude uses launch-local managed settings containing only aiterm's Stop hook: normal user/project/local hooks are not inherited
|
|
188
|
+
The vendor CLI must be installed and authenticated (`claude` for `claude_agent`; `codex` for `codex_agent`; `grok` for both Grok tools). aiterm resolves the binary via `CLAUDE_BIN` / `CODEX_BIN` / `GROK_BIN`, then `~/.local/bin/claude` / `~/.local/bin/codex` / `~/.grok/bin/grok`, then `PATH`. Prerequisites are checked **before** a session exists: empty `model` values and unsupported effort values are rejected up front; a missing CLI binary or a nonexistent `cwd` fails for all four. Before creating a Claude session, aiterm also requires a successful structured `claude auth status --json` result with `loggedIn: true`; unavailable, malformed, or failed authentication leaves **zero leftover session**. Claude sessions share the vendor-owned credential store rather than copying credentials per launch, so multiple sessions can reuse one healthy login. Managed Claude rejects exact `/login` and `/logout` dispatches, including forced sends: repair authentication once in a normal terminal, then relaunch any stale unauthenticated sessions. Claude and Codex launchers forward `model` and `reasoning_effort` through their vendor CLI's public flags; Grok/Composer reject `reasoning_effort` because it is headless-only. Pass an absolute path for `cwd` — `~` is not expanded. Durable callers can make a promptless Claude launch exactly replayable by passing an explicit `session_name` and a `launch_operation_id` formatted as `sha256:<64 lowercase hex>`. Repeating the identical launch returns the same structured session receipt without starting the CLI twice; a different correlation ID or launch argument for that session fails explicitly. Claude uses launch-local managed settings containing only aiterm's Stop hook: normal user/project/local hooks are not inherited. User-scoped `mcpServers` are copied separately from `~/.claude.json` into a launch-local owner-only config and passed through `--mcp-config`; project/local MCPs remain isolated. The hook event contains no answer body, and the bounded owner-only result is returned by `pty_read({ agent_transcript:true })` without reading Claude's private transcript. A late result remains recoverable from the same session without re-sending the prompt. While a managed Claude turn is active, raw sends and non-interrupt keys are rejected. If Claude displays `Do you want to proceed?`, call `claude_approval(action:"inspect", ...)`, decide from the visible prompt, then call `respond` with the returned digest and either `approve_once` or `deny`. The response is accepted only while the same operation and screen digest remain current; arbitrary text and persistent-allow choices are never relayed. Use `pty_key("C-c")` to interrupt and `pty_close` to abandon the session. For unconstrained manual key-by-key driving, open a plain `pty_open` session and start the vendor CLI yourself. Codex uses a managed `CODEX_HOME`; Grok/Composer isolate their managed homes and pass validated OAuth state through `GROK_AUTH_PATH`. Before the first unbound dispatch, aiterm waits for the vendor TUI's input prompt and fails before sending if it is not ready. Managed completion requires POSIX filesystem semantics (Linux, WSL2, macOS).
|
|
182
189
|
|
|
183
190
|
The managed Codex home links authentication, privately snapshots `config.toml` and `agents/*.toml` custom-role definitions, and keeps sessions/caches isolated. A symlinked role definition is resolved into a regular-file snapshot rather than shared with the source home. aiterm does not install a Codex Stop hook: the root rollout transcript is the completion source, so a missing hook executable cannot strand `aiterm-wait`.
|
|
184
191
|
|
package/dist/core.js
CHANGED
|
@@ -412,6 +412,12 @@ function agentManagedClaudeSettingsPath(name, launchId) {
|
|
|
412
412
|
throw new AitermError(`launch_id が不正です: ${launchId}`, 2);
|
|
413
413
|
return path.join(agentsDir(), `${name}.${launchId}.claude-settings.json`);
|
|
414
414
|
}
|
|
415
|
+
function agentManagedClaudeMcpConfigPath(name, launchId) {
|
|
416
|
+
assertSessionName(name);
|
|
417
|
+
if (!LAUNCH_ID_RE.test(launchId))
|
|
418
|
+
throw new AitermError(`launch_id が不正です: ${launchId}`, 2);
|
|
419
|
+
return path.join(agentsDir(), `${name}.${launchId}.claude-mcp.json`);
|
|
420
|
+
}
|
|
415
421
|
function agentClaudeResultPath(name, launchId) {
|
|
416
422
|
assertSessionName(name);
|
|
417
423
|
if (!LAUNCH_ID_RE.test(launchId))
|
|
@@ -494,6 +500,7 @@ function cleanupAgentState(name) {
|
|
|
494
500
|
f.endsWith(".events.jsonl") ||
|
|
495
501
|
f.endsWith(".wait.lock") ||
|
|
496
502
|
f.endsWith(".claude-settings.json") ||
|
|
503
|
+
f.endsWith(".claude-mcp.json") ||
|
|
497
504
|
f.endsWith(".claude-result.json") ||
|
|
498
505
|
f.endsWith(".claude-operation.json") ||
|
|
499
506
|
f.endsWith(".claude-approval.json") ||
|
|
@@ -1354,6 +1361,7 @@ export function killAll() {
|
|
|
1354
1361
|
f.endsWith(".events.jsonl") ||
|
|
1355
1362
|
f.endsWith(".wait.lock") ||
|
|
1356
1363
|
f.endsWith(".claude-settings.json") ||
|
|
1364
|
+
f.endsWith(".claude-mcp.json") ||
|
|
1357
1365
|
f.endsWith(".claude-result.json") ||
|
|
1358
1366
|
f.endsWith(".claude-operation.json") ||
|
|
1359
1367
|
f.endsWith(".claude-dispatch") ||
|
|
@@ -1656,6 +1664,52 @@ function createManagedClaudeSettings(name, launchId) {
|
|
|
1656
1664
|
});
|
|
1657
1665
|
return settings;
|
|
1658
1666
|
}
|
|
1667
|
+
function createManagedClaudeMcpConfig(name, launchId) {
|
|
1668
|
+
const home = process.env.HOME?.trim() || os.homedir();
|
|
1669
|
+
const source = path.join(home, ".claude.json");
|
|
1670
|
+
let canonical;
|
|
1671
|
+
try {
|
|
1672
|
+
canonical = fs.realpathSync(source);
|
|
1673
|
+
}
|
|
1674
|
+
catch (error) {
|
|
1675
|
+
if (error.code === "ENOENT")
|
|
1676
|
+
return null;
|
|
1677
|
+
throw new AitermError(`Claude user MCP設定を読めません: ${error.message}`, 2);
|
|
1678
|
+
}
|
|
1679
|
+
let fd;
|
|
1680
|
+
let parsed;
|
|
1681
|
+
try {
|
|
1682
|
+
fd = fs.openSync(canonical, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK);
|
|
1683
|
+
const st = fs.fstatSync(fd);
|
|
1684
|
+
if (!st.isFile() || st.uid !== currentUid() || st.size > 16 * 1024 * 1024) {
|
|
1685
|
+
throw new AitermError("Claude user MCP設定の安全検証に失敗しました", 2);
|
|
1686
|
+
}
|
|
1687
|
+
parsed = JSON.parse(fs.readFileSync(fd, "utf8"));
|
|
1688
|
+
}
|
|
1689
|
+
catch (error) {
|
|
1690
|
+
if (error instanceof AitermError)
|
|
1691
|
+
throw error;
|
|
1692
|
+
throw new AitermError(`Claude user MCP設定を読めません: ${error.message}`, 2);
|
|
1693
|
+
}
|
|
1694
|
+
finally {
|
|
1695
|
+
if (fd !== undefined)
|
|
1696
|
+
fs.closeSync(fd);
|
|
1697
|
+
}
|
|
1698
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
1699
|
+
throw new AitermError("Claude user MCP設定のtop-level JSONはobjectである必要があります", 2);
|
|
1700
|
+
}
|
|
1701
|
+
const servers = parsed.mcpServers;
|
|
1702
|
+
if (servers === undefined)
|
|
1703
|
+
return null;
|
|
1704
|
+
if (!servers || typeof servers !== "object" || Array.isArray(servers)) {
|
|
1705
|
+
throw new AitermError("Claude user MCP設定のmcpServersはobjectである必要があります", 2);
|
|
1706
|
+
}
|
|
1707
|
+
if (Object.keys(servers).length === 0)
|
|
1708
|
+
return null;
|
|
1709
|
+
const destination = agentManagedClaudeMcpConfigPath(name, launchId);
|
|
1710
|
+
writeJson0600(destination, { mcpServers: servers });
|
|
1711
|
+
return destination;
|
|
1712
|
+
}
|
|
1659
1713
|
function realGrokHome() {
|
|
1660
1714
|
return path.resolve(process.env.GROK_HOME || path.join(process.env.HOME ?? os.homedir(), ".grok"));
|
|
1661
1715
|
}
|
|
@@ -2227,6 +2281,7 @@ function createClaudeAgentMetadata(name, cwd, initialPrompt, launchOperationId,
|
|
|
2227
2281
|
createEmpty0600NoFollow(eventFile);
|
|
2228
2282
|
createEmpty0600NoFollow(resultFile);
|
|
2229
2283
|
const claudeSettings = createManagedClaudeSettings(name, launchId);
|
|
2284
|
+
const claudeMcpConfig = createManagedClaudeMcpConfig(name, launchId);
|
|
2230
2285
|
const meta = {
|
|
2231
2286
|
kind: "claude",
|
|
2232
2287
|
aiterm_session: name,
|
|
@@ -2241,6 +2296,7 @@ function createClaudeAgentMetadata(name, cwd, initialPrompt, launchOperationId,
|
|
|
2241
2296
|
hook_route: "managed_claude_settings",
|
|
2242
2297
|
node_platform: process.platform,
|
|
2243
2298
|
claude_settings: claudeSettings,
|
|
2299
|
+
claude_mcp_config: claudeMcpConfig,
|
|
2244
2300
|
result_file: resultFile,
|
|
2245
2301
|
};
|
|
2246
2302
|
writeAgentMetadata(meta);
|
|
@@ -2325,11 +2381,14 @@ function loadAgentMetadata(name) {
|
|
|
2325
2381
|
}
|
|
2326
2382
|
if (m.kind === "claude") {
|
|
2327
2383
|
const expectedSettings = agentManagedClaudeSettingsPath(name, m.launch_id);
|
|
2384
|
+
const expectedMcpConfig = agentManagedClaudeMcpConfigPath(name, m.launch_id);
|
|
2328
2385
|
const expectedResult = agentClaudeResultPath(name, m.launch_id);
|
|
2386
|
+
const claudeMcpConfig = m.claude_mcp_config ?? null;
|
|
2329
2387
|
const launchOperationId = m.launch_operation_id ?? null;
|
|
2330
2388
|
const launchRequestDigest = m.launch_request_digest ?? null;
|
|
2331
2389
|
if (m.hook_route !== "managed_claude_settings" ||
|
|
2332
2390
|
m.claude_settings !== expectedSettings ||
|
|
2391
|
+
(claudeMcpConfig !== null && claudeMcpConfig !== expectedMcpConfig) ||
|
|
2333
2392
|
m.result_file !== expectedResult ||
|
|
2334
2393
|
((launchOperationId === null) !== (launchRequestDigest === null)) ||
|
|
2335
2394
|
(launchOperationId !== null && !OPERATION_ID_RE.test(launchOperationId)) ||
|
|
@@ -2351,6 +2410,7 @@ function loadAgentMetadata(name) {
|
|
|
2351
2410
|
hook_route: "managed_claude_settings",
|
|
2352
2411
|
node_platform: process.platform,
|
|
2353
2412
|
claude_settings: expectedSettings,
|
|
2413
|
+
claude_mcp_config: claudeMcpConfig === expectedMcpConfig ? expectedMcpConfig : null,
|
|
2354
2414
|
result_file: expectedResult,
|
|
2355
2415
|
};
|
|
2356
2416
|
}
|
|
@@ -3639,6 +3699,8 @@ function buildAgentCmd(kind, bin, model, effort, prompt, meta = null) {
|
|
|
3639
3699
|
if (kind === "claude") {
|
|
3640
3700
|
if (meta?.kind === "claude") {
|
|
3641
3701
|
parts.push("--setting-sources", shq(""), "--settings", shq(meta.claude_settings ?? ""));
|
|
3702
|
+
if (meta.claude_mcp_config)
|
|
3703
|
+
parts.push("--mcp-config", shq(meta.claude_mcp_config));
|
|
3642
3704
|
}
|
|
3643
3705
|
if (model)
|
|
3644
3706
|
parts.push("--model", shq(model));
|
|
@@ -825,13 +825,17 @@ function forceKill(child) {
|
|
|
825
825
|
catch { /* already exited */ }
|
|
826
826
|
return;
|
|
827
827
|
}
|
|
828
|
+
// taskkill 自体の起動が混雑した Windows runner で遅れても、deadline を越えた
|
|
829
|
+
// worker 本体の副作用を許さない。まず Node のハンドルから即時停止し、その後に
|
|
830
|
+
// taskkill /T で worker が残した子孫だけを回収する。
|
|
831
|
+
try {
|
|
832
|
+
child.kill("SIGKILL");
|
|
833
|
+
}
|
|
834
|
+
catch { /* already exited */ }
|
|
828
835
|
const killer = spawn("taskkill.exe", ["/pid", String(child.pid), "/T", "/F"], {
|
|
829
836
|
stdio: "ignore", windowsHide: true,
|
|
830
837
|
});
|
|
831
|
-
killer.once("error", () => {
|
|
832
|
-
child.kill("SIGKILL");
|
|
833
|
-
}
|
|
834
|
-
catch { /* already exited */ } });
|
|
838
|
+
killer.once("error", () => { });
|
|
835
839
|
killer.unref();
|
|
836
840
|
}
|
|
837
841
|
function processExists(pid) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiterm-mcp",
|
|
3
|
-
"version": "0.21.
|
|
3
|
+
"version": "0.21.4",
|
|
4
4
|
"mcpName": "io.github.kitepon-rgb/aiterm-mcp",
|
|
5
5
|
"description": "Persistent tmux terminal MCP that lets Claude Code drive Codex CLI's interactive TUI, including slash commands and $imagegen. Also runs durable PTY sessions for SSH, containers, REPLs, and coding agents.",
|
|
6
6
|
"keywords": [
|