aiterm-mcp 0.29.20 → 0.29.22

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,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.29.22] - 2026-09-02
11
+
12
+ ### Fixed
13
+
14
+ - Treat Codex's passive update notice as ordinary startup output, while still stopping for the interactive update menu that requires a selection.
15
+
16
+ ## [0.29.21] - 2026-09-02
17
+
18
+ ### Fixed
19
+
20
+ - Detect Cursor prompts left in the composer when the arrow and first prompt line share one row, and fail dispatch instead of returning a successful receipt for text that was not submitted.
21
+
10
22
  ## [0.29.20] - 2026-09-01
11
23
 
12
24
  ### Changed
@@ -1469,7 +1481,9 @@ prototype (preserved under `prototype/python/` as the porting source and referen
1469
1481
  `ubuntu-latest` for Node 18/20/22, publishing to npm on `v*` tags with
1470
1482
  provenance.
1471
1483
 
1472
- [Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.20...HEAD
1484
+ [Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.22...HEAD
1485
+ [0.29.22]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.21...v0.29.22
1486
+ [0.29.21]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.20...v0.29.21
1473
1487
  [0.29.20]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.19...v0.29.20
1474
1488
  [0.29.19]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.18...v0.29.19
1475
1489
  [0.29.18]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.17...v0.29.18
package/README.ja.md CHANGED
@@ -153,7 +153,7 @@ runtime-error store は canonical dotagents config の `collection.enabled: true
153
153
  場合だけ収集し、既定OFF、network送信は行いません。tag起点CIのnpm provenance(OIDC Trusted
154
154
  Publishing)で公開し、GitHub Release が Official MCP Registry を再登録します。
155
155
 
156
- **状態:** 開発継続中 · 現行公開版 **v0.29.20** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
156
+ **状態:** 開発継続中 · 現行公開版 **v0.29.22** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
157
157
 
158
158
  ### 更新と巻き戻し
159
159
 
@@ -187,7 +187,7 @@ pty_read(id, { wait: true }) → 削減済みの出力を読む(完了
187
187
 
188
188
  同じprimitiveが別エージェントのTUIを宿す。`agent_launch`の`harness`はagent loop・認証・hook・session・transcriptを所有する実行基盤、`model`は独立した選択。起動processは直接CLIと同じproject/user環境を使い、通常config、MCP、plugin、skill、permission、trust、memory、historyをcopy・filter・置換しない。
189
189
 
190
- `aiterm.agent-launch-result.v1`は正規`harness`を返し、旧`provider`は互換fieldとして残す。同じ`harness`はagent dispatch、`aiterm-wait`、`agent_configure`、`pty_list`のagent行にも載り、旧vendor/provider/agent fieldは互換用に残る。Codexは通常rollout、Grok CLIは通常session event、Claudeはlaunch固有Stop hook、Cursorは通常agent transcript末尾の`turn_ended`を完了正本に使う。`pty_send`は非ブロックdispatchで、vendor別完了境界を表すopaqueな整数`event_cursor`を返し、完了通知は`aiterm-wait`を親のターンを塞がない別processで受ける。
190
+ `aiterm.agent-launch-result.v1`は正規`harness`を返し、旧`provider`は互換fieldとして残す。同じ`harness`はagent dispatch、`aiterm-wait`、`agent_configure`、`pty_list`のagent行にも載り、旧vendor/provider/agent fieldは互換用に残る。Codexは通常rollout、Grok CLIは通常session event、Claudeはlaunch固有Stop hook、Cursorは通常agent transcript末尾の`turn_ended`を完了正本に使う。`pty_send`は非ブロックdispatchで、vendor別完了境界を表すopaqueな整数`event_cursor`を返し、完了通知は`aiterm-wait`を親のターンを塞がない別processで受ける。送信textがCursorのcomposerへ残った場合は成功receiptを返さず失敗する。
191
191
 
192
192
  `agent_launch`は任意の`write_scope`も受ける。Codex/Grokのread-onlyは`--sandbox read-only`、Cursorは公式`--mode ask`で実効化する。path説明は同等CLI引数がないためdeclaration-only。
193
193
 
package/README.md CHANGED
@@ -169,7 +169,7 @@ collection is off by default and performs no network I/O. It ships via
169
169
  tag-triggered CI with npm provenance (OIDC Trusted Publishing); the GitHub
170
170
  Release re-registers the Official MCP Registry entry.
171
171
 
172
- **Status:** actively maintained · current public release **v0.29.20** · 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).
172
+ **Status:** actively maintained · current public release **v0.29.22** · 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).
173
173
 
174
174
  ### Update and rollback
175
175
 
@@ -209,7 +209,7 @@ pty_read(id, { wait: true }) → read the token-reduced output, completion
209
209
 
210
210
  The same primitive hosts another agent's TUI. `agent_launch` starts a selected execution harness inside a fresh persistent terminal and returns a `session_id`. `harness` names the component that owns the agent loop, authentication, hooks, session, and transcript; `model` remains an independent choice. The launched process sees the same project and user environment as a direct CLI invocation: normal configuration, MCPs, plugins, skills, permissions, trust decisions, memory, and history are not copied, filtered, or replaced. Aiterm adds only completion correlation and a non-user sub-agent context containing `role=subagent`, the parent session, delegation depth, lineage, and `delegation_allowed=true`.
211
211
 
212
- The human-readable launch text is accompanied by an `aiterm.agent-launch-result.v1` structured receipt containing the canonical `harness`; the old `provider` field remains for compatibility. The same `harness` is carried by agent dispatch, `aiterm-wait`, `agent_configure`, and agent rows in `pty_list`, while their old vendor/provider/agent fields remain compatibility fields. Codex completion comes from its normal durable rollout transcript, Grok CLI from its normal session events, Claude Code from a launch-specific Stop hook settings addition, and Cursor from its normal agent transcript's terminal `turn_ended` record. Sending to any agent session is a non-blocking **dispatch** — the call returns immediately with an opaque, harness-specific integer `event_cursor`, and completion arrives via [`aiterm-wait`](#completion-push-for-parent-agents-aiterm-wait).
212
+ The human-readable launch text is accompanied by an `aiterm.agent-launch-result.v1` structured receipt containing the canonical `harness`; the old `provider` field remains for compatibility. The same `harness` is carried by agent dispatch, `aiterm-wait`, `agent_configure`, and agent rows in `pty_list`, while their old vendor/provider/agent fields remain compatibility fields. Codex completion comes from its normal durable rollout transcript, Grok CLI from its normal session events, Claude Code from a launch-specific Stop hook settings addition, and Cursor from its normal agent transcript's terminal `turn_ended` record. Sending to any agent session is a non-blocking **dispatch** — the call returns immediately with an opaque, harness-specific integer `event_cursor`, and completion arrives via [`aiterm-wait`](#completion-push-for-parent-agents-aiterm-wait). If submitted text remains in Cursor's composer, its dispatch fails instead of returning a successful receipt.
213
213
 
214
214
  `agent_launch` accepts an optional `write_scope`: either `"read-only"` or a human-readable description of writable paths. Codex/Grok use `--sandbox read-only`; Cursor uses its official read-only `--mode ask`. A path description remains declaration-only because these CLI launch surfaces provide no equivalent path allowlist flag.
215
215
 
package/dist/core.js CHANGED
@@ -19,7 +19,7 @@ import { sleep, currentUid, runtimeStateBase, safeStatSize, readFileRange, write
19
19
  import { GROK_MODEL_DEFAULTS, realGrokHome, resolveAndValidateGrokAuth, assertGrokModelAvailable, grokEventsTranscript, latestGrokCompletion, observeGrokDone, buildGrokAgentCmd, grokLaunchNote, grokEnvTokens, grokTuiReady, GROK_COMPOSER_MARKER_RE, grokFooterHasConfiguration, grokTranscriptText, createGrokAgentMetadata, } from "./harnesses/grok.js";
20
20
  import { bindCodexTranscriptSession, latestCodexCompletion, observeCodexDone, buildCodexAgentCmd, codexLaunchNote, codexTuiReady, codexLaunchBlockingDialog, CODEX_COMPOSER_MARKER_RE, codexModelChoice, codexEffortChoice, codexMoreReasoningChoice, codexTranscriptText, createCodexAgentMetadata, } from "./harnesses/codex.js";
21
21
  import { OPERATION_ID_RE, CLAUDE_RESULT_MAX_BYTES, CLAUDE_EFFORTS, agentManagedClaudeSettingsPath, agentClaudeResultPath, agentClaudeOperationPath, agentClaudeApprovalReceiptPath, agentClaudeDispatchReceiptPath, validateOperationId, readClaudeResultText, assertClaudeAuthenticationReady, buildClaudeAgentCmd, claudeLaunchNote, claudeTuiReady, CLAUDE_COMPOSER_MARKER_RE, createClaudeAgentMetadata, } from "./harnesses/claude.js";
22
- import { bindCursorTranscriptSession, cursorTurnBoundary, latestCursorCompletion, observeCursorDone, cursorTranscriptText, assertCursorAuthenticationReady, assertCursorModelAvailable, buildCursorAgentCmd, cursorPromptWithLineage, createCursorAgentMetadata, cursorLaunchNote, cursorEffortNavigation, cursorTuiReady, CURSOR_COMPOSER_MARKER_RE, validateCursorModelEffort, } from "./harnesses/cursor.js";
22
+ import { bindCursorTranscriptSession, cursorTurnBoundary, latestCursorCompletion, observeCursorDone, cursorTranscriptText, assertCursorAuthenticationReady, assertCursorModelAvailable, buildCursorAgentCmd, cursorPromptWithLineage, createCursorAgentMetadata, cursorLaunchNote, cursorEffortNavigation, cursorTuiReady, CURSOR_COMPOSER_CONTENT_MARKER_RE, validateCursorModelEffort, } from "./harnesses/cursor.js";
23
23
  import { resolveAgentBin, resolveThroughlineBin, runThroughlineHandoffContext, isWindowsNativeExecutable, agentBinForPaneShell, resolveWinPaneShell } from "./agent-resolver.js";
24
24
  export { AitermError } from "./errors.js";
25
25
  export { tmuxSpawnEnv } from "./tmux-runtime.js";
@@ -2346,8 +2346,7 @@ function isAgentTuiIdleReady(kind, screen) {
2346
2346
  // `initial_prompt=not_sent`を返してsessionを生かしたままcallerへ制御を戻す。
2347
2347
  function isAgentTuiActionRequired(kind, screen) {
2348
2348
  if (kind === "codex") {
2349
- return screen.includes("Update available!")
2350
- || screen.includes("Do you trust the contents of this directory?")
2349
+ return codexLaunchBlockingDialog(screen) !== null
2351
2350
  || screen.includes("Hooks need review")
2352
2351
  || screen.includes("Allow the room MCP server to run tool")
2353
2352
  || screen.includes("Would you like to run the following command?");
@@ -2417,7 +2416,7 @@ function agentSubmitResidueOnScreen(kind, screen, tail) {
2417
2416
  : kind === "claude"
2418
2417
  ? CLAUDE_COMPOSER_MARKER_RE
2419
2418
  : kind === "cursor"
2420
- ? CURSOR_COMPOSER_MARKER_RE
2419
+ ? CURSOR_COMPOSER_CONTENT_MARKER_RE
2421
2420
  : GROK_COMPOSER_MARKER_RE;
2422
2421
  let markerIdx = -1;
2423
2422
  for (let i = lines.length - 1; i >= 0; i--) {
@@ -2464,6 +2463,15 @@ export function agentSubmitResidueWarning(name, residue) {
2464
2463
  `pty_read(${name}, screen:true) で状態を確認してから、座礁していれば pty_key(${name}, "Enter") で再 submit、` +
2465
2464
  `破棄するなら pty_key(${name}, "Escape") を使う。盲目的に Enter を送らない(queued だった場合の二重 submit 防止)。`);
2466
2465
  }
2466
+ function assertAgentSubmitDelivered(name, kind, residue) {
2467
+ if (kind !== "cursor" || residue.residue !== true)
2468
+ return;
2469
+ throw new AitermError(`submit_residue=true vendor=${kind} session=${name}\n` +
2470
+ "送信 text がcomposerへ残っており、turnを開始できませんでした。", 2);
2471
+ }
2472
+ export function __testAssertAgentSubmitDelivered(name, kind, residue) {
2473
+ assertAgentSubmitDelivered(name, kind, residue);
2474
+ }
2467
2475
  async function settleAgentDoneScreenImpl(sample, sleepFn, opts = {}) {
2468
2476
  const minDelayMs = opts.minDelayMs ?? AGENT_DONE_SETTLE_MIN_MS;
2469
2477
  const pollMs = opts.pollMs ?? AGENT_DONE_SCREEN_SETTLE_POLL_MS;
@@ -2592,6 +2600,13 @@ export async function sendInitialAgentPrompt(name, text, o = {}) {
2592
2600
  `起動時promptがCursorのcomposerへ残り、Enter再送後もturnを開始できませんでした。`, 2);
2593
2601
  }
2594
2602
  }
2603
+ try {
2604
+ assertAgentSubmitDelivered(name, meta.kind, residue);
2605
+ }
2606
+ catch (e) {
2607
+ setInitialPromptState(meta, "failed");
2608
+ throw e;
2609
+ }
2595
2610
  return {
2596
2611
  text: `initial_prompt=pending vendor=${meta.kind} event_cursor=${startOffset} harness=${agentHarness(meta.kind)}\n` +
2597
2612
  `起動時 prompt を送信した。${agentDispatchGuide(name, startOffset)}` +
@@ -2850,6 +2865,7 @@ export async function dispatchAgentTurn(name, text, o = {}) {
2850
2865
  await sleep(AGENT_SUBMIT_DELAY_MS);
2851
2866
  sendKey(name, "Enter", { preserveAgentOperation: meta.kind === "claude" });
2852
2867
  const residue = await detectAgentSubmitResidue(name, meta.kind, dispatchText);
2868
+ assertAgentSubmitDelivered(name, meta.kind, residue);
2853
2869
  return {
2854
2870
  schema: "aiterm.agent-dispatch.v1",
2855
2871
  session_id: meta.aiterm_session,
@@ -387,7 +387,8 @@ export const CODEX_COMPOSER_MARKER_RE = /^\s*[›>]/;
387
387
  // 文字列は実機captureの逐語。既知2種に一致しない「Press enter to continue」も
388
388
  // 同型のmodalとして拾う(種別不明のまま握りつぶさない)。
389
389
  export function codexLaunchBlockingDialog(screen) {
390
- if (screen.includes("Update available!"))
390
+ if (screen.includes("Update available!")
391
+ && (/(^|\n)\s*›?\s*1\.\s+Update now\b/m.test(screen) || screen.includes("Press enter to continue")))
391
392
  return "update確認ダイアログ";
392
393
  if (screen.includes("Do you trust the contents of this directory"))
393
394
  return "directory trust確認ダイアログ";
@@ -392,6 +392,9 @@ export function cursorLaunchNote(model, effort, meta) {
392
392
  return `${modelNote}${writeScopeLaunchNote("cursor", meta?.write_scope)}`;
393
393
  }
394
394
  export const CURSOR_COMPOSER_MARKER_RE = /(?:^|\n)\s*(?:>|→|->)\s*(?:\n|$)/m;
395
+ // 送信後の残留検出では、本文が矢印と同じ行に残る現行UIもcomposerとして扱う。
396
+ // ready判定には使わない。本文入りcomposerを入力待ちと誤認させないため。
397
+ export const CURSOR_COMPOSER_CONTENT_MARKER_RE = /^\s*(?:->|>|→)(?:\s|$)/;
395
398
  const CURSOR_FOLLOWUP_MARKER_RE = /(?:^|\n)\s*(?:→|->)\s*Add a follow-up\b/im;
396
399
  const CURSOR_START_PROMPT_MARKER_RE = /(?:^|\n)\s*(?:→|->)\s*Plan,\s*search,\s*build anything\s*(?:\n|$)/im;
397
400
  export function cursorTuiReady(screen) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiterm-mcp",
3
- "version": "0.29.20",
3
+ "version": "0.29.22",
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": [