aiterm-mcp 0.20.3 → 0.21.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 +2 -0
- package/README.md +2 -0
- package/dist/aiterm-wait-cli.js +0 -0
- package/dist/core.js +25 -7
- package/dist/index.js +25 -1
- package/dist/runtime-errors-cli.js +0 -0
- package/package.json +4 -3
package/README.ja.md
CHANGED
|
@@ -135,6 +135,8 @@ pty_read(id, { wait: true }) → 削減済みの出力を読む(完了
|
|
|
135
135
|
|
|
136
136
|
同じ 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`、そして `submit_residue` 観測を含む(true=prompt が composer に未 submit で残存している疑い=案内に従い画面確認から復旧 / false=残存観測せず・成立の保証ではない / null=対象外)。dispatch receipt にも同じ観測が付く。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 を自分で起動する。
|
|
137
137
|
|
|
138
|
+
`codex_agent`・`grok_agent`・`composer_agent`は任意の`write_scope`(`"read-only"`または書込み許可パスの説明)も受ける。指定値はlaunch receipt・session metadata・`pty_list`へ保存する。Codexの`write_scope:"read-only"`だけは実効能力壁であり、aitermがCLIの`--sandbox read-only`を付ける。Grok/Composerには対応する対話起動sandboxがなく、Codexにもパス説明をallowlistへ変換するフラグがないため、それらは強制済みと偽らず`write_scope_enforcement:"declaration_only_unsupported"`を返す。`write_scope`を省略した起動は従来どおりである。
|
|
139
|
+
|
|
138
140
|
```text
|
|
139
141
|
codex_agent({ session_name: "codex1", cwd: "/repo",
|
|
140
142
|
prompt: "port test/legacy.py to vitest" })
|
package/README.md
CHANGED
|
@@ -145,6 +145,8 @@ pty_read(id, { wait: true }) → read the token-reduced output, completion
|
|
|
145
145
|
|
|
146
146
|
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`, a ready-made `wait_command` for the completion waiter, and a `submit_residue` observation (`true` = the prompt is likely still sitting unsubmitted in the composer — the hint explains recovery; `false` = no residue observed, not a proof of submission; `null` = not applicable). 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).
|
|
147
147
|
|
|
148
|
+
`codex_agent`, `grok_agent`, and `composer_agent` also accept an optional `write_scope`: either `"read-only"` or a human-readable description of writable paths. A supplied value is retained in the launch receipt, session metadata, and `pty_list`. For Codex, `write_scope: "read-only"` is an effective boundary: aiterm adds the CLI's `--sandbox read-only` flag. Grok/Composer have no corresponding interactive-launch sandbox, and Codex has no path-description allowlist flag; those cases return `write_scope_enforcement: "declaration_only_unsupported"` rather than claiming enforcement. Omitting `write_scope` preserves prior behavior.
|
|
149
|
+
|
|
148
150
|
For a managed Claude turn stopped at `Do you want to proceed?`, use `claude_approval(action: "inspect", ...)` to capture the active operation and SHA-256 screen digest, review the displayed command, then call `respond` with that exact digest and either `approve_once` or `deny`. The relay rechecks the operation and screen under the send lock, never exposes arbitrary input or permanent approval, keeps the active marker intact, and records a prompt-free owner-only receipt. `pty_send(force: true)` does not bypass this boundary.
|
|
149
151
|
|
|
150
152
|
```text
|
package/dist/aiterm-wait-cli.js
CHANGED
|
File without changes
|
package/dist/core.js
CHANGED
|
@@ -1230,6 +1230,7 @@ export function listSessions() {
|
|
|
1230
1230
|
const agent = [
|
|
1231
1231
|
`agent=${meta.kind}`,
|
|
1232
1232
|
"agent_done=true",
|
|
1233
|
+
meta.write_scope === undefined ? null : `write_scope=${JSON.stringify(meta.write_scope)}`,
|
|
1233
1234
|
meta.vendor_session_id ? `vendor_session_id=${meta.vendor_session_id}` : null,
|
|
1234
1235
|
]
|
|
1235
1236
|
.filter(Boolean)
|
|
@@ -2261,7 +2262,7 @@ function createClaudeAgentMetadata(name, cwd, initialPrompt, launchOperationId,
|
|
|
2261
2262
|
writeAgentMetadata(meta);
|
|
2262
2263
|
return meta;
|
|
2263
2264
|
}
|
|
2264
|
-
function createCodexAgentMetadata(name, cwd, initialPrompt, overrides = {}) {
|
|
2265
|
+
function createCodexAgentMetadata(name, cwd, initialPrompt, overrides = {}, writeScope) {
|
|
2265
2266
|
const launchId = randomBytes(16).toString("hex");
|
|
2266
2267
|
const eventFile = agentEventPath(name, launchId);
|
|
2267
2268
|
createEmpty0600NoFollow(eventFile);
|
|
@@ -2273,6 +2274,7 @@ function createCodexAgentMetadata(name, cwd, initialPrompt, overrides = {}) {
|
|
|
2273
2274
|
event_file: eventFile,
|
|
2274
2275
|
created_at: new Date().toISOString(),
|
|
2275
2276
|
cwd,
|
|
2277
|
+
...(writeScope === undefined ? {} : { write_scope: writeScope }),
|
|
2276
2278
|
vendor_session_id: null,
|
|
2277
2279
|
initial_prompt: initialPrompt,
|
|
2278
2280
|
hook_route: "managed_codex_home",
|
|
@@ -2282,7 +2284,7 @@ function createCodexAgentMetadata(name, cwd, initialPrompt, overrides = {}) {
|
|
|
2282
2284
|
writeAgentMetadata(meta);
|
|
2283
2285
|
return meta;
|
|
2284
2286
|
}
|
|
2285
|
-
function createGrokAgentMetadata(kind, name, cwd, initialPrompt, authPath) {
|
|
2287
|
+
function createGrokAgentMetadata(kind, name, cwd, initialPrompt, authPath, writeScope) {
|
|
2286
2288
|
const launchId = randomBytes(16).toString("hex");
|
|
2287
2289
|
const eventFile = agentEventPath(name, launchId);
|
|
2288
2290
|
createEmpty0600NoFollow(eventFile);
|
|
@@ -2294,6 +2296,7 @@ function createGrokAgentMetadata(kind, name, cwd, initialPrompt, authPath) {
|
|
|
2294
2296
|
event_file: eventFile,
|
|
2295
2297
|
created_at: new Date().toISOString(),
|
|
2296
2298
|
cwd,
|
|
2299
|
+
...(writeScope === undefined ? {} : { write_scope: writeScope }),
|
|
2297
2300
|
vendor_session_id: null,
|
|
2298
2301
|
initial_prompt: initialPrompt,
|
|
2299
2302
|
hook_route: "managed_grok_home",
|
|
@@ -2355,6 +2358,7 @@ function loadAgentMetadata(name) {
|
|
|
2355
2358
|
event_file: expectedEvent,
|
|
2356
2359
|
created_at: typeof m.created_at === "string" ? m.created_at : "",
|
|
2357
2360
|
cwd: typeof m.cwd === "string" ? m.cwd : null,
|
|
2361
|
+
...(typeof m.write_scope === "string" ? { write_scope: m.write_scope } : {}),
|
|
2358
2362
|
vendor_session_id: typeof m.vendor_session_id === "string" ? m.vendor_session_id : null,
|
|
2359
2363
|
initial_prompt: normalizeInitialPromptState(m.initial_prompt),
|
|
2360
2364
|
launch_operation_id: launchOperationId,
|
|
@@ -2377,6 +2381,7 @@ function loadAgentMetadata(name) {
|
|
|
2377
2381
|
event_file: expectedEvent,
|
|
2378
2382
|
created_at: typeof m.created_at === "string" ? m.created_at : "",
|
|
2379
2383
|
cwd: typeof m.cwd === "string" ? m.cwd : null,
|
|
2384
|
+
...(typeof m.write_scope === "string" ? { write_scope: m.write_scope } : {}),
|
|
2380
2385
|
vendor_session_id: typeof m.vendor_session_id === "string" ? m.vendor_session_id : null,
|
|
2381
2386
|
initial_prompt: normalizeInitialPromptState(m.initial_prompt),
|
|
2382
2387
|
hook_route: "managed_codex_home",
|
|
@@ -2400,6 +2405,7 @@ function loadAgentMetadata(name) {
|
|
|
2400
2405
|
event_file: expectedEvent,
|
|
2401
2406
|
created_at: typeof m.created_at === "string" ? m.created_at : "",
|
|
2402
2407
|
cwd: typeof m.cwd === "string" ? m.cwd : null,
|
|
2408
|
+
...(typeof m.write_scope === "string" ? { write_scope: m.write_scope } : {}),
|
|
2403
2409
|
vendor_session_id: typeof m.vendor_session_id === "string" ? m.vendor_session_id : null,
|
|
2404
2410
|
initial_prompt: normalizeInitialPromptState(m.initial_prompt),
|
|
2405
2411
|
hook_route: "managed_grok_home",
|
|
@@ -3448,6 +3454,10 @@ function buildAgentCmd(kind, bin, model, effort, prompt, meta = null) {
|
|
|
3448
3454
|
else if (kind === "codex") {
|
|
3449
3455
|
if (meta?.kind === "codex")
|
|
3450
3456
|
parts.push("--dangerously-bypass-hook-trust");
|
|
3457
|
+
// `codex --help` で確認した実在フラグ。read-only 宣言だけはCLI sandboxへ落とし、
|
|
3458
|
+
// launcher自身が実効能力壁を作る。パス説明はCodex CLIに同等のallowlist引数がないため宣言のまま残す。
|
|
3459
|
+
if (meta?.kind === "codex" && meta.write_scope === "read-only")
|
|
3460
|
+
parts.push("--sandbox", "read-only");
|
|
3451
3461
|
// model/effort は CLI 引数で明示(config 継承より優先)。agent_done 時は managed home 側
|
|
3452
3462
|
// config.toml も同値で上書き済み(applyCodexConfigOverrides)。
|
|
3453
3463
|
if (model)
|
|
@@ -3516,12 +3526,17 @@ function agentLabel(kind) {
|
|
|
3516
3526
|
// model_reasoning_effort)が対話子へ波及する構造のため、引数・端末config継承・CLI既定の
|
|
3517
3527
|
// どれで起動したかを起動時点で可視化し、実効 effort=ultra は proactive 自動委譲 ON を警告する。
|
|
3518
3528
|
function buildAgentLaunchNote(kind, model, effort, meta) {
|
|
3529
|
+
const writeScopeNote = meta?.write_scope === undefined
|
|
3530
|
+
? ""
|
|
3531
|
+
: kind === "codex" && meta.write_scope === "read-only"
|
|
3532
|
+
? `\n能力宣言: write_scope=${JSON.stringify(meta.write_scope)}。Codex CLIへ --sandbox read-only を付与し、書込みを実効禁止。`
|
|
3533
|
+
: `\n能力宣言: write_scope=${JSON.stringify(meta.write_scope)}。${kind === "grok" || kind === "composer" ? "このCLIには起動sandbox機構がないため" : "パス単位のsandbox allowlistに対応するCLI引数がないため"}宣言の記録のみ(構造的unsupported)。`;
|
|
3519
3534
|
if (kind === "claude") {
|
|
3520
|
-
return `起動設定: model=${model ?? "CLI既定"} effort=${effort ?? "CLI既定"}
|
|
3535
|
+
return `起動設定: model=${model ?? "CLI既定"} effort=${effort ?? "CLI既定"}。${writeScopeNote}`;
|
|
3521
3536
|
}
|
|
3522
3537
|
if (kind !== "codex") {
|
|
3523
3538
|
return (`起動設定: model=${model ?? GROK_MODEL_DEFAULTS[kind]}(${model ? "引数" : "ツール既定"})。` +
|
|
3524
|
-
"reasoning effort は対話 TUI 非対応=未指定で起動。");
|
|
3539
|
+
"reasoning effort は対話 TUI 非対応=未指定で起動。" + writeScopeNote);
|
|
3525
3540
|
}
|
|
3526
3541
|
const configPath = meta?.kind === "codex" && meta.codex_home
|
|
3527
3542
|
? path.join(meta.codex_home, "config.toml")
|
|
@@ -3540,7 +3555,7 @@ function buildAgentLaunchNote(kind, model, effort, meta) {
|
|
|
3540
3555
|
? "⚠ effort=ultra は max 推論+proactive 自動委譲 ON(子エージェント自動生成・使用量急増に注意)。"
|
|
3541
3556
|
: "");
|
|
3542
3557
|
const summary = meta?.kind === "codex" && meta.codex_home ? managedCodexConfigSummary(configPath, true) : "";
|
|
3543
|
-
return summary ? `${launch}\n${summary}\n` : launch;
|
|
3558
|
+
return (summary ? `${launch}\n${summary}\n` : launch) + writeScopeNote;
|
|
3544
3559
|
}
|
|
3545
3560
|
function claudeLaunchRequestDigest({ sessionName, model, effort, cwd, agentDone, }) {
|
|
3546
3561
|
const canonical = JSON.stringify({
|
|
@@ -3582,6 +3597,7 @@ export function openAgent(kind, opts = {}) {
|
|
|
3582
3597
|
throw new AitermError("model が空文字です(省略するか有効なモデル名を指定してください)", 2);
|
|
3583
3598
|
}
|
|
3584
3599
|
const effort = opts.reasoning_effort ?? null;
|
|
3600
|
+
const writeScope = opts.write_scope;
|
|
3585
3601
|
if (effort && kind === "claude" && !CLAUDE_EFFORTS.has(effort)) {
|
|
3586
3602
|
throw new AitermError("Claude Code の reasoning_effort は low/medium/high/xhigh/max のいずれかです", 2);
|
|
3587
3603
|
}
|
|
@@ -3690,8 +3706,8 @@ export function openAgent(kind, opts = {}) {
|
|
|
3690
3706
|
? kind === "claude"
|
|
3691
3707
|
? createClaudeAgentMetadata(sid, cwd, opts.prompt ? "pending" : "none", launchOperationId, launchRequestDigest)
|
|
3692
3708
|
: kind === "codex"
|
|
3693
|
-
? createCodexAgentMetadata(sid, cwd, opts.prompt ? "pending" : "none", { model, effort })
|
|
3694
|
-
: createGrokAgentMetadata(kind, sid, cwd, opts.prompt ? "pending" : "none", grokAuthPath)
|
|
3709
|
+
? createCodexAgentMetadata(sid, cwd, opts.prompt ? "pending" : "none", { model, effort }, writeScope)
|
|
3710
|
+
: createGrokAgentMetadata(kind, sid, cwd, opts.prompt ? "pending" : "none", grokAuthPath, writeScope)
|
|
3695
3711
|
: null;
|
|
3696
3712
|
if (meta)
|
|
3697
3713
|
agentMetadataNegativeCache.delete(sid);
|
|
@@ -3754,6 +3770,7 @@ export async function openAgentWithInitialPrompt(kind, opts = {}) {
|
|
|
3754
3770
|
prompt,
|
|
3755
3771
|
agent_done: true,
|
|
3756
3772
|
launch_operation_id: opts.launch_operation_id ?? null,
|
|
3773
|
+
write_scope: opts.write_scope,
|
|
3757
3774
|
});
|
|
3758
3775
|
// argv prompt(grok/composer)は composer を経由しないため submit 座礁観測の対象外。
|
|
3759
3776
|
return [sid, hint, prompt ? 0 : null, null];
|
|
@@ -3766,6 +3783,7 @@ export async function openAgentWithInitialPrompt(kind, opts = {}) {
|
|
|
3766
3783
|
prompt: null,
|
|
3767
3784
|
agent_done: true,
|
|
3768
3785
|
launch_operation_id: opts.launch_operation_id ?? null,
|
|
3786
|
+
write_scope: opts.write_scope,
|
|
3769
3787
|
});
|
|
3770
3788
|
try {
|
|
3771
3789
|
const initial = await sendInitialAgentPrompt(sid, prompt, {
|
package/dist/index.js
CHANGED
|
@@ -420,6 +420,19 @@ const agentCompletionDesc = `起動して投げたら投げっぱなしでよい
|
|
|
420
420
|
`結果回収は pty_read(agent_transcript:true)。`;
|
|
421
421
|
function registerAgentTool(toolName, kind, desc) {
|
|
422
422
|
const correlatedLaunchSchema = {};
|
|
423
|
+
const supportsWriteScope = kind === "codex" || kind === "grok" || kind === "composer";
|
|
424
|
+
const writeScopeInputSchema = supportsWriteScope
|
|
425
|
+
? {
|
|
426
|
+
write_scope: z.string().min(1).optional().describe("能力宣言。read-only、または書込みを許可するパスの説明文字列。Codexのread-onlyだけはCLI sandboxで実効禁止する"),
|
|
427
|
+
}
|
|
428
|
+
: {};
|
|
429
|
+
const writeScopeOutputSchema = supportsWriteScope
|
|
430
|
+
? {
|
|
431
|
+
// write_scope省略時は既存launch receiptを完全に保つため両fieldを出さない。
|
|
432
|
+
write_scope: z.string().optional(),
|
|
433
|
+
write_scope_enforcement: z.enum(["enforced_read_only", "declaration_only_unsupported"]).optional(),
|
|
434
|
+
}
|
|
435
|
+
: {};
|
|
423
436
|
if (kind === "claude") {
|
|
424
437
|
correlatedLaunchSchema.launch_operation_id = z
|
|
425
438
|
.string()
|
|
@@ -437,6 +450,7 @@ function registerAgentTool(toolName, kind, desc) {
|
|
|
437
450
|
reasoning_effort: z.string().nullish().describe(agentEffortDesc(kind)),
|
|
438
451
|
cwd: z.string().nullish().describe("作業ディレクトリ(対象リポのルート等・任意)"),
|
|
439
452
|
session_name: z.string().nullish().describe("セッション名(省略で自動採番)"),
|
|
453
|
+
...writeScopeInputSchema,
|
|
440
454
|
...correlatedLaunchSchema,
|
|
441
455
|
},
|
|
442
456
|
outputSchema: {
|
|
@@ -451,8 +465,9 @@ function registerAgentTool(toolName, kind, desc) {
|
|
|
451
465
|
// 初回prompt dispatch後のsubmit座礁観測(additive)。true=composerに残存を確認(submit未成立の疑い)/
|
|
452
466
|
// false=残存を観測せず(submit成立の保証ではない)/ null=promptなし・argv prompt・判定不能。
|
|
453
467
|
submit_residue: z.boolean().nullable(),
|
|
468
|
+
...writeScopeOutputSchema,
|
|
454
469
|
},
|
|
455
|
-
}, async ({ prompt, model, reasoning_effort, cwd, session_name, launch_operation_id }) => {
|
|
470
|
+
}, async ({ prompt, model, reasoning_effort, cwd, session_name, launch_operation_id, write_scope }) => {
|
|
456
471
|
try {
|
|
457
472
|
const [sid, hint, eventCursor, submitResidue] = await core.openAgentWithInitialPrompt(kind, {
|
|
458
473
|
prompt: prompt ?? undefined,
|
|
@@ -461,6 +476,7 @@ function registerAgentTool(toolName, kind, desc) {
|
|
|
461
476
|
cwd: cwd ?? undefined,
|
|
462
477
|
session_name: session_name ?? undefined,
|
|
463
478
|
launch_operation_id: launch_operation_id ?? undefined,
|
|
479
|
+
...(supportsWriteScope ? { write_scope } : {}),
|
|
464
480
|
});
|
|
465
481
|
const structured = {
|
|
466
482
|
schema: "aiterm.agent-launch-result.v1",
|
|
@@ -470,6 +486,14 @@ function registerAgentTool(toolName, kind, desc) {
|
|
|
470
486
|
event_cursor: eventCursor,
|
|
471
487
|
wait_command: eventCursor === null ? null : `aiterm-wait --session ${sid} --cursor ${eventCursor}`,
|
|
472
488
|
submit_residue: submitResidue,
|
|
489
|
+
...(supportsWriteScope && write_scope !== undefined
|
|
490
|
+
? {}
|
|
491
|
+
: supportsWriteScope ? {
|
|
492
|
+
write_scope,
|
|
493
|
+
write_scope_enforcement: kind === "codex" && write_scope === "read-only"
|
|
494
|
+
? "enforced_read_only"
|
|
495
|
+
: "declaration_only_unsupported",
|
|
496
|
+
} : {}),
|
|
473
497
|
};
|
|
474
498
|
return {
|
|
475
499
|
content: [{ type: "text", text: `session_id: ${sid}\n${hint}` }],
|
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiterm-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"mcpName": "io.github.kitepon-rgb/aiterm-mcp",
|
|
5
5
|
"description": "Persistent tmux terminal MCP that lets Claude Code drive Codex CLI's interactive TUI, including slash commands and $imagegen. Also runs durable PTY sessions for SSH, containers, REPLs, and coding agents.",
|
|
6
6
|
"keywords": [
|
|
@@ -54,9 +54,10 @@
|
|
|
54
54
|
"scripts": {
|
|
55
55
|
"build": "tsc",
|
|
56
56
|
"mcpb:build": "npm run build && node scripts/build-mcpb.mjs && npm ci --omit=dev --ignore-scripts --no-audit --no-fund --prefix dist/mcpb-stage/server && npx --yes @anthropic-ai/mcpb@2.1.2 validate dist/mcpb-stage/manifest.json && npx --yes @anthropic-ai/mcpb@2.1.2 pack dist/mcpb-stage dist/aiterm-mcp.mcpb",
|
|
57
|
-
"
|
|
57
|
+
"verify:release-commit": "node scripts/verify-release-commit.mjs",
|
|
58
|
+
"prepublishOnly": "npm run verify:release-commit && npm run build",
|
|
58
59
|
"start": "node dist/index.js",
|
|
59
|
-
"test": "npm run build && node --test test/*.test.mjs"
|
|
60
|
+
"test": "npm run build && node --test scripts/verify-release-commit.test.mjs test/*.test.mjs"
|
|
60
61
|
},
|
|
61
62
|
"dependencies": {
|
|
62
63
|
"@modelcontextprotocol/sdk": "^1.29.0",
|