aiterm-mcp 0.41.0 → 0.41.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,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.41.1] - 2026-09-27
11
+
12
+ ### 修正
13
+
14
+ - CodexとCursorの回答回収(`pty_read(agent_transcript:true)`と親への自動配送)が、作業途中の報告を回答の前につないで返していた。Codexはturnのassistant本文を`phase`を見ずに全部つなぎ、Cursorは道具呼び出しの前に書いた文も含めていた。Codexは`phase=final_answer`の本文だけを、Cursorは最後の道具呼び出しより後の本文だけを返す。`phase`の無い旧形式のCodex記録と、道具呼び出し後に本文の無いCursorのturnは従来どおり扱う。Claude CodeとGrokは元から最後の回答だけを返している。
15
+
10
16
  ## [0.41.0] - 2026-09-27
11
17
 
12
18
  ### 削除
@@ -1810,7 +1816,8 @@ prototype (preserved under `prototype/python/` as the porting source and referen
1810
1816
  `ubuntu-latest` for Node 18/20/22, publishing to npm on `v*` tags with
1811
1817
  provenance.
1812
1818
 
1813
- [Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.41.0...HEAD
1819
+ [Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.41.1...HEAD
1820
+ [0.41.1]: https://github.com/kitepon/aiterm-mcp/compare/v0.41.0...v0.41.1
1814
1821
  [0.41.0]: https://github.com/kitepon/aiterm-mcp/compare/v0.40.3...v0.41.0
1815
1822
  [0.40.3]: https://github.com/kitepon/aiterm-mcp/compare/v0.40.2...v0.40.3
1816
1823
  [0.40.2]: https://github.com/kitepon/aiterm-mcp/compare/v0.40.1...v0.40.2
package/README.ja.md CHANGED
@@ -203,7 +203,7 @@ runtime-error store は canonical dotagents config の `collection.enabled: true
203
203
  場合だけ収集し、既定OFF、network送信は行いません。tag起点CIのnpm provenance(OIDC Trusted
204
204
  Publishing)で公開し、GitHub Release が Official MCP Registry を再登録します。
205
205
 
206
- **状態:** 開発継続中 · 現行公開版 **v0.41.0** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
206
+ **状態:** 開発継続中 · 現行公開版 **v0.41.1** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
207
207
 
208
208
  ### 更新と巻き戻し
209
209
 
package/README.md CHANGED
@@ -217,7 +217,7 @@ collection is off by default and performs no network I/O. It ships via
217
217
  tag-triggered CI with npm provenance (OIDC Trusted Publishing); the GitHub
218
218
  Release re-registers the Official MCP Registry entry.
219
219
 
220
- **Status:** actively maintained · current public release **v0.41.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).
220
+ **Status:** actively maintained · current public release **v0.41.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).
221
221
 
222
222
  ### Update and rollback
223
223
 
@@ -588,7 +588,7 @@ export function codexTranscriptText(meta, turnId, readTranscriptLines, transcrip
588
588
  const lines = readTranscriptLines(transcript);
589
589
  if (exactCompletion) {
590
590
  // 同じturnの本文だけを使う。完了event内の本文と、turn ID付きoutput_textの両形式を扱う。
591
- const matching = [];
591
+ const matching = codexTurnAnswer();
592
592
  for (const line of lines) {
593
593
  let record;
594
594
  try {
@@ -598,24 +598,19 @@ export function codexTranscriptText(meta, turnId, readTranscriptLines, transcrip
598
598
  continue;
599
599
  }
600
600
  const payload = record?.payload;
601
- if (record?.type === "response_item" && payload?.type === "message" && payload?.role === "assistant"
602
- && payload?.internal_chat_message_metadata_passthrough?.turn_id === turnId && Array.isArray(payload?.content)) {
603
- for (const item of payload.content) {
604
- if (item?.type === "output_text" && typeof item.text === "string")
605
- matching.push(item.text);
606
- }
607
- }
601
+ matching.add(record, turnId);
608
602
  if (record?.type === "event_msg" && payload?.type === "task_complete" && payload.turn_id === turnId) {
609
603
  if (typeof payload.last_agent_message === "string")
610
604
  return payload.last_agent_message;
611
- if (matching.length > 0)
612
- return matching.join("\n");
605
+ const text = matching.text();
606
+ if (text)
607
+ return text;
613
608
  transcriptUnavailable();
614
609
  }
615
610
  }
616
611
  transcriptUnavailable();
617
612
  }
618
- const matching = [];
613
+ const matching = codexTurnAnswer();
619
614
  let finalAnswer = "";
620
615
  for (const line of lines) {
621
616
  if (!line.trim())
@@ -628,16 +623,7 @@ export function codexTranscriptText(meta, turnId, readTranscriptLines, transcrip
628
623
  continue;
629
624
  }
630
625
  const payload = record?.payload;
631
- if (record?.type === "response_item" &&
632
- payload?.type === "message" &&
633
- payload?.role === "assistant" &&
634
- payload?.internal_chat_message_metadata_passthrough?.turn_id === turnId &&
635
- Array.isArray(payload?.content)) {
636
- for (const item of payload.content) {
637
- if (item?.type === "output_text" && typeof item.text === "string")
638
- matching.push(item.text);
639
- }
640
- }
626
+ matching.add(record, turnId);
641
627
  if (record?.type === "event_msg" &&
642
628
  payload?.type === "agent_message" &&
643
629
  payload?.phase === "final_answer" &&
@@ -645,7 +631,31 @@ export function codexTranscriptText(meta, turnId, readTranscriptLines, transcrip
645
631
  finalAnswer = payload.message;
646
632
  }
647
633
  }
648
- return matching.join("\n") || finalAnswer;
634
+ return matching.text() || finalAnswer;
635
+ }
636
+ // turnのassistant本文を集める。Codexは作業途中の報告をphase=commentary、回答をphase=final_answerで残すので、
637
+ // final_answerがあるturnは途中の報告を回答に含めない。phaseの無い旧形式はturnの本文を全部つなぐ。
638
+ function codexTurnAnswer() {
639
+ const all = [];
640
+ const finals = [];
641
+ return {
642
+ add(record, turnId) {
643
+ const payload = record?.payload;
644
+ if (record?.type !== "response_item" || payload?.type !== "message" || payload?.role !== "assistant"
645
+ || payload?.internal_chat_message_metadata_passthrough?.turn_id !== turnId || !Array.isArray(payload?.content))
646
+ return;
647
+ for (const item of payload.content) {
648
+ if (item?.type !== "output_text" || typeof item.text !== "string")
649
+ continue;
650
+ all.push(item.text);
651
+ if (payload.phase === "final_answer")
652
+ finals.push(item.text);
653
+ }
654
+ },
655
+ text() {
656
+ return (finals.length > 0 ? finals : all).join("\n");
657
+ },
658
+ };
649
659
  }
650
660
  export function createCodexAgentMetadata(name, cwd, initialPrompt, overrides = {}, writeScope, lineageContext) {
651
661
  const launchId = randomBytes(16).toString("hex");
@@ -235,7 +235,8 @@ export function cursorTranscriptText(meta, readTranscriptLines, transcriptUnavai
235
235
  const transcript = cursorTranscript(meta);
236
236
  if (!transcript)
237
237
  transcriptUnavailable();
238
- let current = [];
238
+ // tool_useで区切った本文の塊を持つ。道具を呼ぶ前の文は作業途中の報告なので、回答は最後の塊だけにする。
239
+ let current = [[]];
239
240
  let completed = null;
240
241
  for (const line of readTranscriptLines(transcript)) {
241
242
  if (!line.trim())
@@ -248,19 +249,21 @@ export function cursorTranscriptText(meta, readTranscriptLines, transcriptUnavai
248
249
  continue;
249
250
  }
250
251
  if (record?.role === "user")
251
- current = [];
252
+ current = [[]];
252
253
  if (record?.role === "assistant" && Array.isArray(record?.message?.content)) {
253
254
  for (const part of record.message.content) {
254
255
  if (part?.type === "text" && typeof part?.text === "string")
255
- current.push(part.text);
256
+ current.at(-1).push(part.text);
257
+ else if (part?.type === "tool_use" && current.at(-1).length > 0)
258
+ current.push([]);
256
259
  }
257
260
  }
258
261
  if (record?.type === "turn_ended")
259
- completed = [...current];
262
+ completed = current.map((chunk) => [...chunk]);
260
263
  }
261
264
  if (completed === null)
262
265
  transcriptUnavailable();
263
- return completed.join("\n");
266
+ return (completed.filter((chunk) => chunk.length > 0).at(-1) ?? []).join("\n");
264
267
  }
265
268
  export function createCursorAgentMetadata(name, cwd, initialPrompt, writeScope, lineage) {
266
269
  const launchId = randomBytes(16).toString("hex");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiterm-mcp",
3
- "version": "0.41.0",
3
+ "version": "0.41.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": [