aiterm-mcp 0.24.0 → 0.24.3

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 CHANGED
@@ -96,6 +96,16 @@ host統合は、kitepon.devの製品開発を支える内部基盤
96
96
 
97
97
  14 ツール: 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 を新しい端末の中に起動し、`agent_configure`が起動中のCodex/Claudeのmodel・effortを再起動なしで変更し、`claude_turn`がdurable caller向けの構造化issue/recoveryを、`claude_approval`が相関済みClaude承認UI中継を、`diagnostics`が安全なfactory readinessを返す。バックエンドは **tmux** なので、MCP サーバや AI クライアントが再起動してもセッションは生き残る。
98
98
 
99
+ **v0.24.3ではlauncherへ渡す環境変数を現在のMCP processから明示選択できる。** `env_vars`へ
100
+ 変数名だけを指定すると、aitermは起動時の現在値を読み、存在する値だけをそのagentへ渡す。永続tmux
101
+ serverがMCP processより先に起動していても、古いserver環境に席identityやworkflow変数を消されない。
102
+ あわせてCodex v0.147が長寿命footerへ加える任意`fast`を認識し、idleな`medium fast ·` sessionでも
103
+ 再描画・再試行・再起動なしに`agent_configure`できる。
104
+
105
+ **v0.24.2では長寿命Codexでも設定変更を維持。** 起動時headerがcapture範囲外へ流れた後は、
106
+ 常駐するmodel/effort footerと入力欄でCodexを識別する。idle sessionをそのまま変更でき、
107
+ caller側の画面再描画、再試行、agent再起動は不要。
108
+
99
109
  **v0.24.0では起動中agentの設定変更を追加。** `agent_configure`はvendor標準操作を使って、
100
110
  起動中のCodex/Claudeのmodelとreasoning effortを変更する。PTY、vendor session、会話contextは維持する。
101
111
 
@@ -176,10 +186,17 @@ $ aiterm-wait --session codex1 --cursor <event_cursor> # exit 0=done / 3=timeo
176
186
 
177
187
  | ツール | 起動するもの | 主な引数 |
178
188
  | --- | --- | --- |
179
- | `claude_agent` | Claude Code CLI(Anthropic) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?`(`low`/`medium`/`high`/`xhigh`/`max`), `cwd?`, `session_name?` |
180
- | `codex_agent` | Codex CLI(OpenAI・端末設定/CLI既定、`model?`で上書き) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?`(`low`/`medium`/`high`/`xhigh`/`max`/`ultra`), `cwd?`, `session_name?`, `write_scope?` |
181
- | `grok_agent` | Grok Build(xAI、既定`grok-4.5`、`model?`で上書き) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?`は非対応(指定時は明示エラー), `cwd?`, `session_name?`, `write_scope?` |
182
- | `composer_agent` | Grok Build(xAI、既定`grok-composer-2.5-fast`、`model?`で上書き) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?`は非対応(指定時は明示エラー), `cwd?`, `session_name?`, `write_scope?` |
189
+ | `claude_agent` | Claude Code CLI(Anthropic) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?`(`low`/`medium`/`high`/`xhigh`/`max`), `env_vars?`, `cwd?`, `session_name?` |
190
+ | `codex_agent` | Codex CLI(OpenAI・端末設定/CLI既定、`model?`で上書き) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?`(`low`/`medium`/`high`/`xhigh`/`max`/`ultra`), `env_vars?`, `cwd?`, `session_name?`, `write_scope?` |
191
+ | `grok_agent` | Grok Build(xAI、既定`grok-4.5`、`model?`で上書き) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?`は非対応(指定時は明示エラー), `env_vars?`, `cwd?`, `session_name?`, `write_scope?` |
192
+ | `composer_agent` | Grok Build(xAI、既定`grok-composer-2.5-fast`、`model?`で上書き) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?`は非対応(指定時は明示エラー), `env_vars?`, `cwd?`, `session_name?`, `write_scope?` |
193
+
194
+ `env_vars`は環境変数の**名前**だけを並べるallowlistであり、name/value mapではない。aitermは
195
+ launcher起動時に現在のMCP processから各名前を読み、存在する値をshell quoteして、その1回のvendor
196
+ 起動コマンドへ入れる。未設定名は省略し、shell変数名として不正な名前はsession作成前に失敗する。
197
+ 全環境の暗黙copy、tmux server再起動、retry、fallbackは行わない。値はMCP tool引数には入らないが、
198
+ PTYの起動コマンドとして送られ、sessionの`.lastcmd`にも保持されるため、起動先vendorと同じOS userへ
199
+ 到達する。秘密転送路ではなく、席identityやworkflow用の非secret変数だけに使う。
183
200
 
