aiterm-mcp 0.3.1 → 0.4.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 +1 -1
- package/README.md +1 -1
- package/dist/core.js +32 -13
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -179,7 +179,7 @@ claude mcp add --scope user --transport stdio aiterm -- aiterm-mcp
|
|
|
179
179
|
|
|
180
180
|
## 既知の制約(バグではなく仕様)
|
|
181
181
|
|
|
182
|
-
- **ネスト中(ssh / docker / REPL)は quiescence が原理的に効かない。** 前面コマンドがシェル集合(bash/sh/zsh/fish/dash
|
|
182
|
+
- **ネスト中(ssh / docker / REPL)は quiescence が原理的に効かない。** 前面コマンドがシェル集合(bash/sh/zsh/fish/dash)の外になるため。ネスト中で `until` 未指定のときは、待っても完了を確定できる信号が無いので、`pty_read({ wait: true })` はフル `timeout` を空費せず出力静止時点で `is_complete=False via nested` と早期に返し、`until`(プロンプト等の正規表現)か `mark: true`(終了コード付き sentinel)の指定を促す。
|
|
183
183
|
- **`is_complete=False` は失敗ではない。** 「timeout 内に完了を観測できなかった」という意味。長時間コマンドでは `timeout` を伸ばすか `until`/`mark` を使う。
|
|
184
184
|
- **破壊ゲートはサンドボックスではなく tripwire。** よくある破壊形だけを弾く。相対パスの `rm`、`$VAR` 展開後に危険化するもの、ssh 先で実行されるコマンドは捕捉しない。
|
|
185
185
|
- **`pty_send({ rtk: true })` は単行コマンドのみ+外部 `rtk` バイナリが必要**(無ければ素通し)。一方 `pty_read({ rtk: true })` の reducer は自前実装で rtk 非依存。
|
package/README.md
CHANGED
|
@@ -179,7 +179,7 @@ Before sending, `pty_send` blocks destructive commands (`rm -rf /`, `mkfs`, `dd
|
|
|
179
179
|
|
|
180
180
|
## Known constraints (by design, not bugs)
|
|
181
181
|
|
|
182
|
-
- **While nested (ssh / docker / REPL), quiescence cannot fire by design**, because the foreground command is no longer in the shell set (bash/sh/zsh/fish/dash).
|
|
182
|
+
- **While nested (ssh / docker / REPL), quiescence cannot fire by design**, because the foreground command is no longer in the shell set (bash/sh/zsh/fish/dash). When nested with no `until`, `pty_read({ wait: true })` returns early as `is_complete=False via nested` (rather than burning the full `timeout`, since no signal can confirm completion there) with a note to pass `until` (a regex for the prompt) or `mark: true` (an exit-code sentinel) for a confirmed completion.
|
|
183
183
|
- **`is_complete=False` is not a failure.** It means "completion was not observed within `timeout`." For long commands, raise `timeout` or use `until`/`mark`.
|
|
184
184
|
- **The destructive gate is a tripwire, not a sandbox.** It blocks common destructive forms only. It does **not** catch relative-path `rm`, things that become dangerous after `$VAR` expansion, or commands run on the far side of an SSH session.
|
|
185
185
|
- **`pty_send({ rtk: true })` is single-line only and needs the external `rtk` binary** (passthrough without it). The `pty_read({ rtk: true })` reducer, by contrast, is self-contained and rtk-independent.
|
package/dist/core.js
CHANGED
|
@@ -332,7 +332,7 @@ async function settleWinLog(name) {
|
|
|
332
332
|
await sleep(POLL * 1000);
|
|
333
333
|
}
|
|
334
334
|
}
|
|
335
|
-
/**
|
|
335
|
+
/** 完了境界: dead / until 一致 / (出力静止 ∧ シェル復帰)=quiescent / (ネスト中+until無しで出力静止)=nested(未確定・早期返却) / timeout。 */
|
|
336
336
|
async function waitCompletion(name, untilRe, timeout) {
|
|
337
337
|
// 締切は単調時計で測る。Date.now() は NTP 補正やサスペンドで巻き戻り、長時間待ちで誤判定する(Python は time.monotonic)。
|
|
338
338
|
const deadline = performance.now() + timeout * 1000;
|
|
@@ -362,10 +362,22 @@ async function waitCompletion(name, untilRe, timeout) {
|
|
|
362
362
|
}
|
|
363
363
|
if (size === lastSize) {
|
|
364
364
|
stable++;
|
|
365
|
-
if (stable >= STABLE_POLLS
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
365
|
+
if (stable >= STABLE_POLLS) {
|
|
366
|
+
const fg = paneCurrentCommand(name);
|
|
367
|
+
if (SHELLS.has(fg)) {
|
|
368
|
+
if (isWin)
|
|
369
|
+
await settleWinLog(name);
|
|
370
|
+
return [true, "quiescent"]; // 出力静止 ∧ シェル復帰 = 確証つき完了
|
|
371
|
+
}
|
|
372
|
+
// ネスト中(前面が ssh/docker/REPL 等でシェル集合外)は quiescence の「シェル復帰」条件を
|
|
373
|
+
// 原理的に満たせない。until 未指定ならこれ以上待っても確証は増えない(until/dead/quiescent の
|
|
374
|
+
// いずれも発火し得ない)ので、出力が静止した時点で「未確定」のまま早期返却し until/mark を促す。
|
|
375
|
+
// fg==="" は前面コマンド取得失敗=ネスト断定不可なので早期返却せず従来どおり timeout まで待つ。
|
|
376
|
+
if (!until && fg !== "") {
|
|
377
|
+
if (isWin)
|
|
378
|
+
await settleWinLog(name);
|
|
379
|
+
return [false, "nested"];
|
|
380
|
+
}
|
|
369
381
|
}
|
|
370
382
|
}
|
|
371
383
|
else {
|
|
@@ -377,6 +389,17 @@ async function waitCompletion(name, untilRe, timeout) {
|
|
|
377
389
|
await sleep(POLL * 1000);
|
|
378
390
|
}
|
|
379
391
|
}
|
|
392
|
+
// 完了ステータス → is_complete 表記。確証のある層のみ True(until/dead/quiescent)。
|
|
393
|
+
// timeout と nested(ネスト中・出力静止だが確証なし)は False。nested は until/mark を促す注記を添える。
|
|
394
|
+
function completionSuffix(status) {
|
|
395
|
+
const complete = status === "until" || status === "dead" || status === "quiescent";
|
|
396
|
+
let s = ` [is_complete=${complete ? "True" : "False"} via ${status}]`;
|
|
397
|
+
if (status === "nested")
|
|
398
|
+
s +=
|
|
399
|
+
" ネスト中(前面が ssh/docker/REPL 等)は出力静止だけでは完了を確定できません。" +
|
|
400
|
+
"until(リモートのプロンプト等の正規表現)か mark:true で完了を指定してください。";
|
|
401
|
+
return s;
|
|
402
|
+
}
|
|
380
403
|
function rtkRewrite(text) {
|
|
381
404
|
if (text.trim().includes("\n"))
|
|
382
405
|
return text;
|
|
@@ -506,20 +529,16 @@ export async function readOutput(name, o = {}) {
|
|
|
506
529
|
const [reduced, rname] = rtk.reduce(cmd, framed);
|
|
507
530
|
if (reduced !== null) {
|
|
508
531
|
const meta = `[aiterm ${name}: rtk:${rname} 適用 / ~${estimateTokens(reduced)} tok (raw ~${estimateTokens(text)} tok)]`;
|
|
509
|
-
if (status)
|
|
510
|
-
|
|
511
|
-
return reduced + "\n" + meta + ` [is_complete=${complete ? "True" : "False"} via ${status}]`;
|
|
512
|
-
}
|
|
532
|
+
if (status)
|
|
533
|
+
return reduced + "\n" + meta + completionSuffix(status);
|
|
513
534
|
return reduced + "\n" + meta;
|
|
514
535
|
}
|
|
515
536
|
}
|
|
516
537
|
// reducer 非該当 → 汎用削減へフォールバック
|
|
517
538
|
}
|
|
518
539
|
const [body, meta] = reduceOutput(text, name, !o.range);
|
|
519
|
-
if (status)
|
|
520
|
-
|
|
521
|
-
return body + "\n" + meta + ` [is_complete=${complete ? "True" : "False"} via ${status}]`;
|
|
522
|
-
}
|
|
540
|
+
if (status)
|
|
541
|
+
return body + "\n" + meta + completionSuffix(status);
|
|
523
542
|
return body + "\n" + meta;
|
|
524
543
|
}
|
|
525
544
|
export function listSessions() {
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
12
12
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
13
13
|
import { z } from "zod";
|
|
14
14
|
import * as core from "./core.js";
|
|
15
|
-
const server = new McpServer({ name: "aiterm", version: "0.
|
|
15
|
+
const server = new McpServer({ name: "aiterm", version: "0.4.0" });
|
|
16
16
|
function ok(s) {
|
|
17
17
|
return { content: [{ type: "text", text: s }] };
|
|
18
18
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiterm-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"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. Token-reducing reads.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|