aiterm-mcp 0.57.0 → 0.57.2
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 +44 -1
- package/README.ja.md +6 -1
- package/README.md +6 -1
- package/dist/core.js +117 -5
- package/dist/harnesses/codex.js +52 -20
- package/dist/harnesses/cursor.js +1 -0
- package/dist/harnesses/grok.js +1 -0
- package/dist/interim-words.js +4 -2
- package/docs/DESIGN.md +14 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,47 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.57.2] - 2026-10-07
|
|
11
|
+
|
|
12
|
+
### 修正
|
|
13
|
+
|
|
14
|
+
- Codexのturnがサービスの誤りや通信の失敗(HTTP 500・401・途中で切れる応答など)で終わった時、完了待ちが`done`・空の回答を返していた件を直す(ADR 0103)。
|
|
15
|
+
Codexは、この時も記録へ`task_complete`を書く(回答は無く、`error`が付く)。Aitermは利用上限だけを`rate_limited`に分けていたので、
|
|
16
|
+
ほかの失敗は、呼んだ側に、空の回答の完了として届いていた。
|
|
17
|
+
- 完了待ちは`outcome: "error"`を返す。`aiterm-wait`はexit 7、親への配送は`outcome=error`。
|
|
18
|
+
- `error`は、応答の本文とURLを落とした1行の文にする(例「unexpected status 401 Unauthorized」)。
|
|
19
|
+
- Codexが記録した種類(`internal_server_error`・`http_connection_failed`など)を、新しい項目`error_kind`で返す。ほかの席と、`error`でない返りでは`null`。
|
|
20
|
+
- 合間の言葉(`kind: "error"`)も、利用上限のほかは同じ1行にする。
|
|
21
|
+
- 引数、`done`と`rate_limited`の返り、断りの文面、Claude Code・Grok・Cursorの席は変えていない。
|
|
22
|
+
|
|
23
|
+
### 文書
|
|
24
|
+
|
|
25
|
+
- 通信の失敗・取消・待ちの時間切れを実行時エラーとして記録しない事と、重さの決め方を、決まりとして書く(ADR 0102)。動きは変えない。
|
|
26
|
+
|
|
27
|
+
## [0.57.1] - 2026-10-07
|
|
28
|
+
|
|
29
|
+
### 修正
|
|
30
|
+
|
|
31
|
+
- Windowsで、`pty_close`されたClaude Codeが会話終了のhook(SessionEnd)を走らせない件を直す(ADR 0100)。psmuxは、sessionを止める時に
|
|
32
|
+
画面のprocessへ切断の合図を送らない(POSIXのtmuxは送る)。
|
|
33
|
+
- WindowsのClaude Codeの席を閉じる時、止める前にC-cを間を空けずに2回送り、Claude Codeが自分で終わるのを最大4秒待つ。
|
|
34
|
+
動いている番の席へは、先にC-cを1回送って入力待ちに戻るのを最大1.5秒待つ。終わらなくても、その後は今までどおり止める。
|
|
35
|
+
- `pty_close`は、WindowsのClaude Codeの席でだけ遅くなる(実物で、入力待ちの席は約2.3秒、動いている番の席は約3.2秒)。
|
|
36
|
+
- Linux・macOS、Codex・Grok・Cursorの席、返りの形は変わらない。
|
|
37
|
+
- Codexが回答を流している間に届いた文を、新しいturnでなく差し込み(`mode: agent_steer`)として返す(ADR 0101)。Codex(0.160.1)は
|
|
38
|
+
回答を流している間、画面に動作中の行を出さない。今までは「入力待ち」と読んで新しいturnとして返し、Codexはその文を動いている
|
|
39
|
+
turnへ取り込むので、同じ1つの回答が2回の完了として届いていた(親への配送があれば2通)。
|
|
40
|
+
- 画面に入力欄が見え、この起動の記録(rollout)の最後の境界がturnの開始で、Codexのprocessが生きていて、0.4秒おいて見直しても
|
|
41
|
+
記録が同じturnの開始のままで画面が動いている時だけ、動いていると数える。1つでも欠けたら、今までどおり新しいturnで返す。
|
|
42
|
+
- その間に届いた文の受け付けは、5.6秒から約0.8秒になる(入力受付の11回の確かめを通らない。Windowsは約2秒)。
|
|
43
|
+
- 引数・返りの形・断りの文面、Claude Code・Grok・Cursorの席、画面に動作中の行が出ている時の動きは変わらない。
|
|
44
|
+
- 配送パッケージ`aiterm-steer-delivery`を0.3.1へ上げる。
|
|
45
|
+
- Codexの親配送の登録(`aiterm-setup --codex-steer enable`、`ensureCodexParentSteer`)が、登録の間に終わったCodexを、再起動待ちの記録
|
|
46
|
+
(`stale_processes`)へ残さない。ほかの導入が設定のために一時的に起こして止めたCodexが、止まり切る前の一覧に載って残っていた。
|
|
47
|
+
居ないprocessは照合で当たらないので、配送は止まっていなかった。
|
|
48
|
+
- Codexを起こす時、PATHにnodeの場所が無ければ足す。0.56.1で`aiterm-parent-delivery`が自分でしていた事を、MCPの本体からCodexを
|
|
49
|
+
起こす所(認証の確かめ、model一覧、親配送)にも広げる。
|
|
50
|
+
|
|
10
51
|
## [0.57.0] - 2026-10-07
|
|
11
52
|
|
|
12
53
|
### 追加
|
|
@@ -2356,7 +2397,9 @@ prototype (preserved under `prototype/python/` as the porting source and referen
|
|
|
2356
2397
|
`ubuntu-latest` for Node 18/20/22, publishing to npm on `v*` tags with
|
|
2357
2398
|
provenance.
|
|
2358
2399
|
|
|
2359
|
-
[Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.57.
|
|
2400
|
+
[Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.57.2...HEAD
|
|
2401
|
+
[0.57.2]: https://github.com/kitepon/aiterm-mcp/compare/v0.57.1...v0.57.2
|
|
2402
|
+
[0.57.1]: https://github.com/kitepon/aiterm-mcp/compare/v0.57.0...v0.57.1
|
|
2360
2403
|
[0.57.0]: https://github.com/kitepon/aiterm-mcp/compare/v0.56.1...v0.57.0
|
|
2361
2404
|
[0.56.1]: https://github.com/kitepon/aiterm-mcp/compare/v0.56.0...v0.56.1
|
|
2362
2405
|
[0.56.0]: https://github.com/kitepon/aiterm-mcp/compare/v0.55.4...v0.56.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.57.
|
|
212
|
+
**状態:** 開発継続中 · 現行公開版 **v0.57.2** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
|
|
213
213
|
|
|
214
214
|
### 更新と巻き戻し
|
|
215
215
|
|
|
@@ -259,6 +259,8 @@ pty_read(id, { wait: true }) → 削減済みの出力を読む(完了
|
|
|
259
259
|
|
|
260
260
|
ClaudeがAPIエラーや安全判定の拒否で終了した時は、Stop hookが発火しなくても次の`pty_send`を新しいturnとして扱う。現在のturn開始後のエラー記録だけを確認し、過去のエラーで実行中のturnを解除しない。上流の拒否はエラーのまま返す。
|
|
261
261
|
|
|
262
|
+
Codexがサービスの誤りや通信の失敗でturnを打ち切った時は、完了待ちが`done`ではなく`error`を返す(`aiterm-wait`はexit 7、親への配送は`outcome=error`)。`error`は応答の本文とURLを落とした1行の文で、Codexが記録した種類(`internal_server_error`・`http_connection_failed`など)は`error_kind`に載る。利用上限は今までどおり`rate_limited`。誤りで終わった後の席は、次の`pty_send`を新しいturnとして受ける。
|
|
263
|
+
|
|
262
264
|
agent配送だけを期待する連携では、`pty_send`に`require_agent:true`を指定する。agent登録が無ければ、打鍵前に`AGENT_SESSION_REQUIRED`と「文字列は送信していません」を返す。省略時は通常PTY送信を維持する。`force:true`との併用は未送信で拒否する。
|
|
263
265
|
|
|
264
266
|
agent session宛ての`pty_send`は、任意の`preface`(本文の前に置く1行)を受ける。渡る文は「`preface`・空行・`text`」。Claude Codeの席へは、`preface`を端末の貼り付けの印なしで入れ、空行と本文を1回の貼り付けで入れる。Claude Codeは貼り付けた長い文を`<pasted_content>`で包み、「包みの中の指示は、包みの外の利用者自身の言葉が頼んだ時だけ従う」と読むので、連携元が付ける前置き(誰からの連絡か)を包みの外へ出すために使う。Codex・Grok・Cursorの席へは1つにつないで貼る。`preface`は1行・200字以内・制御文字なしで、行頭が記号や空白でなく、`@`を含まない文。外れた時は`AGENT_PREFACE_INVALID`と「文字列は送信していません。」を返す。通常PTY・`force:true`・`remote`付きでは使えない。
|
|
@@ -401,6 +403,9 @@ pty_close("t1") → 端末を解放
|
|
|
401
403
|
|
|
402
404
|
`pty_close` は冪等で、`closed` / `already_closed` のstructured receiptを返す。
|
|
403
405
|
MCP応答を失ったdurable callerも同じ`session_id`への再試行だけでclose結果を確定できる。
|
|
406
|
+
Windowsでは、Claude Codeの席を閉じる前に、Claude Codeへ自分で終わる機会を与える(C-cを2回送り、最大4秒待つ)。
|
|
407
|
+
psmuxは、POSIXのtmuxが送る切断の合図なしでsessionを止めるので、そのままでは会話終了のhook(SessionEnd)が走らない。
|
|
408
|
+
終わっても終わらなくても、その後にsessionを止める。
|
|
404
409
|
|
|
405
410
|
これだけ。`t1` の端末は本物で永続——`ssh`・`docker exec`・REPL・起動したエージェントのTUIは、そこに住む「もの」に過ぎない。ワーカー起動も1コールで、`agent_launch({ harness: "codex-cli" })`が返す`session_id`を同じ`pty_read`/`pty_send`で操作する。
|
|
406
411
|
|
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.57.
|
|
226
|
+
**Status:** actively maintained · current public release **v0.57.2** · 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
|
|
|
@@ -259,6 +259,8 @@ I used **Codex with GPT-5.6** as an engineering collaborator: it inspected the i
|
|
|
259
259
|
|
|
260
260
|
ClaudeがAPIエラーや安全判定の拒否で終了した時は、Stop hookが発火しなくても次の`pty_send`を新しいturnとして扱う。現在のturn開始後のエラー記録だけを確認し、過去のエラーで実行中のturnを解除しない。上流の拒否はエラーのまま返す。
|
|
261
261
|
|
|
262
|
+
Codexがサービスの誤りや通信の失敗でturnを打ち切った時は、完了待ちが`done`ではなく`error`を返す(`aiterm-wait`はexit 7、親への配送は`outcome=error`)。`error`は応答の本文とURLを落とした1行の文で、Codexが記録した種類(`internal_server_error`・`http_connection_failed`など)は`error_kind`に載る。利用上限は今までどおり`rate_limited`。誤りで終わった後の席は、次の`pty_send`を新しいturnとして受ける。
|
|
263
|
+
|
|
262
264
|
## Two ways to use it
|
|
263
265
|
|
|
264
266
|
### 1. Drive SSH, containers, and REPLs in one persistent terminal — the primitive
|
|
@@ -431,6 +433,9 @@ pty_close("t1") → terminal released
|
|
|
431
433
|
|
|
432
434
|
`pty_close` is idempotent and returns a structured `closed` / `already_closed`
|
|
433
435
|
receipt, so durable callers can retry the same `session_id` after losing the MCP response.
|
|
436
|
+
On Windows, closing a Claude Code session first asks Claude Code to exit on its own (Ctrl-C twice, then a wait of up to 4 seconds)
|
|
437
|
+
so that its `SessionEnd` hooks run; psmux stops a session without the hangup signal that tmux sends on POSIX. The session is stopped
|
|
438
|
+
afterwards either way.
|
|
434
439
|
|
|
435
440
|
That's it. The terminal in `t1` is real and persistent — `ssh`, `docker exec`, a REPL, or a launched agent's TUI are just things that live inside it. To launch a worker agent instead, one call does it: `agent_launch({ harness: "codex-cli" })` returns a `session_id` you drive with the same `pty_read` / `pty_send`.
|
|
436
441
|
|
package/dist/core.js
CHANGED
|
@@ -22,7 +22,7 @@ import { isWin, SOCKDIR, tmuxCommand, sendPsmuxPayload, loadPtyBufferChunk, past
|
|
|
22
22
|
import { sleep, currentUid, runtimeStateBase, safeStatSize, readFileRange, writeJson0600, createEmpty0600, shq, LAUNCH_ID_RE, AGENT_DONE_POLL_MS, AGENT_RATE_LIMIT_POLL_MS, pollGate, AGENT_EVENT_MAX_BYTES, assertSessionName, agentsDir, agentEventPath, agentMetadataPath, writeAgentMetadata, AGENT_EVENT_TAIL_BYTES, agentLabel, agentHarness, subagentInstruction, agentLineageFields, } from "./agent-shared.js";
|
|
23
23
|
import { catalogUnavailable } from "./model-catalog.js";
|
|
24
24
|
import { grokAuthPlan, grokAuthStatus, grokAuthPane, realGrokHome, resolveAndValidateGrokAuth, assertGrokModelAvailable, grokModelChoices, grokEventsTranscript, latestGrokCompletion, grokTurnSettled, observeGrokDone, buildGrokAgentCmd, grokLaunchNote, grokEnvTokens, grokTuiReady, grokTuiBusy, grokPaneObservation, grokRateLimitDialog, grokStartupAction, grokLaunchBlockingDialog, assertGrokSandboxNotRejected, GROK_COMPOSER_MARKER_RE, grokFooterHasConfiguration, grokTranscriptText, createGrokAgentMetadata, } from "./harnesses/grok.js";
|
|
25
|
-
import { codexAuthPlan, codexAuthStatus, codexAuthPane, bindCodexTranscriptSession, latestCodexCompletion, codexTurnSettled, observeCodexDone, buildCodexAgentCmd, codexLaunchNote, codexTuiReady, codexPaneObservation, codexTuiBusy, codexHelperProcess, codexRateLimitModelSwitchDialog, codexApprovalDialog, codexStartupAction, CODEX_COMPOSER_MARKER_RE, codexModelChoice, codexEffortChoice, codexMoreReasoningChoice, codexTranscriptText, createCodexAgentMetadata, codexModelChoices, } from "./harnesses/codex.js";
|
|
25
|
+
import { codexAuthPlan, codexAuthStatus, codexAuthPane, bindCodexTranscriptSession, latestCodexCompletion, codexTurnSettled, codexRunningTurn, observeCodexDone, buildCodexAgentCmd, codexLaunchNote, codexTuiReady, codexPaneObservation, codexTuiBusy, codexHelperProcess, codexRateLimitModelSwitchDialog, codexApprovalDialog, codexStartupAction, CODEX_COMPOSER_MARKER_RE, codexModelChoice, codexEffortChoice, codexMoreReasoningChoice, codexTranscriptText, createCodexAgentMetadata, codexModelChoices, } from "./harnesses/codex.js";
|
|
26
26
|
import { claudeAuthPlan, claudeAuthStatus, claudeAuthPane, OPERATION_ID_RE, CLAUDE_RESULT_MAX_BYTES, CLAUDE_EFFORTS, agentManagedClaudeSettingsPath, agentClaudeResultPath, agentClaudeOperationPath, agentClaudeApprovalReceiptPath, agentClaudeDispatchReceiptPath, validateOperationId, readClaudeResultText, assertClaudeAuthenticationReady, claudeModelChoices, buildClaudeAgentCmd, claudeLaunchNote, claudeTuiReady, claudePaneObservation, claudeUsageLimit, claudeStartupAction, claudeLoginMethodMenu, CLAUDE_COMPOSER_MARKER_RE, createClaudeAgentMetadata, claudeSessionTranscriptPath, claudeApiErrorFromLine, claudeApiErrorAfter, } from "./harnesses/claude.js";
|
|
27
27
|
import { cursorAuthPlan, cursorAuthStatus, cursorAuthPane, bindCursorTranscriptSession, cursorTurnBoundary, latestCursorCompletion, observeCursorDone, cursorTranscriptText, assertCursorAuthenticationReady, assertCursorModelAvailable, cursorModelChoices, buildCursorAgentCmd, cursorAgentArgv, cursorPwshLaunchLine, cursorPromptWithLineage, createCursorAgentMetadata, cursorLaunchNote, cursorEffortNavigation, cursorTuiReady, cursorPaneObservation, cursorPromptHooksRunning, cursorUsageLimit, CURSOR_SUBMIT_SEQUENCE, CURSOR_COMPOSER_CONTENT_MARKER_RE, validateCursorModelEffort, } from "./harnesses/cursor.js";
|
|
28
28
|
import { readInterimWords, recordInterimBoundary } from "./interim-words.js";
|
|
@@ -1386,8 +1386,8 @@ export function readOnlyPtyListDiagnostic(runTmux = tmux) {
|
|
|
1386
1386
|
}
|
|
1387
1387
|
return { status: "unverified", session_count: null };
|
|
1388
1388
|
}
|
|
1389
|
-
|
|
1390
|
-
|
|
1389
|
+
/** 別processが待機中・送信中のsessionは閉じない。閉じる前の操作(下のClaude Codeへの終了の鍵)より先に確かめる。 */
|
|
1390
|
+
function assertSessionClosable(name) {
|
|
1391
1391
|
{
|
|
1392
1392
|
// 別プロセスの待機は in-memory Set に映らない。生きた file lock があれば close で state を消さない
|
|
1393
1393
|
const foreign = liveWaitLocks(name);
|
|
@@ -1403,6 +1403,80 @@ function closeSessionInternal(name, observeDependency = true) {
|
|
|
1403
1403
|
throw new AitermError(`session '${name}' は別プロセス${d.pid != null ? `(pid ${d.pid})` : ""}の送信中のため close できません`, 2);
|
|
1404
1404
|
}
|
|
1405
1405
|
}
|
|
1406
|
+
}
|
|
1407
|
+
// Windowsのpsmuxは、sessionを止める時に画面のprocessへ切断の合図を送らない(POSIXのtmuxはSIGHUPを送り、Claude Codeは
|
|
1408
|
+
// 片付けて終わる)。合図なしで止められたClaude Codeは、会話終了のhook(SessionEnd)を走らせない。
|
|
1409
|
+
// 止める前に、Claude Codeへ自分で終わる機会を与える(ADR 0100)。
|
|
1410
|
+
// 動いている番を止めた後、入力待ちに戻るのを待つ上限。
|
|
1411
|
+
const CLAUDE_EXIT_INTERRUPT_WAIT_MS = 1500;
|
|
1412
|
+
// 終了の受付(「Press Ctrl-C again to exit」)は短い。実物では、間が0.3〜0.7秒の2回は通り、2.2秒の2回は切れた。
|
|
1413
|
+
const CLAUDE_EXIT_KEY_GAP_MS = 200;
|
|
1414
|
+
// 2回目の後、会話終了のhookを走らせて終わるのを待つ上限。実物(fox)では、hookが走ったのは2回目の約1秒後で、processはその
|
|
1415
|
+
// 0.2〜0.3秒後に終わった。hookが遅い端末でも走り切れるように、余りを取る。
|
|
1416
|
+
const CLAUDE_EXIT_WAIT_MS = 4000;
|
|
1417
|
+
const CLAUDE_EXIT_POLL_MS = 100;
|
|
1418
|
+
/**
|
|
1419
|
+
* Claude Codeへ終了を頼む鍵と待ちの順番。
|
|
1420
|
+
* 入力待ちでない席(動いている番など)へは、先にC-cを1回送って入力待ちに戻るのを待つ(そのC-cは番を止めるのに使われ、
|
|
1421
|
+
* 終了の受付にならない)。その後、C-cを間を空けずに2回送り、processが終わるのを待つ。
|
|
1422
|
+
* 終わらなかった時も、呼ぶ側は今までどおりsessionを止める。
|
|
1423
|
+
*/
|
|
1424
|
+
export function requestClaudeExit(steps) {
|
|
1425
|
+
if (!steps.idle()) {
|
|
1426
|
+
steps.interrupt();
|
|
1427
|
+
const until = steps.now() + CLAUDE_EXIT_INTERRUPT_WAIT_MS;
|
|
1428
|
+
while (!steps.idle() && steps.now() < until)
|
|
1429
|
+
steps.pause(CLAUDE_EXIT_POLL_MS);
|
|
1430
|
+
}
|
|
1431
|
+
steps.interrupt();
|
|
1432
|
+
steps.pause(CLAUDE_EXIT_KEY_GAP_MS);
|
|
1433
|
+
steps.interrupt();
|
|
1434
|
+
const until = steps.now() + CLAUDE_EXIT_WAIT_MS;
|
|
1435
|
+
for (;;) {
|
|
1436
|
+
if (!steps.alive())
|
|
1437
|
+
return "exited";
|
|
1438
|
+
if (steps.now() >= until)
|
|
1439
|
+
return "still_running";
|
|
1440
|
+
steps.pause(CLAUDE_EXIT_POLL_MS);
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
let claudeExitBeforeCloseTestOverride = null;
|
|
1444
|
+
/** 試験用: POSIXでも、閉じる前にClaude Codeへ終了を頼む(nullで既定へ戻す)。 */
|
|
1445
|
+
export function __testSetClaudeExitBeforeClose(value) {
|
|
1446
|
+
claudeExitBeforeCloseTestOverride = value;
|
|
1447
|
+
}
|
|
1448
|
+
/**
|
|
1449
|
+
* 閉じる席がWindowsのClaude Codeで、processが生きている時だけ、止める前に終了を頼む。
|
|
1450
|
+
* 待ちは同期のまま(最大で数秒)。待つ間にほかの呼び出しを通すと、閉じかけの席へ送信が入る。
|
|
1451
|
+
* 席の観測や鍵の送信に失敗した時は、何もせずに今までどおり止める(閉じる事を妨げない)。
|
|
1452
|
+
*/
|
|
1453
|
+
function letClaudeExitBeforeClose(name) {
|
|
1454
|
+
if (!(claudeExitBeforeCloseTestOverride ?? isWin))
|
|
1455
|
+
return;
|
|
1456
|
+
try {
|
|
1457
|
+
if (tryLoadAgentMetadata(name)?.kind !== "claude" || !sessionExists(name))
|
|
1458
|
+
return;
|
|
1459
|
+
const seen = observeSession(name);
|
|
1460
|
+
if (seen.harness_alive !== true)
|
|
1461
|
+
return;
|
|
1462
|
+
const harness = seen.harness_process;
|
|
1463
|
+
const pause = new Int32Array(new SharedArrayBuffer(4));
|
|
1464
|
+
requestClaudeExit({
|
|
1465
|
+
idle: () => claudePaneObservation(captureScreen(name, AGENT_TUI_READY_LINES)).state === "idle",
|
|
1466
|
+
interrupt: () => { tmux("send-keys", "-t", name, "C-c"); },
|
|
1467
|
+
// processが1つに決まらない席は、席の観測で見る(Windowsではprocessの一覧を引くので遅い)。
|
|
1468
|
+
alive: () => harness ? isPidAlive(harness.pid) : observeSession(name).harness_alive === true,
|
|
1469
|
+
pause: ms => { Atomics.wait(pause, 0, 0, ms); },
|
|
1470
|
+
now: () => performance.now(),
|
|
1471
|
+
});
|
|
1472
|
+
}
|
|
1473
|
+
catch { /* 終了を頼めなかった席は、今までどおり止める */ }
|
|
1474
|
+
}
|
|
1475
|
+
function closeSessionInternal(name, observeDependency = true, o = {}) {
|
|
1476
|
+
assertSessionName(name);
|
|
1477
|
+
assertSessionClosable(name);
|
|
1478
|
+
if (o.letHarnessExit)
|
|
1479
|
+
letClaudeExitBeforeClose(name);
|
|
1406
1480
|
(observeDependency ? tmux : tmuxCleanup)("kill-session", "-t", name);
|
|
1407
1481
|
for (const p of [logpath(name), offsetpath(name), lastcmdpath(name), markpath(name), sendLockPath(name)]) {
|
|
1408
1482
|
try {
|
|
@@ -1430,7 +1504,7 @@ export function closeSession(name) {
|
|
|
1430
1504
|
export function closeSessionResult(name) {
|
|
1431
1505
|
assertSessionName(name);
|
|
1432
1506
|
const existed = sessionExists(name);
|
|
1433
|
-
closeSessionInternal(name, true);
|
|
1507
|
+
closeSessionInternal(name, true, { letHarnessExit: true });
|
|
1434
1508
|
return {
|
|
1435
1509
|
schema: "aiterm.pty-close-result.v1",
|
|
1436
1510
|
session_id: name,
|
|
@@ -3084,6 +3158,7 @@ export async function observeAgentDone(name, o = {}) {
|
|
|
3084
3158
|
at: ev?.at ?? apiError?.at ?? null,
|
|
3085
3159
|
rate_limit: rateLimit,
|
|
3086
3160
|
error: apiError?.text ?? null,
|
|
3161
|
+
error_kind: null,
|
|
3087
3162
|
});
|
|
3088
3163
|
for (;;) {
|
|
3089
3164
|
o.signal?.throwIfAborted();
|
|
@@ -4396,6 +4471,39 @@ async function waitSteerScreen(name, predicate, stillRunning) {
|
|
|
4396
4471
|
export function __testSteerQueued(kind, screen) {
|
|
4397
4472
|
return kind === "cursor" ? cursorSteerQueued(screen) : grokSteerQueued(screen);
|
|
4398
4473
|
}
|
|
4474
|
+
// 記録の上でturnが動いている席を、間を置いて見直すまでの待ち。回答を流している画面は、この間に必ず動く(実測で0.15秒ごと)。
|
|
4475
|
+
const CODEX_RECORD_RUNNING_CONFIRM_MS = 400;
|
|
4476
|
+
/**
|
|
4477
|
+
* Codexの席で、画面は入力待ちに見えるが、記録の上ではturnが動いているか(回答を流している間。Codex 0.160.1は、その間
|
|
4478
|
+
* 動作中の行を出さない)。
|
|
4479
|
+
* 止まっている席を動いていると読むと、文は新しいturnになるのに差し込みとして返り、その完了を誰も待たない。
|
|
4480
|
+
* 読み違えない方へ倒し、次を全部満たす時だけtrueにする。1つでも欠けたら、今までどおり新しいturnの道へ回す。
|
|
4481
|
+
* - 画面に入力欄が見えている(承認などの画面は、新しいturnの道が今までどおり打鍵前に断る)。
|
|
4482
|
+
* - この起動の記録の最後の境界がturnの開始で、harnessのprocessが生きている(Codexは、生きている間はturnの終わりを必ず書く)。
|
|
4483
|
+
* - 間を置いて見直しても、記録は同じturnの開始のままで、画面が動いている(止まっている席の画面は動かない)。
|
|
4484
|
+
*/
|
|
4485
|
+
async function codexTurnRunningBehindIdleScreen(name, meta, screen) {
|
|
4486
|
+
try {
|
|
4487
|
+
if (!isAgentTuiIdleReady("codex", screen))
|
|
4488
|
+
return false;
|
|
4489
|
+
const turn = codexRunningTurn(meta);
|
|
4490
|
+
if (turn === null)
|
|
4491
|
+
return false;
|
|
4492
|
+
if (observeSession(name).harness_alive !== true)
|
|
4493
|
+
return false;
|
|
4494
|
+
await sleep(CODEX_RECORD_RUNNING_CONFIRM_MS);
|
|
4495
|
+
const later = captureScreen(name, AGENT_TUI_READY_LINES);
|
|
4496
|
+
if (codexRunningTurn(meta) !== turn)
|
|
4497
|
+
return false;
|
|
4498
|
+
// 見直す間に動作中の行が出た時は、画面の読みでも動いている。
|
|
4499
|
+
if (isAgentTuiBusy("codex", later))
|
|
4500
|
+
return true;
|
|
4501
|
+
return later !== screen && isAgentTuiIdleReady("codex", later);
|
|
4502
|
+
}
|
|
4503
|
+
catch {
|
|
4504
|
+
return false; /* 読めない時は、動いていると数えない */
|
|
4505
|
+
}
|
|
4506
|
+
}
|
|
4399
4507
|
/**
|
|
4400
4508
|
* agent sessionへの唯一の送信口。呼び出し側は子の状態を知らないまま呼び、Aitermがこの時点の画面で振り分ける。
|
|
4401
4509
|
* 実行中なら現在のturnへ差し込み(steer)、そうでなければ新しいturnとしてdispatchする。
|
|
@@ -4414,7 +4522,8 @@ async function sendAgentMessageInLock(name, text, o) {
|
|
|
4414
4522
|
const meta = loadAgentMetadata(name);
|
|
4415
4523
|
// 前面回復は busy 判定より先(bash 前面のままだと画面の実行中マーカーを読んでも打鍵が届かない)。
|
|
4416
4524
|
const paneInputRecovery = await ensureAgentOwnsPaneInput(name, meta.kind);
|
|
4417
|
-
|
|
4525
|
+
const screen = captureScreen(name, AGENT_TUI_READY_LINES);
|
|
4526
|
+
let running = isAgentTuiBusy(meta.kind, screen);
|
|
4418
4527
|
// Claudeのtool処理中は画面のbusy表示が消えることがある。Stopまで保持するturnの印を正とし、
|
|
4419
4528
|
// APIエラーでStopが来なかった印は、会話記録の終了時刻を確認して消す。
|
|
4420
4529
|
// 有効な印がある間は差し込み、終了後は画面にbusy表示が残っても新しいturnとして送る。
|
|
@@ -4427,6 +4536,9 @@ async function sendAgentMessageInLock(name, text, o) {
|
|
|
4427
4536
|
// turnは終わっているので新しいturnとして送る。dispatchは入力を受け付けるまで待ってから送る。
|
|
4428
4537
|
if (running && meta.kind === "cursor" && latestCursorCompletion(meta, readTranscriptLines) !== null)
|
|
4429
4538
|
running = false;
|
|
4539
|
+
// Codexは回答を流している間、画面に動作中の行を出さない。その間に届いた文を、Codexは動いているturnへ取り込む(ADR 0101)。
|
|
4540
|
+
if (!running && meta.kind === "codex" && await codexTurnRunningBehindIdleScreen(name, meta, screen))
|
|
4541
|
+
running = true;
|
|
4430
4542
|
if (running) {
|
|
4431
4543
|
return steerRunningTurn(name, meta, text, { raw: o.raw, pane_input_recovery: paneInputRecovery, preface: o.preface });
|
|
4432
4544
|
}
|
package/dist/harnesses/codex.js
CHANGED
|
@@ -254,6 +254,16 @@ export function codexTurnError(record) {
|
|
|
254
254
|
return null;
|
|
255
255
|
return { message: message || info, info };
|
|
256
256
|
}
|
|
257
|
+
// 呼んだ側の画面にそのまま出る1行の文。Codexの文は、応答の本文・URLを含む事がある
|
|
258
|
+
// (実物 2026-10-07、codex 0.160.1: "unexpected status 401 Unauthorized: <応答の文>, url: http://…/v1/responses")。
|
|
259
|
+
// 「unexpected status」はHTTPの状態までで切り、ほかの文はURLを伏せる。改行は畳み、長さを切る。
|
|
260
|
+
const CODEX_ERROR_LINE_MAX = 200;
|
|
261
|
+
export function codexTurnErrorLine(error) {
|
|
262
|
+
const flat = error.message.replace(/\s+/g, " ").trim();
|
|
263
|
+
const status = /^unexpected status (\d{3}(?: [A-Za-z][A-Za-z' -]*)?)/.exec(flat);
|
|
264
|
+
const text = status ? `unexpected status ${status[1].trim()}` : flat.replace(/https?:\/\/[^\s)\]>"']+/gi, "…");
|
|
265
|
+
return text.length > CODEX_ERROR_LINE_MAX ? `${text.slice(0, CODEX_ERROR_LINE_MAX - 1)}…` : text;
|
|
266
|
+
}
|
|
257
267
|
// 利用上限はtask_completeのcodex_error_infoで見分ける。token_countのused_percentは100%のまま
|
|
258
268
|
// 返事が続くことがある(macbookの実記録で7千件以上)ので上限の印にしない。
|
|
259
269
|
// rate_limit_exceededは短い間の混雑で、Codexが自分で再試行するので上限に数えない。
|
|
@@ -262,24 +272,23 @@ export function codexUsageLimit(record) {
|
|
|
262
272
|
return error?.info === "usage_limit_exceeded" ? error.message : null;
|
|
263
273
|
}
|
|
264
274
|
/**
|
|
265
|
-
* この起動のroot rollout
|
|
266
|
-
* Codexはturnの開始でtask_started、終わりでtask_complete
|
|
267
|
-
*
|
|
268
|
-
* rolloutが無い、この起動に結び付かない、書いている途中、境界が読む範囲に無い時はfalse(分からない時は「終わった」と数えない)。
|
|
275
|
+
* この起動のroot rolloutの、末尾から見て最初のturnの境界。
|
|
276
|
+
* Codexはturnの開始でtask_started、終わりでtask_complete、止めた時はturn_aborted(reasonはinterrupted)を書く(0.160.1の実記録)。
|
|
277
|
+
* rolloutが無い、この起動に結び付かない、書いている途中、境界が読む範囲に無い時はnull。
|
|
269
278
|
*/
|
|
270
|
-
|
|
279
|
+
function codexLatestTurnBoundary(meta) {
|
|
271
280
|
let transcript;
|
|
272
281
|
try {
|
|
273
282
|
transcript = codexRootTranscript(meta);
|
|
274
283
|
}
|
|
275
284
|
catch {
|
|
276
|
-
return
|
|
285
|
+
return null;
|
|
277
286
|
}
|
|
278
287
|
if (!transcript)
|
|
279
|
-
return
|
|
288
|
+
return null;
|
|
280
289
|
const lines = readTailLinesNewestFirst(transcript, AGENT_TURN_BOUNDARY_TAIL_BYTES);
|
|
281
290
|
if (!lines)
|
|
282
|
-
return
|
|
291
|
+
return null;
|
|
283
292
|
for (const line of lines) {
|
|
284
293
|
if (!line.includes("task_started") && !line.includes("task_complete") && !line.includes("turn_aborted"))
|
|
285
294
|
continue;
|
|
@@ -288,19 +297,36 @@ export function codexTurnSettled(meta) {
|
|
|
288
297
|
record = JSON.parse(line);
|
|
289
298
|
}
|
|
290
299
|
catch {
|
|
291
|
-
return
|
|
300
|
+
return null;
|
|
292
301
|
}
|
|
293
302
|
if (record?.type !== "event_msg")
|
|
294
303
|
continue;
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
return typeof record.payload.turn_id === "string" && record.payload.turn_id !== "";
|
|
299
|
-
// 見たのはEscで止めた時の形だけ。他の理由(別のturnへの置き換え等)は、次のturnが続くかも知れないので数えない。
|
|
300
|
-
if (record?.payload?.type === "turn_aborted")
|
|
301
|
-
return record.payload.reason === "interrupted";
|
|
304
|
+
const type = record?.payload?.type;
|
|
305
|
+
if (type === "task_started" || type === "task_complete" || type === "turn_aborted")
|
|
306
|
+
return { type, turn_id: record.payload.turn_id, reason: record.payload.reason };
|
|
302
307
|
}
|
|
303
|
-
return
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* この起動のroot rolloutで、最後のturnが終わっていて、次のturnが始まっていないか。
|
|
312
|
+
* 末尾から見て最初の境界が、task_completeか、止めた時のturn_abortedの時だけtrue。
|
|
313
|
+
* rolloutが無い、この起動に結び付かない、書いている途中、境界が読む範囲に無い時はfalse(分からない時は「終わった」と数えない)。
|
|
314
|
+
*/
|
|
315
|
+
export function codexTurnSettled(meta) {
|
|
316
|
+
const boundary = codexLatestTurnBoundary(meta);
|
|
317
|
+
if (boundary?.type === "task_complete")
|
|
318
|
+
return typeof boundary.turn_id === "string" && boundary.turn_id !== "";
|
|
319
|
+
// 見たのはEscで止めた時の形だけ。他の理由(別のturnへの置き換え等)は、次のturnが続くかも知れないので数えない。
|
|
320
|
+
return boundary?.type === "turn_aborted" && boundary.reason === "interrupted";
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* この起動のroot rolloutの上で動いているturnのID。末尾から見て最初の境界がtask_startedの時だけ返す。
|
|
324
|
+
* rolloutが無い、この起動に結び付かない、書いている途中、境界が読む範囲に無い時はnull(分からない時は「動いている」と数えない)。
|
|
325
|
+
* Codexは、processが生きている間、turnの終わりを必ず書く。書かずに終わるのは落ちた時なので、呼ぶ側はprocessの生死も見る。
|
|
326
|
+
*/
|
|
327
|
+
export function codexRunningTurn(meta) {
|
|
328
|
+
const boundary = codexLatestTurnBoundary(meta);
|
|
329
|
+
return boundary?.type === "task_started" && typeof boundary.turn_id === "string" && boundary.turn_id !== "" ? boundary.turn_id : null;
|
|
304
330
|
}
|
|
305
331
|
export function latestCodexCompletion(meta, readTranscriptLines) {
|
|
306
332
|
const transcript = codexRootTranscript(meta);
|
|
@@ -330,7 +356,7 @@ export async function observeCodexDone(meta, timeout, requestedCursor, signal) {
|
|
|
330
356
|
let discardLeadingFragment = false;
|
|
331
357
|
let initializedBoundary = false;
|
|
332
358
|
const deadline = performance.now() + timeout * 1000;
|
|
333
|
-
const observation = (outcome, ev = null, rateLimit = null) => ({
|
|
359
|
+
const observation = (outcome, ev = null, rateLimit = null, failed = null) => ({
|
|
334
360
|
schema: "aiterm.agent-wait-result.v1",
|
|
335
361
|
session_id: meta.aiterm_session,
|
|
336
362
|
launch_id: meta.launch_id,
|
|
@@ -343,7 +369,8 @@ export async function observeCodexDone(meta, timeout, requestedCursor, signal) {
|
|
|
343
369
|
malformed_events: malformedEvents,
|
|
344
370
|
at: ev?.at ?? null,
|
|
345
371
|
rate_limit: rateLimit,
|
|
346
|
-
error: null,
|
|
372
|
+
error: failed ? codexTurnErrorLine(failed) : null,
|
|
373
|
+
error_kind: failed?.info ?? null,
|
|
347
374
|
});
|
|
348
375
|
for (;;) {
|
|
349
376
|
signal?.throwIfAborted();
|
|
@@ -389,7 +416,12 @@ export async function observeCodexDone(meta, timeout, requestedCursor, signal) {
|
|
|
389
416
|
// 上限の知らせはこのturnの終わりにだけ書かれる。画面やpane logの文字は、上限が明けた後も
|
|
390
417
|
// 残り、道具の出力や依頼文にも現れるので見ない(2026-09-28)。
|
|
391
418
|
const limited = codexUsageLimit(record);
|
|
392
|
-
|
|
419
|
+
if (limited)
|
|
420
|
+
return observation("rate_limited", done, limited);
|
|
421
|
+
// サービスの誤りや通信の失敗で終わったturnも、Codexはtask_completeを書く(errorつき、回答は無い)。
|
|
422
|
+
// 完了として返すと、失敗が空の回答に見える。Claude CodeのAPIエラーと同じく、typedな終了として返す(ADR 0103)。
|
|
423
|
+
const failed = codexTurnError(record);
|
|
424
|
+
return failed ? observation("error", done, null, failed) : observation("done", done);
|
|
393
425
|
}
|
|
394
426
|
}
|
|
395
427
|
catch {
|
package/dist/harnesses/cursor.js
CHANGED
package/dist/harnesses/grok.js
CHANGED
|
@@ -273,6 +273,7 @@ export async function observeGrokDone(meta, timeout, requestedCursor, detectRate
|
|
|
273
273
|
at: ev?.at ?? null,
|
|
274
274
|
rate_limit: rateLimit,
|
|
275
275
|
error: ev?.done_status === "turn_error" ? ev.reason : null,
|
|
276
|
+
error_kind: null,
|
|
276
277
|
});
|
|
277
278
|
for (;;) {
|
|
278
279
|
signal?.throwIfAborted();
|
package/dist/interim-words.js
CHANGED
|
@@ -14,7 +14,7 @@ import * as path from "node:path";
|
|
|
14
14
|
import { AitermError } from "./errors.js";
|
|
15
15
|
import { agentHarness, agentsDir, assertSessionName, LAUNCH_ID_RE, readFileRange, safeStatSize, writeJson0600, } from "./agent-shared.js";
|
|
16
16
|
import { claudeSessionTranscriptPath } from "./harnesses/claude.js";
|
|
17
|
-
import { codexRootTranscript, codexTurnError } from "./harnesses/codex.js";
|
|
17
|
+
import { codexRootTranscript, codexTurnError, codexTurnErrorLine } from "./harnesses/codex.js";
|
|
18
18
|
import { grokSessionDirectory } from "./harnesses/grok.js";
|
|
19
19
|
import { cursorTranscript } from "./harnesses/cursor.js";
|
|
20
20
|
/** BellTeamが要求の_metaへ入れる呼び手の印。値が "BellTeam" の時だけ合間の言葉を返す。 */
|
|
@@ -90,7 +90,9 @@ export function codexInterimWords(lines) {
|
|
|
90
90
|
const error = codexTurnError(record);
|
|
91
91
|
if (error) {
|
|
92
92
|
words.push({
|
|
93
|
-
|
|
93
|
+
// 利用上限はCodexの利用者向けの文をそのまま出す。ほかの誤りは、完了の返り(error)と同じ1行にする
|
|
94
|
+
// (応答の本文やURLが混ざる文があるため)。
|
|
95
|
+
text: error.info === "usage_limit_exceeded" ? error.message : codexTurnErrorLine(error),
|
|
94
96
|
kind: "error",
|
|
95
97
|
at: typeof record.timestamp === "string" ? record.timestamp : null,
|
|
96
98
|
turn_id: typeof payload.turn_id === "string" && payload.turn_id ? payload.turn_id : null,
|
package/docs/DESIGN.md
CHANGED
|
@@ -62,6 +62,14 @@ agentの席への`pty_send`は、任意の`preface`(本文の前に置く1行
|
|
|
62
62
|
ほかのharnessの席へは1つにつないで貼る。`preface`は入力欄がそのまま読むので、1行・200字以内・制御文字なし・行頭が記号や空白でない・
|
|
63
63
|
`@`を含まない文だけを通し、外れた時は打鍵前に断る。
|
|
64
64
|
|
|
65
|
+
Codexは回答を流している間、画面に動作中の行を出さない。`pty_send`の振り分けは、Codexの席に限り、画面が入力待ちでも、この起動の記録の
|
|
66
|
+
最後の境界がturnの開始で、processが生きていて、0.4秒おいて見直しても記録が同じturnのままで画面が動いている時を、動いていると数える
|
|
67
|
+
(ADR 0101)。止まっている席を動いていると読まないよう、1つでも欠けたら新しいturnの道へ回す。
|
|
68
|
+
|
|
69
|
+
Windowsの`pty_close`は、Claude Codeの席を止める前に、C-cを間を空けずに2回送って、Claude Codeが自分で終わるのを待つ(ADR 0100)。
|
|
70
|
+
psmuxは切断の合図なしでsessionを止めるので、そのままでは会話終了のhook(SessionEnd)が走らない。動いている番の席へは、先にC-cを
|
|
71
|
+
1回送って入力待ちに戻るのを待つ。待ちは同期で、上限つき。終わらなくても、その後にsessionを止める。POSIXとほかのharnessの席は変えない。
|
|
72
|
+
|
|
65
73
|
`pty_observe`は存在、pane/harnessの生存、画面状態と理由、native process identityを分ける。
|
|
66
74
|
PIDは開始識別子・argv digestと組にし、paneとharnessを同一視しない。特定できないidentityはnull。
|
|
67
75
|
同じlaunchに属するnpm shimとnative本体は、中間の非候補processも含めた祖先関係から一つの起動として扱う。
|
|
@@ -340,6 +348,10 @@ agent sessionへの送信1本を守る`<name>.agent-send.lock`は持つ時間が
|
|
|
340
348
|
終了した持ち主のpidを別のprocessが使い回すと、pidだけでは生きて見える。生きて見える持ち主は、processが始まってからの経過とlockを作ってからの時間を比べ、
|
|
341
349
|
lockより後に始まったprocessなら別人と読んで片付ける。消す役の印は、5秒より古ければ残った物と読む。`pty_close`は、どちらも片付ける。
|
|
342
350
|
|
|
351
|
+
Codexは、サービスの誤りや通信の失敗でturnを打ち切る時も、記録へ`task_complete`を書く(回答は無く、`error`が付く)。完了待ちは、
|
|
352
|
+
利用上限(`usage_limit_exceeded`)を`rate_limited`、ほかの`error`つきを`error`で返す。`error`は応答の本文とURLを落とした1行の文、
|
|
353
|
+
Codexが書いた種類は`error_kind`で返す。失敗を空の回答の完了として返さない(ADR 0103)。判定と文の整え方は`src/harnesses/codex.ts`が所有する。
|
|
354
|
+
|
|
343
355
|
Grokのread-only sandbox起動拒否は、`src/harnesses/grok.ts`の
|
|
344
356
|
`assertGrokSandboxNotRejected`がCLIのエラー表示から検出する。`src/core.ts`の共通入力受付待機は
|
|
345
357
|
Grokの場合だけこの判定を呼び、`GROK_SANDBOX_STARTUP_FAILED`で原因と未送信を返す。
|
|
@@ -382,7 +394,8 @@ Claude・Grokは2秒、Cursorは1秒に1回で、待ちに入った最初の周
|
|
|
382
394
|
`diagnostics`はread-onlyで、PTY backendとagent dependencyを検査する。runtime error aggregateは
|
|
383
395
|
製品所有のlocal stateに固定codeと集約metadataだけを保存し、既定ではnetwork I/Oを持たない。
|
|
384
396
|
BugHubへの報告は、利用者が明示して有効にし、合鍵のファイルがある端末だけが、別processで行う。
|
|
385
|
-
きっかけは記録・解決・起動・手動の4つで、定期的な見張りは置かない。受け取り済みにするのは応答の署名まで確かめた時だけ(ADR 0079
|
|
397
|
+
きっかけは記録・解決・起動・手動の4つで、定期的な見張りは置かない。受け取り済みにするのは応答の署名まで確かめた時だけ(ADR 0079)。
|
|
398
|
+
記録するのは、Aitermが動く前提が欠けた時の固定の3種類だけ。通信の失敗・取消・待ちの時間切れは記録せず、呼んだ側へ返す(ADR 0102)。工場reporterとの
|
|
386
399
|
連携は明示opt-inの任意adapterであり、未設定時もAiterm本体は単独動作する。raw error、prompt、出力、
|
|
387
400
|
transcript、path、credentialを保存・公開しない。
|
|
388
401
|
親配送hook(Claude Code・Cursor)の登録状態は`src/parent-hook-diagnostic.ts`が利用者設定の読取りだけで要約し、
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiterm-mcp",
|
|
3
|
-
"version": "0.57.
|
|
3
|
+
"version": "0.57.2",
|
|
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": [
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
},
|
|
73
73
|
"dependencies": {
|
|
74
74
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
75
|
-
"aiterm-steer-delivery": "^0.3.
|
|
75
|
+
"aiterm-steer-delivery": "^0.3.1",
|
|
76
76
|
"ws": "8.21.3",
|
|
77
77
|
"zod": "^4.4.3"
|
|
78
78
|
},
|