aiterm-mcp 0.19.2 → 0.19.3
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/README.ja.md +8 -8
- package/README.md +17 -17
- package/dist/core.js +36 -13
- package/dist/index.js +25 -12
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -20,17 +20,17 @@
|
|
|
20
20
|
>
|
|
21
21
|
> *MCP = Model Context Protocol — Claude Code のようなツールが AI に機能を差し込むためのオープン標準。*
|
|
22
22
|
|
|
23
|
+
**工場での役割:** aiterm-mcpはdotagents開発工場が管理する自作コア10製品の一つです。
|
|
24
|
+
永続PTYと外部agent実行レーンを所有し、dotagentsが製品横断の導入・統合契約を所有します。
|
|
25
|
+
|
|
23
26
|
**言葉でなく実測で:** このリポジトリ自身の 203 テストで、`pty_read` はコンテキストに載るトークンを生ログの **約 7.1 分の 1** に減らす。しかも pass/fail の判定は畳んでも残る。→ [組み込みシェルツールとの使い分け](#組み込みシェルツールとの使い分け)
|
|
24
27
|
|
|
25
28
|
13 ツール: 6 つの **PTY ツール**(`pty_open` / `pty_send` / `pty_read` / `pty_key` / `pty_close` / `pty_list`)で 1 本の永続端末を開き・操作し・読む。加えて 4 つの **エージェント起動ツール**(`claude_agent` / `codex_agent` / `grok_agent` / `composer_agent`)が別のコーディングエージェントの TUI を新しい端末の中に起動し、`claude_turn`がdurable caller向けの構造化issue/recoveryを、`claude_approval`がmanaged Claudeの相関済み承認UI中継を、`diagnostics`が安全なfactory readinessを返す。バックエンドは **tmux** なので、MCP サーバや AI クライアントが再起動してもセッションは生き残る。
|
|
26
29
|
|
|
27
|
-
**v0.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
negotiation)で包み、語中の文字化けと Enter 取り落としを抑制。初回 prompt 前の ready gate は
|
|
32
|
-
busy 表示中(esc to interrupt)の Codex/Claude を ready と数えない。
|
|
33
|
-
v0.16/0.17 以来、親エージェントは aiterm 上で一切ブロックしない:
|
|
30
|
+
**v0.19.2 を 2026-07-20 に公開。** v0.19系では相関済みmanaged Claude approval中継を追加し、
|
|
31
|
+
複数行shell配送を維持し、native Windowsのfactory diagnosticsを拡張しました。v0.18系では
|
|
32
|
+
`submit_residue`、tmux bracketed paste、busyなCodex/Claude画面をreadyと数えないgateにより
|
|
33
|
+
agent dispatchを強化しました。v0.16/0.17以来、親エージェントはaiterm上で一切ブロックしません:
|
|
34
34
|
agent session への send は常に非ブロック dispatch になり、完了待ちは `aiterm-wait` 一本
|
|
35
35
|
(exit code が receipt の outcome を映す: 0=done / 3=timeout=未完了 / 4=closed)、初回 prompt 付き
|
|
36
36
|
launch は structured receipt にコピペ可能な `wait_command` を含む。factory diagnostics と local
|
|
@@ -290,7 +290,7 @@ consumer は `aiterm-runtime-errors snapshot` を読み、durable ingestion 後
|
|
|
290
290
|
| `grok_agent` | Grok Build(xAI、既定`grok-4.5`、`model?`で上書き) | `prompt?`, `model?`, `reasoning_effort?`は非対応(指定時は明示エラー), `cwd?`, `session_name?` |
|
|
291
291
|
| `composer_agent` | Grok Build(xAI、既定`grok-composer-2.5-fast`、`model?`で上書き) | `prompt?`, `model?`, `reasoning_effort?`は非対応(指定時は明示エラー), `cwd?`, `session_name?` |
|
|
292
292
|
|
|
293
|
-
対応するCLI(`claude` / `codex` / `grok`)の導入・認証が必要。解決順は`CLAUDE_BIN` / `CODEX_BIN` / `GROK_BIN`、既定path、`PATH`。前提違反はsession作成前に明示失敗する。4 launcherすべてが同じ非ブロックdispatch契約を使い、Claude/Codexの初回promptはready gate経由で送信される。Claudeはisolated managed settingsとhook-captured resultを使い、private transcript
|
|
293
|
+
対応するCLI(`claude` / `codex` / `grok`)の導入・認証が必要。解決順は`CLAUDE_BIN` / `CODEX_BIN` / `GROK_BIN`、既定path、`PATH`。前提違反はsession作成前に明示失敗する。4 launcherすべてが同じ非ブロックdispatch契約を使い、Claude/Codexの初回promptはready gate経由で送信される。Claudeはisolated managed settingsとhook-captured resultを使い、private transcriptへ依存しない。Claude/Codex/Grok/Composerのlive smokeはすべてgreenであり、fixtureによる検証とは区別して記録する。
|
|
294
294
|
|
|
295
295
|
エージェントの回答が画面 tailより長ければ、対話callerは`pty_read({ agent_transcript:true })`で再promptなしに全文回収する。Claudeはmanaged Stop hookがowner-only resultへ保存した本文をdigest/byte数で検証して返し、private transcriptを読まない。durable machine callerは`claude_turn`を使う。`issue`は一度だけ送信し、`recover`は決して再送せず、`pending`を破損やidentity不一致と区別する。検証済みの`completed`だけがexact `raw_output`を持ち、`unknown`は未dispatchと帰属不能を区別する。不一致・破損は成功statusへ丸めずtool errorのままにする。IDなしの対話turnも匿名markerで直列化するため、現在Stop待ちの間に古い回答を返さない。CodexはStop hookの`turn_id`で構造化transcriptへjoinし、Grok/Composerは最後の実user行より後ろのassistant行を採る。不在・非agent・抽出不能は明示エラー。
|
|
296
296
|
|
package/README.md
CHANGED
|
@@ -20,24 +20,24 @@
|
|
|
20
20
|
>
|
|
21
21
|
> *MCP = Model Context Protocol — the open standard that lets tools like Claude Code plug capabilities into an AI.*
|
|
22
22
|
|
|
23
|
+
**Factory role:** aiterm-mcp is one of the ten self-owned core products managed by
|
|
24
|
+
the dotagents development factory. It owns the persistent PTY and external-agent
|
|
25
|
+
execution lane; dotagents owns the cross-product installation and integration
|
|
26
|
+
contract.
|
|
27
|
+
|
|
23
28
|
**Measured, not claimed:** on this repo's own 203-test suite, a `pty_read` puts **~7.1× fewer tokens** in your context than the raw log — and the pass/fail verdict survives the fold. → [When to reach for it vs. the built-in shell](#when-to-reach-for-it-vs-the-built-in-shell)
|
|
24
29
|
|
|
25
30
|
Thirteen tools: six **PTY tools** — `pty_open` / `pty_send` / `pty_read` / `pty_key` / `pty_close` / `pty_list` — to open, drive, and read one persistent terminal, four **agent launchers** — `claude_agent` / `codex_agent` / `grok_agent` / `composer_agent` — that each start another coding agent's TUI inside a fresh one, `claude_turn` for durable structured issue/recovery, `claude_approval` for correlated managed-Claude approval prompts, and `diagnostics` for safe factory readiness. The backend is **tmux**, so sessions survive even if the MCP server or the AI client restarts.
|
|
26
31
|
|
|
27
|
-
**v0.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
agent never blocks on aiterm: every send to an agent session is a non-blocking
|
|
37
|
-
dispatch, completion is one universal `aiterm-wait` waiter whose exit codes
|
|
38
|
-
mirror the receipt outcome (`0`=done / `3`=timeout, not finished /
|
|
39
|
-
`4`=closed), and a launch with an initial prompt returns a ready-made
|
|
40
|
-
`wait_command` in its structured receipt.
|
|
32
|
+
**v0.19.2 was published on 2026-07-20.** The v0.19 line adds the correlated
|
|
33
|
+
managed-Claude approval relay, preserves multiline shell delivery, and extends
|
|
34
|
+
factory diagnostics on native Windows. The v0.18 line hardened agent dispatch
|
|
35
|
+
with `submit_residue`, tmux bracketed paste, and a ready gate that rejects busy
|
|
36
|
+
Codex/Claude screens. As of v0.16/0.17 a parent agent never blocks on aiterm:
|
|
37
|
+
every send to an agent session is a non-blocking dispatch, completion is one
|
|
38
|
+
universal `aiterm-wait` waiter whose exit codes mirror the receipt outcome
|
|
39
|
+
(`0`=done / `3`=timeout, not finished / `4`=closed), and a launch with an
|
|
40
|
+
initial prompt returns a ready-made `wait_command` in its structured receipt.
|
|
41
41
|
Factory diagnostics and the local runtime-error store collect only when
|
|
42
42
|
canonical dotagents config explicitly sets `collection.enabled: true`;
|
|
43
43
|
collection is off by default and performs no network I/O. It ships via
|
|
@@ -84,7 +84,7 @@ codex_agent({ session_name: "codex1", cwd: "/repo",
|
|
|
84
84
|
pty_read("codex1", { screen: true }) → read what it's doing (token-reduced)
|
|
85
85
|
pty_send("codex1", "also fix the imports it broke")
|
|
86
86
|
→ non-blocking dispatch; receipt carries event_cursor
|
|
87
|
-
$ aiterm-wait --session codex1 --cursor <event_cursor> #
|
|
87
|
+
$ aiterm-wait --session codex1 --cursor <event_cursor> # never in the parent's foreground; exit 0=done, 3=timeout (not done), 4=closed
|
|
88
88
|
pty_read("codex1", { agent_transcript: true }) → collect the full answer
|
|
89
89
|
```
|
|
90
90
|
|
|
@@ -309,7 +309,7 @@ Each launcher starts a specific vendor's interactive coding-agent TUI inside a f
|
|
|
309
309
|
| `grok_agent` | Grok Build, model `grok-4.5` by default (`model?` overrides) (xAI) | `prompt?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error; Grok CLI `--effort` is headless-only), `cwd?`, `session_name?` |
|
|
310
310
|
| `composer_agent` | Grok Build, model `grok-composer-2.5-fast` by default (`model?` overrides) (xAI) | `prompt?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error), `cwd?`, `session_name?` |
|
|
311
311
|
|
|
312
|
-
The vendor CLI must be installed and authenticated (`claude` for `claude_agent`; `codex` for `codex_agent`; `grok` for both Grok tools). Binary resolution uses `CLAUDE_BIN` / `CODEX_BIN` / `GROK_BIN`, then each documented default location, then `PATH`. Missing binaries, invalid model/effort values, and nonexistent `cwd` fail before a session is created. All four share the same non-blocking dispatch contract for follow-up turns; `claude_agent`/`codex_agent` submit an initial `prompt` through the ready gate. Claude uses isolated managed settings and a hook-captured bounded result rather than private transcript access. Codex
|
|
312
|
+
The vendor CLI must be installed and authenticated (`claude` for `claude_agent`; `codex` for `codex_agent`; `grok` for both Grok tools). Binary resolution uses `CLAUDE_BIN` / `CODEX_BIN` / `GROK_BIN`, then each documented default location, then `PATH`. Missing binaries, invalid model/effort values, and nonexistent `cwd` fail before a session is created. All four share the same non-blocking dispatch contract for follow-up turns; `claude_agent`/`codex_agent` submit an initial `prompt` through the ready gate. Claude uses isolated managed settings and a hook-captured bounded result rather than private transcript access. Claude, Codex, Grok, and Composer live smokes are green; fixture coverage remains a separate claim. Native Windows can launch agents but managed completion is not supported yet.
|
|
313
313
|
|
|
314
314
|
When an agent's answer is longer than the on-screen tail (pane height ≈ 24 lines), callers recover it in full with `pty_read({ agent_transcript: true })`. It returns the most recently completed turn's final assistant message in plain text with no re-prompting. Claude reads the bounded owner-only result captured by the managed Stop hook and verifies its digest/byte count; it never reads Claude's private transcript. Durable machine callers should use `claude_turn`: `issue` sends once, `recover` never sends, `pending` is distinct from unsafe or malformed state, and only `completed` carries the exact verified `raw_output`. `unknown` distinguishes `operation_not_found` from a receipt whose result can no longer be attributed. Mismatch and corruption remain tool errors rather than being folded into a successful status. ID-less interactive Claude turns are still serialized by an anonymous marker, so an older answer is not returned while the current Stop is pending. Codex joins its structured transcript on the Stop hook `turn_id`; Grok/Composer take the assistant rows after the last real user row. A missing result/transcript, a non-agent session, or an unextractable message is an explicit error, never a silent empty.
|
|
315
315
|
|
|
@@ -323,7 +323,7 @@ As of v0.16 a parent agent **never blocks** on aiterm — there is no wait param
|
|
|
323
323
|
|
|
324
324
|
1. Launch the child (`claude_agent` / `codex_agent` / ...; every launch is managed). Send a turn with plain `pty_send` (or `claude_turn issue` for durable Claude operations). The call passes the TUI ready gate, submits, and returns immediately with an `event_cursor` in its structured receipt — plus a `submit_residue` observation: `true` means the sent text still lingered in the composer after submit (likely stranded; inspect the screen before re-pressing Enter), `false` means no residue was observed (not a proof of submission), `null` means not applicable.
|
|
325
325
|
2. Run `aiterm-wait --session <id> --cursor <event_cursor> [--operation sha256:<64hex>] [--timeout <sec>]` (a launch with an initial `prompt` returns this command ready-made as `wait_command` in its structured receipt). It observes the vendor Stop-hook completion event as a **pure reader** and exits with a one-line `aiterm.agent-wait-result.v1` receipt. **Exit ≠ done**: the receipt's `outcome` is authoritative, and the exit code mirrors it — `0` = `done`, `3` = `timeout` (the turn is **not** finished; default `--timeout` is 600 s), `4` = `closed`, `1` = error. On `timeout` just re-run the waiter with the same cursor. The `--cursor` boundary makes it start-order independent: no completion can slip past even if the waiter starts late.
|
|
326
|
-
3.
|
|
326
|
+
3. **The parent never runs the waiter in its own foreground.** Waiting is correct — but the waiter is a separate process, not the parent's turn. A harness that re-invokes its agent when a background task exits (Claude Code) runs the waiter **in the background** and gets woken with zero polling. So that this is not left to interpretation, aiterm reads `clientInfo.name` from the MCP `initialize` handshake and its receipts name the concrete invocation for the detected host — for Claude Code, literally `Bash(command: "aiterm-wait …", run_in_background: true)`. Unknown or undeclared hosts get the generic "start it as a process that does not block the parent's turn" wording; nothing else about the contract changes. Every receipt leads with the same rule: dispatch and let go, then go do something else or end the turn.
|
|
327
327
|
4. Collect the result exactly as before: `pty_read(agent_transcript: true)`, or `claude_turn recover` for durable Claude operations. The waiter carries the signal, never the payload.
|
|
328
328
|
|
|
329
329
|
`aiterm-wait` takes no locks, never writes session state, and never dispatches — any number can run beside the MCP server and each other, and `pty_close`/concurrent sends are unaffected.
|
package/dist/core.js
CHANGED
|
@@ -2497,7 +2497,7 @@ function bindCompletedInitialPrompt(meta) {
|
|
|
2497
2497
|
}
|
|
2498
2498
|
const size = safeStatSize(meta.event_file);
|
|
2499
2499
|
if (size === 0) {
|
|
2500
|
-
throw new AitermError(`agent session '${meta.aiterm_session}' は起動時 prompt
|
|
2500
|
+
throw new AitermError(`agent session '${meta.aiterm_session}' は起動時 prompt の完了待ちです。${agentWaitGuide(meta.aiterm_session)}`, 2);
|
|
2501
2501
|
}
|
|
2502
2502
|
const text = readFileRange(meta.event_file, 0, size).toString("utf8");
|
|
2503
2503
|
const lines = text.split("\n");
|
|
@@ -2509,7 +2509,7 @@ function bindCompletedInitialPrompt(meta) {
|
|
|
2509
2509
|
if (!scanned.event) {
|
|
2510
2510
|
const malformed = scanned.malformedEvents ? ` malformed_events=${scanned.malformedEvents}` : "";
|
|
2511
2511
|
const partial = tail.trim() ? " partial_event=true" : "";
|
|
2512
|
-
throw new AitermError(`agent session '${meta.aiterm_session}' は起動時 prompt の完了 event
|
|
2512
|
+
throw new AitermError(`agent session '${meta.aiterm_session}' は起動時 prompt の完了 event をまだ確認できません。${agentWaitGuide(meta.aiterm_session)}${malformed}${partial}`, 2);
|
|
2513
2513
|
}
|
|
2514
2514
|
bindAgentVendorSession(meta, scanned.event);
|
|
2515
2515
|
setInitialPromptState(meta, "done");
|
|
@@ -2630,11 +2630,8 @@ function findLatestCodexTranscript(codexHome, vendorSessionId) {
|
|
|
2630
2630
|
visit(sessionsDir);
|
|
2631
2631
|
return latestFile;
|
|
2632
2632
|
}
|
|
2633
|
-
// 未完了系エラーの共通出口案内。pollingへ誘導せず、正規の完了待ち手段を必ず指す。
|
|
2634
|
-
const AGENT_WAIT_GUIDE = "完了待ちは aiterm-wait --session <session_id> のバックグラウンド実行で受ける(polling不要。" +
|
|
2635
|
-
"receiptのoutcome=doneを確認してから再取得)。";
|
|
2636
2633
|
function transcriptUnavailable() {
|
|
2637
|
-
throw new AitermError(`transcript がまだありません。ターン完了後に再取得してください。${
|
|
2634
|
+
throw new AitermError(`transcript がまだありません。ターン完了後に再取得してください。${agentWaitGuide()}`, 2);
|
|
2638
2635
|
}
|
|
2639
2636
|
function transcriptNotFound(vendor) {
|
|
2640
2637
|
throw new AitermError(`最終 assistant メッセージを特定できませんでした(vendor=${vendor})。screen で確認してください。`, 2);
|
|
@@ -2701,18 +2698,18 @@ export async function readAgentTranscript(name, o = {}) {
|
|
|
2701
2698
|
const active = readClaudeOperationMarker(meta);
|
|
2702
2699
|
if (active) {
|
|
2703
2700
|
const label = active.operationId ? `operation ${active.operationId}` : "operation_idなしのClaude turn";
|
|
2704
|
-
throw new AitermError(`${label} はまだ完了していません。Stop完了後に同じsessionから再取得してください。${
|
|
2701
|
+
throw new AitermError(`${label} はまだ完了していません。Stop完了後に同じsessionから再取得してください。${agentWaitGuide(name)}`, 2);
|
|
2705
2702
|
}
|
|
2706
2703
|
}
|
|
2707
2704
|
// wait timeout は「失敗」ではなく状態不明。後着した同一launchの完了eventから
|
|
2708
2705
|
// vendor session をbindし、promptを再送せず結果だけ回収できるようにする。
|
|
2709
2706
|
recoverAgentVendorSession(meta);
|
|
2710
2707
|
if (!meta.vendor_session_id) {
|
|
2711
|
-
throw new AitermError(`agent session '${name}' はまだターンが完了していません。agent_done 完了後に再取得してください。${
|
|
2708
|
+
throw new AitermError(`agent session '${name}' はまだターンが完了していません。agent_done 完了後に再取得してください。${agentWaitGuide(name)}`, 2);
|
|
2712
2709
|
}
|
|
2713
2710
|
const done = latestAgentDoneEvent(meta, operationId);
|
|
2714
2711
|
if (operationId && !done) {
|
|
2715
|
-
throw new AitermError(`operation ${operationId} はまだ完了していません。同じoperation_idで後から再取得してください。${
|
|
2712
|
+
throw new AitermError(`operation ${operationId} はまだ完了していません。同じoperation_idで後から再取得してください。${agentWaitGuide(name)}`, 2);
|
|
2716
2713
|
}
|
|
2717
2714
|
const turnId = done?.turn_id ?? null;
|
|
2718
2715
|
let text = "";
|
|
@@ -2853,10 +2850,37 @@ function assertInitialPromptNotPendingForSend(name, force) {
|
|
|
2853
2850
|
if (meta.initial_prompt !== "pending" && meta.initial_prompt !== "sent")
|
|
2854
2851
|
return;
|
|
2855
2852
|
throw new AitermError(`agent session '${name}' は起動時 prompt の完了待ちです。通常 pty_send は混入防止のため送信しません。` +
|
|
2856
|
-
|
|
2853
|
+
`${agentWaitGuide(name)}完了後に再度 pty_send するか、手動介入が必要な場合だけ force:true を明示してください。`, 2);
|
|
2857
2854
|
}
|
|
2858
2855
|
// aiterm-wait の exit 契約(CLI と各所の案内文で共有する正)。exit≠完了: outcome が done の時だけ完了。
|
|
2859
2856
|
export const AITERM_WAIT_OUTCOME_NOTE = `exit 0=done / 3=timeout(既定${DEFAULT_AGENT_DONE_TIMEOUT}秒・未完了) / 4=closed。receiptのoutcomeが正で、done以外は未完了`;
|
|
2857
|
+
// 親ホストの識別(MCP initialize の clientInfo.name)。完了待ちコマンドを「親のターンを塞がない
|
|
2858
|
+
// 起動形」で名指しするためだけに使う。分からない時は汎用文へ落ち、機能は一切変えない。
|
|
2859
|
+
let parentClientName = null;
|
|
2860
|
+
export function setParentClient(name) {
|
|
2861
|
+
const trimmed = typeof name === "string" ? name.trim() : "";
|
|
2862
|
+
parentClientName = trimmed === "" ? null : trimmed;
|
|
2863
|
+
}
|
|
2864
|
+
// 完了待ちを親のターンを塞がない形で起動する具体形。ホストが分かる時は実際の呼び出し形を名指しする
|
|
2865
|
+
// (抽象名詞の「バックグラウンドで」だけでは親が foreground 実行へ落ちるため・ADR 0017)。
|
|
2866
|
+
export function agentWaitLaunchForm(command) {
|
|
2867
|
+
if (parentClientName === "claude-code") {
|
|
2868
|
+
return `Bash(command: ${JSON.stringify(command)}, run_in_background: true)`;
|
|
2869
|
+
}
|
|
2870
|
+
return `\`${command}\` を親のターンを塞がない別プロセスとして起動`;
|
|
2871
|
+
}
|
|
2872
|
+
// dispatch / 起動時 prompt 送信後の共通案内。第一文で「待たない」を宣言し、待ち方は後段に置く。
|
|
2873
|
+
export function agentDispatchGuide(session, cursor) {
|
|
2874
|
+
const cmd = `aiterm-wait --session ${session} --cursor ${cursor}`;
|
|
2875
|
+
return (`投げっぱなしでよい=ここで待たない。親は自分の作業へ戻るか、このターンを終える。\n` +
|
|
2876
|
+
`完了通知: ${agentWaitLaunchForm(cmd)}。exit が完了通知(${AITERM_WAIT_OUTCOME_NOTE})。\n` +
|
|
2877
|
+
`foreground 実行は親を最大 ${DEFAULT_AGENT_DONE_TIMEOUT} 秒塞ぐので使わない。回収: pty_read(agent_transcript:true)`);
|
|
2878
|
+
}
|
|
2879
|
+
// 未完了 session へ触った時の共通案内。ここでも待つのは waiter プロセスであって親ではない。
|
|
2880
|
+
export function agentWaitGuide(session) {
|
|
2881
|
+
const cmd = `aiterm-wait --session ${session ?? "<session_id>"} --cursor 0`;
|
|
2882
|
+
return `完了通知は ${agentWaitLaunchForm(cmd)} で受ける(親はここで待たない・polling 不要)。receipt の outcome=done を確認してから再取得する。`;
|
|
2883
|
+
}
|
|
2860
2884
|
// 外部waiterプロセス用の純リーダー観測。lock・PTY・metadata書込・dispatch状態には一切触れない。
|
|
2861
2885
|
// event fileのtail規律(未終端行保持・増分上限)はwaitAgentDoneEventと同一だが、
|
|
2862
2886
|
// vendor_session_idのbind永続化を行わない点だけ意図的に異なる(waiterは観測者であって所有者でない)。
|
|
@@ -3147,8 +3171,7 @@ export async function sendInitialAgentPrompt(name, text, o = {}) {
|
|
|
3147
3171
|
const residue = await detectAgentSubmitResidue(name, meta.kind, text);
|
|
3148
3172
|
return {
|
|
3149
3173
|
text: `initial_prompt=pending vendor=${meta.kind} event_cursor=${startOffset}\n` +
|
|
3150
|
-
`起動時 prompt
|
|
3151
|
-
`exit 時に receipt の outcome で判定する(${AITERM_WAIT_OUTCOME_NOTE})。回収は pty_read(agent_transcript:true) を使う。` +
|
|
3174
|
+
`起動時 prompt を送信した。${agentDispatchGuide(name, startOffset)}` +
|
|
3152
3175
|
agentSubmitResidueWarning(name, residue.residue),
|
|
3153
3176
|
event_cursor: startOffset,
|
|
3154
3177
|
submit_residue: residue.residue,
|
|
@@ -3622,7 +3645,7 @@ export function openAgent(kind, opts = {}) {
|
|
|
3622
3645
|
}
|
|
3623
3646
|
const driveHint = agentDone && kind === "claude"
|
|
3624
3647
|
? `TUI の描画には数秒かかる。少し置いてから pty_read(${sid}, screen:true) で画面を読み、` +
|
|
3625
|
-
`turnはpty_send(${sid}, "...")で送る(自動で非ブロックdispatch
|
|
3648
|
+
`turnはpty_send(${sid}, "...")で送る(自動で非ブロックdispatch=投げっぱなしでよい・完了通知はaiterm-wait)。中断はpty_key(${sid}, "C-c")、` +
|
|
3626
3649
|
`Stopが来ない場合の解除はpty_close(${sid})を使う。`
|
|
3627
3650
|
: `TUI の描画には数秒かかる。少し置いてから pty_read(${sid}, screen:true) で画面を読み、` +
|
|
3628
3651
|
`pty_send(${sid}, "...") で入力・pty_key(${sid}, "Enter"/"Up"/"C-c" 等) で操作する(対話)。`;
|
package/dist/index.js
CHANGED
|
@@ -20,6 +20,15 @@ import { createRequire } from "node:module";
|
|
|
20
20
|
// 除去済み=どちらの静的構文も 18〜22 全域を満たせないため(実行時 require が唯一全域で動く)。
|
|
21
21
|
const pkg = createRequire(import.meta.url)("../package.json");
|
|
22
22
|
const server = new McpServer({ name: "aiterm", version: pkg.version });
|
|
23
|
+
/**
|
|
24
|
+
* dispatch 系の説明で共有する非ブロック規範。tool description は registerTool 時=initialize 前に
|
|
25
|
+
* 固定されるため親ホストを名指しできない(ホスト別の具体形は receipt 側が core.agentWaitLaunchForm で出す)。
|
|
26
|
+
* ここでは「待つな」を断定形で先に置き、foreground 実行の禁止までを説明の側に含める。
|
|
27
|
+
*/
|
|
28
|
+
const NON_BLOCKING_RULE = "dispatch した子は投げっぱなしでよい=親はここで待たない。" +
|
|
29
|
+
"完了通知は `aiterm-wait --session <id> --cursor <event_cursor>` を親のターンを塞がない別プロセスとして起動して受け、" +
|
|
30
|
+
`exit を完了通知として扱う(${core.AITERM_WAIT_OUTCOME_NOTE}。ポーリング不要)。` +
|
|
31
|
+
"この待ちコマンドを foreground で実行して親のターンを塞ぐことはしない(receipt が実際の起動形を示す)。";
|
|
23
32
|
function ok(s) {
|
|
24
33
|
return { content: [{ type: "text", text: s }] };
|
|
25
34
|
}
|
|
@@ -88,9 +97,8 @@ server.registerTool("pty_open", {
|
|
|
88
97
|
server.registerTool("pty_send", {
|
|
89
98
|
description: "セッションへテキストを送る。通常PTYへは送信のみ(出力は pty_read で取得)。" +
|
|
90
99
|
"agent session(launcher起動)への send は自動で dispatch になる: TUI の ready gate と submit 分離を通して即返り、" +
|
|
91
|
-
"receipt の event_cursor
|
|
92
|
-
|
|
93
|
-
`(${core.AITERM_WAIT_OUTCOME_NOTE}。ポーリング不要)。` +
|
|
100
|
+
"receipt の event_cursor を返す。" +
|
|
101
|
+
NON_BLOCKING_RULE +
|
|
94
102
|
"結果回収は pty_read(agent_transcript:true)、Claude の durable turn は claude_turn を使う。" +
|
|
95
103
|
"force:true は非Claude agent sessionへの手動介入用の素送信。managed Claudeの承認UIはclaude_approvalを使う。",
|
|
96
104
|
inputSchema: {
|
|
@@ -137,9 +145,8 @@ server.registerTool("pty_send", {
|
|
|
137
145
|
content: [
|
|
138
146
|
{
|
|
139
147
|
type: "text",
|
|
140
|
-
text: `dispatchした(vendor=${receipt.vendor}
|
|
141
|
-
|
|
142
|
-
"回収: pty_read(agent_transcript:true)" +
|
|
148
|
+
text: `dispatchした(vendor=${receipt.vendor})。\n` +
|
|
149
|
+
core.agentDispatchGuide(receipt.session_id, receipt.event_cursor) +
|
|
143
150
|
core.agentSubmitResidueWarning(receipt.session_id, receipt.submit_residue),
|
|
144
151
|
},
|
|
145
152
|
],
|
|
@@ -404,12 +411,12 @@ const agentEffortDesc = (kind) => kind === "claude"
|
|
|
404
411
|
"composer は effort 自体非対応)。指定すると起動前にエラーを返す"
|
|
405
412
|
: "reasoning effort(思考レベル)。low/medium/high/xhigh/max/ultra(CLI 版依存)。" +
|
|
406
413
|
"ultra は max 推論+proactive 自動委譲 ON=使用量急増注意(明示要求時のみ)。省略時は端末 config/CLI 既定。";
|
|
407
|
-
// 全launcher
|
|
408
|
-
// event_cursor
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
`aiterm-wait --session <id> --cursor <event_cursor>
|
|
412
|
-
|
|
414
|
+
// 全launcher共通の完了受信ガイド。待ちコマンドは起動応答の wait_command(初回prompt時)または
|
|
415
|
+
// pty_send dispatch の event_cursor から組む。文型は NON_BLOCKING_RULE と同じく「待たない」が先。
|
|
416
|
+
const agentCompletionDesc = `起動して投げたら投げっぱなしでよい=親はここで待たない。` +
|
|
417
|
+
`完了通知は起動応答の wait_command(初回prompt時)または pty_send dispatch 後の ` +
|
|
418
|
+
`aiterm-wait --session <id> --cursor <event_cursor> を親のターンを塞がない別プロセスとして起動して受ける` +
|
|
419
|
+
`(${core.AITERM_WAIT_OUTCOME_NOTE}。ポーリング不要・foreground実行はしない)。` +
|
|
413
420
|
`結果回収は pty_read(agent_transcript:true)。`;
|
|
414
421
|
function registerAgentTool(toolName, kind, desc) {
|
|
415
422
|
const correlatedLaunchSchema = {};
|
|
@@ -492,6 +499,12 @@ registerAgentTool("composer_agent", "composer", "【Grok Build の Composer モ
|
|
|
492
499
|
agentCompletionDesc +
|
|
493
500
|
"model を引数で指定可。reasoning_effort は非対応(指定はエラー)。");
|
|
494
501
|
async function main() {
|
|
502
|
+
// 親ホストを initialize の clientInfo.name から確定させ、receipt の完了待ちコマンドを
|
|
503
|
+
// そのホストの実際の起動形で名指しする(実測: claude-code は initialize → notifications/initialized
|
|
504
|
+
// → tools/list の順で送るため、どの tool 呼び出しより先に確定する)。取れない時は汎用文へ落ちるだけ。
|
|
505
|
+
server.server.oninitialized = () => {
|
|
506
|
+
core.setParentClient(server.server.getClientVersion()?.name ?? null);
|
|
507
|
+
};
|
|
495
508
|
const transport = new StdioServerTransport();
|
|
496
509
|
await server.connect(transport);
|
|
497
510
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiterm-mcp",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.3",
|
|
4
4
|
"mcpName": "io.github.kitepon-rgb/aiterm-mcp",
|
|
5
5
|
"description": "AI-driven persistent terminal as a local stdio MCP server (tmux-backed). Holds one local PTY; SSH and containers are just commands you send into it. Also launches interactive Claude/Codex/Grok/Composer agent TUIs in a persistent terminal. Token-reducing reads.",
|
|
6
6
|
"keywords": [
|