aiterm-mcp 0.54.0 → 0.55.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/CHANGELOG.md CHANGED
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.55.0] - 2026-10-06
11
+
12
+ ### 変更
13
+
14
+ - `agent_launch`は、起動時promptの開始を確認できなかった返り(`initial_prompt.status`が`submitted_unconfirmed`)に
15
+ `isError`を付けない(ADR 0093)。sessionは立ち、promptは入力欄を離れ、親への配送も登録済みなので、状態は
16
+ `initial_prompt`と本文で伝える。本文には「turnの開始は未確認(reason=…)。再送もagentの起動し直しもしない。
17
+ 確かめる時は pty_observe」の案内が付く。誤りの印でこの状態を見分けていた呼び出し側は、`initial_prompt.status`を見る。
18
+ 送信の途中で失敗した起動は、今までどおり誤りで返る。`remote`付きの起動は、現地が旧版で誤りを返しても同じ形で返す。
19
+
20
+ ### 修正
21
+
22
+ - Claude Code親が起こした子の回答が、親へ届かない事があった。開始未確認の返りを誤りで返していて、Claude Codeは
23
+ 誤りの返りでは受け口のhook(`PostToolUse`)を走らせない。配送は`sending`のまま残り、返りの本文は「回答は自動配送する。
24
+ 回収は不要」と案内していた。上の変更で、受け口が出来て回答が届く。
25
+ - 動いているClaude Codeを、入力待ち(`idle`/`composer_ready`)と読む事があった。Claude Code(2.1.289〜2.1.291で確認)は、
26
+ 複数行のprompt(貼り付けの形で入る)を送った後の約8秒、足元の行を`paste again to expand`へ置き換える。動作中の印に
27
+ していた`esc to interrupt`がその間は画面に無い。複数行のpromptを付けたClaudeの子の起動は毎回、開始未確認になり、
28
+ `pty_observe`もその間`idle`を返していた。動いている間は入力欄の上に進行行(`✶ Slithering… (3s · ↓ 225 tokens)`)が
29
+ 出続けるので、それも動作中の印にする。Linux・Mac・Windowsの実画面で確かめた。Codex・Grok・Cursorの読み方は変えていない。
30
+
10
31
  ## [0.54.0] - 2026-10-06
11
32
 
12
33
  ### 変更
