aiterm-mcp 0.29.25 → 0.29.26

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,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.29.26] - 2026-09-02
11
+
12
+ ### Fixed
13
+
14
+ - Cursorの冷間起動時は、貼り付けたpromptがcomposerへ反映されたことを確認してからEnterを送り、入力準備前の早送信による未配達を防ぐ。
15
+
10
16
  ## [0.29.25] - 2026-09-02
11
17
 
12
18
  ### Fixed
@@ -1500,7 +1506,8 @@ prototype (preserved under `prototype/python/` as the porting source and referen
1500
1506
  `ubuntu-latest` for Node 18/20/22, publishing to npm on `v*` tags with
1501
1507
  provenance.
1502
1508
 
1503
- [Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.25...HEAD
1509
+ [Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.26...HEAD
1510
+ [0.29.26]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.25...v0.29.26
1504
1511
  [0.29.25]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.24...v0.29.25
1505
1512
  [0.29.24]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.23...v0.29.24
1506
1513
  [0.29.23]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.22...v0.29.23
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.25** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
156
+ **状態:** 開発継続中 · 現行公開版 **v0.29.26** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
157
157
 
158
158
  ### 更新と巻き戻し
159
159
 
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.25** · 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.26** · 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
 
package/dist/core.js CHANGED
@@ -61,6 +61,8 @@ const AGENT_SUBMIT_RESIDUE_POLL_MS = 300;
61
61
  const AGENT_SUBMIT_RESIDUE_MAX_SAMPLES = 5;
62
62
  const AGENT_SUBMIT_RESIDUE_TAIL_CHARS = 32;
63
63
  const AGENT_SUBMIT_RESIDUE_MIN_TAIL_CHARS = 8;
64
+ const CURSOR_PROMPT_VISIBLE_POLL_MS = 100;
65
+ const CURSOR_PROMPT_VISIBLE_MAX_SAMPLES = 50;
64
66
  // 出力削減(RTK の CAP 思想を移植)
65
67
  const MAX_LINES_BEFORE_ELIDE = 60;
66
68
  const HEAD_LINES = 30;
@@ -2480,6 +2482,22 @@ async function detectAgentSubmitResidueImpl(kind, text, sample, sleepFn, opts =
2480
2482
  async function detectAgentSubmitResidue(name, kind, text) {
2481
2483
  return detectAgentSubmitResidueImpl(kind, text, () => captureScreen(name, AGENT_TUI_READY_LINES), sleep);
2482
2484
  }
2485
+ async function waitCursorPromptVisibleImpl(text, sample, sleepFn, opts = {}) {
2486
+ const tail = agentSubmitResidueTail(text) ?? normalizeResidueText(text);
2487
+ const pollMs = opts.pollMs ?? CURSOR_PROMPT_VISIBLE_POLL_MS;
2488
+ const maxSamples = opts.maxSamples ?? CURSOR_PROMPT_VISIBLE_MAX_SAMPLES;
2489
+ for (let i = 0; i < maxSamples; i++) {
2490
+ if (agentSubmitResidueOnScreen("cursor", sample(), tail) === true) {
2491
+ return { visible: true, samples: i + 1 };
2492
+ }
2493
+ if (i < maxSamples - 1)
2494
+ await sleepFn(pollMs);
2495
+ }
2496
+ return { visible: false, samples: maxSamples };
2497
+ }
2498
+ async function waitCursorPromptVisible(name, text) {
2499
+ return waitCursorPromptVisibleImpl(text, () => captureScreen(name, AGENT_TUI_READY_LINES), sleep);
2500
+ }
2483
2501
  export function agentSubmitResidueWarning(name, residue) {
2484
2502
  if (residue !== true)
2485
2503
  return "";
@@ -2558,13 +2576,23 @@ export async function __testDetectAgentSubmitResidue(kind, text, samples, opts =
2558
2576
  }, opts);
2559
2577
  return { ...result, sleeps };
2560
2578
  }
2579
+ export async function __testWaitCursorPromptVisible(text, samples, opts = {}) {
2580
+ if (samples.length === 0)
2581
+ throw new AitermError("Cursor prompt反映待ちのtest samplesが空です", 2);
2582
+ let i = 0;
2583
+ const sleeps = [];
2584
+ const result = await waitCursorPromptVisibleImpl(text, () => samples[Math.min(i++, samples.length - 1)], async (ms) => {
2585
+ sleeps.push(ms);
2586
+ }, opts);
2587
+ return { ...result, sleeps };
2588
+ }
2561
2589
  export function __testSetAgentTuiReadyStableSamples(value) {
2562
2590
  if (value !== null && (!Number.isInteger(value) || value < 1 || value > 1000)) {
2563
2591
  throw new AitermError("test ready stable samplesが不正です", 2);
2564
2592
  }
2565
2593
  agentTuiReadyStableSamplesTestOverride = value;
2566
2594
  }
2567
- async function sendAgentPromptText(name, text) {
2595
+ async function sendAgentPromptText(name, text, kind) {
2568
2596
  send(name, text, {
2569
2597
  enter: false,
2570
2598
  force: true,
@@ -2574,7 +2602,16 @@ async function sendAgentPromptText(name, text) {
2574
2602
  preserveAgentOperation: true,
2575
2603
  bracketedPaste: true,
2576
2604
  });
2577
- await sleep(AGENT_SUBMIT_DELAY_MS);
2605
+ if (kind === "cursor") {
2606
+ const visible = await waitCursorPromptVisible(name, text);
2607
+ if (!visible.visible) {
2608
+ throw new AitermError(`vendor=cursor session=${name}\n` +
2609
+ "送信promptがCursorのcomposerへ反映されたことを確認できないため、Enterは送信していません。", 2);
2610
+ }
2611
+ }
2612
+ else {
2613
+ await sleep(AGENT_SUBMIT_DELAY_MS);
2614
+ }
2578
2615
  sendKey(name, "Enter", { preserveAgentOperation: true });
2579
2616
  }
2580
2617
  export async function sendInitialAgentPrompt(name, text, o = {}) {
@@ -2614,7 +2651,7 @@ export async function sendInitialAgentPrompt(name, text, o = {}) {
2614
2651
  prepareSendText(text, { raw: false });
2615
2652
  reserveAnonymousClaudeTurn(meta);
2616
2653
  }
2617
- await sendAgentPromptText(name, promptText);
2654
+ await sendAgentPromptText(name, promptText, meta.kind);
2618
2655
  setInitialPromptState(meta, "pending");
2619
2656
  }
2620
2657
  catch (e) {
@@ -2751,12 +2788,12 @@ export async function configureAgent(name, opts) {
2751
2788
  // Cursor TUIの `/model <base model>` はmodelを直接切り替える一方、flatten済みcatalog ID
2752
2789
  // (例: gpt-5.6-luna-high)を渡すとno matchesのfilter画面へ入る。effortは標準model pickerの
2753
2790
  // parameter editorで選び、同じsessionと会話contextを保つ。
2754
- await sendAgentPromptText(name, `/model ${model}`);
2791
+ await sendAgentPromptText(name, `/model ${model}`, meta.kind);
2755
2792
  const modelReady = await waitAgentTuiReady(name, meta, AGENT_TUI_READY_TIMEOUT_MS);
2756
2793
  if (!modelReady.ready)
2757
2794
  throw new AitermError("Cursorのmodel変更完了を確認できません", 2);
2758
2795
  if (effort) {
2759
- await sendAgentPromptText(name, "/model");
2796
+ await sendAgentPromptText(name, "/model", meta.kind);
2760
2797
  await waitForScreenText(name, "Available models");
2761
2798
  sendMenuChoice(name, "Tab");
2762
2799
  const parameterScreen = await waitForScreenText(name, "Edit Parameters");
@@ -2895,8 +2932,19 @@ export async function dispatchAgentTurn(name, text, o = {}) {
2895
2932
  preserveAgentOperation: meta.kind === "claude",
2896
2933
  bracketedPaste: true,
2897
2934
  });
2898
- // Codex TUI は literal text 投入直後の Enter を取り落とすことがある。agent 経路だけ submit を分離する。
2899
- await sleep(AGENT_SUBMIT_DELAY_MS);
2935
+ // Cursorの冷間起動ではbracketed pasteの反映が250msを超えることがある。本文がcomposerへ
2936
+ // 現れた実測をsubmit条件にし、未反映のままEnterだけを失う競合を作らない。
2937
+ if (meta.kind === "cursor") {
2938
+ const visible = await waitCursorPromptVisible(name, dispatchText);
2939
+ if (!visible.visible) {
2940
+ throw new AitermError(`vendor=cursor session=${name}\n` +
2941
+ "送信promptがCursorのcomposerへ反映されたことを確認できないため、Enterは送信していません。", 2);
2942
+ }
2943
+ }
2944
+ else {
2945
+ // Codex TUI は literal text 投入直後の Enter を取り落とすことがある。agent 経路だけ submit を分離する。
2946
+ await sleep(AGENT_SUBMIT_DELAY_MS);
2947
+ }
2900
2948
  sendKey(name, "Enter", { preserveAgentOperation: meta.kind === "claude" });
2901
2949
  const residue = await detectAgentSubmitResidue(name, meta.kind, dispatchText);
2902
2950
  assertAgentSubmitDelivered(name, meta.kind, residue);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiterm-mcp",
3
- "version": "0.29.25",
3
+ "version": "0.29.26",
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": [