184
201
  各ベンダーのCLIが導入・認証済みであること。CLI不在・不正なmodel/effort・実在しない`cwd`はsession作成前に失敗し、残骸を残さない。ClaudeはさらにPTY作成前に同じCLIの`auth status --json`が`loggedIn:true`を返すことを要求する。4 launcherは通常のvendor credential/config storeをその場で使い、fake `HOME`、private `CODEX_HOME`/`GROK_HOME`、project/user config snapshotを作らない。Claudeだけは完了相関用Stop hook settingsを通常の`user,project,local` settingsへ加算する。Grok/Composerは画面入力欄だけでなく通常sessionの`mcp_init_completed` eventも確認してから送信し、共有MCP初期化中の早送信を防ぐ。相関付きClaudeのactive turn中はC-c以外の`pty_key`と素送信を拒否し、承認UIは`claude_approval`で単発Yes/Noだけを相関付きで中継する。
185
202
 
@@ -377,7 +394,7 @@ aiterm は同じ核心の洞察——端末を出会いの場にする——を
377
394
 
378
395
  `aiterm-runtime-errors snapshot` は dotagents factory adapter 向けに、製品所有のローカル snapshot を機械可読 JSON で返す。canonical dotagents factory-reporter config が schema-exact、host profile が実行 OS と一致し、`collection.enabled` が JSON boolean `true` の時だけ収集する。reporting field は schema 検証するが endpoint/credential file へ接続・読取せず network I/O も行わない。観測 API は core owner layer の固定3 code(PTY dependency・persistence・任意 vendor launcher)だけを受け、保存するのも固定 template と aggregate metadata(SHA-256 fingerprint、count、first/last、status、monotonic sequence)だけ。exception、stderr/stdout、stack、prompt、PTY/transcript/event body、path、任意 context は受け付けない。保存済み JSON も top/record exact・固定定義一致・fingerprint 再計算を通し、明示 DTO だけを返す。
379
396
 