@@ -2235,7 +2256,8 @@ prototype (preserved under `prototype/python/` as the porting source and referen
2235
2256
  `ubuntu-latest` for Node 18/20/22, publishing to npm on `v*` tags with
2236
2257
  provenance.
2237
2258
 
2238
- [Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.54.0...HEAD
2259
+ [Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.55.0...HEAD
2260
+ [0.55.0]: https://github.com/kitepon/aiterm-mcp/compare/v0.54.0...v0.55.0
2239
2261
  [0.54.0]: https://github.com/kitepon/aiterm-mcp/compare/v0.53.2...v0.54.0
2240
2262
  [0.53.2]: https://github.com/kitepon/aiterm-mcp/compare/v0.53.1...v0.53.2
2241
2263
  [0.53.1]: https://github.com/kitepon/aiterm-mcp/compare/v0.53.0...v0.53.1
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.54.0** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
212
+ **状態:** 開発継続中 · 現行公開版 **v0.55.0** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
213
213
 
214
214
  ### 更新と巻き戻し
215
215
 
@@ -546,7 +546,10 @@ Claude Code初回起動の文字表示テーマ選択では、画面で選択済
546
546
  それでも描かれなければ、今までと同じく未送信(`initial_prompt=not_sent`)で返り、sessionは残る。
547
547
  WindowsのCodexもhook確認を認識し、npm shim経由の起動を一つのharnessとして識別する。
548
548
  初手の`initial_prompt.status`は`not_requested`/`not_sent`/`submitted_unconfirmed`/`started`を区別する。
549
- 未送信・未確認の失敗もsession付きstructuredContentを保持する。未確認のpromptを再送せず、返ったcursorで観測する。
549
+ 未送信の失敗もsession付きstructuredContentを保持する。
550
+ `submitted_unconfirmed`(promptは入力欄を離れたが、確認時間の内に開始を見られなかった)は誤りにしない。`isError`は付かず、
551
+ 本文に未確認の案内が付く。sessionは立っていて、親への配送も登録済み。未確認のpromptを再送せず、agentも起動し直さず、
552
+ 返ったcursorか`pty_observe`で観測する。
550
553
 
551
554
  Codexの実行中承認は`agent_approval({ action: "inspect", session_id })`の`prompt`と`choices`を確認し、
552
555
  `respond`へ`observed_prompt_digest`と`approval_choice`(`approve_once`/`deny`)を渡す。
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.54.0** · 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.55.0** · 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
 
@@ -583,7 +583,10 @@ waits up to 50 seconds from startup. If nothing is drawn by then, it still retur
583
583
  A prompt-free launch without this option retains `startup.status="not_checked"`. `initial_prompt.status` distinguishes
584
584
  `not_requested`, `not_sent`, `submitted_unconfirmed`, and `started`. Failure responses retain structured session information.
585
585
  WindowsのCodexもhook確認を認識し、npm shim経由の起動を一つのharnessとして識別する。
586
- Do not resend an unconfirmed prompt; observe or wait using its returned cursor.
586
+ `submitted_unconfirmed` (the prompt left the composer, but the turn start was not observed within the confirmation window) is
587
+ not a tool error: `isError` is not set, the text carries an unconfirmed-start note, the session is alive and the parent
588
+ delivery stays registered. Do not resend an unconfirmed prompt or relaunch the agent; observe with `pty_observe` or wait
589
+ using its returned cursor.
587
590
 
588
591
  For a live Codex approval, inspect with `agent_approval({ action: "inspect", session_id })`, review `prompt` and `choices`,
589
592
  then respond with `observed_prompt_digest` and `approval_choice` (`approve_once` or `deny`). Unknown or changed dialogs return
package/dist/core.js CHANGED
@@ -3323,6 +3323,20 @@ async function waitCursorPromptVisibleImpl(text, sample, sleepFn, opts = {}) {
3323
3323
  async function waitCursorPromptVisible(name, text) {
3324
3324
  return waitCursorPromptVisibleImpl(text, () => captureScreen(name, AGENT_TUI_READY_LINES), sleep);
3325
3325
  }
3326
+ // 起動時promptは入力欄を離れたが、確認時間の内にturnの開始を見られなかった時の案内。この返りは誤り(isError)にしない。
3327
+ // 誤りで返すと、Claude Code親は受け口のhook(PostToolUse)を走らせず、登録済みの配送が届かない(ADR 0093)。
3328
+ // 親が同じ依頼で起動し直すと子が2つ動くので、再送も再起動もしない事を先に書く。
3329
+ export const INITIAL_PROMPT_UNCONFIRMED_MARK = "turnの開始は未確認";
3330
+ export function initialPromptUnconfirmedNote(name, reason) {
3331
+ return (`注意: ${INITIAL_PROMPT_UNCONFIRMED_MARK}(reason=${reason})。promptは入力欄を離れているので、再送もagentの起動し直しもしない。` +
3332
+ `開始していれば結果は上の方法で届く。確かめる時は pty_observe(${name}) で状態を見る。`);
3333
+ }
3334
+ // 起動そのものは普通に返り、初手の開始だけが未確認の返りか。送信の途中で失敗した起動も同じstatusを持つ
3335
+ // (その時のstartup.reasonは失敗の理由になる)ので、起動が普通に返った形(ready/composer_ready)と組で見る。
3336
+ export function launchStartUnconfirmed(structured) {
3337
+ return structured.initial_prompt?.status === "submitted_unconfirmed"
3338
+ && structured.startup?.status === "ready" && structured.startup?.reason === "composer_ready";
3339
+ }
3326
3340
  export function agentSubmitResidueWarning(name, residue) {
3327
3341
  if (residue !== true)
3328
3342
  return "";
@@ -3622,6 +3636,7 @@ async function sendInitialAgentPromptInLock(name, text, o) {
3622
3636
  return {
3623
3637
  text: `initial_prompt=pending vendor=${meta.kind} event_cursor=${startOffset} harness=${agentHarness(meta.kind)}\n` +
3624
3638
  `起動時 prompt を送信した。${agentDispatchGuide(name, startOffset)}` +
3639
+ (delivery.status === "submitted_unconfirmed" ? `\n${initialPromptUnconfirmedNote(name, delivery.reason)}` : "") +
3625
3640
  agentSubmitResidueWarning(name, residue.residue),
3626
3641
  event_cursor: startOffset,
3627
3642
  submit_residue: residue.residue,
@@ -281,13 +281,42 @@ export function claudeTuiReady(screen) {
281
281
  // その下に描画された現在のcomposerを優先する。
282
282
  return !/^❯\s*(?:\d+\.|\[|Enable selected\b|No,\s*exit\b|Yes,\s*I trust this folder\b)/iu.test(lastMarker);
283
283
  }
284
+ // Claude Codeは動いている間、入力欄の上へ進行行を出し続ける(2.1.291の実画面 2026-10-06)。
285
+ // ✻ Swirling… (running UserPromptSubmit hook · 0s)
286
+ // * Swirling…
287
+ // ✶ Slithering… (3s · ↓ 225 tokens · thought for 2s)
288
+ // ✢ コマンド実行中… (12s · ↓ 1.0k tokens · thinking) ← 作業の一覧を使う時は、進行中の項目の文になる
289
+ // ⎿ ◼ 下の命令を1回だけ動かす ← 一覧は進行行の下へ字下げで並ぶ
290
+ // 終わると同じ位置が「✻ Cogitated for 11s · done 4:45 AM」へ変わる(「…」が無く、「·」で区切る)。
291
+ const CLAUDE_PROGRESS_LINE_RE = /^[·✢✳✶✻✽*∗] [^·…\s][^·…]*…(?: \(.*\))?\s*$/u;
292
+ // 入力欄の上の罫線から上へ、空行と字下げの行を飛ばし、行頭から始まる最初の行が進行行かを見る。
293
+ // 会話欄の行(「●」の回答、「❯」の依頼文、字下げの道具の出力)は進行行の形にならない。
294
+ function claudeTurnProgress(screen) {
295
+ const lines = screen.split(/\r?\n/u);
296
+ let marker = lines.length - 1;
297
+ while (marker >= 0 && !CLAUDE_COMPOSER_MARKER_RE.test(lines[marker]))
298
+ marker--;
299
+ if (marker <= 0 || !/^\s*─{8,}\s*$/u.test(lines[marker - 1]))
300
+ return false;
301
+ for (let i = marker - 2; i >= 0; i--) {
302
+ if (lines[i].trim() === "" || /^\s/u.test(lines[i]))
303
+ continue;
304
+ return CLAUDE_PROGRESS_LINE_RE.test(lines[i]);
305
+ }
306
+ return false;
307
+ }
308
+ // 足元の「esc to interrupt」は、貼り付けの知らせ(paste again to expand)へ置き換わる間は出ない。複数行のpromptを
309
+ // 送った後の約8秒がそうで、その間は動いているのに入力待ちと読んでいた(2.1.291、2026-10-06)。進行行も動作中の印にする。
310
+ export function claudeTuiBusy(screen) {
311
+ return /esc to interrupt/i.test(screen.split("\n").slice(-32).join("\n")) || claudeTurnProgress(screen);
312
+ }
284
313
  export function claudePaneObservation(screen) {
285
314
  const tail = screen.split("\n").slice(-32).join("\n");
286
315
  if (claudeLoginMethodMenu(screen))
287
316
  return { state: "blocked", reason: "vendor_onboarding_required" };
288
317
  if (/Do you want to proceed\?/.test(tail) && /(?:^|\n)\s*[❯>]?\s*\d+\.\s+(?:Yes|No)\s*$/m.test(tail))
289
318
  return { state: "blocked", reason: "tool_approval" };
290
- if (/esc to interrupt/i.test(tail))
319
+ if (claudeTuiBusy(screen))
291
320
  return { state: "busy", reason: "turn_running" };
292
321
  if (claudeTuiReady(screen))
293
322
  return { state: "idle", reason: "composer_ready" };
package/dist/index.js CHANGED
@@ -913,12 +913,17 @@ async function launchRemoteAgent(target, harness, args, extra) {
913
913
  return fail(new Error(`別端末でagentは起動しましたが、回答配送を登録できませんでした(session_id=${structured.session_id}): ${e instanceof Error ? e.message : String(e)}`));
914
914
  }
915
915
  const waited = await remoteCompletionWait(delivery, target, structured.session_id, structured.event_cursor);
916
+ // 現地が開始未確認を誤りで返す版(0.54.0以前)でも、ここでは誤りにしない(ADR 0093)。案内が無ければ足す。
917
+ const unconfirmed = core.launchStartUnconfirmed(structured);
918
+ const noted = result.content.some(item => item.type === "text" && item.text.includes(core.INITIAL_PROMPT_UNCONFIRMED_MARK));
916
919
  return {
917
920
  content: [...result.content, remoteNote(target, result),
921
+ ...(unconfirmed && !noted
922
+ ? [{ type: "text", text: core.initialPromptUnconfirmedNote(structured.session_id, structured.initial_prompt.reason) }] : []),
918
923
  { type: "text", text: `以後このsessionを操作する時は、同じremoteを付けて呼ぶ。${deliveryIdLine(delivery)}` }],
919
924
  structuredContent: { ...structured, ...waited, ...(delivery?.result() ? { parent_delivery: delivery.result() } : {}),
920
925
  remote_host: remoteLabel(target), remote_version: result.remote_version },
921
- ...(result.isError ? { isError: true } : {}),
926
+ ...(result.isError && !unconfirmed ? { isError: true } : {}),
922
927
  };
923
928
  }
924
929
  async function launchAgent(kind, args, extra) {
@@ -967,10 +972,11 @@ async function launchAgent(kind, args, extra) {
967
972
  }
968
973
  : {}),
969
974
  };
975
+ // 開始未確認(submitted_unconfirmed)は誤りにしない。sessionは立ち、promptは入力欄を離れ、配送も登録済み。
976
+ // 誤りで返すとClaude Code親は受け口のhookを走らせず、子の回答が届かない(ADR 0093)。状態はinitial_promptと本文で伝える。
970
977
  return {
971
978
  content: [{ type: "text", text: `session_id: ${sid}\n${hint}${deliveryIdLine(delivery)}` }],
972
979
  structuredContent: structured,
973
- ...(initialDelivery.status === "submitted_unconfirmed" ? { isError: true } : {}),
974
980
  };
975
981
  }
976
982
  catch (e) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiterm-mcp",
3
- "version": "0.54.0",
3
+ "version": "0.55.0",
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": [