aiterm-mcp 0.45.1 → 0.45.2
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/CHANGELOG.md +10 -1
- package/README.ja.md +2 -1
- package/README.md +2 -1
- package/dist/remote.js +16 -2
- package/dist/tmux-runtime.js +2 -1
- package/dist/windows-codex-state.js +2 -1
- package/docs/DESIGN.md +8 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.45.2] - 2026-10-01
|
|
11
|
+
|
|
12
|
+
### 修正
|
|
13
|
+
|
|
14
|
+
- WindowsのSteer設定を再実行すると、PowerShellのSet-Aclが監査ACLの権限まで要求し、Network Serviceで失敗していた。所有者とDACLの変更だけを.NETのAPIへ渡し、再実行時も追加権限を要求しない。
|
|
15
|
+
- macOSのAqua外でmodel照会のCLIが応答前にエラー終了すると、標準入力を保持する処理が終了を認識せずtimeoutしていた。CLIの終了で入力保持も終え、元の終了コードとstderrを返す。
|
|
16
|
+
- macOSの長いTMPDIRで`remote`呼び出しが`REMOTE_CONNECT_FAILED`(`ControlPath too long`)となっていた。POSIXのSSH共有ソケットを短い`/tmp`の専用領域へ置き、OpenSSHの作成時suffixまで含めて98 bytesに収める。state rootごとの分離、process間の接続共有と`ControlPersist=600`によるcleanupを保つ。共有領域の所有者・権限・種類が不正なら`REMOTE_CONTROL_DIR_INVALID`で止め、既存領域を変更しない。公開APIとstate schemaは変わらず、旧版への巻き戻しは通常のnpm installとMCP client再起動で行える。
|
|
17
|
+
|
|
10
18
|
## [0.45.1] - 2026-10-01
|
|
11
19
|
|
|
12
20
|
### 修正
|
|
@@ -1944,7 +1952,8 @@ prototype (preserved under `prototype/python/` as the porting source and referen
|
|
|
1944
1952
|
`ubuntu-latest` for Node 18/20/22, publishing to npm on `v*` tags with
|
|
1945
1953
|
provenance.
|
|
1946
1954
|
|
|
1947
|
-
[Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.45.
|
|
1955
|
+
[Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.45.2...HEAD
|
|
1956
|
+
[0.45.2]: https://github.com/kitepon/aiterm-mcp/compare/v0.45.1...v0.45.2
|
|
1948
1957
|
[0.45.1]: https://github.com/kitepon/aiterm-mcp/compare/v0.45.0...v0.45.1
|
|
1949
1958
|
[0.45.0]: https://github.com/kitepon/aiterm-mcp/compare/v0.44.1...v0.45.0
|
|
1950
1959
|
[0.44.1]: https://github.com/kitepon/aiterm-mcp/compare/v0.44.0...v0.44.1
|
package/README.ja.md
CHANGED
|
@@ -203,7 +203,7 @@ runtime-error store は canonical dotagents config の `collection.enabled: true
|
|
|
203
203
|
場合だけ収集し、既定OFF、network送信は行いません。tag起点CIのnpm provenance(OIDC Trusted
|
|
204
204
|
Publishing)で公開し、GitHub Release が Official MCP Registry を再登録します。
|
|
205
205
|
|
|
206
|
-
**状態:** 開発継続中 · 現行公開版 **v0.45.
|
|
206
|
+
**状態:** 開発継続中 · 現行公開版 **v0.45.2** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
|
|
207
207
|
|
|
208
208
|
### 更新と巻き戻し
|
|
209
209
|
|
|
@@ -620,6 +620,7 @@ agent_launch({ "harness": "codex-cli", "remote": { "host": "rabbit" }, "cwd": "/
|
|
|
620
620
|
- 以後の`pty_send`、`pty_read`、`pty_close`、`pty_observe`などにも同じ`remote`を付ける。session名は現地のもので、この端末の同名sessionとは別に扱う。
|
|
621
621
|
- Codex/Claude Code/Cursor親には、この端末の子と同じく回答本文が自動で届く。完了は`ssh <host> aiterm-wait`で観測し、SSHが切れても同じcursorでつなぎ直す。それ以外の親には、sshを使う`wait_process`を返す。
|
|
622
622
|
- 同じ接続先への呼び出しはControlMasterで1本のSSHに相乗りする。`remote`付きの`image`添付と`claude_turn issue`は未対応。
|
|
623
|
+
- POSIXのSSH共有ソケットは長いTMPDIRでも動く短い専用領域に置く。state rootごとに分離し、無通信600秒後の接続終了とソケット削除はOpenSSHが行う。
|
|
623
624
|
|
|
624
625
|
### トークン削減
|
|
625
626
|
|
package/README.md
CHANGED
|
@@ -217,7 +217,7 @@ collection is off by default and performs no network I/O. It ships via
|
|
|
217
217
|
tag-triggered CI with npm provenance (OIDC Trusted Publishing); the GitHub
|
|
218
218
|
Release re-registers the Official MCP Registry entry.
|
|
219
219
|
|
|
220
|
-
**Status:** actively maintained · current public release **v0.45.
|
|
220
|
+
**Status:** actively maintained · current public release **v0.45.2** · runs on Linux · WSL2 · macOS · native Windows (tmux on POSIX, the tmux-CLI-compatible [psmux](https://github.com/psmux/psmux) on native Windows — no WSL required) · MIT · see the [CHANGELOG](CHANGELOG.md).
|
|
221
221
|
|
|
222
222
|
### Update and rollback
|
|
223
223
|
|
|
@@ -666,6 +666,7 @@ agent_launch({ "harness": "codex-cli", "remote": { "host": "rabbit" }, "cwd": "/
|
|
|
666
666
|
- Pass the same `remote` to later `pty_send`, `pty_read`, `pty_close`, `pty_observe`, and so on. Session names belong to the remote machine and never collide with local sessions of the same name.
|
|
667
667
|
- Codex, Claude Code, and Cursor parents receive the answer automatically, as with a local child. Completion is observed with `ssh <host> aiterm-wait`, reconnecting at the same cursor if SSH drops. Other parents get an ssh-based `wait_process`.
|
|
668
668
|
- Calls to the same destination share one SSH connection through ControlMaster. `image` attachments and `claude_turn issue` are not yet supported with `remote`.
|
|
669
|
+
- POSIX SSH control sockets use a short private directory even with a long TMPDIR. Connections stay isolated by state root; OpenSSH closes idle masters and removes their sockets after 600 seconds.
|
|
669
670
|
|
|
670
671
|
### Token reduction
|
|
671
672
|
|
package/dist/remote.js
CHANGED
|
@@ -9,7 +9,8 @@ import { z } from "zod";
|
|
|
9
9
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
10
10
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
11
11
|
import { AitermError, observeAgentDone, readAgentTranscriptResult, windowsStartProcessArgumentList } from "./core.js";
|
|
12
|
-
import { ensureStateRoot } from "./agent-shared.js";
|
|
12
|
+
import { ensureStateRoot, stateRoot } from "./agent-shared.js";
|
|
13
|
+
import { currentUid } from "./state-root.js";
|
|
13
14
|
const pkg = createRequire(import.meta.url)("../package.json");
|
|
14
15
|
// ssh_configの接続名、DNS名、IPv4/IPv6。先頭の`-`はsshのoptionとして解釈されるため受け付けない。
|
|
15
16
|
const hostPattern = /^(?!-)[A-Za-z0-9._%:\[\]-]{1,255}$/;
|
|
@@ -51,6 +52,19 @@ function remoteDir() {
|
|
|
51
52
|
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
52
53
|
return dir;
|
|
53
54
|
}
|
|
55
|
+
function controlPath() {
|
|
56
|
+
// TMPDIRやXDG_RUNTIME_DIRは長くなり得る。%Cの40字とOpenSSHの一時suffix(17字)を含めても
|
|
57
|
+
// macOSの104 byte制限に収まる短い領域へ、state rootごとに共有ソケットだけを置く。
|
|
58
|
+
const namespace = createHash("sha256").update(stateRoot()).digest("hex").slice(0, 20);
|
|
59
|
+
const dir = path.join("/tmp", `aiterm-ssh-${namespace}`);
|
|
60
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
61
|
+
// 共有/tmpに先に作られた他者の領域やsymlinkを使わず、既存領域の権限も変更しない。
|
|
62
|
+
const stat = fs.lstatSync(dir);
|
|
63
|
+
if (!stat.isDirectory() || stat.uid !== currentUid() || (stat.mode & 0o777) !== 0o700) {
|
|
64
|
+
throw new AitermError("REMOTE_CONTROL_DIR_INVALID: SSH共有ソケットの領域が自分所有の0700ディレクトリではありません", 2);
|
|
65
|
+
}
|
|
66
|
+
return path.join(dir, "cm-%C");
|
|
67
|
+
}
|
|
54
68
|
function askpassScript() {
|
|
55
69
|
const file = path.join(remoteDir(), "askpass.sh");
|
|
56
70
|
const body = "#!/bin/sh\nprintf '%s\\n' \"$AITERM_SSH_PASSPHRASE\"\n";
|
|
@@ -78,7 +92,7 @@ export function sshInvocation(target, remoteCommand, options = {}) {
|
|
|
78
92
|
const args = ["-T", "-o", "ConnectTimeout=15", "-o", "ServerAliveInterval=15", "-o", "ServerAliveCountMax=4"];
|
|
79
93
|
// 同じ接続先への後続呼び出しと完了待ちを一本のSSHに相乗りさせる。Windows版OpenSSHはControlMaster非対応。
|
|
80
94
|
if (process.platform !== "win32") {
|
|
81
|
-
args.push("-o", "ControlMaster=auto", "-o", `ControlPath=${
|
|
95
|
+
args.push("-o", "ControlMaster=auto", "-o", `ControlPath=${controlPath()}`, "-o", "ControlPersist=600");
|
|
82
96
|
}
|
|
83
97
|
const passphrase = options.passphrase === false ? null : passphraseFor(target);
|
|
84
98
|
if (passphrase) {
|
package/dist/tmux-runtime.js
CHANGED
|
@@ -225,7 +225,8 @@ function runInMacGui(argv, env, cwd, timeoutMs, timeoutMessage, input, until) {
|
|
|
225
225
|
fs.writeFileSync(inputFile, input, { mode: 0o600 });
|
|
226
226
|
argv = until === undefined
|
|
227
227
|
? ["/bin/sh", "-c", 'f=$1; shift; exec "$@" <"$f"', "aiterm-gui-input", inputFile, ...argv]
|
|
228
|
-
|
|
228
|
+
// CLIが応答前に終了した場合も入力の保持を終え、pipeline全体がCLIの終了コードを返す。
|
|
229
|
+
: ["/bin/sh", "-c", 'f=$1; m=$2; o=$3; shift 3; { cat "$f"; while [ ! -e "$f.done" ] && ! grep -qF -- "$m" "$o" 2>/dev/null; do sleep 0.05; done; } | { "$@"; r=$?; touch "$f.done"; exit "$r"; }',
|
|
229
230
|
"aiterm-gui-input", inputFile, until, path.join(dir, "out"), ...argv];
|
|
230
231
|
}
|
|
231
232
|
fs.writeFileSync(plist, macGuiTmuxPlist(label, dir, argv, env, cwd));
|
|
@@ -32,7 +32,8 @@ $acl.SetOwner($sid)
|
|
|
32
32
|
$acl.SetAccessRuleProtection($true, $false)
|
|
33
33
|
$rule = [System.Security.AccessControl.FileSystemAccessRule]::new($sid, 'FullControl', '${directory ? "ContainerInherit, ObjectInherit" : "None"}', 'None', 'Allow')
|
|
34
34
|
$acl.AddAccessRule($rule)
|
|
35
|
-
Set-Acl
|
|
35
|
+
# Set-Aclは再実行時にSACL更新の権限まで要求する。所有者とDACLの変更だけを.NETへ渡す。
|
|
36
|
+
[System.IO.FileSystemAclExtensions]::SetAccessControl([System.IO.${directory ? "DirectoryInfo" : "FileInfo"}]::new($target), $acl)
|
|
36
37
|
$actual = Get-Acl -LiteralPath $target
|
|
37
38
|
if ($actual.GetOwner([System.Security.Principal.SecurityIdentifier]).Value -ne $sid.Value -or !$actual.AreAccessRulesProtected) { throw 'ACLの適用を確認できません' }
|
|
38
39
|
`);
|
package/docs/DESIGN.md
CHANGED
|
@@ -120,6 +120,8 @@ macOSの専用LaunchAgent、Windowsのユーザー環境変数、所有外の値
|
|
|
120
120
|
`ready`は公式APIによるhook登録・承認の読戻しと、更新前processの終了を確認した状態である。
|
|
121
121
|
Codexの通常起動はAitermのNode、module、socketに依存しない。
|
|
122
122
|
Windowsでは公式Desktopが展開した実行ファイルを照合して配送用の公式APIへ接続する。Desktop更新後はsetupで再検出する。
|
|
123
|
+
WindowsのSteer領域は所有者とDACLだけを.NETのFileSystemAclExtensionsで更新する。監査ACLは変更せず、
|
|
124
|
+
再実行にSeSecurityPrivilegeを要求しない。所有者の照合と更新後の読戻しは維持する。
|
|
123
125
|
LinuxのSteer選択はunsupportedとし、単品のキュー配送は全対応OSで維持する。
|
|
124
126
|
|
|
125
127
|
`parent_delivery`は配送IDと状態を返し、自動配送時の`wait_process`/`wait_command`はnullとなる。
|
|
@@ -211,6 +213,12 @@ WindowsはユーザーのPATHで`aiterm-mcp`と`aiterm-wait`をそのまま呼
|
|
|
211
213
|
`SSH_ASKPASS`でsshへ渡す。受け取っていない時は`BatchMode`で止め、端末での対話入力はしない。
|
|
212
214
|
同じ接続先への呼び出しはControlMasterで1本のSSHに相乗りする。
|
|
213
215
|
|
|
216
|
+
POSIXの共有ソケットは`/tmp/aiterm-ssh-<state rootのSHA-256先頭20桁>/cm-%C`に置く。
|
|
217
|
+
TMPDIRやXDG_RUNTIME_DIRが長くても、OpenSSHが作成時に付ける17字のsuffix込みで98 bytesとなり、
|
|
218
|
+
macOSの104 bytes制限に収まる。state rootごとの分離とprocess間の共有を維持し、askpassと配送記録の場所は変えない。
|
|
219
|
+
共有`/tmp`の既存領域は、自分所有の0700ディレクトリだけを使い、それ以外は`REMOTE_CONTROL_DIR_INVALID`で止める。
|
|
220
|
+
ソケットの寿命と削除は従来どおりOpenSSHの`ControlPersist=600`が所有する。判断はADR 0076。
|
|
221
|
+
|
|
214
222
|
自動配送は`ParentDeliveryManager`を別インスタンスで使い、記録を`remote-`付きの保存場所へ分ける。
|
|
215
223
|
旧版のreaderは`boundary.remote`を知らないため、同じ保存場所に置くと旧processの照会が壊れる。
|
|
216
224
|
子の予約と照会の単位は`deliveryKey`で、接続先のhashを前置きして、この端末の同名sessionと衝突させない。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiterm-mcp",
|
|
3
|
-
"version": "0.45.
|
|
3
|
+
"version": "0.45.2",
|
|
4
4
|
"mcpName": "io.github.kitepon/aiterm-mcp",
|
|
5
5
|
"description": "Persistent terminal MCP with one harness-based launcher for Claude Code, Codex CLI, Grok CLI, and Cursor Agent CLI, plus durable PTYs for SSH, containers, and REPLs.",
|
|
6
6
|
"keywords": [
|