380
- consumer は `aiterm-runtime-errors snapshot` を読み、durable ingestion 後に `aiterm-runtime-errors ack --cursor N` を呼ぶ。運用上の明示操作は `resolve|reopen --fingerprint SHA256`。MCP からの収集・diagnostic read は timeout 付き child process に隔離し、FIFOや停止 filesystem が端末本体を止めない。store mutation は期限付き bakery ticket queue で直列化する。各waiterは PID+process start identity+owner token を持つ再利用されない固有ticketを所有するため、死んだownerだけを固有名で除去でき、固定path回収のABAを作らない。POSIX state は `$XDG_STATE_HOME/aiterm-mcp/`(既定 `~/.local/state/aiterm-mcp/`)へ atomic replacement で置き、every read で owner/mode を再検証する。Windows native は `%LOCALAPPDATA%\aiterm-mcp\` で current SID の非継承 FullControl ACE 1件だけへ DACL を再構築し readback する。今回 Windows は path/DACL/timeout の純粋テストだけであり、新しい実機統合成功は主張しない。
397
+ consumer は `aiterm-runtime-errors snapshot` を読み、durable ingestion 後に `aiterm-runtime-errors ack --cursor N` を呼ぶ。運用上の明示操作は `resolve|reopen --fingerprint SHA256`。MCP からの収集・diagnostic read は timeout 付き child process に隔離し、FIFOや停止 filesystem が端末本体を止めない。store mutation は期限付き bakery ticket queue で直列化する。各waiterは PID+process start identity+owner token を持つ再利用されない固有ticketを所有するため、死んだownerだけを固有名で除去でき、固定path回収のABAを作らない。queueの期限は正常な前任者を含む総待ち時間ではなく、同じ先頭ownerが進まない時間を測る。通常pollはprocessの生存確認だけを行い、process start identityはblockerがstallした時に照合する。POSIX state は `$XDG_STATE_HOME/aiterm-mcp/`(既定 `~/.local/state/aiterm-mcp/`)へ atomic replacement で置き、every read で owner/mode を再検証する。Windows native は `%LOCALAPPDATA%\aiterm-mcp\` で current SID の非継承 FullControl ACE 1件だけへ DACL を再構築し readback する。今回 Windows は path/DACL/timeout の純粋テストだけであり、新しい実機統合成功は主張しない。
381
398
 
382
399
  ### 対話エージェント起動ツール
383
400
 
@@ -387,10 +404,10 @@ consumer は `aiterm-runtime-errors snapshot` を読み、durable ingestion 後
387
404
 
388
405
  | ツール | 起動するもの | 主な引数 |
389
406
  | --- | --- | --- |
390
- | `claude_agent` | Claude Code CLI(Anthropic) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?`(`low`/`medium`/`high`/`xhigh`/`max`), `cwd?`, `session_name?` |
391
- | `codex_agent` | Codex CLI(OpenAI・端末設定/CLI既定、`model?`で上書き) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?`(`low`/`medium`/`high`/`xhigh`/`max`/`ultra`), `cwd?`, `session_name?`, `write_scope?` |
392
- | `grok_agent` | Grok Build(xAI、既定`grok-4.5`、`model?`で上書き) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?`は非対応(指定時は明示エラー), `cwd?`, `session_name?`, `write_scope?` |
393
- | `composer_agent` | Grok Build(xAI、既定`grok-composer-2.5-fast`、`model?`で上書き) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?`は非対応(指定時は明示エラー), `cwd?`, `session_name?`, `write_scope?` |
407
+ | `claude_agent` | Claude Code CLI(Anthropic) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?`(`low`/`medium`/`high`/`xhigh`/`max`), `env_vars?`, `cwd?`, `session_name?` |
408
+ | `codex_agent` | Codex CLI(OpenAI・端末設定/CLI既定、`model?`で上書き) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?`(`low`/`medium`/`high`/`xhigh`/`max`/`ultra`), `env_vars?`, `cwd?`, `session_name?`, `write_scope?` |
409
+ | `grok_agent` | Grok Build(xAI、既定`grok-4.5`、`model?`で上書き) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?`は非対応(指定時は明示エラー), `env_vars?`, `cwd?`, `session_name?`, `write_scope?` |
410
+ | `composer_agent` | Grok Build(xAI、既定`grok-composer-2.5-fast`、`model?`で上書き) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?`は非対応(指定時は明示エラー), `env_vars?`, `cwd?`, `session_name?`, `write_scope?` |
394
411
 
395
412
  対応するCLI(`claude` / `codex` / `grok`)の導入・認証が必要。前提違反はsession作成前に明示失敗する。4 launcherすべてが通常project/user環境と同じ非ブロックdispatch契約を使う。Claude/Codex/Grok/Composerのdepth 1 live smokeと、Claude親→Claude孫のdepth 2 nested delegation smokeはgreenであり、fixtureによる検証とは区別して記録する。
396
413
 
package/README.md CHANGED
@@ -96,6 +96,18 @@ toolchain behind kitepon.dev's products.
96
96
 
97
97
  Fourteen 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, `agent_configure` to change a running Codex/Claude session's model and effort without restarting it, `claude_turn` for durable structured issue/recovery, `claude_approval` for correlated 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.
98
98
 
99
+ **v0.24.3 forwards explicitly selected launcher environment variables from the current MCP process.**
100
+ Pass variable names in `env_vars`; aiterm reads their current values at launch and injects only the
101
+ present ones into that agent. This works even when the persistent tmux server predates the MCP
102
+ process, so a stale tmux-server environment cannot erase per-seat identity or workflow variables.
103
+ It also recognizes Codex v0.147's optional `fast` token in long-lived model/effort footers, keeping
104
+ `agent_configure` available on an idle `medium fast ·` session without redraw, retry, or restart.
105
+
106
+ **v0.24.2 keeps in-place configuration working in long-lived Codex sessions.** Once the
107
+ startup header has scrolled out of the captured pane, aiterm recognizes Codex by its persistent
108
+ model/effort footer together with the input prompt. An idle session is therefore configured
109
+ directly; callers do not need to redraw the TUI, retry, or restart the agent.
110
+
99
111
  **v0.24.0 adds in-place agent configuration.** `agent_configure` uses each vendor's
100
112
  native controls to change the model and/or reasoning effort of a running Codex or Claude
101
113
  session while preserving its PTY, vendor session, and conversation context.
@@ -196,10 +208,19 @@ One call per model, so the tool name itself tells you which model you get:
196
208
 
197
209
  | Tool | Launches | Key args |
198
210
  | --- | --- | --- |
199
- | `claude_agent` | Claude Code CLI (Anthropic) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?` (`low`/`medium`/`high`/`xhigh`/`max`), `cwd?`, `session_name?`, `launch_operation_id?` |
200
- | `codex_agent` | Codex CLI (OpenAI; terminal config/CLI default unless overridden) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?` (`low`/`medium`/`high`/`xhigh`/`max`/`ultra`; ultra enables proactive automatic delegation), `cwd?`, `session_name?`, `write_scope?` |
201
- | `grok_agent` | Grok Build, model `grok-4.5` by default (`model?` overrides) (xAI) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error; Grok CLI `--effort` is headless-only), `cwd?`, `session_name?`, `write_scope?` |
202
- | `composer_agent` | Grok Build, model `grok-composer-2.5-fast` by default (`model?` overrides) (xAI) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error), `cwd?`, `session_name?`, `write_scope?` |
211
+ | `claude_agent` | Claude Code CLI (Anthropic) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?` (`low`/`medium`/`high`/`xhigh`/`max`), `env_vars?`, `cwd?`, `session_name?`, `launch_operation_id?` |
212
+ | `codex_agent` | Codex CLI (OpenAI; terminal config/CLI default unless overridden) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?` (`low`/`medium`/`high`/`xhigh`/`max`/`ultra`; ultra enables proactive automatic delegation), `env_vars?`, `cwd?`, `session_name?`, `write_scope?` |
213
+ | `grok_agent` | Grok Build, model `grok-4.5` by default (`model?` overrides) (xAI) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error; Grok CLI `--effort` is headless-only), `env_vars?`, `cwd?`, `session_name?`, `write_scope?` |
214
+ | `composer_agent` | Grok Build, model `grok-composer-2.5-fast` by default (`model?` overrides) (xAI) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error), `env_vars?`, `cwd?`, `session_name?`, `write_scope?` |
215
+
216
+ `env_vars` is an allowlist of environment-variable **names**, not a name/value map. At launch,
217
+ aiterm reads each valid name from its current MCP process, shell-quotes present values, and places
218
+ them on that one vendor launch command. Missing names are omitted; invalid shell variable names
219
+ fail before session creation. There is no implicit whole-environment copy, tmux-server restart,
220
+ retry, or fallback. Values do not enter the MCP tool arguments, but they are delivered through the
221
+ PTY launch command and retained in aiterm's per-session `.lastcmd`; the launched vendor and other
222
+ processes with access to the same OS user may read them. Use this for non-secret seat identity and
223
+ workflow variables, not as a secret transport.
203
224
 
204
225
  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 each documented default location, 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**. All launchers use the normal vendor-owned credential and configuration stores in place. No launcher creates a fake `HOME`, a private `CODEX_HOME`/`GROK_HOME`, or a snapshot of project/user configuration.
205
226
 
@@ -402,7 +423,7 @@ On top of that sits a productized layer a raw tmux bridge doesn't have: **token-
402
423
 
403
424
  `aiterm-runtime-errors snapshot` exposes a machine-readable, product-owned local snapshot for the dotagents factory adapter. Collection is fail-closed unless the canonical dotagents factory-reporter config is schema-exact, its host profile matches the executing OS, and it contains the JSON boolean `collection.enabled: true`; reporting fields are schema-validated but endpoints and credential files are never contacted, and the store performs no network I/O. The only accepted observations are three fixed codes owned by the core boundary (PTY dependency, persistence, and optional vendor launcher). Stored data is limited to fixed templates and aggregate metadata (SHA-256 fingerprint, count, first/last seen, status, and monotonic sequence); exceptions, stderr/stdout, stacks, prompts, terminal/transcript/event bodies, paths, and arbitrary context cannot enter the API. Persisted JSON is revalidated with exact top/record fields and a recomputed fingerprint before explicit DTO projection.
404
425
 
405
- Consumer flow is `aiterm-runtime-errors snapshot`, then `aiterm-runtime-errors ack --cursor N` after durable ingestion. Operators can use `resolve|reopen --fingerprint SHA256`. MCP collection and diagnostic reads run in timeout-bounded child processes, so a FIFO or stalled filesystem cannot block terminal work; child failure emits only the fixed store diagnostic. Store mutation uses a bounded bakery ticket queue: every waiter owns a never-reused ticket containing PID, process-start identity, and an owner token, so dead owners are removed by unique filename without fixed-path reclaim ABA. Worker deadlines use forced termination so a SIGTERM-ignoring child cannot mutate state after timeout. POSIX state is atomically replaced under `$XDG_STATE_HOME/aiterm-mcp/` (default `~/.local/state/aiterm-mcp/`) with owner/mode rechecked on every read. Windows native uses `%LOCALAPPDATA%\aiterm-mcp\`; each DACL is rebuilt and read back as one non-inherited FullControl ACE for the current SID. Windows path/DACL/timeout behavior is covered by pure tests in this change; no new Windows integration success is claimed.
426
+ Consumer flow is `aiterm-runtime-errors snapshot`, then `aiterm-runtime-errors ack --cursor N` after durable ingestion. Operators can use `resolve|reopen --fingerprint SHA256`. MCP collection and diagnostic reads run in timeout-bounded child processes, so a FIFO or stalled filesystem cannot block terminal work; child failure emits only the fixed store diagnostic. Store mutation uses a bounded bakery ticket queue: every waiter owns a never-reused ticket containing PID, process-start identity, and an owner token, so dead owners are removed by unique filename without fixed-path reclaim ABA. The queue deadline measures lack of progress by the same head owner, not total wait behind healthy predecessors; normal polling uses the native process-liveness check and validates process-start identity only when a blocker stalls. Worker deadlines use forced termination so a SIGTERM-ignoring child cannot mutate state after timeout. POSIX state is atomically replaced under `$XDG_STATE_HOME/aiterm-mcp/` (default `~/.local/state/aiterm-mcp/`) with owner/mode rechecked on every read. Windows native uses `%LOCALAPPDATA%\aiterm-mcp\`; each DACL is rebuilt and read back as one non-inherited FullControl ACE for the current SID. Windows path/DACL/timeout behavior is covered by pure tests in this change; no new Windows integration success is claimed.
406
427
 
407
428
  ### Interactive agent launchers
408
429
 
@@ -412,10 +433,10 @@ Each launcher starts a specific vendor's interactive coding-agent TUI inside a f
412
433
 
413
434
  | Tool | Launches | Key args |
414
435
  | --- | --- | --- |
415
- | `claude_agent` | Claude Code CLI (Anthropic) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?` (`low`/`medium`/`high`/`xhigh`/`max`), `cwd?`, `session_name?`, `launch_operation_id?` |
416
- | `codex_agent` | Codex CLI (OpenAI; terminal config/CLI default unless overridden) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?` (`low`/`medium`/`high`/`xhigh`/`max`/`ultra`; ultra enables proactive automatic delegation), `cwd?`, `session_name?`, `write_scope?` |
417
- | `grok_agent` | Grok Build, model `grok-4.5` by default (`model?` overrides) (xAI) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error; Grok CLI `--effort` is headless-only), `cwd?`, `session_name?`, `write_scope?` |
418
- | `composer_agent` | Grok Build, model `grok-composer-2.5-fast` by default (`model?` overrides) (xAI) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error), `cwd?`, `session_name?`, `write_scope?` |
436
+ | `claude_agent` | Claude Code CLI (Anthropic) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?` (`low`/`medium`/`high`/`xhigh`/`max`), `env_vars?`, `cwd?`, `session_name?`, `launch_operation_id?` |
437
+ | `codex_agent` | Codex CLI (OpenAI; terminal config/CLI default unless overridden) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?` (`low`/`medium`/`high`/`xhigh`/`max`/`ultra`; ultra enables proactive automatic delegation), `env_vars?`, `cwd?`, `session_name?`, `write_scope?` |
438
+ | `grok_agent` | Grok Build, model `grok-4.5` by default (`model?` overrides) (xAI) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error; Grok CLI `--effort` is headless-only), `env_vars?`, `cwd?`, `session_name?`, `write_scope?` |
439
+ | `composer_agent` | Grok Build, model `grok-composer-2.5-fast` by default (`model?` overrides) (xAI) | `prompt?`, `throughline_source_session?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error), `env_vars?`, `cwd?`, `session_name?`, `write_scope?` |
419
440
 
