aiterm-mcp 0.28.3 → 0.29.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/agent-resolver.js +8 -2
- package/dist/core.js +9 -7
- package/dist/harnesses/codex.js +14 -0
- package/dist/index.js +2 -1
- package/dist/runtime-error-os.js +8 -5
- package/dist/windows-powershell.js +42 -0
- package/package.json +1 -1
package/README.ja.md
CHANGED
|
@@ -459,7 +459,7 @@ handoff contextを前置きできる。この任意経路は`throughline >= 0.9.
|
|
|
459
459
|
- **Node.js >= 18**
|
|
460
460
|
- **tmux または psmux**(実行時の前提)
|
|
461
461
|
- **macOS / Linux / WSL2** は tmux を直接使う。macOS は同梱されないので `brew install tmux` で導入する。MCP クライアントがターミナルでなく **GUI から起動**された場合、Homebrew の bin(Apple Silicon: `/opt/homebrew/bin`、Intel: `/usr/local/bin`)が `PATH` に入らないことがある。その場合 aiterm が自動で探索するか、**`AITERM_TMUX=/path/to/tmux`** で明示指定する。
|
|
462
|
-
- **Windows ネイティブ**は WSL を使わず、tmux CLI互換の [psmux](https://github.com/psmux/psmux) **3.3.8
|
|
462
|
+
- **Windows ネイティブ**は WSL を使わず、tmux CLI互換の [psmux](https://github.com/psmux/psmux) **3.3.8以上**をAitermのterminal/session multiplexer backendとして使う(`winget install marlocarlo.psmux`)。**psmuxはshellではない。** `pty_open`の既定shellはPowerShell 7(`pwsh.exe`)で、Windows PowerShell 5.1・PowerShell 6・`cmd.exe`へfallbackしない。5.1しかなければMicrosoft公式installer/package managerで7を導入してから使う。Git for Windowsはharness launcherが内部で明示するBash shell用に引き続き必要。解決先は **`AITERM_PSMUX`**/**`AITERM_BASH`** で上書きできる。他製品はpsmuxへ直接依存せず、永続端末をAiterm公開APIから利用する。
|
|
463
463
|
- **agent harness**を使う場合: 対応CLIを製品所有者の公式経路で導入・認証する。CursorはmacOS/Linux/WSLで`curl https://cursor.com/install -fsS | bash`、Windows nativeで`irm 'https://cursor.com/install?win32=true' | iex`を使い、`agent login`で認証、`agent update`で更新する。Aitermは`cursor-agent`を起動する。portable forkだけは追加で`throughline >= 0.9.0`が必要。
|
|
464
464
|
- 任意: [`rtk`](https://github.com/rtk-ai/rtk) バイナリ(`pty_send` の `rtk: true` 委譲で使う。無くても動く)
|
|
465
465
|
|
package/README.md
CHANGED
|
@@ -501,7 +501,7 @@ Sessions live on a shared tmux socket on POSIX or a shared psmux namespace on na
|
|
|
501
501
|
- **Node.js >= 18**
|
|
502
502
|
- **tmux or psmux** (platform runtime prerequisite)
|
|
503
503
|
- **macOS / Linux / WSL2** run tmux directly. On macOS install it with `brew install tmux` (stock macOS ships none). If your MCP client is launched from the **GUI** rather than a terminal, Homebrew's bin (`/opt/homebrew/bin` on Apple Silicon, `/usr/local/bin` on Intel) may be off its `PATH`; aiterm auto-searches those locations, or set **`AITERM_TMUX=/path/to/tmux`** to point at it explicitly.
|
|
504
|
-
- **Native Windows** has no tmux, so aiterm drives [psmux](https://github.com/psmux/psmux) — a tmux-CLI-compatible native multiplexer — with a per-install `-L` namespace. **
|
|
504
|
+
- **Native Windows** has no tmux, so aiterm drives [psmux](https://github.com/psmux/psmux) — a tmux-CLI-compatible native terminal/session multiplexer — with a per-install `-L` namespace. **psmux is not a shell.** `pty_open` defaults to PowerShell 7 (`pwsh.exe`) and never falls back to Windows PowerShell 5.1, PowerShell 6, or `cmd.exe`; if only 5.1 is installed, use Microsoft's official installer or package manager first. Install psmux **3.3.8 or newer** (`winget install marlocarlo.psmux`; 3.3.8 is the first release whose `pipe-pane` file sink, byte-exact `paste-buffer` wire, and foreground `#{pane_current_command}` behave the way aiterm's capture/dispatch paths rely on). [Git for Windows](https://gitforwindows.org/) remains required for the explicit Bash shell used internally by harness launchers; System32's `bash.exe` is the WSL launcher and is deliberately not used. Override multiplexer/Bash resolution with **`AITERM_PSMUX`** / **`AITERM_BASH`**. Other products consume persistent terminals through Aiterm's public API instead of depending on psmux directly.
|
|
505
505
|
- For **agent harnesses**: the selected CLI, installed and authenticated through its product owner's official path — `claude`, `codex`, `grok`, or Cursor's `cursor-agent`. Portable fork additionally needs `throughline >= 0.9.0`; ordinary clean launch does not. (Not needed if you only use the PTY tools.)
|
|
506
506
|
- Optional: the [`rtk`](https://github.com/rtk-ai/rtk) binary (used by `pty_send`'s `rtk: true` delegation; works fine without it)
|
|
507
507
|
|
package/dist/agent-resolver.js
CHANGED
|
@@ -5,6 +5,7 @@ import * as fs from "node:fs";
|
|
|
5
5
|
import * as path from "node:path";
|
|
6
6
|
import * as os from "node:os";
|
|
7
7
|
import { AitermError } from "./errors.js";
|
|
8
|
+
import { resolveWindowsPowerShell7 } from "./windows-powershell.js";
|
|
8
9
|
import { isWin } from "./tmux-runtime.js";
|
|
9
10
|
export function isUsableExecutableFile(candidate) {
|
|
10
11
|
try {
|
|
@@ -84,7 +85,12 @@ export function spawnAgentControlCommand(bin, args, _cwd, options) {
|
|
|
84
85
|
return spawnSync(bin, args, options);
|
|
85
86
|
}
|
|
86
87
|
export function resolveWinPaneShell(shell) {
|
|
87
|
-
if (!isWin
|
|
88
|
+
if (!isWin)
|
|
89
|
+
return shell;
|
|
90
|
+
if (["powershell", "powershell.exe", "pwsh", "pwsh.exe"].includes(path.basename(shell).toLowerCase())) {
|
|
91
|
+
return resolveWindowsPowerShell7();
|
|
92
|
+
}
|
|
93
|
+
if (shell !== "bash")
|
|
88
94
|
return shell;
|
|
89
95
|
const fromEnv = process.env.AITERM_BASH;
|
|
90
96
|
if (fromEnv) {
|
|
@@ -166,7 +172,7 @@ export function runThroughlineHandoffContext(bin, sessionId) {
|
|
|
166
172
|
if (isWin && /\.(?:cmd|bat)$/i.test(bin)) {
|
|
167
173
|
const ps1 = path.join(path.dirname(bin), `${path.basename(bin, path.extname(bin))}.ps1`);
|
|
168
174
|
if (fs.existsSync(ps1)) {
|
|
169
|
-
return spawnSync(
|
|
175
|
+
return spawnSync(resolveWindowsPowerShell7(), [
|
|
170
176
|
"-NoLogo",
|
|
171
177
|
"-NoProfile",
|
|
172
178
|
"-NonInteractive",
|
package/dist/core.js
CHANGED
|
@@ -16,7 +16,7 @@ import { AitermError, telemetryOwnedFailure, ownTelemetryFailure } from "./error
|
|
|
16
16
|
import { isWin, SOCKDIR, tmuxCommand, loadPtyBufferChunk, pasteBufferBaseArgs, TMUX_EMPTY_CONFIG, attachCommand, normalizePaneCommand, appendMarkSentinel, settlePaneLog, paneCwdArgument, } from "./tmux-runtime.js";
|
|
17
17
|
import { sleep, currentUid, runtimeStateBase, safeStatSize, readFileRange, writeJson0600, createEmpty0600, shq, LAUNCH_ID_RE, AGENT_DONE_POLL_MS, AGENT_EVENT_MAX_BYTES, assertSessionName, agentsDir, agentEventPath, agentMetadataPath, writeAgentMetadata, AGENT_EVENT_TAIL_BYTES, agentLabel, agentHarness, subagentInstruction, agentLineageFields, } from "./agent-shared.js";
|
|
18
18
|
import { GROK_MODEL_DEFAULTS, realGrokHome, resolveAndValidateGrokAuth, assertGrokModelAvailable, grokEventsTranscript, latestGrokCompletion, grokInitializationComplete, observeGrokDone, buildGrokAgentCmd, grokLaunchNote, grokEnvTokens, grokTuiReady, GROK_COMPOSER_MARKER_RE, grokFooterHasConfiguration, grokTranscriptText, createGrokAgentMetadata, } from "./harnesses/grok.js";
|
|
19
|
-
import { bindCodexTranscriptSession, latestCodexCompletion, observeCodexDone, buildCodexAgentCmd, codexLaunchNote, codexTuiReady, CODEX_COMPOSER_MARKER_RE, codexModelChoice, codexEffortChoice, codexMoreReasoningChoice, codexTranscriptText, createCodexAgentMetadata, } from "./harnesses/codex.js";
|
|
19
|
+
import { bindCodexTranscriptSession, latestCodexCompletion, observeCodexDone, buildCodexAgentCmd, codexLaunchNote, codexTuiReady, codexLaunchBlockingDialog, CODEX_COMPOSER_MARKER_RE, codexModelChoice, codexEffortChoice, codexMoreReasoningChoice, codexTranscriptText, createCodexAgentMetadata, } from "./harnesses/codex.js";
|
|
20
20
|
import { OPERATION_ID_RE, CLAUDE_RESULT_MAX_BYTES, CLAUDE_EFFORTS, agentManagedClaudeSettingsPath, agentClaudeResultPath, agentClaudeOperationPath, agentClaudeApprovalReceiptPath, agentClaudeDispatchReceiptPath, validateOperationId, readClaudeResultText, assertClaudeAuthenticationReady, buildClaudeAgentCmd, claudeLaunchNote, claudeTuiReady, CLAUDE_COMPOSER_MARKER_RE, createClaudeAgentMetadata, } from "./harnesses/claude.js";
|
|
21
21
|
import { bindCursorTranscriptSession, cursorTurnBoundary, latestCursorCompletion, observeCursorDone, cursorTranscriptText, assertCursorAuthenticationReady, assertCursorModelAvailable, buildCursorAgentCmd, createCursorAgentMetadata, cursorLaunchNote, cursorEffortNavigation, cursorTuiReady, CURSOR_COMPOSER_MARKER_RE, validateCursorModelEffort, } from "./harnesses/cursor.js";
|
|
22
22
|
import { resolveAgentBin, resolveThroughlineBin, runThroughlineHandoffContext, isWindowsNativeExecutable, agentBinForPaneShell, resolveWinPaneShell } from "./agent-resolver.js";
|
|
@@ -2508,12 +2508,14 @@ export async function sendInitialAgentPrompt(name, text, o = {}) {
|
|
|
2508
2508
|
setInitialPromptState(meta, "not_sent");
|
|
2509
2509
|
const ready = await waitAgentTuiReady(name, meta, o.ready_timeout ?? AGENT_TUI_READY_TIMEOUT_MS);
|
|
2510
2510
|
if (!ready.ready) {
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2511
|
+
// ready失敗は成功形で返さず明示エラーにする(実被弾 2026-08-25: Codexのupdate確認ダイアログで
|
|
2512
|
+
// 未送信のまま成功形receiptが返り、呼び出し側が40分気づけなかった)。sessionは調査/復旧用に残る。
|
|
2513
|
+
const dialog = meta.kind === "codex" ? codexLaunchBlockingDialog(ready.lastScreen) : null;
|
|
2514
|
+
const causeNote = dialog
|
|
2515
|
+
? `${dialog}が入力を塞いでいます。pty_read(screen:true)で画面を確認し、pty_keyでダイアログに応答してから、pty_sendでpromptを送ってください。`
|
|
2516
|
+
: `pty_read(screen:true)で画面を確認し、入力受付になってからpty_sendでpromptを送ってください。`;
|
|
2517
|
+
throw new AitermError(`initial_prompt=not_sent vendor=${meta.kind} ready=false samples=${ready.samples} harness=${agentHarness(meta.kind)}\n` +
|
|
2518
|
+
`agent session '${name}' の ${agentLabel(meta.kind)} TUI が入力受付状態にならず、prompt は送信していません。${causeNote}`, 2);
|
|
2517
2519
|
}
|
|
2518
2520
|
const startOffset = agentCompletionCursor(meta);
|
|
2519
2521
|
try {
|
package/dist/harnesses/codex.js
CHANGED
|
@@ -381,6 +381,20 @@ export function codexTuiReady(screen) {
|
|
|
381
381
|
}
|
|
382
382
|
// submit座礁観測のcomposer領域マーカー(ready判定と同じ記号を行頭基準で探す)。
|
|
383
383
|
export const CODEX_COMPOSER_MARKER_RE = /^\s*[›>]/;
|
|
384
|
+
// Codexの起動前modalダイアログ検知。表示中はheader/footerが描かれず codexTuiReady が
|
|
385
|
+
// 恒久falseになるため、ready gate失敗の原因究明用に画面から種別を特定する
|
|
386
|
+
// (実被弾 2026-08-25: update確認で初手prompt未送信のまま30秒timeout→40分停滞)。
|
|
387
|
+
// 文字列は実機captureの逐語。既知2種に一致しない「Press enter to continue」も
|
|
388
|
+
// 同型のmodalとして拾う(種別不明のまま握りつぶさない)。
|
|
389
|
+
export function codexLaunchBlockingDialog(screen) {
|
|
390
|
+
if (screen.includes("Update available!"))
|
|
391
|
+
return "update確認ダイアログ";
|
|
392
|
+
if (screen.includes("Do you trust the contents of this directory"))
|
|
393
|
+
return "directory trust確認ダイアログ";
|
|
394
|
+
if (screen.includes("Press enter to continue"))
|
|
395
|
+
return "起動時ダイアログ(種別未特定)";
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
384
398
|
export function codexModelChoice(screen, model) {
|
|
385
399
|
for (const line of screen.slice(screen.lastIndexOf("Select Model and Effort")).split("\n")) {
|
|
386
400
|
const match = line.match(/^\s*(?:›\s*)?(\d+)\.\s+(\S+)/);
|
package/dist/index.js
CHANGED
|
@@ -84,13 +84,14 @@ server.registerTool("diagnostics", {
|
|
|
84
84
|
description: "Factory 向け read-only 診断。安全な状態語彙だけを機械可読 JSON で返す(PTY 内容・認証情報・path・環境値は返さない)。",
|
|
85
85
|
inputSchema: {},
|
|
86
86
|
}, async () => ok(await factoryDiagnostics()));
|
|
87
|
+
const DEFAULT_PTY_SHELL = process.platform === "win32" ? "pwsh" : "bash";
|
|
87
88
|
server.registerTool("pty_open", {
|
|
88
89
|
description: "ローカル永続端末(tmux セッション)を1個開き、session_id を返す。tmux サーバ常駐ゆえ本サーバや " +
|
|
89
90
|
"クライアントが再起動してもセッションは生存する。リモート操作は専用ツールにせず、開いた端末の中で " +
|
|
90
91
|
'pty_send(session_id, "ssh host") と打って入る。',
|
|
91
92
|
inputSchema: {
|
|
92
93
|
name: z.string().nullish().describe("セッション名(省略時は t1, t2... を自動採番)"),
|
|
93
|
-
shell: z.string().default(
|
|
94
|
+
shell: z.string().default(DEFAULT_PTY_SHELL).describe(`起動シェル(既定 ${DEFAULT_PTY_SHELL})`),
|
|
94
95
|
},
|
|
95
96
|
}, async ({ name, shell }) => {
|
|
96
97
|
try {
|
package/dist/runtime-error-os.js
CHANGED
|
@@ -5,6 +5,7 @@ import { spawn, spawnSync } from "node:child_process";
|
|
|
5
5
|
import * as fs from "node:fs";
|
|
6
6
|
import * as os from "node:os";
|
|
7
7
|
import * as path from "node:path";
|
|
8
|
+
import { resolveWindowsPowerShell7, windowsPowerShell7Command } from "./windows-powershell.js";
|
|
8
9
|
export function defaultRuntimeErrorPaths(options = {}) {
|
|
9
10
|
const platform = options.platform ?? process.platform;
|
|
10
11
|
const home = options.home ?? os.homedir();
|
|
@@ -26,7 +27,9 @@ const WINDOWS_DACL_VERIFY_SCRIPT = String.raw `
|
|
|
26
27
|
$ErrorActionPreference='Stop'
|
|
27
28
|
$target=$env:AITERMMCP_ACL_PATH; $kind=$env:AITERMMCP_ACL_KIND
|
|
28
29
|
$sid=[Security.Principal.WindowsIdentity]::GetCurrent().User
|
|
29
|
-
$
|
|
30
|
+
$item=Get-Item -LiteralPath $target
|
|
31
|
+
$sections=[Security.AccessControl.AccessControlSections]::Access -bor [Security.AccessControl.AccessControlSections]::Owner
|
|
32
|
+
$check=[IO.FileSystemAclExtensions]::GetAccessControl($item,$sections)
|
|
30
33
|
$ownerSid=$check.GetOwner([Security.Principal.SecurityIdentifier]).Value
|
|
31
34
|
$rules=@($check.GetAccessRules($true,$true,[Security.Principal.SecurityIdentifier]))
|
|
32
35
|
if($ownerSid -ne $sid.Value -or $rules.Count -ne 1 -or $rules[0].IdentityReference.Value -ne $sid.Value -or $rules[0].AccessControlType -ne 'Allow' -or $rules[0].IsInherited -or (($rules[0].FileSystemRights -band [Security.AccessControl.FileSystemRights]::FullControl) -ne [Security.AccessControl.FileSystemRights]::FullControl)){exit 9}
|
|
@@ -38,18 +41,18 @@ $sid=[Security.Principal.WindowsIdentity]::GetCurrent().User
|
|
|
38
41
|
if($kind -eq 'directory'){$acl=New-Object Security.AccessControl.DirectorySecurity;$inherit=[Security.AccessControl.InheritanceFlags]'ContainerInherit,ObjectInherit'}else{$acl=New-Object Security.AccessControl.FileSecurity;$inherit=[Security.AccessControl.InheritanceFlags]::None}
|
|
39
42
|
$acl.SetOwner($sid); $acl.SetAccessRuleProtection($true,$false)
|
|
40
43
|
$rule=New-Object Security.AccessControl.FileSystemAccessRule($sid,[Security.AccessControl.FileSystemRights]::FullControl,$inherit,[Security.AccessControl.PropagationFlags]::None,[Security.AccessControl.AccessControlType]::Allow)
|
|
41
|
-
$acl.AddAccessRule($rule);
|
|
44
|
+
$acl.AddAccessRule($rule); $item=Get-Item -LiteralPath $target; [IO.FileSystemAclExtensions]::SetAccessControl($item,$acl)
|
|
42
45
|
` + WINDOWS_DACL_VERIFY_SCRIPT;
|
|
43
46
|
export function windowsPrivateDaclCommand(target, kind = "directory") {
|
|
44
47
|
return {
|
|
45
|
-
command:
|
|
48
|
+
command: windowsPowerShell7Command(),
|
|
46
49
|
args: ["-NoLogo", "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", WINDOWS_DACL_SCRIPT],
|
|
47
50
|
env: { ...process.env, AITERMMCP_ACL_PATH: target, AITERMMCP_ACL_KIND: kind },
|
|
48
51
|
};
|
|
49
52
|
}
|
|
50
53
|
export function windowsPrivateDaclVerifyCommand(target, kind = "file") {
|
|
51
54
|
return {
|
|
52
|
-
command:
|
|
55
|
+
command: windowsPowerShell7Command(),
|
|
53
56
|
args: ["-NoLogo", "-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Command", WINDOWS_DACL_VERIFY_SCRIPT],
|
|
54
57
|
env: { ...process.env, AITERMMCP_ACL_PATH: target, AITERMMCP_ACL_KIND: kind },
|
|
55
58
|
};
|
|
@@ -128,7 +131,7 @@ export function processStartIdentity(pid, platform, timeoutMs = 1000) {
|
|
|
128
131
|
}
|
|
129
132
|
if (platform === "win32") {
|
|
130
133
|
const script = "$p=Get-Process -Id $env:AITERMMCP_PROCESS_ID -ErrorAction Stop; $p.StartTime.ToUniversalTime().Ticks";
|
|
131
|
-
const result = spawnSync(
|
|
134
|
+
const result = spawnSync(resolveWindowsPowerShell7(), ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", script], {
|
|
132
135
|
encoding: "utf8", timeout: timeoutMs, maxBuffer: 4096, windowsHide: true,
|
|
133
136
|
env: { ...process.env, AITERMMCP_PROCESS_ID: String(pid) },
|
|
134
137
|
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Windows PowerShell実体の唯一の解決境界。5.1/cmd fallbackを持たず、検出したpwsh自身の
|
|
2
|
+
// edition/majorを実行時に検証してから絶対pathを返す。
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import { AitermError } from "./errors.js";
|
|
6
|
+
export const WINDOWS_POWERSHELL_7_COMMAND = "pwsh.exe";
|
|
7
|
+
export const WINDOWS_POWERSHELL_7_INSTALL = "winget install --id Microsoft.PowerShell --source winget";
|
|
8
|
+
export const WINDOWS_POWERSHELL_7_FIXTURE = "C:\\Program Files\\PowerShell\\7\\pwsh.exe";
|
|
9
|
+
const defaultProbe = (command, args) => spawnSync(command, [...args], {
|
|
10
|
+
encoding: "utf8", timeout: 5000, maxBuffer: 16 * 1024, windowsHide: true,
|
|
11
|
+
});
|
|
12
|
+
let resolvedDefault = null;
|
|
13
|
+
export function resolveWindowsPowerShell7(probe = defaultProbe) {
|
|
14
|
+
if (probe === defaultProbe && resolvedDefault !== null)
|
|
15
|
+
return resolvedDefault;
|
|
16
|
+
const located = probe("where.exe", [WINDOWS_POWERSHELL_7_COMMAND]);
|
|
17
|
+
const resolved = located.stdout?.split(/\r?\n/u)
|
|
18
|
+
.find(candidate => path.win32.isAbsolute(candidate)
|
|
19
|
+
&& path.win32.basename(candidate).toLowerCase() === WINDOWS_POWERSHELL_7_COMMAND);
|
|
20
|
+
const fail = () => {
|
|
21
|
+
throw new AitermError(`PowerShell 7が必要です。Microsoft公式経路で導入してください: ${WINDOWS_POWERSHELL_7_INSTALL}`, 2);
|
|
22
|
+
};
|
|
23
|
+
if (located.status !== 0 || typeof resolved !== "string")
|
|
24
|
+
fail();
|
|
25
|
+
const executable = resolved;
|
|
26
|
+
const version = probe(executable, ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command",
|
|
27
|
+
'[ordered]@{ edition = $PSVersionTable.PSEdition; major = $PSVersionTable.PSVersion.Major } | ConvertTo-Json -Compress']);
|
|
28
|
+
let identity = null;
|
|
29
|
+
try {
|
|
30
|
+
identity = JSON.parse(version.stdout?.trim() ?? "");
|
|
31
|
+
}
|
|
32
|
+
catch { /* typed failure below */ }
|
|
33
|
+
if (version.status !== 0 || identity?.edition !== "Core"
|
|
34
|
+
|| !Number.isInteger(identity.major) || Number(identity.major) < 7)
|
|
35
|
+
fail();
|
|
36
|
+
if (probe === defaultProbe)
|
|
37
|
+
resolvedDefault = executable;
|
|
38
|
+
return executable;
|
|
39
|
+
}
|
|
40
|
+
export function windowsPowerShell7Command(platform = process.platform) {
|
|
41
|
+
return platform === "win32" ? resolveWindowsPowerShell7() : WINDOWS_POWERSHELL_7_FIXTURE;
|
|
42
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiterm-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
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": [
|