aiterm-mcp 0.51.0 → 0.51.1

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,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.51.1] - 2026-10-04
11
+
12
+ ### 修正
13
+
14
+ - `pty_observe`の`activity.post_startup_process_count`で、harnessが立て直した起動時のprocessを数えない(ADR 0083)。
15
+ Cursorは起動時にstdioのMCPを立て、最初のつなぎが済むと止めて立て直す。つながるのが遅いMCPがあると、立て直しが
16
+ 起動完了の後になり、何もしていない席で数が残っていた(実物で、直結3・中継ごし4)。起動時のprocessが終了していて、
17
+ 同じ親の下に同じargvで立っているprocessは、その立て直しとして扱う。その下で動くprocessは今までどおり数える。
18
+ この版より前のAitermが起動したagentは、今までどおり数える。
19
+
10
20
  ## [0.51.0] - 2026-10-04
11
21
 
12
22
  ### 追加
@@ -2050,7 +2060,8 @@ prototype (preserved under `prototype/python/` as the porting source and referen
2050
2060
  `ubuntu-latest` for Node 18/20/22, publishing to npm on `v*` tags with
2051
2061
  provenance.
2052
2062
 
2053
- [Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.51.0...HEAD
2063
+ [Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.51.1...HEAD
2064
+ [0.51.1]: https://github.com/kitepon/aiterm-mcp/compare/v0.51.0...v0.51.1
2054
2065
  [0.51.0]: https://github.com/kitepon/aiterm-mcp/compare/v0.50.0...v0.51.0
2055
2066
  [0.50.0]: https://github.com/kitepon/aiterm-mcp/compare/v0.49.0...v0.50.0
2056
2067
  [0.49.0]: https://github.com/kitepon/aiterm-mcp/compare/v0.48.0...v0.49.0
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.51.0** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
212
+ **状態:** 開発継続中 · 現行公開版 **v0.51.1** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
213
213
 
214
214
  ### 更新と巻き戻し
215
215
 
@@ -519,7 +519,8 @@ sessionへ登録する名前の配列で、`pty_list({ env_keys: ["JOB_OWNER"] }
519
519
  agent sessionを閉じると失うものは、次の2項目で分かる。`activity.post_startup_process_count`は、`agent_launch`の起動準備が
520
520
  完了した時点(初手を送る前)に居なかったprocessの数。起動直後の1分に始めた裏の作業も数える。数えないものは2つ。Codex自身の
521
521
  補助process(`codex-code-mode-host`)と、中継`mcp-lazy`の直接の子(初めて使う時に起こすMCPの本体と、先行起動の判定)。
522
- その下で動くprocessは数える。`pending_child_deliveries`は、そのsessionが親として待っていて、まだ届け終えていない
522
+ その下で動くprocessは数える。harnessが立て直した起動時のprocess(終了した起動時のprocessと同じ親の下に、同じargvで立ったもの。
523
+ つなぎ直したMCPなど)も数えない。`pending_child_deliveries`は、そのsessionが親として待っていて、まだ届け終えていない
523
524
  子の結果の数。呼び出した側が誰でも付く。どちらも、分からない時はnull(通常PTY、harnessのprocessを特定できない時。
524
525
  processの数は0.48.0以前が起動したagentも)。別端末が旧版の時は項目ごと無い。nullと項目なしは「分からない」で、0ではない。
525
526
 
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.51.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.51.1** · 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
 
@@ -552,7 +552,8 @@ Two fields tell a caller what closing an agent session would lose. `activity.pos
552
552
  processes in the session that did not exist when `agent_launch` finished startup (before the first prompt), so background work
553
553
  started in the first minute is counted too. Two kinds of process are not counted: Codex's own `codex-code-mode-host` helper, and
554
554
  the direct children of an `mcp-lazy` relay (the MCP server it starts on first use and its wake predicate). What runs below them
555
- is counted. `pending_child_deliveries`
555
+ is counted. A startup process that the harness restarted (a process with the same parent and the same arguments as a startup
556
+ process that has exited, such as a reconnected MCP server) is not counted either. `pending_child_deliveries`
556
557
  is the number of sub-agent results this session is still waiting for as a parent, whoever the caller is. Both are null when
557
558
  Aiterm cannot tell (ordinary terminals, agents launched by 0.48.0 or earlier for the process count, or an unresolved harness
558
559
  process), and may be absent when a remote host runs an older Aiterm. Treat null or absent as unknown, not as zero.
package/dist/core.js CHANGED
@@ -1077,17 +1077,53 @@ export function selectHarnessProcesses(meta, rows, subtree) {
1077
1077
  });
1078
1078
  return roots;
1079
1079
  }
1080
+ const processKey = (row) => `${row.pid}:${row.started_identity}`;
1081
+ /** 起動完了の控えに入れたprocessの、親とargvのdigest。控えた後に終了したprocessは入らない。 */
1082
+ export function startupProcessShapes(identities, rows) {
1083
+ const byPid = new Map(rows.map(row => [row.pid, row]));
1084
+ const byKey = new Map(rows.map(row => [processKey(row), row]));
1085
+ return identities.flatMap(identity => {
1086
+ const row = byKey.get(identity);
1087
+ if (!row)
1088
+ return [];
1089
+ const parent = parentProcess(row, byPid);
1090
+ return [{ identity, parent: parent ? processKey(parent) : null, argv_digest: row.argv_digest }];
1091
+ });
1092
+ }
1080
1093
  // 起動完了の控えに無いprocessの数。harnessと中継が自分のために立てるprocessは、利用者の作業ではないので数えない。
1081
1094
  // その下で動くprocessは数える。
1082
- export function postStartupProcessCount(kind, activityRows, rows, startup) {
1095
+ // harnessは起動の足場(MCP、language server)を自分で立て直す。控えた後に立て直されると、控えに無いprocessとして残る。
1096
+ // 控えの物が終了していて、同じ親の下に同じargvで立ったprocessは、その立て直しとして数えない。
1097
+ // 親も立て直されている時は、立て直された親の下を見る。終了した控え1つにつき、数えないのは1つまで。
1098
+ export function postStartupProcessCount(kind, activityRows, rows, startup, shapes = []) {
1083
1099
  const byPid = new Map(rows.map(row => [row.pid, row]));
1084
1100
  const relayChild = (row) => {
1085
1101
  const parent = parentProcess(row, byPid);
1086
1102
  return parent !== undefined && lazyRelayProcess(parent.command);
1087
1103
  };
1088
- return new Set(activityRows
1089
- .filter(row => !(kind === "codex" && codexHelperProcess(row.command)) && !relayChild(row))
1090
- .map(row => `${row.pid}:${row.started_identity}`).filter(identity => !startup.has(identity))).size;
1104
+ const present = new Set(activityRows.map(processKey));
1105
+ const added = new Map(activityRows
1106
+ .filter(row => !startup.has(processKey(row)) && !(kind === "codex" && codexHelperProcess(row.command)) && !relayChild(row))
1107
+ .map(row => [processKey(row), row]));
1108
+ const gone = shapes.filter(shape => startup.has(shape.identity) && !present.has(shape.identity));
1109
+ const replacedBy = new Map();
1110
+ for (let changed = gone.length > 0; changed;) {
1111
+ changed = false;
1112
+ for (const [key, row] of added) {
1113
+ const parent = parentProcess(row, byPid);
1114
+ if (!parent)
1115
+ continue;
1116
+ const parentKey = processKey(parent);
1117
+ const original = gone.find(shape => !replacedBy.has(shape.identity) && shape.argv_digest === row.argv_digest
1118
+ && shape.parent !== null && (shape.parent === parentKey || replacedBy.get(shape.parent) === parentKey));
1119
+ if (!original)
1120
+ continue;
1121
+ replacedBy.set(original.identity, key);
1122
+ added.delete(key);
1123
+ changed = true;
1124
+ }
1125
+ }
1126
+ return added.size;
1091
1127
  }
1092
1128
  export function observeSession(name, cursor) {
1093
1129
  assertSessionName(name);
@@ -1190,7 +1226,8 @@ export function observeSession(name, cursor) {
1190
1226
  background_cpu_seconds: Object.values(backgroundCpu).reduce((sum, cpu) => sum + cpu, 0),
1191
1227
  background_cpu_delta_seconds: comparable ? Object.entries(backgroundCpu).reduce((sum, [identity, cpu]) => sum + cpu - (previous.background_processes[identity] ?? 0), 0) : null,
1192
1228
  background_cpu_delta_complete: comparable ? Object.keys(previous.background_processes).every(identity => identity in backgroundCpu) : null,
1193
- post_startup_process_count: startup ? postStartupProcessCount(meta.kind, activityRows, rows, startup) : null,
1229
+ post_startup_process_count: startup
1230
+ ? postStartupProcessCount(meta.kind, activityRows, rows, startup, meta.startup_process_shapes) : null,
1194
1231
  };
1195
1232
  return result;
1196
1233
  }
@@ -2013,8 +2050,10 @@ function loadAgentMetadata(name) {
2013
2050
  initial_prompt_delivery: m.initial_prompt_delivery, initial_prompt_cursor: m.initial_prompt_cursor,
2014
2051
  };
2015
2052
  const executableFields = m.agent_executable === undefined ? {} : { agent_executable: m.agent_executable };
2053
+ const startupShapes = Array.isArray(m.startup_process_shapes) && m.startup_process_shapes.every((shape) => shape && typeof shape.identity === "string" && (shape.parent === null || typeof shape.parent === "string") && typeof shape.argv_digest === "string")
2054
+ ? { startup_process_shapes: m.startup_process_shapes } : {};
2016
2055
  const startupFields = Array.isArray(m.startup_processes) && m.startup_processes.every((identity) => typeof identity === "string")
2017
- ? { startup_processes: m.startup_processes } : {};
2056
+ ? { startup_processes: m.startup_processes, ...startupShapes } : {};
2018
2057
  if (m.kind === "claude") {
2019
2058
  const expectedSettings = agentManagedClaudeSettingsPath(name, m.launch_id);
2020
2059
  const expectedResult = agentClaudeResultPath(name, m.launch_id);
@@ -3235,6 +3274,7 @@ async function prepareAgentInput(name, meta, options) {
3235
3274
  // ここまでに居るprocessは起動時の足場(harness・MCP・起動時hook)。初手を送る前に控える。
3236
3275
  if (live.activity.cursor !== null) {
3237
3276
  meta.startup_processes = Object.keys(decodeActivityCursor(live.activity.cursor, name).processes);
3277
+ meta.startup_process_shapes = startupProcessShapes(meta.startup_processes, readRuntimeProcesses());
3238
3278
  writeAgentMetadata(meta);
3239
3279
  }
3240
3280
  return { status: "ready", reason: "composer_ready" };
package/docs/DESIGN.md CHANGED
@@ -55,6 +55,7 @@ POSIXの停止状態はOSのprocess表から取得し、SIGSTOP中は残画面
55
55
  sessionを閉じると失うものは数で返す(ADR 0080)。`activity.post_startup_process_count`は起動完了の時点に居なかったprocessの数、
56
56
  `pending_child_deliveries`はそのsessionが親として待つ未配送の数。数えられない時はnullで、0と区別する。
57
57
  harnessと中継が自分のために立てるprocessは数えない(Codexの`codex-code-mode-host`、中継`mcp-lazy`の直接の子。ADR 0082)。その下は数える。
58
+ harnessが同じ親の下に同じargvで立て直した起動時のprocessも数えない(ADR 0083)。
58
59
  中継の後ろで眠っている本体を配送の引き取りのために起こすかは、`aiterm-delivery-wake`が返す(ADR 0082)。
59
60
  Claude Codeの入力待ちは、起動時の見出しが取得範囲から流れ出た後も、入力欄の形(`❯`行の上下の罫線)で読む。
60
61
  画面本文とargv本文は返さず、活動cursorには画面digestとprocess別CPUだけを持たせる。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiterm-mcp",
3
- "version": "0.51.0",
3
+ "version": "0.51.1",
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": [