420
441
  The vendor CLI must be installed and authenticated (`claude` for `claude_agent`; `codex` for `codex_agent`; `grok` for both Grok tools). Binary resolution uses `CLAUDE_BIN` / `CODEX_BIN` / `GROK_BIN`, then each documented default location, then `PATH`. Missing binaries, invalid model/effort values, and nonexistent `cwd` fail before a session is created. Claude additionally requires a structured healthy authentication status before any PTY exists, and correlated Claude sessions reject `/login` and `/logout`; repair authentication once in a normal terminal. All four launchers share the normal project/user environment and the same non-blocking dispatch contract. Claude, Codex, Grok, and Composer depth-1 live smokes and a Claude depth-2 nested-delegation smoke are green; fixture coverage remains a separate claim. Native Windows can launch agents but correlated completion is not supported yet.
421
442
 
@@ -511,6 +532,11 @@ symlink, filter, or replace vendor configuration, authentication, MCP, plugin, s
511
532
  trust, memory, or history stores. Cleanup removes only aiterm-owned launch metadata and completion
512
533
  correlation files.
513
534
 
535
+ The ordinary environment still comes from the shell/tmux session. When a caller needs a value that
536
+ belongs to the current MCP process rather than the older persistent tmux server, every launcher
537
+ accepts `env_vars: ["NAME", ...]`. Only those names are refreshed at launch; this is a narrow
538
+ per-launch overlay, not a replacement environment or configuration snapshot.
539
+
514
540
  ## License
