aiterm-mcp 0.29.29 → 0.29.31

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,7 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ## [0.29.29] - 2026-09-02
10
+ ## [0.29.31] - 2026-09-04
11
+
12
+ ### Fixed
13
+
14
+ - agent session への打鍵前に、pane tty 上の agent が前面プロセスグループでなければ `fg` で前面へ戻し、tty が cooked(icanon/echo)なら `raw -echo` へ戻してから送る(`pty_send` dispatch・起動時 prompt・`agent_steer`)。Codex 0.153 はツール実行後に前面を bash へ返したまま動き続ける/termios を cooked のまま残すことがあり、貼付本文が bash に落ちて `^[[200~` が生で残っていた(実測 2026-09-04)。dispatch receipt に `pane_input_recovery` を追加。判定は `ps -t` の STAT と `stty -a` だけを使う。
15
+
16
+ ### Changed
17
+
18
+ - push時のCIをLinux 1環境へ絞り、WindowsはWindows固有ファイルの変更時だけ、3環境の全テストは週1回の定期実行だけにした。tag起点のnpm公開はmain CIの成功を待たず、既定ブランチの祖先確認だけで進める。
19
+ - `npm run release -- <version>`でversion同期・CHANGELOG見出し・commit・tag・MCPB・GitHub Releaseを一回で行う。
20
+
21
+ ## [0.29.30] - 2026-09-02
22
+
23
+ ### Fixed
24
+
25
+ - 起動直後のClaude Codeへの初回dispatchが入力受付gateを素通りし、composer描画前に届いた貼付本文だけが残ってEnterが失われる競合を直した。完了eventも進行中turnもないClaude sessionは他harnessと同じready gateを通してから送信する。
26
+
11
27
 
12
28
  ### Fixed
13
29
 
