aiterm-mcp 0.16.0 → 0.17.0
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 -5
- package/README.md +14 -12
- package/dist/aiterm-wait-cli.js +6 -1
- package/dist/core.js +25 -11
- package/dist/index.js +30 -7
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -24,10 +24,13 @@
|
|
|
24
24
|
|
|
25
25
|
12 ツール: 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を、`diagnostics`が安全なfactory readinessを返す。バックエンドは **tmux** なので、MCP サーバや AI クライアントが再起動してもセッションは生き残る。
|
|
26
26
|
|
|
27
|
-
**v0.
|
|
27
|
+
**v0.17.0 を 2026-07-18 に公開。** 親エージェントは aiterm 上で一切ブロックしない:
|
|
28
|
+
agent session への send は常に非ブロック dispatch になり、完了待ちは `aiterm-wait` 一本
|
|
29
|
+
(exit code が receipt の outcome を映す: 0=done / 3=timeout=未完了 / 4=closed)、初回 prompt 付き
|
|
30
|
+
launch は structured receipt にコピペ可能な `wait_command` を含む。factory diagnostics と local
|
|
28
31
|
runtime-error store は canonical dotagents config の `collection.enabled: true` が明示された
|
|
29
|
-
場合だけ収集し、既定OFF、network送信は行いません。
|
|
30
|
-
|
|
32
|
+
場合だけ収集し、既定OFF、network送信は行いません。tag起点CIのnpm provenance(OIDC Trusted
|
|
33
|
+
Publishing)で公開し、GitHub Release が Official MCP Registry を再登録します。
|
|
31
34
|
|
|
32
35
|
**状態:** 開発継続中 · この分野では新参で、別の形に賭けている([既存手段との比較](#既存手段との比較)参照)· 動作対象は Linux · WSL2 · macOS · Windows ネイティブ(core PTY ツール。`agent_done` は現時点では POSIX/WSL/macOS のみ)· MIT · [変更履歴](CHANGELOG.md)。
|
|
33
36
|
|
|
@@ -52,7 +55,7 @@ pty_read(id, { wait: true }) → 削減済みの出力を読む(完了
|
|
|
52
55
|
|
|
53
56
|
### 2. その端末の中に他のコーディングエージェントを起動する — オーケストレーションの旗艦
|
|
54
57
|
|
|
55
|
-
同じ primitive が別エージェントの TUI を宿す。4 つの起動ツールが、Claude/Codex/Grok/Composer の対話 TUI を新しい永続端末の中に起動し、`session_id` を返す。既存の人間向けtextに加えて`aiterm.agent-launch-result.v1` structured receiptも返すため、durable callerは表示文字列を解析せずsession handleを取得できる。以後は同じ `pty_read` / `pty_send` で継続操作する。**起動は常に managed**(aiterm 所有の Stop hook 付き)で、agent session への `pty_send` は非ブロックの **dispatch** になり `event_cursor` 入り receipt を即返す。完了通知は `aiterm-wait --session <id> --cursor <event_cursor>`
|
|
58
|
+
同じ primitive が別エージェントの TUI を宿す。4 つの起動ツールが、Claude/Codex/Grok/Composer の対話 TUI を新しい永続端末の中に起動し、`session_id` を返す。既存の人間向けtextに加えて`aiterm.agent-launch-result.v1` structured receiptも返すため、durable callerは表示文字列を解析せずsession handleを取得できる。以後は同じ `pty_read` / `pty_send` で継続操作する。**起動は常に managed**(aiterm 所有の Stop hook 付き)で、agent session への `pty_send` は非ブロックの **dispatch** になり `event_cursor` 入り receipt を即返す。完了通知は `aiterm-wait --session <id> --cursor <event_cursor>` をホストのバックグラウンドタスクとして実行し、exit 時に receipt の `outcome` で判定する(exit 0=done / 3=timeout=未完了・既定600秒 / 4=closed。親はブロックもポーリングもしない)。起動時 `prompt` を渡した launch は structured receipt にコピペ可能な `wait_command` と `event_cursor` を含む。durable machine callerは`claude_turn({ action:"issue"|"recover", session_id, operation_id, ... })`を使い、人間向けerror文字列を解析せず`accepted`/`pending`/`completed`/`unknown`を判定できる。recoveryは再送せず、検証済み完了だけがexact `raw_output`を持つ。通常の`pty_send`/`pty_read`は対話callerと人間向けに維持する。`C-c`後もmarkerを保持し、Stopが来なければsessionをcloseする。`claude_agent` と `codex_agent` の初回 `prompt` は ready gate 経由で送信して待たずに返る(Grok/Composer は argv 渡し)。手動でキー操作したい場合は `pty_open` で素の端末を開き vendor CLI を自分で起動する。
|
|
56
59
|
|
|
57
60
|
```text
|
|
58
61
|
codex_agent({ session_name: "codex1", cwd: "/repo",
|
|
@@ -60,7 +63,7 @@ codex_agent({ session_name: "codex1", cwd: "/repo",
|
|
|
60
63
|
→ { session_id: "codex1", … } # Codex が永続端末で稼働開始
|
|
61
64
|
pty_read("codex1", { screen: true }) → 何をしているか読む(トークン削減)
|
|
62
65
|
pty_send("codex1", "also fix the imports it broke") # 非ブロックdispatch=event_cursor入りreceipt
|
|
63
|
-
$ aiterm-wait --session codex1 --cursor <event_cursor> # exit
|
|
66
|
+
$ aiterm-wait --session codex1 --cursor <event_cursor> # exit 0=done / 3=timeout(未完了) / 4=closed。回収は pty_read(agent_transcript:true)
|
|
64
67
|
→ 操舵し、Codex の次の入力境界で返る
|
|
65
68
|
```
|
|
66
69
|
|
package/README.md
CHANGED
|
@@ -24,14 +24,16 @@
|
|
|
24
24
|
|
|
25
25
|
Twelve 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, and `diagnostics` for safe factory readiness. The backend is **tmux**, so sessions survive even if the MCP server or the AI client restarts.
|
|
26
26
|
|
|
27
|
-
**v0.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
`
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
**v0.17.0 was published on 2026-07-18.** A parent agent never blocks on aiterm:
|
|
28
|
+
every send to an agent session is a non-blocking dispatch, completion is one
|
|
29
|
+
universal `aiterm-wait` waiter whose exit codes mirror the receipt outcome
|
|
30
|
+
(`0`=done / `3`=timeout, not finished / `4`=closed), and a launch with an
|
|
31
|
+
initial prompt returns a ready-made `wait_command` in its structured receipt.
|
|
32
|
+
Factory diagnostics and the local runtime-error store collect only when
|
|
33
|
+
canonical dotagents config explicitly sets `collection.enabled: true`;
|
|
34
|
+
collection is off by default and performs no network I/O. It ships via
|
|
35
|
+
tag-triggered CI with npm provenance (OIDC Trusted Publishing); the GitHub
|
|
36
|
+
Release re-registers the Official MCP Registry entry.
|
|
35
37
|
|
|
36
38
|
**Status:** actively maintained · the newcomer here, betting on a different shape (see [vs. the alternatives](#vs-the-alternatives)) · runs on Linux · WSL2 · macOS · native Windows for the core PTY tools (managed completion is POSIX/WSL/macOS only for now) · MIT · see the [CHANGELOG](CHANGELOG.md).
|
|
37
39
|
|
|
@@ -62,7 +64,7 @@ pty_read(id, { wait: true }) → read the token-reduced output, completion
|
|
|
62
64
|
|
|
63
65
|
### 2. Launch other coding agents into that terminal — the orchestration flagship
|
|
64
66
|
|
|
65
|
-
The same primitive hosts another agent's TUI. Four launchers each start one vendor's interactive coding-agent TUI inside a fresh persistent terminal and return a `session_id`. Their existing human-readable text is accompanied by an `aiterm.agent-launch-result.v1` structured receipt, so durable callers never parse display text for the session handle. From there you drive it with the same `pty_read` / `pty_send` you'd use on any shell: read its output token-reduced, send it the next step. (The TUIs are full-screen apps, so `pty_read({ screen: true })` gives you the rendered view.) Every launch is **managed**: aiterm installs its own Stop hook, so turn completion is a first-class event. Sending to an agent session is a non-blocking **dispatch** — the call returns immediately with an `event_cursor`, and completion arrives via [`aiterm-wait`](#completion-push-for-parent-agents-aiterm-wait). Durable machine callers use `claude_turn({ action: "issue" | "recover", session_id, operation_id, ... })`: it returns fixed `accepted` / `pending` / `completed` / `unknown` states without parsing human-facing errors, never resends during recovery, and includes exact `raw_output` only for a verified completion. The same operation ID is carried through the dispatch receipt, active marker, Stop event, and result. The ordinary `pty_send` / `pty_read` surface remains available for interactive callers and humans. `C-c` keeps the marker for a delayed Stop; if no Stop arrives, close the session. An initial `prompt` on `claude_agent`/`codex_agent` is submitted through the same ready gate and the launcher returns without waiting; on Grok/Composer it is passed on the CLI's argv. This needs the vendor's own CLI installed and authenticated — see [Requirements](#requirements).
|
|
67
|
+
The same primitive hosts another agent's TUI. Four launchers each start one vendor's interactive coding-agent TUI inside a fresh persistent terminal and return a `session_id`. Their existing human-readable text is accompanied by an `aiterm.agent-launch-result.v1` structured receipt, so durable callers never parse display text for the session handle; when the launch carries an initial `prompt`, the receipt also includes the `event_cursor` and a ready-made `wait_command` for the completion waiter. From there you drive it with the same `pty_read` / `pty_send` you'd use on any shell: read its output token-reduced, send it the next step. (The TUIs are full-screen apps, so `pty_read({ screen: true })` gives you the rendered view.) Every launch is **managed**: aiterm installs its own Stop hook, so turn completion is a first-class event. Sending to an agent session is a non-blocking **dispatch** — the call returns immediately with an `event_cursor`, and completion arrives via [`aiterm-wait`](#completion-push-for-parent-agents-aiterm-wait). Durable machine callers use `claude_turn({ action: "issue" | "recover", session_id, operation_id, ... })`: it returns fixed `accepted` / `pending` / `completed` / `unknown` states without parsing human-facing errors, never resends during recovery, and includes exact `raw_output` only for a verified completion. The same operation ID is carried through the dispatch receipt, active marker, Stop event, and result. The ordinary `pty_send` / `pty_read` surface remains available for interactive callers and humans. `C-c` keeps the marker for a delayed Stop; if no Stop arrives, close the session. An initial `prompt` on `claude_agent`/`codex_agent` is submitted through the same ready gate and the launcher returns without waiting; on Grok/Composer it is passed on the CLI's argv. This needs the vendor's own CLI installed and authenticated — see [Requirements](#requirements).
|
|
66
68
|
|
|
67
69
|
```text
|
|
68
70
|
codex_agent({ session_name: "codex1", cwd: "/repo",
|
|
@@ -71,7 +73,7 @@ codex_agent({ session_name: "codex1", cwd: "/repo",
|
|
|
71
73
|
pty_read("codex1", { screen: true }) → read what it's doing (token-reduced)
|
|
72
74
|
pty_send("codex1", "also fix the imports it broke")
|
|
73
75
|
→ non-blocking dispatch; receipt carries event_cursor
|
|
74
|
-
$ aiterm-wait --session codex1 --cursor <event_cursor> # host background task;
|
|
76
|
+
$ aiterm-wait --session codex1 --cursor <event_cursor> # host background task; exit code 0=done, 3=timeout (not done), 4=closed
|
|
75
77
|
pty_read("codex1", { agent_transcript: true }) → collect the full answer
|
|
76
78
|
```
|
|
77
79
|
|
|
@@ -303,10 +305,10 @@ When an agent's answer is longer than the on-screen tail (pane height ≈ 24 lin
|
|
|
303
305
|
|
|
304
306
|
### Completion push for parent agents (`aiterm-wait`)
|
|
305
307
|
|
|
306
|
-
As of v0.16
|
|
308
|
+
As of v0.16 a parent agent **never blocks** on aiterm — there is no wait parameter anywhere (v0.17 makes the waiter's exit codes mirror its outcome). The whole flow is dispatch + one universal waiter:
|
|
307
309
|
|
|
308
310
|
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.
|
|
309
|
-
2. Run `aiterm-wait --session <id> --cursor <event_cursor> [--operation sha256:<64hex>] [--timeout <sec>]
|
|
311
|
+
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.
|
|
310
312
|
3. Host integration picks the invocation style: 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; a host without that mechanism runs it as a foreground shell command. Either way the aiterm MCP call itself never blocks.
|
|
311
313
|
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.
|
|
312
314
|
|
package/dist/aiterm-wait-cli.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// aiterm-wait — agent turn 完了eventの純リーダー観測CLI。
|
|
3
3
|
// 完了/timeout/close を1行のJSON receiptで返してexitする。lock・PTY・dispatch状態には一切触れない。
|
|
4
|
-
// 親AIホストのバックグラウンドタスクとして起動し、exit
|
|
4
|
+
// 親AIホストのバックグラウンドタスクとして起動し、exitを「観測終了の通知」として使う。
|
|
5
|
+
// exit≠完了: exit code は outcome を映す(0=done / 3=timeout=未完了 / 4=closed / 1=エラー)。
|
|
6
|
+
// receipt の outcome が正で、done 以外は未完了。timeout の既定は core の DEFAULT_AGENT_DONE_TIMEOUT(600秒)。
|
|
5
7
|
import { fileURLToPath } from "node:url";
|
|
6
8
|
import * as fs from "node:fs";
|
|
7
9
|
import { AitermError, observeAgentDone } from "./core.js";
|
|
@@ -62,6 +64,8 @@ export function parseArgs(argv) {
|
|
|
62
64
|
function emit(value) {
|
|
63
65
|
process.stdout.write(JSON.stringify(value) + "\n");
|
|
64
66
|
}
|
|
67
|
+
// outcome → exit code。exit status しか見えないホストでも done とそれ以外を誤読できないようにする。
|
|
68
|
+
const OUTCOME_EXIT_CODES = { done: 0, timeout: 3, closed: 4 };
|
|
65
69
|
export async function main(argv) {
|
|
66
70
|
const cmd = parseArgs(argv);
|
|
67
71
|
const result = await observeAgentDone(cmd.session, {
|
|
@@ -70,6 +74,7 @@ export async function main(argv) {
|
|
|
70
74
|
cursor: cmd.cursor,
|
|
71
75
|
});
|
|
72
76
|
emit(result);
|
|
77
|
+
process.exitCode = OUTCOME_EXIT_CODES[result.outcome];
|
|
73
78
|
}
|
|
74
79
|
function isDirectExecution() {
|
|
75
80
|
const entry = process.argv[1];
|
package/dist/core.js
CHANGED
|
@@ -2426,8 +2426,11 @@ function findLatestCodexTranscript(codexHome, vendorSessionId) {
|
|
|
2426
2426
|
visit(sessionsDir);
|
|
2427
2427
|
return latestFile;
|
|
2428
2428
|
}
|
|
2429
|
+
// 未完了系エラーの共通出口案内。pollingへ誘導せず、正規の完了待ち手段を必ず指す。
|
|
2430
|
+
const AGENT_WAIT_GUIDE = "完了待ちは aiterm-wait --session <session_id> のバックグラウンド実行で受ける(polling不要。" +
|
|
2431
|
+
"receiptのoutcome=doneを確認してから再取得)。";
|
|
2429
2432
|
function transcriptUnavailable() {
|
|
2430
|
-
throw new AitermError(
|
|
2433
|
+
throw new AitermError(`transcript がまだありません。ターン完了後に再取得してください。${AGENT_WAIT_GUIDE}`, 2);
|
|
2431
2434
|
}
|
|
2432
2435
|
function transcriptNotFound(vendor) {
|
|
2433
2436
|
throw new AitermError(`最終 assistant メッセージを特定できませんでした(vendor=${vendor})。screen で確認してください。`, 2);
|
|
@@ -2494,18 +2497,18 @@ export async function readAgentTranscript(name, o = {}) {
|
|
|
2494
2497
|
const active = readClaudeOperationMarker(meta);
|
|
2495
2498
|
if (active) {
|
|
2496
2499
|
const label = active.operationId ? `operation ${active.operationId}` : "operation_idなしのClaude turn";
|
|
2497
|
-
throw new AitermError(`${label} はまだ完了していません。Stop完了後に同じsession
|
|
2500
|
+
throw new AitermError(`${label} はまだ完了していません。Stop完了後に同じsessionから再取得してください。${AGENT_WAIT_GUIDE}`, 2);
|
|
2498
2501
|
}
|
|
2499
2502
|
}
|
|
2500
2503
|
// wait timeout は「失敗」ではなく状態不明。後着した同一launchの完了eventから
|
|
2501
2504
|
// vendor session をbindし、promptを再送せず結果だけ回収できるようにする。
|
|
2502
2505
|
recoverAgentVendorSession(meta);
|
|
2503
2506
|
if (!meta.vendor_session_id) {
|
|
2504
|
-
throw new AitermError(`agent session '${name}' はまだターンが完了していません。agent_done
|
|
2507
|
+
throw new AitermError(`agent session '${name}' はまだターンが完了していません。agent_done 完了後に再取得してください。${AGENT_WAIT_GUIDE}`, 2);
|
|
2505
2508
|
}
|
|
2506
2509
|
const done = latestAgentDoneEvent(meta, operationId);
|
|
2507
2510
|
if (operationId && !done) {
|
|
2508
|
-
throw new AitermError(`operation ${operationId} はまだ完了していません。同じoperation_id
|
|
2511
|
+
throw new AitermError(`operation ${operationId} はまだ完了していません。同じoperation_idで後から再取得してください。${AGENT_WAIT_GUIDE}`, 2);
|
|
2509
2512
|
}
|
|
2510
2513
|
const turnId = done?.turn_id ?? null;
|
|
2511
2514
|
let text = "";
|
|
@@ -2648,6 +2651,8 @@ function assertInitialPromptNotPendingForSend(name, force) {
|
|
|
2648
2651
|
throw new AitermError(`agent session '${name}' は起動時 prompt の完了待ちです。通常 pty_send は混入防止のため送信しません。` +
|
|
2649
2652
|
`完了後に pty_send(wait:"agent_done") するか、手動介入が必要な場合だけ force:true を明示してください。`, 2);
|
|
2650
2653
|
}
|
|
2654
|
+
// aiterm-wait の exit 契約(CLI と各所の案内文で共有する正)。exit≠完了: outcome が done の時だけ完了。
|
|
2655
|
+
export const AITERM_WAIT_OUTCOME_NOTE = `exit 0=done / 3=timeout(既定${DEFAULT_AGENT_DONE_TIMEOUT}秒・未完了) / 4=closed。receiptのoutcomeが正で、done以外は未完了`;
|
|
2651
2656
|
// 外部waiterプロセス用の純リーダー観測。lock・PTY・metadata書込・dispatch状態には一切触れない。
|
|
2652
2657
|
// event fileのtail規律(未終端行保持・増分上限)はwaitAgentDoneEventと同一だが、
|
|
2653
2658
|
// vendor_session_idのbind永続化を行わない点だけ意図的に異なる(waiterは観測者であって所有者でない)。
|
|
@@ -2829,8 +2834,11 @@ export async function sendInitialAgentPrompt(name, text, o = {}) {
|
|
|
2829
2834
|
setInitialPromptState(meta, "not_sent");
|
|
2830
2835
|
const ready = await waitAgentTuiReady(name, meta, o.ready_timeout ?? AGENT_TUI_READY_TIMEOUT_MS);
|
|
2831
2836
|
if (!ready.ready) {
|
|
2832
|
-
return
|
|
2833
|
-
`
|
|
2837
|
+
return {
|
|
2838
|
+
text: `initial_prompt=not_sent vendor=${meta.kind} ready=false samples=${ready.samples}\n` +
|
|
2839
|
+
`agent session '${name}' の ${agentLabel(meta.kind)} TUI が入力受付状態になりません。prompt は送信していません。`,
|
|
2840
|
+
event_cursor: null,
|
|
2841
|
+
};
|
|
2834
2842
|
}
|
|
2835
2843
|
const startOffset = safeStatSize(meta.event_file);
|
|
2836
2844
|
try {
|
|
@@ -2845,9 +2853,12 @@ export async function sendInitialAgentPrompt(name, text, o = {}) {
|
|
|
2845
2853
|
setInitialPromptState(meta, "failed");
|
|
2846
2854
|
throw e;
|
|
2847
2855
|
}
|
|
2848
|
-
return
|
|
2849
|
-
|
|
2850
|
-
|
|
2856
|
+
return {
|
|
2857
|
+
text: `initial_prompt=pending vendor=${meta.kind} event_cursor=${startOffset}\n` +
|
|
2858
|
+
`起動時 prompt を送信した。完了通知は aiterm-wait --session ${name} --cursor ${startOffset} をホストのバックグラウンドタスクとして実行し、` +
|
|
2859
|
+
`exit 時に receipt の outcome で判定する(${AITERM_WAIT_OUTCOME_NOTE})。回収は pty_read(agent_transcript:true) を使う。`,
|
|
2860
|
+
event_cursor: startOffset,
|
|
2861
|
+
};
|
|
2851
2862
|
}
|
|
2852
2863
|
export function isAgentSession(name) {
|
|
2853
2864
|
assertSessionName(name);
|
|
@@ -3329,8 +3340,10 @@ export async function openAgentWithInitialPrompt(kind, opts = {}) {
|
|
|
3329
3340
|
}
|
|
3330
3341
|
// v0.16.0: launcher は常に managed(Stop hook つき)で立つ。手動運転したい場合は
|
|
3331
3342
|
// pty_open で素の PTY を開き、vendor CLI を自分で send する。
|
|
3343
|
+
// 第3要素は「起動時点でturnが走っているか」の event_cursor: Grok/Composer の argv prompt は
|
|
3344
|
+
// event file 新規作成直後の起動=境界0、prompt なしの起動は turn なし=null。
|
|
3332
3345
|
if (!prompt || (kind !== "codex" && kind !== "claude")) {
|
|
3333
|
-
|
|
3346
|
+
const [sid, hint] = openAgent(kind, {
|
|
3334
3347
|
session_name: opts.session_name ?? null,
|
|
3335
3348
|
model: opts.model ?? null,
|
|
3336
3349
|
reasoning_effort: opts.reasoning_effort ?? null,
|
|
@@ -3339,6 +3352,7 @@ export async function openAgentWithInitialPrompt(kind, opts = {}) {
|
|
|
3339
3352
|
agent_done: true,
|
|
3340
3353
|
launch_operation_id: opts.launch_operation_id ?? null,
|
|
3341
3354
|
});
|
|
3355
|
+
return [sid, hint, prompt ? 0 : null];
|
|
3342
3356
|
}
|
|
3343
3357
|
const [sid, hint] = openAgent(kind, {
|
|
3344
3358
|
session_name: opts.session_name ?? null,
|
|
@@ -3353,7 +3367,7 @@ export async function openAgentWithInitialPrompt(kind, opts = {}) {
|
|
|
3353
3367
|
const initial = await sendInitialAgentPrompt(sid, prompt, {
|
|
3354
3368
|
ready_timeout: opts.ready_timeout ?? undefined,
|
|
3355
3369
|
});
|
|
3356
|
-
return [sid, `${hint}\n${initial}
|
|
3370
|
+
return [sid, `${hint}\n${initial.text}`, initial.event_cursor];
|
|
3357
3371
|
}
|
|
3358
3372
|
catch (e) {
|
|
3359
3373
|
const code = e instanceof AitermError ? e.code : 1;
|
package/dist/index.js
CHANGED
|
@@ -89,7 +89,8 @@ server.registerTool("pty_send", {
|
|
|
89
89
|
description: "セッションへテキストを送る。通常PTYへは送信のみ(出力は pty_read で取得)。" +
|
|
90
90
|
"agent session(launcher起動)への send は自動で dispatch になる: TUI の ready gate と submit 分離を通して即返り、" +
|
|
91
91
|
"receipt の event_cursor を返す=親はブロックしない。完了通知は `aiterm-wait --session <id> --cursor <event_cursor>` を" +
|
|
92
|
-
"
|
|
92
|
+
"ホストのバックグラウンドタスクとして実行し、exit時にreceiptのoutcomeで判定する" +
|
|
93
|
+
`(${core.AITERM_WAIT_OUTCOME_NOTE}。ポーリング不要)。` +
|
|
93
94
|
"結果回収は pty_read(agent_transcript:true)、Claude の durable turn は claude_turn を使う。" +
|
|
94
95
|
"force:true は agent session への手動介入用の素送信。",
|
|
95
96
|
inputSchema: {
|
|
@@ -134,7 +135,8 @@ server.registerTool("pty_send", {
|
|
|
134
135
|
{
|
|
135
136
|
type: "text",
|
|
136
137
|
text: `dispatchした(vendor=${receipt.vendor})。完了通知: aiterm-wait --session ${receipt.session_id} --cursor ${receipt.event_cursor} を` +
|
|
137
|
-
|
|
138
|
+
`ホストのバックグラウンドタスクとして実行し、exit時にreceiptのoutcomeで判定(${core.AITERM_WAIT_OUTCOME_NOTE})。` +
|
|
139
|
+
"回収: pty_read(agent_transcript:true)",
|
|
138
140
|
},
|
|
139
141
|
],
|
|
140
142
|
structuredContent: {
|
|
@@ -342,6 +344,13 @@ const agentEffortDesc = (kind) => kind === "claude"
|
|
|
342
344
|
"composer は effort 自体非対応)。指定すると起動前にエラーを返す"
|
|
343
345
|
: "reasoning effort(思考レベル)。low/medium/high/xhigh/max/ultra(CLI 版依存)。" +
|
|
344
346
|
"ultra は max 推論+proactive 自動委譲 ON=使用量急増注意(明示要求時のみ)。省略時は端末 config/CLI 既定。";
|
|
347
|
+
// 全launcher共通の完了受信ガイド。launch応答のwait_command(起動時promptあり時)/pty_send dispatchの
|
|
348
|
+
// event_cursorから組んだaiterm-waitをホストのバックグラウンドタスクとして1本実行し、exit時にreceiptの
|
|
349
|
+
// outcomeで判定する。
|
|
350
|
+
const agentCompletionDesc = `完了通知は起動応答の wait_command(初回prompt時)または pty_send dispatch 後の ` +
|
|
351
|
+
`aiterm-wait --session <id> --cursor <event_cursor> をホストのバックグラウンドタスクとして実行し、` +
|
|
352
|
+
`exit時にreceiptのoutcomeで判定する(${core.AITERM_WAIT_OUTCOME_NOTE}。ポーリング不要)。` +
|
|
353
|
+
`結果回収は pty_read(agent_transcript:true)。`;
|
|
345
354
|
function registerAgentTool(toolName, kind, desc) {
|
|
346
355
|
const correlatedLaunchSchema = {};
|
|
347
356
|
if (kind === "claude") {
|
|
@@ -368,10 +377,14 @@ function registerAgentTool(toolName, kind, desc) {
|
|
|
368
377
|
provider: z.literal(kind),
|
|
369
378
|
session_id: z.string().regex(/^[A-Za-z0-9_-]{1,64}$/),
|
|
370
379
|
managed_completion: z.boolean(),
|
|
380
|
+
// 起動時 prompt でturnが走っている時だけ非null(additive拡張)。wait_command はそのままホストの
|
|
381
|
+
// バックグラウンドタスクとして実行できる完了待ちコマンド。
|
|
382
|
+
event_cursor: z.number().int().nullable(),
|
|
383
|
+
wait_command: z.string().nullable(),
|
|
371
384
|
},
|
|
372
385
|
}, async ({ prompt, model, reasoning_effort, cwd, session_name, launch_operation_id }) => {
|
|
373
386
|
try {
|
|
374
|
-
const [sid, hint] = await core.openAgentWithInitialPrompt(kind, {
|
|
387
|
+
const [sid, hint, eventCursor] = await core.openAgentWithInitialPrompt(kind, {
|
|
375
388
|
prompt: prompt ?? undefined,
|
|
376
389
|
model: model ?? undefined,
|
|
377
390
|
reasoning_effort: reasoning_effort ?? undefined,
|
|
@@ -384,6 +397,8 @@ function registerAgentTool(toolName, kind, desc) {
|
|
|
384
397
|
provider: kind,
|
|
385
398
|
session_id: sid,
|
|
386
399
|
managed_completion: true,
|
|
400
|
+
event_cursor: eventCursor,
|
|
401
|
+
wait_command: eventCursor === null ? null : `aiterm-wait --session ${sid} --cursor ${eventCursor}`,
|
|
387
402
|
};
|
|
388
403
|
return {
|
|
389
404
|
content: [{ type: "text", text: `session_id: ${sid}\n${hint}` }],
|
|
@@ -396,14 +411,22 @@ function registerAgentTool(toolName, kind, desc) {
|
|
|
396
411
|
});
|
|
397
412
|
}
|
|
398
413
|
registerAgentTool("claude_agent", "claude", "【Claude Code (Anthropic)】の対話エージェントTUIを永続端末に起動する。`claude -p`ではなく、" +
|
|
399
|
-
"同じ利用者可視sessionへpty_sendで継続入力する。常にmanaged(isolated settingsのStop hook
|
|
414
|
+
"同じ利用者可視sessionへpty_sendで継続入力する。常にmanaged(isolated settingsのStop hook)で起動する。" +
|
|
415
|
+
agentCompletionDesc +
|
|
416
|
+
"Claude の durable turn は claude_turn でも回収できる。");
|
|
400
417
|
registerAgentTool("codex_agent", "codex", "【Codex (OpenAI)】の対話エージェント TUI を永続端末に起動する。実装・レビュー・調査を対話で回す。" +
|
|
401
|
-
"
|
|
418
|
+
"turn は pty_send で送る(自動で非ブロック dispatch になる)。" +
|
|
419
|
+
agentCompletionDesc +
|
|
420
|
+
"model / reasoning_effort を引数で指定可" +
|
|
402
421
|
"(省略時は端末 config/CLI 既定を継承。実効値は起動応答に明示)。");
|
|
403
422
|
registerAgentTool("grok_agent", "grok", "【Grok Build の Grok モデル (既定 grok-4.5)】の対話エージェント TUI を永続端末に起動する。" +
|
|
404
|
-
"
|
|
423
|
+
"turn は pty_send で送る(自動で非ブロック dispatch になる)。" +
|
|
424
|
+
agentCompletionDesc +
|
|
425
|
+
"model を引数で指定可。reasoning_effort は対話 TUI 非対応(指定はエラー)。");
|
|
405
426
|
registerAgentTool("composer_agent", "composer", "【Grok Build の Composer モデル (既定 grok-composer-2.5-fast)】の対話エージェント TUI を永続端末に起動する。" +
|
|
406
|
-
"
|
|
427
|
+
"turn は pty_send で送る(自動で非ブロック dispatch になる)。" +
|
|
428
|
+
agentCompletionDesc +
|
|
429
|
+
"model を引数で指定可。reasoning_effort は非対応(指定はエラー)。");
|
|
407
430
|
async function main() {
|
|
408
431
|
const transport = new StdioServerTransport();
|
|
409
432
|
await server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiterm-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
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": [
|