515
541
 
516
542
  MIT
package/dist/core.js CHANGED
@@ -3323,7 +3323,11 @@ function isAgentTuiReady(kind, screen) {
3323
3323
  return screen.includes("Claude Code") && /(^|\n)\s*❯/.test(screen);
3324
3324
  }
3325
3325
  if (kind === "codex") {
3326
- return screen.includes("OpenAI Codex") && /(^|\n)\s*[›>]/.test(screen);
3326
+ // 起動直後は製品header、長寿命sessionでは常駐footerがCodex TUIの識別子になる。
3327
+ // capture-paneは直近45行だけなので、会話が進むとheaderは正常に画面外へ流れる。
3328
+ const codexFrontend = screen.includes("OpenAI Codex")
3329
+ || /(^|\n)\s*\S+\s+(?:low|medium|high|xhigh|max|ultra)(?:\s+fast)?\s+·\s+\S.*$/m.test(screen);
3330
+ return codexFrontend && /(^|\n)\s*[›>]/.test(screen);
3327
3331
  }
3328
3332
  // Grok Build 0.2.117 は起動完了後に製品名を消し、model footerだけを残す。
3329
3333
  // Composerも同じfrontendでmodel名だけが異なるため、両方をvendor UIの根拠にする。
@@ -4016,10 +4020,15 @@ function buildAgentCmd(kind, bin, model, effort, prompt, meta = null) {
4016
4020
  parts.push(shq(prompt)); // 初手プロンプト(任意)
4017
4021
  return parts.join(" ");
4018
4022
  }