@@ -1524,7 +1540,9 @@ prototype (preserved under `prototype/python/` as the porting source and referen
1524
1540
  `ubuntu-latest` for Node 18/20/22, publishing to npm on `v*` tags with
1525
1541
  provenance.
1526
1542
 
1527
- [Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.29...HEAD
1543
+ [Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.31...HEAD
1544
+ [0.29.31]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.30...v0.29.31
1545
+ [0.29.30]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.29...v0.29.30
1528
1546
  [0.29.29]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.28...v0.29.29
1529
1547
  [0.29.28]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.27...v0.29.28
1530
1548
  [0.29.27]: https://github.com/kitepon/aiterm-mcp/compare/v0.29.26...v0.29.27
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.29** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
156
+ **状態:** 開発継続中 · 現行公開版 **v0.29.31** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
157
157
 
158
158
  ### 更新と巻き戻し
159
159
 
@@ -496,10 +496,11 @@ npm test # build してから node:test 回帰スイート(tmux ま
496
496
  npm link # ローカルで `aiterm-mcp` を PATH に
497
497
  ```
498
498
 
499
- 開発中は変更に直結するfocused testを先にローカルで実行します。GitHub Actionsは実装の依存関係から
500
- 必要なテストを選び、依存を確定できない変更とrelease変更だけ3環境の全テストへ広げます。
501
- tag起点のnpm公開は、同じcommitのmain CIが3環境greenであり、tagged commitが`origin/main`の
502
- 祖先であることを確認した後だけ実行します。tag側で同じ3環境試験は繰り返しません。
499
+ 開発中は変更に直結するfocused testを先にローカルで実行します。GitHub Actionsはpushごとにself-hostedの
500
+ `linux-workstation` 1環境で試験を回し、Windows固有ファイルを触った変更だけ`windows-native`を加え、
501
+ 3環境(`macos-native`、`linux-workstation`、`windows-native`)の全テストは週1回の健康診断だけで回します。
502
+ `npm run release -- <version>`がversion同期・commit・tag・GitHub Releaseを一回で行い、tag起点のnpm公開は
503
+ tagged commitが`origin/main`の祖先であることだけを確認して、他のCI結果を待ちません。
503
504
 
504
505
  共通進行は`src/core.ts`、harness固有は`src/harnesses/`、OS差は`src/tmux-runtime.ts`/`src/agent-resolver.ts`、reducerは`src/rtk.ts`、公開面は`src/index.ts`が所有する。現行設計は[`docs/DESIGN.md`](docs/DESIGN.md)、release手順は[`docs/RELEASE.md`](docs/RELEASE.md)を正とする。`prototype/python/`はreducerの歴史的移植元であり、pytest reducerは本家rtk 0.42.0と一致する(上記の`FAILED`行の差異だけは意図的・回帰テストで固定)。
505
506
 
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.29** · 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.31** · 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
 
@@ -542,11 +542,12 @@ npm test # build, then the node:test regression suite (requires tmux o
542
542
  npm link # put `aiterm-mcp` on PATH locally
543
543
  ```
544
544
 
545
- Development uses focused local tests first. GitHub Actions selects tests from the changed implementation's
546
- dependency graph and expands unknown or release changes to the full suite on the self-hosted
547
- `macos-native`, `linux-workstation`, and `windows-native` runners. Tag-triggered npm publishing reuses
548
- the successful main CI for the same commit instead of repeating it, and runs only after the tagged commit
549
- is confirmed on `origin/main`. The native
545
+ Development uses focused local tests first. GitHub Actions runs the suite on the self-hosted
546
+ `linux-workstation` runner for every push, adds `windows-native` only when Windows-specific files change,
547
+ and runs all three runners (`macos-native`, `linux-workstation`, `windows-native`) once a week as a health
548
+ check. `npm run release -- <version>` syncs the version, commits, tags, and publishes the GitHub Release in
549
+ one command; tag-triggered npm publishing checks only that the tagged commit is on `origin/main` and does not
550
+ wait for another CI run. The native
550
551
  Windows runner needs psmux ≥ 3.3.8 and Git for Windows on its PATH, and must run as an
551
552
  interactive Windows user; `NETWORK SERVICE` lacks the per-user environment the pane shell and
552
553
  harness CLIs rely on and is not a valid runner identity.
package/dist/core.js CHANGED
@@ -108,6 +108,129 @@ function paneCurrentCommand(name) {
108
108
  return "";
109
109
  return normalizePaneCommand(r.stdout.trim());
110
110
  }
111
+ // ---- pane 入力の到達性(agent が tty の前面か・tty が raw か)----
112
+ // 打鍵が届く先は pane tty の前面プロセスグループだけであり、TUI は raw termios で読む。
113
+ // Codex 0.153 はツール実行のあと、①前面を子 shell(bash)へ返したまま agent が背面(STAT S)で
114
+ // 動き続ける、②前面へ戻っても termios を子 shell の cooked(icanon/echo)のまま残す、の2形を出す
115
+ // (実測 2026-09-04: Codex 席3つが順に該当。貼付本文が bash に落ちて `^[[200~` が生で残り、
116
+ // 打鍵が行バッファに溜まって `^L` が echo された)。どちらも PTY の状態であり aiterm が所有する。
117
+ // 停止(T)だけでなく背面で動く(S)agent も `fg` で前面へ戻せる。判定は OS が直接教える
118
+ // `ps -t <tty>` の STAT `+`/`T` と `stty -f <tty> -a` だけを使い、画面の文字列で推測しない。
119
+ const PANE_TTY_SHELLS = new Set([...SHELLS, "tcsh", "csh", "ksh"]);
120
+ const AGENT_FOREGROUND_RECOVERY_TIMEOUT_MS = 3_000;
121
+ const AGENT_FOREGROUND_RECOVERY_POLL_MS = 200;
122
+ // harness の実プロセスを command 行から見分ける。agent が起動した子(bash -lc、ssh、git 等)は agent ではない。
123
+ const AGENT_COMMAND_PATTERNS = {
124
+ codex: /(^|[\s/])codex([\s]|$)/,
125
+ claude: /(^|[\s/])claude([\s]|$)/,
126
+ grok: /(^|[\s/])grok(-[^\s/]+)?([\s]|$)/,
127
+ composer: /(^|[\s/])(composer|grok(-[^\s/]+)?)([\s]|$)/,
128
+ cursor: /(^|[\s/])(cursor-agent|agent)([\s]|$)/,
129
+ };
130
+ /**
131
+ * `ps -t <tty> -o stat=,command=` の出力を分類する(純粋関数)。
132
+ * ログイン shell は command が `-zsh` のように先頭 `-` 付きで出るので剥がして判定する。
133
+ */
134
+ export function classifyPaneTtyProcesses(psOutput, agentPattern = /./) {
135
+ const state = {
136
+ agentPresent: false, agentForeground: false, agentStopped: false, toolForeground: false, foregroundShell: null,
137
+ };
138
+ for (const raw of psOutput.split("\n")) {
139
+ const m = raw.trim().match(/^(\S+)\s+(.*)$/);
140
+ if (!m)
141
+ continue;
142
+ const stat = m[1];
143
+ const command = m[2];
144
+ const base = ((command.split(/\s+/, 1)[0] ?? "").split("/").pop() ?? "").replace(/^-/, "");
145
+ if (PANE_TTY_SHELLS.has(base)) {
146
+ // session leader(STAT の `s`)が pane の login shell。agent が起動した子 shell(`bash -lc …`)は
147
+ // `s` を持たない。前面の子 shell は「ツール実行中」であり、fg も stty も触らない。
148
+ if (stat.includes("+")) {
149
+ if (stat.includes("s"))
150
+ state.foregroundShell = base;
151
+ else
152
+ state.toolForeground = true;
153
+ }
154
+ continue;
155
+ }
156
+ if (!agentPattern.test(command)) {
157
+ if (stat.includes("+"))
158
+ state.toolForeground = true;
159
+ continue;
160
+ }
161
+ state.agentPresent = true;
162
+ if (stat.includes("+"))
163
+ state.agentForeground = true;
164
+ if (stat.startsWith("T"))
165
+ state.agentStopped = true;
166
+ }
167
+ return state;
168
+ }
169
+ /** `stty -a` の出力が cooked(icanon または echo が有効)かを判定する(純粋関数)。 */
170
+ export function termiosIsCooked(sttyOutput) {
171
+ const tokens = sttyOutput.split(/[\s;]+/);
172
+ return tokens.includes("icanon") || tokens.includes("echo");
173
+ }
174
+ function paneTtyOf(name) {
175
+ const r = tmux("display-message", "-p", "-t", name, "#{pane_tty}");
176
+ if (r.code !== 0)
177
+ return null;
178
+ const tty = r.stdout.trim();
179
+ return tty.startsWith("/dev/") ? tty : null;
180
+ }
181
+ /**
182
+ * agent session への打鍵前に、agent が tty の前面で raw で読める状態にする。
183
+ * 戻り値は行った回復("fg" / "fg_stopped" / "stty_raw")。何もしなければ空。
184
+ * agent が tty 上に実在しない時は触らない(ready gate が入力受付不能として止める)。
185
+ */
186
+ export async function ensureAgentOwnsPaneInput(name, kind) {
187
+ if (isWin)
188
+ return [];
189
+ const tty = paneTtyOf(name);
190
+ if (!tty)
191
+ return [];
192
+ const ttyId = tty.replace(/^\/dev\//, "");
193
+ const psEnv = { ...process.env, LC_ALL: "C" };
194
+ const observe = () => classifyPaneTtyProcesses(spawnSync("/bin/ps", ["-t", ttyId, "-o", "stat=,command="], { encoding: "utf8", timeout: 5000, env: psEnv }).stdout ?? "", AGENT_COMMAND_PATTERNS[kind]);
195
+ const recovery = [];
196
+ let state = observe();
197
+ // agent が起動したツール/子 shell が前面なら、その tty 状態はツールの物。fg も stty も触らず ready gate に任せる。
198
+ if (state.toolForeground)
199
+ return [];
200
+ if (state.agentPresent && !state.agentForeground) {
201
+ const wasStopped = state.agentStopped;
202
+ tmux("send-keys", "-t", name, "C-u");
203
+ tmux("send-keys", "-l", "-t", name, "fg");
204
+ tmux("send-keys", "-t", name, "Enter");
205
+ const deadline = performance.now() + AGENT_FOREGROUND_RECOVERY_TIMEOUT_MS;
206
+ for (;;) {
207
+ await sleep(AGENT_FOREGROUND_RECOVERY_POLL_MS);
208
+ state = observe();
209
+ if (state.agentForeground)
210
+ break;
211
+ if (performance.now() >= deadline) {
212
+ throw new AitermError(`AGENT_TUI_BACKGROUNDED session=${name} foreground=${state.foregroundShell ?? "不明"}\n` +
213
+ "pane tty 上に agent が実在するが前面プロセスグループでなく、fg でも前面へ戻りません。" +
214
+ "打鍵は shell に落ちるため送信していません。pty_read(screen:true) で画面を確認してください。", 2);
215
+ }
216
+ }
217
+ recovery.push(wasStopped ? "fg_stopped" : "fg");
218
+ }
219
+ if (state.agentPresent && !state.toolForeground) {
220
+ // 別 tty を指す flag は macOS/BSD が `-f`、Linux(coreutils)が `-F`。OS 差はここ一箇所で吸収する。
221
+ const ttyFlag = process.platform === "linux" ? "-F" : "-f";
222
+ const stty = spawnSync("/bin/stty", [ttyFlag, tty, "-a"], { encoding: "utf8", timeout: 5000, env: psEnv });
223
+ if (stty.status === 0 && termiosIsCooked(stty.stdout ?? "")) {
224
+ const set = spawnSync("/bin/stty", [ttyFlag, tty, "raw", "-echo"], { encoding: "utf8", timeout: 5000, env: psEnv });
225
+ if (set.status !== 0) {
226
+ throw new AitermError(`AGENT_TTY_COOKED session=${name}\n` +
227
+ `tty が icanon/echo のままで raw へ戻せません: ${(set.stderr ?? "").trim() || `code=${set.status}`}。送信していません。`, 2);
228
+ }
229
+ recovery.push("stty_raw");
230
+ }
231
+ }
232
+ return recovery;
233
+ }
111
234
  function paneCurrentCommandForMark(name) {
112
235
  const foreground = paneCurrentCommand(name);
113
236
  if (!isWin || foreground === "powershell" || foreground === "pwsh")
@@ -2658,6 +2781,9 @@ export async function sendInitialAgentPrompt(name, text, o = {}) {
2658
2781
  throw new AitermError(`agent session '${name}' は起動時 prompt の完了待ちです。初回応答完了後に再度操作してください。`, 2);
2659
2782
  }
2660
2783
  setInitialPromptState(meta, "not_sent");
2784
+ // 起動直後の hooks 実行で bash が前面に残ると ready gate が恒久 false になり、brief 未送信で
2785
+ // 席が巻き戻る(実測 2026-09-04: Codex 0.153 の初回起動が3回中2回)。打鍵の前に前面と raw を整える。
2786
+ await ensureAgentOwnsPaneInput(name, meta.kind);
2661
2787
  let ready = await waitAgentTuiReady(name, meta, o.ready_timeout ?? AGENT_TUI_READY_TIMEOUT_MS);
2662
2788
  // 無人Claude起動でCLI自身が順に出す、bypass mode確認とworkspace trustだけを
2663
2789
  // 起動処理の一部として進める。通常turn中の権限確認やMCP承認には触れない。
@@ -2934,7 +3060,15 @@ export async function dispatchAgentTurn(name, text, o = {}) {
2934
3060
  // Codex/Grok/Composerはbind済みのfollow-upでも毎回idleを確認してからtranscript境界を切る。
2935
3061
  // Grok/Composerはsession IDが起動前から既知でも、共有MCPの初期化完了前には送信しない。
2936
3062
  // 同じcursorへ複数turnを帰属させる余地や、初期化中TUIへの早送信を作らない。
2937
- if (meta.kind !== "claude" || !meta.vendor_session_id) {
3063
+ // Claudeはsession IDを起動時に採番するため「bind済み」では初回を区別できず、起動直後の
3064
+ // dispatchがready gateを素通りしていた。composer描画前に貼付とEnterが届くと起動時の一塊の
3065
+ // 入力として読まれ、本文だけがcomposerへ残る(実被弾 2026-09-02: 停止中Botへの初回配送)。
3066
+ // 完了eventも進行中turnもないClaude sessionだけを起動直後とみなし、他harnessと同じgateを通す。
3067
+ const claudeColdStart = meta.kind === "claude"
3068
+ && agentCompletionCursor(meta) === 0
3069
+ && readClaudeOperationMarker(meta) === null;
3070
+ const paneInputRecovery = await ensureAgentOwnsPaneInput(name, meta.kind);
3071
+ if (meta.kind !== "claude" || claudeColdStart) {
2938
3072
  const ready = await waitAgentTuiReady(name, meta, o.ready_timeout ?? AGENT_TUI_READY_TIMEOUT_MS);
2939
3073
  if (!ready.ready) {
2940
3074
  throw new AitermError(`agent session '${name}' の ${agentLabel(meta.kind)} TUI が入力受付状態になりません。文字列は送信していません。` +
@@ -2994,6 +3128,7 @@ export async function dispatchAgentTurn(name, text, o = {}) {
2994
3128
  event_cursor: startOffset,
2995
3129
  operation_id: operationId,
2996
3130
  submit_residue: residue.residue,
3131
+ pane_input_recovery: paneInputRecovery,
2997
3132
  };
2998
3133
  }
2999
3134
  export async function steerAgentTurn(name, text) {
@@ -3009,8 +3144,11 @@ export async function steerAgentTurn(name, text) {
3009
3144
  vendor: meta.kind,
3010
3145
  harness: agentHarness(meta.kind),
3011
3146
  };
3012
- if (!isAgentTuiBusy(meta.kind, captureScreen(name, AGENT_TUI_READY_LINES)))
3013
- return { ...receipt, delivery: "idle" };
3147
+ // 前面回復は busy 判定より先(bash 前面のままだと画面の実行中マーカーを読んでも打鍵が届かない)。
3148
+ const paneInputRecovery = await ensureAgentOwnsPaneInput(name, meta.kind);
3149
+ if (!isAgentTuiBusy(meta.kind, captureScreen(name, AGENT_TUI_READY_LINES))) {
3150
+ return { ...receipt, delivery: "idle", pane_input_recovery: paneInputRecovery };
3151
+ }
3014
3152
  send(name, text, {
3015
3153
  enter: false,
3016
3154
  force: true,
@@ -3021,7 +3159,7 @@ export async function steerAgentTurn(name, text) {
3021
3159
  });
3022
3160
  await sleep(AGENT_SUBMIT_DELAY_MS);
3023
3161
  sendKey(name, "Enter");
3024
- return { ...receipt, delivery: "steered" };
3162
+ return { ...receipt, delivery: "steered", pane_input_recovery: paneInputRecovery };
3025
3163
  }
3026
3164
  export async function runClaudeOperation({ session_id: name, action, operation_id: operationIdInput, text, }) {
3027
3165
  assertSessionName(name);
package/dist/index.js CHANGED
@@ -149,6 +149,8 @@ server.registerTool("pty_send", {
149
149
  // dispatch後のsubmit座礁観測(additive)。true=composerに送信textの残存を確認(submit未成立の疑い)/
150
150
  // false=残存を観測せず(成立の保証ではない)/ null=通常送信・判定不能。
151
151
  submit_residue: z.boolean().nullable(),
152
+ // dispatch前に行った pane 入力の回復("fg" / "fg_stopped" / "stty_raw")。通常送信では省略(additive)。
153
+ pane_input_recovery: z.array(z.string()).optional(),
152
154
  },
153
155
  }, async ({ session_id, text, enter, mark, force, rtk, raw }) => {
154
156
  try {
@@ -180,6 +182,7 @@ server.registerTool("pty_send", {
180
182
  vendor: receipt.vendor,
181
183
  harness: receipt.harness,
182
184
  submit_residue: receipt.submit_residue,
185
+ pane_input_recovery: receipt.pane_input_recovery,
183
186
  },
184
187
  };
185
188
  }
package/docs/DESIGN.md CHANGED
@@ -28,6 +28,7 @@ platform nativeな別process起動情報を返す。waiterは純readerで、親
28
28
  回答はharness所有transcriptから同じturnへ相関して回収し、欠落・曖昧・timeout時にpromptを再送しない。
29
29
  `agent_steer`は実行中のCodex/Grok turnへ追加textを差し込み、idleなら送信せず状態を返す。
30
30
  Cursorのsubmitはadapterがextended keyboard protocolのEnterへ変換し、呼び出し側は通常のdispatchだけを使う。
31
+ 起動直後のClaude sessionへの初回dispatchは、他harnessと同じくTUIの入力受付を確認してから貼付とEnterを送る。
31
32
 
32
33
  ## Layer ownership
33
34
 
package/docs/RELEASE.md CHANGED
@@ -1,53 +1,43 @@
1
1
  # Release
2
2
 
3
- Aitermのreleaseはこのrepositoryが所有する。`.github/workflows/product-full-ci.yml`が変更影響選択、3環境runnerと
3
+ Aitermのreleaseはこのrepositoryが所有する。`.github/workflows/product-full-ci.yml`が変更影響選択、runnerと
4
4
  製品gateの正本であり、dotagentsの工場CIは横断受入のconsumerであってreleaseを制御しない。
5
5
 
6
- ## Version同期
6
+ ## CIの範囲
7
7
 
8
- 新versionでは次を同じ値へ更新する。
8
+ - push/pull request: `linux-workstation` 1環境。変更した実装の依存graphから試験を選び、依存を確定できない変更は
9
+ Linuxの全テストへ広げる。Windows固有ファイル(`src/windows-powershell.ts`、`src/psmux-send-worker.ts`、
10
+ `test/windows-*.test.mjs`)を触った変更だけ`windows-native`を加える。
11
+ - 週1回の定期実行(月曜 03:00 JST)と手動実行だけが、`macos-native`、`linux-workstation`、`windows-native`の
12
+ 3環境で全テストを回す。
13
+ - tag push: 所有確認と、tagged commitが`origin/main`の祖先であることの確認だけを行い、npmへprovenance付きで
14
+ publishする。同じcommitのmain CIの結果は待たない。
9
15
 
10
- - `package.json`と`package-lock.json`
11
- - `server.json`
12
- - `mcpb/manifest.json`
13
- - `README.md`と`README.ja.md`の現行公開版
14
- - `CHANGELOG.md`の新version見出し、`Unreleased`比較先、新version比較link
16
+ 実測(2026-09-02): Linux 2分、macOS 2分、Windows 6分。全環境展開ではWindowsが常にcritical pathになる。
15
17
 
16
- 同じversionのtagやnpm packageを移動・上書きしない。失敗版はそのまま残し、修正版を次のversionで出す。
17
-
18
- ## Local gate
18
+ ## Release手順
19
19
 
20
- 変更に直結するfocused testを通した後、最終確認を一度だけ行う。
20
+ 1. 変更に直結するfocused testを手元で通す。full regressionは手元で回さず、CIに任せる。
21
+ 2. `CHANGELOG.md`の`## [Unreleased]`へ内容を書き、mainへcommitしてpushする。
22
+ 3. 一回で公開する。
21
23
 
22
- ```bash
23
- npm ci
24
- npm test
25
- npm pack --dry-run
26
- npm run mcpb:build
27
- ```
24
+ ```bash
25
+ npm run release -- <version>
26
+ ```
28
27
 
29
- MCPBのstaged serverでversion、16 tools、stderr 0、必要なruntime JavaScriptの同梱を確認する。
28
+ scriptはversion同期(`package.json`、`package-lock.json`、`server.json`、`mcpb/manifest.json`、`README.md`と`README.ja.md`の現行公開版)、
29
+ CHANGELOG見出しと比較link、metadata検査、release commit、main push、`v<version>` tag push、
30
+ MCPB build、GitHub Release作成までを行う。tag pushがnpm publish、Release作成がOfficial MCP Registry登録を起動する。
31
+ scriptはその完了を待たない。
30
32
 
31
- ## Mainと公開
33
+ 4. 後で確認する: `npm view aiterm-mcp@<version> version`、Official Registryの`io.github.kitepon/aiterm-mcp`。
32
34
 
33
- 1. release commitを`main`へpushする。version・manifest・workflowを含むrelease変更は未分類変更として`macos-native`、`linux-workstation`、`windows-native`の全テストへ広がり、3環境をgreenにする。
34
- 2. `npm run verify:release-commit`で対象commitが`origin/main`の祖先かつworktree cleanであることを確認する。
35
- 3. 同じcommitへ`v<version>` tagを付けてpushする。tag CIは同じcommitのmain CI成功を確認し、3環境試験を再実行せずnpmへprovenance付きでpublishする。
36
- 4. build済みMCPBを添付したGitHub Releaseを公開する。release eventがOfficial MCP Registry登録を起動する。
37
- 5. npm、GitHub Release、Official Registryが同じversionを返すまで確認する。
38
-
39
- CI callerは同じrepositoryの`./.github/workflows/product-full-ci.yml`だけを呼ぶ。製品側の変更影響選択、
40
- 全テストへの明示的な拡張、3環境runner、release gateを外部repositoryへ移さず、dotagentsの変更や停止からAitermの受入を独立させる。
35
+ 同じversionのtagやnpm packageを移動・上書きしない。失敗版はそのまま残し、修正版を次のversionで出す。
41
36
 
42
37
  ## 公開後smoke
43
38
 
44
- 公式npm packageを隔離またはglobal installし、次を確認する。
45
-
46
- - `aiterm-mcp`、`aiterm-wait`、`aiterm-runtime-errors`の3 bins。
47
- - MCP initializeのversion、16 tools、stderr 0。
48
- - POSIXはtmux、Windows nativeはpsmux 3.3.8以上とPowerShell 7。
49
- - 変更に触れたharnessの起動、non-blocking dispatch、wait outcome、transcript回収、`pty_close`後の残骸ゼロ。
50
- - Official Registryが`io.github.kitepon/aiterm-mcp`の同じversionをactive/latestとして返す。
39
+ 公式npm packageを隔離またはglobal installし、変更に触れたharnessの起動、non-blocking dispatch、wait outcome、
40
+ transcript回収、`pty_close`後の残骸ゼロを確認する。
51
41
 
52
42
  ## 利用者の更新と巻き戻し
53
43
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiterm-mcp",
3
- "version": "0.29.29",
3
+ "version": "0.29.31",
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": [
@@ -60,6 +60,7 @@
60
60
  "build": "node scripts/clean-build.mjs && tsc",
61
61
  "mcpb:build": "npm run build && node scripts/build-mcpb.mjs && npm ci --omit=dev --ignore-scripts --no-audit --no-fund --prefix dist/mcpb-stage/server && npx --yes @anthropic-ai/mcpb@2.1.2 validate dist/mcpb-stage/manifest.json && npx --yes @anthropic-ai/mcpb@2.1.2 pack dist/mcpb-stage dist/aiterm-mcp.mcpb",
62
62
  "verify:release-commit": "node scripts/verify-release-commit.mjs",
63
+ "release": "node scripts/release.mjs",
63
64
  "test:docs": "node --test test/repository-contract.test.mjs",
64
65
  "prepublishOnly": "npm run verify:release-commit && npm run build",
65
66
  "start": "node dist/index.js",