aiterm-mcp 0.53.1 → 0.53.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 CHANGED
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.53.2] - 2026-10-05
11
+
12
+ ### 修正
13
+
14
+ - 引数なしの`aiterm-setup`が、中継(`mcp-lazy`)で包んだAitermの登録を直結へ書き戻していた(ADR 0091)。
15
+ 連携元が全席の登録を中継つきにした後、1席がsetupを流すだけで、Claude Code・Codex・Grok・Cursorの4つの設定が直結へ戻り、
16
+ 本体を眠らせておく節約が次の書き直しまで消えた。Codexは`mcp add`で作り直されるので、待ち時間(`startup_timeout_sec`・
17
+ `tool_timeout_sec`)と`env_vars`も一緒に消えた。
18
+ commandが`mcp-lazy`で始まる名前の実行ファイルで、argsが直結の登録のcommand+args(中継のflagを`--`の前に置いた形も含む)なら、
19
+ 同じ登録と数えて書き直さない。包んでいる本体のpathが違う時は、今までどおり直結の登録へ書き直す。
20
+
10
21
  ## [0.53.1] - 2026-10-05
11
22
 
12
23
  ### 修正
@@ -2204,7 +2215,8 @@ prototype (preserved under `prototype/python/` as the porting source and referen
2204
2215
  `ubuntu-latest` for Node 18/20/22, publishing to npm on `v*` tags with
2205
2216
  provenance.
2206
2217
 
2207
- [Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.53.1...HEAD
2218
+ [Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.53.2...HEAD
2219
+ [0.53.2]: https://github.com/kitepon/aiterm-mcp/compare/v0.53.1...v0.53.2
2208
2220
  [0.53.1]: https://github.com/kitepon/aiterm-mcp/compare/v0.53.0...v0.53.1
2209
2221
  [0.53.0]: https://github.com/kitepon/aiterm-mcp/compare/v0.52.3...v0.53.0
2210
2222
  [0.52.3]: https://github.com/kitepon/aiterm-mcp/compare/v0.52.2...v0.52.3
package/README.ja.md CHANGED
@@ -209,7 +209,7 @@ runtime-error store は canonical dotagents config の `collection.enabled: true
209
209
  場合だけ収集し、既定OFF、network送信は行いません。tag起点CIのnpm provenance(OIDC Trusted
210
210
  Publishing)で公開し、GitHub Release が Official MCP Registry を再登録します。
211
211
 
212
- **状態:** 開発継続中 · 現行公開版 **v0.53.1** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
212
+ **状態:** 開発継続中 · 現行公開版 **v0.53.2** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
213
213
 
214
214
  ### 更新と巻き戻し
215
215
 
@@ -536,6 +536,8 @@ MCPの本体を初めて使う時まで起こさない中継の後ろにAiterm
536
536
  `MCP_LAZY_WAKE_COMMAND='["/absolute/path/to/node","/absolute/path/to/aiterm-mcp/dist/delivery-wake-cli.js","--parent","claude"]'`
537
537
  持ち主の開始時刻はLinuxでは`/proc`で照合する。それ以外のOSでは、pidがあれば生きている持ち主として扱う。
538
538
 
539
+ `aiterm-setup`は、中継(`mcp-lazy`)で包んだ同じ登録を作り直さない。commandが`mcp-lazy`で始まる名前の実行ファイルで、argsが直結の登録のcommand+args(中継のflagを`--`の前に置いた形も含む)なら、Claude Code・Codex・Grok・Cursorの登録をそのまま残す。包んでいる本体のpathが違う時は、直結の登録へ書き直す。
540
+
539
541
  `agent_launch({ harness, cwd, trust_project: true })`はpromptなしでも既知のworkspace・project hooks・MCP初期同意を
540
542
  進め、入力受付とharness生存を確認して`startup.status="ready"`を返す。指定なしのpromptなし起動は`not_checked`。
541
543
  Claude Code初回起動の文字表示テーマ選択では、画面で選択済みの項目を確定して起動を続ける。
package/README.md CHANGED
@@ -223,7 +223,7 @@ collection is off by default and performs no network I/O. It ships via
223
223
  tag-triggered CI with npm provenance (OIDC Trusted Publishing); the GitHub
224
224
  Release re-registers the Official MCP Registry entry.
225
225
 
226
- **Status:** actively maintained · current public release **v0.53.1** · 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).
226
+ **Status:** actively maintained · current public release **v0.53.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).
227
227
 
228
228
  ### Update and rollback
229
229
 
@@ -572,6 +572,8 @@ same environment as the server:
572
572
  `MCP_LAZY_WAKE_COMMAND='["/absolute/path/to/node","/absolute/path/to/aiterm-mcp/dist/delivery-wake-cli.js","--parent","claude"]'`.
573
573
  Owner start times are checked through `/proc` on Linux; elsewhere an existing PID is treated as a live owner.
574
574
 
575
+ `aiterm-setup` does not rewrite a registration that wraps the same server in the `mcp-lazy` relay. When the registered command is an executable whose name starts with `mcp-lazy` and its args are the direct registration's command followed by its args (relay flags before `--` are allowed), the Claude Code, Codex, Grok, and Cursor registrations are left as they are. If the wrapped server path differs, setup writes the direct registration.
576
+
575
577
  `agent_launch({ harness, cwd, trust_project: true })` completes known workspace, project-hook, and project-MCP startup
576
578
  consent even without a prompt, then verifies input readiness and harness liveness before returning `startup.status="ready"`.
577
579
  For Claude Code's first-run text-style menu, it confirms the item already selected on screen before continuing startup.
@@ -0,0 +1,8 @@
1
+ // 中継(mcp-lazy)の見分け。取り決めはmcp-lazyのREADMEにある(実行ファイルの名前が`mcp-lazy`で始まる)。
2
+ // process表の読み手(process-runtime)と、登録の読み手(setup-integrations)が同じ決まりを使う。
3
+ // setup-integrationsは連携元のprocessへ直接読み込まれるので、ここはnode:pathだけに依存する。
4
+ import path from "node:path";
5
+ /** 実行ファイルのpathが中継(mcp-lazy)か。名前(basename)が`mcp-lazy`で始まる物。 */
6
+ export function lazyRelayExecutable(file) {
7
+ return path.posix.basename(file.replace(/\\/g, "/")).toLowerCase().startsWith("mcp-lazy");
8
+ }
@@ -3,6 +3,7 @@ import { spawnSync } from "node:child_process";
3
3
  import { createHash } from "node:crypto";
4
4
  import path from "node:path";
5
5
  import { AitermError } from "./errors.js";
6
+ import { lazyRelayExecutable } from "./lazy-relay.js";
6
7
  import { isWin } from "./tmux-runtime.js";
7
8
  import { resolveWindowsPowerShell7 } from "./windows-powershell.js";
8
9
  export function processIdentity(process) {
@@ -223,7 +224,7 @@ export function processSubtree(rows, rootPid) {
223
224
  // 見分けるのは起動した実行ファイルの名前(argvの先頭のbasenameが`mcp-lazy`で始まる)。取り決めはmcp-lazyのREADMEにある。
224
225
  export function lazyRelayProcess(command) {
225
226
  const first = /^(?:"([^"]+)"|(\S+))/.exec(command);
226
- return path.posix.basename((first?.[1] ?? first?.[2] ?? "").replace(/\\/g, "/")).toLowerCase().startsWith("mcp-lazy");
227
+ return lazyRelayExecutable(first?.[1] ?? first?.[2] ?? "");
227
228
  }
228
229
  export function backgroundProcesses(rows, root) {
229
230
  // 起動時の足場processを除く既存契約。pane開始から60秒以上後に生成された子孫だけを集計する。
@@ -5,10 +5,29 @@ import { randomUUID } from "node:crypto";
5
5
  import { isDeepStrictEqual } from "node:util";
6
6
  import * as steer from "aiterm-steer-delivery";
7
7
  import { resolveAgentBin } from "./agent-resolver.js";
8
+ import { lazyRelayExecutable } from "./lazy-relay.js";
8
9
  import { SetupError, runSetupCommand } from "./setup-platform.js";
9
10
  import { AITERM_PROFILE } from "./steer-profile.js";
10
11
  export { powershellInvocation } from "./setup-platform.js";
11
12
  const record = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
13
+ /**
14
+ * 既にある登録が、今から書く登録と同じ本体を指しているか。
15
+ * 直結(commandとargsが同じ)に加えて、中継(mcp-lazy)で包んだ同じ登録も同じと数える。
16
+ * 中継つきの形は、commandが`mcp-lazy`で始まる名前の実行ファイルで、argsが直結のcommand+args
17
+ * (中継のflagを`--`の前に置いた形も含む)。中継は本体を道具が呼ばれるまで起こさない。
18
+ * 連携元が全席の登録を中継つきで書いた後、1席が引数なしのsetupを流しても、直結へ戻さない。
19
+ */
20
+ export function sameRegistration(command, args, registration) {
21
+ if (typeof command !== "string" || !Array.isArray(args))
22
+ return false;
23
+ if (command === registration.command && isDeepStrictEqual(args, registration.args))
24
+ return true;
25
+ if (!lazyRelayExecutable(command))
26
+ return false;
27
+ const direct = [registration.command, ...registration.args];
28
+ const separator = args.indexOf("--");
29
+ return isDeepStrictEqual(args, direct) || (separator >= 0 && isDeepStrictEqual(args.slice(separator + 1), direct));
30
+ }
12
31
  export function mergeJsonMcp(file, registration) {
13
32
  let current = {};
14
33
  let target = file;
@@ -36,6 +55,9 @@ export function mergeJsonMcp(file, registration) {
36
55
  }
37
56
  const servers = (current.mcpServers ?? {});
38
57
  const previous = record(servers.aiterm) ? servers.aiterm : {};
58
+ // 中継で包んだ同じ登録は、そのまま残す(直結へ書き戻さない)。
59
+ if (previous.command !== registration.command && sameRegistration(previous.command, previous.args, registration))
60
+ return "unchanged";
39
61
  const updated = { ...previous, ...registration };
40
62
  if (isDeepStrictEqual(servers.aiterm, updated))
41
63
  return "unchanged";
@@ -144,8 +166,8 @@ export function configureIntegrations(home, registration, run = runSetupCommand,
144
166
  if (!Array.isArray(servers))
145
167
  throw new SetupError("config_readback_failed", "CodexのMCP一覧形式を確認できません");
146
168
  const existing = servers.find((entry) => entry.name === "aiterm");
147
- // 公式CLIの追加は登録を作り直し、利用者が足した項目(待ち時間など)を落とす。同じ登録なら書き直さない。
148
- if (existing?.transport?.command !== registration.command || !isDeepStrictEqual(existing?.transport?.args, registration.args)) {
169
+ // 公式CLIの追加は登録を作り直し、利用者が足した項目(待ち時間など)を落とす。同じ登録(中継で包んだ物を含む)なら書き直さない。
170
+ if (!sameRegistration(existing?.transport?.command, existing?.transport?.args, registration)) {
149
171
  const envArgs = Object.entries(existing?.transport?.env ?? {}).flatMap(([key, value]) => ["--env", `${key}=${value}`]);
150
172
  run(executable, ["mcp", "add", "aiterm", ...envArgs, "--", registration.command, ...registration.args]);
151
173
  const value = JSON.parse(run(executable, ["mcp", "get", "aiterm", "--json"]));
@@ -160,7 +182,7 @@ export function configureIntegrations(home, registration, run = runSetupCommand,
160
182
  throw new SetupError("config_readback_failed", "GrokのMCP一覧形式を確認できません");
161
183
  const existing = servers.find((entry) => entry.name === "aiterm" && entry.scope === "user");
162
184
  // Codexと同じく、同じ登録なら書き直さない。
163
- if (existing?.command !== registration.command || !isDeepStrictEqual(existing?.args, registration.args)) {
185
+ if (!sameRegistration(existing?.command, existing?.args, registration)) {
164
186
  const envArgs = Object.entries(existing?.env ?? {}).flatMap(([key, value]) => ["--env", `${key}=${value}`]);
165
187
  run(executable, ["mcp", "add", "--scope", "user", "aiterm", ...envArgs, "--", registration.command, ...registration.args]);
166
188
  const value = JSON.parse(run(executable, ["mcp", "list", "--json"]));
package/docs/DESIGN.md CHANGED
@@ -16,7 +16,7 @@ Claude/CursorのJSONは参照先を原子的に更新して変更前backupを
16
16
  各AIの読戻しは登録内容の確認であり、端末の実動作はその前の公開MCP試験で確認する。
17
17
  失敗は理由付きJSONと非ゼロ終了で返す。対応外の自動導入と全AI未検出を成功扱いしない。
18
18
  global packageは、npmの現在のglobal rootか、実行中のNodeの既定のglobal rootにあるものを指す。
19
- CodexとGrokは登録が同じなら公式CLIで作り直さない。`aiterm-setup --hooks-only`はClaude Code・Cursorの親配送hookだけを登録し、
19
+ CodexとGrokは登録が同じなら公式CLIで作り直さない。中継(`mcp-lazy`)で包んだ同じ登録も「同じ」と数え、4つのclientとも直結へ書き戻さない(ADR 0091)。`aiterm-setup --hooks-only`はClaude Code・Cursorの親配送hookだけを登録し、
20
20
  依存準備、端末の実動作確認、MCP登録、Codex Steerに触れない。判断はADR 0077。
21
21
 
22
22
  ## Terminal model
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiterm-mcp",
3
- "version": "0.53.1",
3
+ "version": "0.53.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": [