4019
- function agentEnvPrefix(meta, sid) {
4023
+ function agentEnvPrefix(meta, sid, envVars = []) {
4024
+ const inherited = envVars.flatMap((name) => {
4025
+ const value = process.env[name];
4026
+ return value === undefined ? [] : [`${name}=${shq(value)}`];
4027
+ });
4020
4028
  if (!meta)
4021
- return "";
4029
+ return inherited.length ? inherited.join(" ") + " " : "";
4022
4030
  const common = [
4031
+ ...inherited,
4023
4032
  `AITERM_AGENT_KIND=${shq(meta.kind)}`,
4024
4033
  `AITERM_SESSION_ID=${shq(sid)}`,
4025
4034
  `AITERM_AGENT_SESSION_ID=${shq(sid)}`,
@@ -4127,6 +4136,12 @@ export function openAgent(kind, opts = {}) {
4127
4136
  }
4128
4137
  const effort = opts.reasoning_effort ?? null;
4129
4138
  const writeScope = opts.write_scope;
4139
+ const envVars = opts.env_vars ?? [];
4140
+ for (const name of envVars) {
4141
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
4142
+ throw new AitermError(`env_vars に無効な環境変数名があります: ${JSON.stringify(name)}`, 2);
4143
+ }
4144
+ }
4130
4145
  if (effort && kind === "claude" && !CLAUDE_EFFORTS.has(effort)) {
4131
4146
  throw new AitermError("Claude Code の reasoning_effort は low/medium/high/xhigh/max のいずれかです", 2);
4132
4147
  }
@@ -4245,7 +4260,7 @@ export function openAgent(kind, opts = {}) {
4245
4260
  agentMetadataNegativeCache.delete(sid);
4246
4261
  launchNote = buildAgentLaunchNote(kind, model, effort, meta);
4247
4262
  const cmd = buildAgentCmd(kind, binForCmd, model, effort, opts.prompt ?? null, meta);
4248
- const envPrefix = agentEnvPrefix(meta, sid);
4263
+ const envPrefix = agentEnvPrefix(meta, sid, envVars);
4249
4264
  const full = cwdForCmd ? `cd ${shq(cwdForCmd)} && ${envPrefix}${cmd}` : `${envPrefix}${cmd}`;
4250
4265
  // force:true で送る。起動骨格は `bin '...'` の固定形で、prompt/cwd/effort は shq でクオート済みの
4251
4266
  // 引数=シェルは決して破壊コマンドとして実行しない。破壊ゲート(生シェルコマンド想定)を prompt に
@@ -4316,6 +4331,7 @@ export async function openAgentWithInitialPrompt(kind, opts = {}) {
4316
4331
  agent_done: true,
4317
4332
  launch_operation_id: opts.launch_operation_id ?? null,
4318
4333
  write_scope: opts.write_scope,
4334
+ env_vars: opts.env_vars,
4319
4335
  });
4320
4336
  // argv prompt(grok/composer)は composer を経由しないため submit 座礁観測の対象外。
4321
4337
  return [sid, hint, prompt ? 0 : null, null];
@@ -4329,6 +4345,7 @@ export async function openAgentWithInitialPrompt(kind, opts = {}) {
4329
4345
  agent_done: true,
4330
4346
  launch_operation_id: opts.launch_operation_id ?? null,
4331
4347
  write_scope: opts.write_scope,
4348
+ env_vars: opts.env_vars,
4332
4349
  });
4333
4350
  try {
4334
4351
  const initial = await sendInitialAgentPrompt(sid, prompt, {
package/dist/index.js CHANGED
@@ -483,6 +483,7 @@ function registerAgentTool(toolName, kind, desc) {
483
483
  // grok/composer の effort は対話 TUI で無効(headless 専用)=core 側が起動前に明示エラーで拒否。
484
484
  // codex は CLI 側の値集合が版で変わるため縛らない(core 側も同方針)。
485
485
  reasoning_effort: z.string().nullish().describe(agentEffortDesc(kind)),
486
+ env_vars: z.array(z.string()).optional().describe("起動したagentへ現在のMCP processから継承する環境変数名。値はtool引数へ渡さない"),
486
487
  cwd: z.string().nullish().describe("作業ディレクトリ(対象リポのルート等・任意)"),
487
488
  session_name: z.string().nullish().describe("セッション名(省略で自動採番)"),
488
489
  ...writeScopeInputSchema,
@@ -502,13 +503,14 @@ function registerAgentTool(toolName, kind, desc) {
502
503
  submit_residue: z.boolean().nullable(),
503
504
  ...writeScopeOutputSchema,
504
505
  },
505
- }, async ({ prompt, throughline_source_session, model, reasoning_effort, cwd, session_name, launch_operation_id, write_scope }) => {
506
+ }, async ({ prompt, throughline_source_session, model, reasoning_effort, env_vars, cwd, session_name, launch_operation_id, write_scope }) => {
506
507
  try {
507
508
  const [sid, hint, eventCursor, submitResidue] = await core.openAgentWithInitialPrompt(kind, {
508
509
  prompt: prompt ?? undefined,
509
510
  throughline_source_session,
510
511
  model: model ?? undefined,
511
512
  reasoning_effort: reasoning_effort ?? undefined,
513
+ env_vars,
512
514
  cwd: cwd ?? undefined,
513
515
  session_name: session_name ?? undefined,
514
516
  launch_operation_id: launch_operation_id ?? undefined,
@@ -532,10 +532,15 @@ export class RuntimeErrorStore {
532
532
  ticket = path.join(queue, ticketName);
533
533
  this.publishOwnerFile(ticket, owner);
534
534
  fs.unlinkSync(choosing);
535
- const deadline = Date.now() + 1_500;
535
+ // 期限はqueue全体の総待ち時間ではなく、同じ先頭ownerが進まない時間を測る。
536
+ // 正常な前任者がticketを順に解放するたびに予算を更新し、長いqueueをbusyと誤認しない。
537
+ let deadline = Date.now() + 1_500;
538
+ let blockingTicket = null;
539
+ let choosingBlockers = new Set();
536
540
  for (;;) {
537
541
  const names = fs.readdirSync(queue).sort();
538
542
  let hasLiveChoosing = false;
543
+ const liveChoosing = new Set();
539
544
  for (const name of names.filter((candidate) => choosingPattern.test(candidate))) {
540
545
  const currentPath = path.join(queue, name);
541
546
  let current;
@@ -549,10 +554,17 @@ export class RuntimeErrorStore {
549
554
  }
550
555
  if (name !== `choosing-${current.token}.json`)
551
556
  throw new Error("runtime error choosing entry が不正です");
552
- const identity = processStartIdentity(current.pid, this.platform, identityTimeoutMs);
553
- const live = identity === current.start_id || (!identity && processExists(current.pid));
554
- if (live)
557
+ // 通常待機ではkill(0)だけを使う。macOSのprocess start identityは外部psを起動するため、
558
+ // 全waiterが全pollで呼ぶとqueue自身が進めなくなる。PID再利用の照合はstall時だけ行う。
559
+ let live = processExists(current.pid);
560
+ if (live && Date.now() >= deadline) {
561
+ const identity = processStartIdentity(current.pid, this.platform, identityTimeoutMs);
562
+ live = identity === current.start_id || (!identity && processExists(current.pid));
563
+ }
564
+ if (live) {
555
565
  hasLiveChoosing = true;
566
+ liveChoosing.add(name);
567
+ }
556
568
  else {
557
569
  try {
558
570
  fs.unlinkSync(currentPath);
@@ -564,11 +576,17 @@ export class RuntimeErrorStore {
564
576
  }
565
577
  }
566
578
  if (hasLiveChoosing) {
579
+ if (choosingBlockers.size === 0
580
+ || [...choosingBlockers].some((name) => !liveChoosing.has(name))) {
581
+ deadline = Date.now() + 1_500;
582
+ }
583
+ choosingBlockers = liveChoosing;
567
584
  if (Date.now() >= deadline)
568
585
  throw new Error("runtime error store is busy");
569
586
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10);
570
587
  continue;
571
588
  }
589
+ choosingBlockers = new Set();
572
590
  let firstLive = null;
573
591
  const ticketNames = fs.readdirSync(queue).sort();
574
592
  for (const name of ticketNames.filter((candidate) => ticketPattern.test(candidate))) {
@@ -584,8 +602,11 @@ export class RuntimeErrorStore {
584
602
  }
585
603
  if (!name.endsWith(`-${current.token}.ticket`))
586
604
  throw new Error("runtime error lock ticket が不正です");
587
- const identity = processStartIdentity(current.pid, this.platform, identityTimeoutMs);
588
- const live = identity === current.start_id || (!identity && processExists(current.pid));
605
+ let live = processExists(current.pid);
606
+ if (live && name === blockingTicket && Date.now() >= deadline) {
607
+ const identity = processStartIdentity(current.pid, this.platform, identityTimeoutMs);
608
+ live = identity === current.start_id || (!identity && processExists(current.pid));
609
+ }
589
610
  if (!live) {
590
611
  try {
591
612
  fs.unlinkSync(currentPath);
@@ -601,6 +622,10 @@ export class RuntimeErrorStore {
601
622
  }
602
623
  if (firstLive === ticketName)
603
624
  break;
625
+ if (firstLive !== blockingTicket) {
626
+ blockingTicket = firstLive;
627
+ deadline = Date.now() + 1_500;
628
+ }
604
629
  if (Date.now() >= deadline)
605
630
  throw new Error("runtime error store is busy");
606
631
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiterm-mcp",
3
- "version": "0.24.0",
3
+ "version": "0.24.3",
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": [