aiterm-mcp 0.61.10 → 0.61.12
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/CHANGELOG.md +42 -1
- package/README.ja.md +5 -2
- package/README.md +5 -2
- package/dist/agent-resolver.js +25 -1
- package/dist/core.js +41 -24
- package/dist/execution-participant-store.js +8 -2
- package/dist/harnesses/claude.js +13 -7
- package/dist/harnesses/codex.js +21 -7
- package/dist/harnesses/cursor.js +1 -24
- package/dist/harnesses/grok.js +19 -10
- package/dist/psmux-send-worker.js +3 -2
- package/dist/tmux-runtime.js +42 -6
- package/docs/DESIGN.md +23 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,45 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.61.12] - 2026-10-24
|
|
11
|
+
|
|
12
|
+
### Validation scope
|
|
13
|
+
|
|
14
|
+
- Linux full validation passed (1579 passed, 46 skipped, 0 failed). The affected native execution path passed its focused macOS gate (110 passed, 0 failed). The same focused gate on hosted Windows passed 23 tests and skipped 87 POSIX-only cases; this patch does not enable POSIX execution checkpoints on Windows or replace the Windows full acceptance recorded for 0.61.11. All fixtures use isolated metadata and CLI substitutes, without production seats or delivery replay.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- A newly connected participant in the opt-in POSIX native execution entry waits within the existing bounded metadata admission before committing its declared roles for its first asynchronous request. Previously, deferred enrollment tried a synchronous lock first and could return `EXECUTION_BUSY` while a concurrent metadata writer was about to finish. Scope and actor checks, synchronous refusal, removed-registration refusal and immediate-stop snapshots are preserved; no input or failed request is replayed.
|
|
19
|
+
|
|
20
|
+
### Tests
|
|
21
|
+
|
|
22
|
+
- Isolated cold-participant fixtures cover dispatch under a held writer, read-only registration, concurrent first requests, scope or actor changes while waiting, and refusal after registration removal. These reproduce and repair the product defect without assigning a cause to historical deliveries whose original native receipt was not retained.
|
|
23
|
+
|
|
24
|
+
## [0.61.11] - 2026-10-24
|
|
25
|
+
|
|
26
|
+
### Validation scope
|
|
27
|
+
|
|
28
|
+
- Windows native full validation passed (908 passed, 709 skipped, 0 failed) on GitHub-hosted Windows 2022, Node 22 and psmux 3.3.8. Linux full validation passed (1574 passed, 46 skipped, 0 failed); macOS acceptance combines its previously passing full suite with the subsequent launch and shell-runtime focused gates. Validation uses isolated CLI fixtures; commercial image and real CLI acceptance remain separate.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- Shell dialect selection, current prompt reconciliation and encoding share one runtime entry for ordinary and marked sends. A stale psmux PowerShell report no longer sends PowerShell syntax into a current Git Bash prompt; raw input and TUI pastes remain literal.
|
|
33
|
+
|
|
34
|
+
- Windows agent launches use the existing native PowerShell 7 launch adaptation for all harnesses. One shared argv construction feeds POSIX quoting and Windows native invocation; accepted shebang wrappers run through noninteractive Git Bash in the same pane. Startup commands no longer depend on the interactive MSYS bash console input loop. The original text limit is checked before the existing ASCII Base64 adaptation; TUI bodies remain literal.
|
|
35
|
+
- Native Windows panes retain runtime additions to the caller PATH instead of replacing them with registry PATH. Explicit PATH entries keep precedence.
|
|
36
|
+
- Non-raw PowerShell shell submissions establish UTF-8 input, output and native pipeline encoding in the submitted script, including single-line commands. Profiles, psmux interactive initialization, deferred Enter and raw PTY input retain their existing behavior.
|
|
37
|
+
- Agent composer pastes retain their sanitized literal text even when the native foreground query still reports a startup shell. Shell encoding is limited to shell submissions.
|
|
38
|
+
- Agent launch commands for Aiterm-owned bash panes are submitted as one physical line through the existing POSIX multiline adaptation, instead of one interactive line per embedded newline joined by continuation prompts. Argument bytes, lineage, metadata, native admission and receipts are unchanged, and the agent composer body remains literal.
|
|
39
|
+
|
|
40
|
+
### Tests
|
|
41
|
+
|
|
42
|
+
- Real Windows Bash panes retain literal multiline file bytes and correct completion for ordinary and marked sends even when the backend foreground report is deliberately replaced with `pwsh`. Native argv fixtures also verify the received read-only sandbox pair without relying on the startup command echo.
|
|
43
|
+
|
|
44
|
+
- POSIX-only native test teardown also stays skipped on Windows. A file-level hook previously reached the psmux `tmux.exe` alias and stopped other fixture namespaces even when every test case was skipped. A native canary regression covers this boundary.
|
|
45
|
+
- Argument fixtures wait for their final output marker within the existing deadline. Nested lineage assertions inspect child output instead of shell echo.
|
|
46
|
+
- The portable-context fake TUI counts a bracketed multiline paste and its submit Enter as one input.
|
|
47
|
+
- A bash round-trip check and a native launch regression compare the argv bytes a fake CLI received, through the CLI's own file, for quotes, backslashes, history characters, percent signs, Japanese text and newlines.
|
|
48
|
+
|
|
10
49
|
## [0.61.10] - 2026-10-23
|
|
11
50
|
|
|
12
51
|
### Validation scope
|
|
@@ -2782,7 +2821,9 @@ prototype (preserved under `prototype/python/` as the porting source and referen
|
|
|
2782
2821
|
`ubuntu-latest` for Node 18/20/22, publishing to npm on `v*` tags with
|
|
2783
2822
|
provenance.
|
|
2784
2823
|
|
|
2785
|
-
[Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.61.
|
|
2824
|
+
[Unreleased]: https://github.com/kitepon/aiterm-mcp/compare/v0.61.12...HEAD
|
|
2825
|
+
[0.61.12]: https://github.com/kitepon/aiterm-mcp/compare/v0.61.11...v0.61.12
|
|
2826
|
+
[0.61.11]: https://github.com/kitepon/aiterm-mcp/compare/v0.61.10...v0.61.11
|
|
2786
2827
|
[0.61.10]: https://github.com/kitepon/aiterm-mcp/compare/v0.61.9...v0.61.10
|
|
2787
2828
|
[0.61.9]: https://github.com/kitepon/aiterm-mcp/compare/v0.61.8...v0.61.9
|
|
2788
2829
|
[0.61.8]: https://github.com/kitepon/aiterm-mcp/compare/v0.61.7...v0.61.8
|
package/README.ja.md
CHANGED
|
@@ -209,7 +209,7 @@ runtime-error store は canonical dotagents config の `collection.enabled: true
|
|
|
209
209
|
場合だけ収集し、既定OFF、network送信は行いません。tag起点CIのnpm provenance(OIDC Trusted
|
|
210
210
|
Publishing)で公開し、GitHub Release が Official MCP Registry を再登録します。
|
|
211
211
|
|
|
212
|
-
**状態:** 開発継続中 · 現行公開版 **v0.61.
|
|
212
|
+
**状態:** 開発継続中 · 現行公開版 **v0.61.12** · 動作対象は Linux · WSL2 · macOS · Windows ネイティブ · MIT · [変更履歴](CHANGELOG.md)。
|
|
213
213
|
|
|
214
214
|
### 更新と巻き戻し
|
|
215
215
|
|
|
@@ -434,6 +434,9 @@ MCP クライアントが aiterm を stdio 越しにプログラムから駆動
|
|
|
434
434
|
|
|
435
435
|
## 仕組み
|
|
436
436
|
|
|
437
|
+
Windows nativeのPowerShell shellへの非raw送信は、Console入出力とnative pipelineをUTF-8へ揃えます。実行時に追加した呼出元PATHは新しいpaneへ渡します。raw PTY入力は従来どおりです。
|
|
438
|
+
agentの起動はPowerShell 7のpaneでargvを渡して実行し、受入済みshebang wrapperだけは同じpane内でGit Bashを非対話実行します。Aitermが作る起動scriptはASCIIの1行にし、agent TUIへ渡す本文は文字どおりに保ちます。
|
|
439
|
+
|
|
437
440
|
```mermaid
|
|
438
441
|
flowchart LR
|
|
439
442
|
AI["AI / MCP client<br/>(the orchestrator)"] -->|"pty_send · pty_observe · agent_launch · agent_models · agent_configure · agent_auth · agent_approval · claude_turn · claude_approval<br/>旧launcher alias · diagnostics"| S["aiterm-mcp<br/>stdio MCP · 18 tools"]
|
|
@@ -750,7 +753,7 @@ CLIが終了した結果不明の空起動には、BellTeam native入口の `age
|
|
|
750
753
|
|
|
751
754
|
## 人が覗く
|
|
752
755
|
|
|
753
|
-
POSIXの明示native実行構成では、検証済みcallerへ通常メッセージが届く間も、そのcallerから別席への送信を継続できる。callerの世代や各requestのslot
|
|
756
|
+
POSIXの明示native実行構成では、検証済みcallerへ通常メッセージが届く間も、そのcallerから別席への送信を継続できる。callerの世代や各requestのslotは書き換えない。新しく接続した参加者も、初回の非同期要求で宣言済みの役割を保存する際は、既存の上限付きmetadata受付で競合を待つ。この待機は入力を再送しない。agentの貼付け・Enterはmetadata mutexの競合を入力前に待ち、不明な操作・世代交代・停止では入力を止める。BellTeamは閉じた席をpromptなしの明示管理`agent_launch`で再作成できる。promptを送る呼出しには元の実行参照が必要である。
|
|
754
757
|
|
|
755
758
|
セッションは共有tmux socket(Windows nativeはpsmux namespace)上にある。`pty_open`/`agent_launch`の戻り値に表示されるattachコマンドで、人間がClaude/Codex/Grok/Cursor harnessの同じ端末へ入り、途中でキーボードを引き取れる。
|
|
756
759
|
POSIXでは、tmuxのソケットがまだ無くても最初の`agent_launch`でserverを起動できる。Aitermは作成したsessionとserverを実際のreceiptから照合して受付を確定し、不明な結果を入力の再送で補わない。
|
package/README.md
CHANGED
|
@@ -227,7 +227,7 @@ collection is off by default and performs no network I/O. It ships via
|
|
|
227
227
|
tag-triggered CI with npm provenance (OIDC Trusted Publishing); the GitHub
|
|
228
228
|
Release re-registers the Official MCP Registry entry.
|
|
229
229
|
|
|
230
|
-
**Status:** actively maintained · current public release **v0.61.
|
|
230
|
+
**Status:** actively maintained · current public release **v0.61.12** · runs on Linux · WSL2 · macOS · native Windows (tmux on POSIX, the tmux-CLI-compatible [psmux](https://github.com/psmux/psmux) on native Windows — no WSL required) · MIT · see the [CHANGELOG](CHANGELOG.md).
|
|
231
231
|
|
|
232
232
|
### Update and rollback
|
|
233
233
|
|
|
@@ -795,7 +795,7 @@ Each `pty_send` accepts at most 64 KiB of UTF-8 text. Sends to the same session
|
|
|
795
795
|
|
|
796
796
|
## A human can watch
|
|
797
797
|
|
|
798
|
-
In the opt-in POSIX native execution entry, an ordinary message arriving at a verified caller can overlap that caller's outgoing send. It does not replace the caller's generation or clear either request's slot. Agent paste/submit segments wait for metadata mutex contention before input; uncertain operations, generation changes and stops still prevent input. BellTeam may explicitly recreate a closed session with a promptless management `agent_launch`; sending a prompt still requires its original execution reference.
|
|
798
|
+
In the opt-in POSIX native execution entry, an ordinary message arriving at a verified caller can overlap that caller's outgoing send. It does not replace the caller's generation or clear either request's slot. A newly connected participant also waits within the existing bounded metadata admission to commit its declared roles before its first asynchronous request; that wait never replays input. Agent paste/submit segments wait for metadata mutex contention before input; uncertain operations, generation changes and stops still prevent input. BellTeam may explicitly recreate a closed session with a promptless management `agent_launch`; sending a prompt still requires its original execution reference.
|
|
799
799
|
|
|
800
800
|
An explicit `agent_execution` action `reconcile_launch` can bind an existing empty launch after a lost launch result in this opt-in entry. Supply the original `request` and exact `target: {session_id, launch_id}`. The server checks the original native/server identity, current managed generation, raw no-prompt state and a live ready harness under metadata admission, then releases only that unknown launch slot. Repeating an accepted empty launch before its send also rechecks the current generation, readiness and absence of competing session operations; a saved acceptance alone cannot confirm a later generation. It never launches, types, closes or resends. `issued` RPCs, unknown input and changed or unverified generations remain blocked. Any subsequent body uses the original reference through normal send admission once; a successful reconciliation does not prove the lost RPC receipt.
|
|
801
801
|
|
|
@@ -806,6 +806,9 @@ Success retains the original unknown record and returns the serving SDK's distin
|
|
|
806
806
|
For a returned unknown launch whose harness has exited, the same native entry admits explicit `pty_close` only after synchronous proof of the original native/server and managed generation, raw no-initial-prompt state, an unissued body send and an exited harness. It releases the failed launch slot after successful close and confirmed absence, preserving the original unknown record. Issued RPCs, live harnesses and missing input or generation evidence remain blocked. The old request is never replayed; a later ordinary request may create a fresh generation.
|
|
807
807
|
|
|
808
808
|
|
|
809
|
+
On native Windows, non-raw commands sent to a PowerShell shell use UTF-8 for Console input/output and native pipelines. Runtime additions to the caller PATH are passed to new panes; raw PTY input is unchanged.
|
|
810
|
+
Agent launches use a PowerShell 7 pane and pass the harness argv directly; accepted shebang wrappers use noninteractive Git Bash in that same pane. The owned startup script is sent as one ASCII line, while agent TUI bodies retain their literal text.
|
|
811
|
+
|
|
809
812
|
Sessions live on a shared tmux socket on POSIX or a shared psmux namespace on native Windows. The attach line printed by `pty_open` and `agent_launch` lets a human attach to the same terminal and intervene, including a Claude/Codex/Grok/Cursor harness session: `tmux -S … attach -t <id>` on POSIX, or `psmux -L <namespace> attach -t <id>` on native Windows.
|
|
810
813
|
On POSIX, the first `agent_launch` can create the tmux server when its socket does not yet exist. Aiterm verifies the exact created session and server before accepting that launch; an uncertain result is reported without retrying the input.
|
|
811
814
|
|
package/dist/agent-resolver.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// エージェント CLI(claude / codex / grok / cursor-agent)・Throughline・pane shell(Windows は Git Bash)の
|
|
1
|
+
// エージェント CLI(claude / codex / grok / cursor-agent)・Throughline・pane shell(Windows は PowerShell / Git Bash)の
|
|
2
2
|
// 実行ファイルをどう見つけ、どう起動するかの所有者(OS 分岐の所有者。tmux とは独立)。
|
|
3
3
|
import { spawn, spawnSync } from "node:child_process";
|
|
4
4
|
import * as fs from "node:fs";
|
|
@@ -257,3 +257,27 @@ export function runThroughlineHandoffContext(bin, sessionId, supplementFile = nu
|
|
|
257
257
|
encoding: "utf8",
|
|
258
258
|
});
|
|
259
259
|
}
|
|
260
|
+
/** Owned Windows agent launch: PowerShell uses argv, without interactive MSYS input. */
|
|
261
|
+
export function windowsAgentLaunchLine(cwd, env, argv) {
|
|
262
|
+
const psq = (value) => `'${value.replace(/'/g, "''")}'`;
|
|
263
|
+
const parts = [];
|
|
264
|
+
if (cwd)
|
|
265
|
+
parts.push(`Set-Location -LiteralPath ${psq(cwd)}`);
|
|
266
|
+
for (const [name, value] of env) {
|
|
267
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
|
|
268
|
+
throw new AitermError("環境変数名が不正です", 2);
|
|
269
|
+
parts.push(`$env:${name}=${psq(value)}`);
|
|
270
|
+
}
|
|
271
|
+
parts.push(`& ${argv.map(psq).join(" ")}`);
|
|
272
|
+
return parts.join("; ");
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Keep accepted shebang wrappers in the same pane, as for control commands.
|
|
276
|
+
* Invoking .sh directly in PowerShell uses its file association and can open a
|
|
277
|
+
* separate Git Bash window whose process outlives the pane (fox, 2026-10-14).
|
|
278
|
+
*/
|
|
279
|
+
export function windowsAgentArgv(argv, scriptShell) {
|
|
280
|
+
if (/\.(?:exe|com|cmd|bat|ps1)$/i.test(argv[0]))
|
|
281
|
+
return argv;
|
|
282
|
+
return [scriptShell(), argv[0].replace(/\\/g, "/"), ...argv.slice(1)];
|
|
283
|
+
}
|
package/dist/core.js
CHANGED
|
@@ -27,19 +27,19 @@ import { unfinishedDeliveriesOwnedBy } from "./parent-delivery-owners.js";
|
|
|
27
27
|
import { readRuntimeProcesses, readProcessIdentities, processSubtree, parentProcess, processIdentity, backgroundProcesses, lazyRelayProcess, aitermProcessProbe, windowsConsoleHost, processElapsedSeconds } from "./process-runtime.js";
|
|
28
28
|
import { liveNodeExecutable } from "./live-node.js";
|
|
29
29
|
import { AitermError, telemetryOwnedFailure, ownTelemetryFailure } from "./errors.js";
|
|
30
|
-
import { isWin, SOCKDIR, SOCK, tmuxCommand, sendPsmuxPayload, loadPtyBufferChunk, pasteBufferBaseArgs, tmuxNewSession, openPsmuxServerToDesktop, registeredSessionEnvironment, attachCommand, normalizePaneCommand, atomicShellMultiline, appendMarkSentinel,
|
|
30
|
+
import { isWin, SOCKDIR, SOCK, tmuxCommand, sendPsmuxPayload, loadPtyBufferChunk, pasteBufferBaseArgs, tmuxNewSession, openPsmuxServerToDesktop, registeredSessionEnvironment, attachCommand, normalizePaneCommand, atomicShellMultiline, appendMarkSentinel, paneShellForSubmission, adaptShellSubmission, settlePaneLog, paneCwdArgument, sessionEnvironmentLaunch, } from "./tmux-runtime.js";
|
|
31
31
|
import { AGENT_DEFAULT_PREFACE, sleep, currentUid, runtimeStateBase, safeStatSize, readFileRange, writeJson0600, createEmpty0600, shq, LAUNCH_ID_RE, AGENT_DONE_POLL_MS, AGENT_RATE_LIMIT_POLL_MS, pollGate, AGENT_EVENT_MAX_BYTES, assertSessionName, agentsDir, agentEventPath, agentMetadataPath, writeAgentMetadata, AGENT_EVENT_TAIL_BYTES, agentLabel, agentHarness, subagentInstruction, agentLineageFields, } from "./agent-shared.js";
|
|
32
32
|
import { catalogUnavailable } from "./model-catalog.js";
|
|
33
33
|
import { FastModeError, fastModeFailure } from "./fast-mode.js";
|
|
34
34
|
import { readFileOrNull, restoreJsonSetting, withUserConfigLock } from "./user-config.js";
|
|
35
35
|
import { isDeepStrictEqual } from "node:util";
|
|
36
|
-
import { grokAuthPlan, grokAuthStatus, grokAuthPane, GROK_MODEL_DEFAULTS, realGrokHome, resolveAndValidateGrokAuth, assertGrokModelAvailable, grokModelChoices, grokModelFromFooter, grokFooterModelName, grokModelDefaultsFromBody, restoreGrokModelDefaults, grokEventsTranscript, latestGrokCompletion, grokTurnSettled, observeGrokDone, buildGrokAgentCmd, grokLaunchNote, grokEnvTokens, grokTuiReady, grokPaneObservation, GROK_INTERRUPT_KEY, grokRateLimitDialog, grokPromptAwaitingAccept, grokUnacceptedPromptRestored, grokStartupAction, grokFooterHasConfiguration, grokTranscriptText, createGrokAgentMetadata, } from "./harnesses/grok.js";
|
|
37
|
-
import { codexAuthPlan, codexAuthStatus, codexAuthPane, realCodexHome, readCodexConfigPins, bindCodexTranscriptSession, latestCodexCompletion, codexTurnSettled, codexRunningTurn, codexInterruptionRecord, observeCodexDone, buildCodexAgentCmd, codexLaunchNote, codexPaneObservation, CODEX_INTERRUPT_KEY, codexHelperProcess, codexRateLimitModelSwitchDialog, codexApprovalDialog, codexStartupAction, codexModelChoice, codexEffortChoice, codexMoreReasoningChoice, codexTranscriptText, createCodexAgentMetadata, codexModelChoices, codexFastCommandOffered, codexFooterShowsFast, codexServiceTierNotices, restoreCodexDefaults, restoreCodexDefaultInFile, } from "./harnesses/codex.js";
|
|
38
|
-
import { claudeAuthPlan, claudeAuthStatus, claudeAuthPane, OPERATION_ID_RE, CLAUDE_RESULT_MAX_BYTES, CLAUDE_EFFORTS, agentManagedClaudeSettingsPath, agentClaudeResultPath, agentClaudeOperationPath, agentClaudeApprovalReceiptPath, agentClaudeDispatchReceiptPath, validateOperationId, readClaudeResultText, assertClaudeAuthenticationReady, claudeModelChoices, claudeConfigDir, claudeFastIndicatorShown, claudeFastResult, buildClaudeAgentCmd, claudeLaunchNote, claudePaneObservation, CLAUDE_INTERRUPT_KEY, claudeUsageLimit, claudeLiveSelectMenu, claudeModelPicker, claudeModelPickerRow, claudeModelSwitchConfirm, claudeModelSwitchResult, claudeStartupAction, createClaudeAgentMetadata, claudeSessionTranscriptPath, claudeApiErrorFromLine, claudeApiErrorAfter, } from "./harnesses/claude.js";
|
|
39
|
-
import { cursorAuthPlan, cursorAuthStatus, cursorAuthPane, bindCursorTranscriptSession, cursorTurnBoundary, latestCursorCompletion, observeCursorDone, cursorTranscriptText, assertCursorAuthenticationReady, assertCursorModelAvailable, cursorModelChoices, cursorModelIsFastVariant, cursorFastParameter, cursorHeaderShowsFast, cursorPickerView, cursorEffortSelected, cursorParameterRows, cursorUserConfigPath, CURSOR_DEFAULT_MODEL_KEYS, realCursorHome, buildCursorAgentCmd, cursorAgentArgv,
|
|
36
|
+
import { grokAuthPlan, grokAuthStatus, grokAuthPane, GROK_MODEL_DEFAULTS, realGrokHome, resolveAndValidateGrokAuth, assertGrokModelAvailable, grokModelChoices, grokModelFromFooter, grokFooterModelName, grokModelDefaultsFromBody, restoreGrokModelDefaults, grokEventsTranscript, latestGrokCompletion, grokTurnSettled, observeGrokDone, buildGrokAgentCmd, grokAgentArgv, grokLaunchNote, grokEnvTokens, grokEnvEntries, grokTuiReady, grokPaneObservation, GROK_INTERRUPT_KEY, grokRateLimitDialog, grokPromptAwaitingAccept, grokUnacceptedPromptRestored, grokStartupAction, grokFooterHasConfiguration, grokTranscriptText, createGrokAgentMetadata, } from "./harnesses/grok.js";
|
|
37
|
+
import { codexAuthPlan, codexAuthStatus, codexAuthPane, realCodexHome, readCodexConfigPins, bindCodexTranscriptSession, latestCodexCompletion, codexTurnSettled, codexRunningTurn, codexInterruptionRecord, observeCodexDone, buildCodexAgentCmd, codexAgentArgv, codexLaunchNote, codexPaneObservation, CODEX_INTERRUPT_KEY, codexHelperProcess, codexRateLimitModelSwitchDialog, codexApprovalDialog, codexStartupAction, codexModelChoice, codexEffortChoice, codexMoreReasoningChoice, codexTranscriptText, createCodexAgentMetadata, codexModelChoices, codexFastCommandOffered, codexFooterShowsFast, codexServiceTierNotices, restoreCodexDefaults, restoreCodexDefaultInFile, } from "./harnesses/codex.js";
|
|
38
|
+
import { claudeAuthPlan, claudeAuthStatus, claudeAuthPane, OPERATION_ID_RE, CLAUDE_RESULT_MAX_BYTES, CLAUDE_EFFORTS, agentManagedClaudeSettingsPath, agentClaudeResultPath, agentClaudeOperationPath, agentClaudeApprovalReceiptPath, agentClaudeDispatchReceiptPath, validateOperationId, readClaudeResultText, assertClaudeAuthenticationReady, claudeModelChoices, claudeConfigDir, claudeFastIndicatorShown, claudeFastResult, buildClaudeAgentCmd, claudeAgentArgv, claudeLaunchNote, claudePaneObservation, CLAUDE_INTERRUPT_KEY, claudeUsageLimit, claudeLiveSelectMenu, claudeModelPicker, claudeModelPickerRow, claudeModelSwitchConfirm, claudeModelSwitchResult, claudeStartupAction, createClaudeAgentMetadata, claudeSessionTranscriptPath, claudeApiErrorFromLine, claudeApiErrorAfter, } from "./harnesses/claude.js";
|
|
39
|
+
import { cursorAuthPlan, cursorAuthStatus, cursorAuthPane, bindCursorTranscriptSession, cursorTurnBoundary, latestCursorCompletion, observeCursorDone, cursorTranscriptText, assertCursorAuthenticationReady, assertCursorModelAvailable, cursorModelChoices, cursorModelIsFastVariant, cursorFastParameter, cursorHeaderShowsFast, cursorPickerView, cursorEffortSelected, cursorParameterRows, cursorUserConfigPath, CURSOR_DEFAULT_MODEL_KEYS, realCursorHome, buildCursorAgentCmd, cursorAgentArgv, cursorPromptWithLineage, createCursorAgentMetadata, cursorLaunchNote, cursorEffortNavigation, cursorTuiReady, cursorPaneObservation, CURSOR_INTERRUPT_KEY, cursorPromptHooksRunning, cursorUsageLimit, CURSOR_SUBMIT_SEQUENCE, validateCursorModelEffort, } from "./harnesses/cursor.js";
|
|
40
40
|
import { interimFromNow, readInterimWords, recordInterimBoundary } from "./interim-words.js";
|
|
41
41
|
import { codexSeatTurn, observeSteerDone, readSteerEntry, recordSteer } from "./steer-follow.js";
|
|
42
|
-
import { resolveAgentBin, resolveThroughlineBin, runThroughlineHandoffContext, isWindowsNativeExecutable, agentBinForPaneShell, resolveWinPaneShell } from "./agent-resolver.js";
|
|
42
|
+
import { resolveAgentBin, resolveThroughlineBin, runThroughlineHandoffContext, isWindowsNativeExecutable, agentBinForPaneShell, resolveWinPaneShell, windowsAgentArgv, windowsAgentLaunchLine } from "./agent-resolver.js";
|
|
43
43
|
export { AitermError } from "./errors.js";
|
|
44
44
|
export { tmuxSpawnEnv } from "./tmux-runtime.js";
|
|
45
45
|
export { agentHarness } from "./agent-shared.js";
|
|
@@ -251,10 +251,7 @@ export async function ensureAgentOwnsPaneInput(name, kind) {
|
|
|
251
251
|
return recovery;
|
|
252
252
|
}
|
|
253
253
|
function paneCurrentCommandForMark(name) {
|
|
254
|
-
|
|
255
|
-
if ((!isWin && foreground !== "ssh") || foreground === "powershell" || foreground === "pwsh")
|
|
256
|
-
return foreground;
|
|
257
|
-
return markShellCommand(foreground, captureScreen(name, 4));
|
|
254
|
+
return paneShellForSubmission(name);
|
|
258
255
|
}
|
|
259
256
|
function pasteBufferSupportsNoSanitizeFlag() {
|
|
260
257
|
const listed = tmux("list-commands");
|
|
@@ -850,16 +847,21 @@ export function send(name, text, o = {}) {
|
|
|
850
847
|
throw new AitermError("aiterm相関付きClaude agent sessionへの通常送信はturn境界を失うため拒否します。" +
|
|
851
848
|
"pty_send(forceなし=自動dispatch)を使うか、通常対話へ切り替えるならsessionをcloseしてpty_openから手動起動し直してください。", 2);
|
|
852
849
|
}
|
|
853
|
-
writeLastcmd(name,
|
|
850
|
+
writeLastcmd(name, o.launchShell ? atomicShellMultiline(text, o.launchShell) : text);
|
|
854
851
|
if (o.rtk)
|
|
855
852
|
text = rtkRewrite(text);
|
|
856
853
|
if (o.mark)
|
|
857
854
|
text = appendMarkSentinel(text, fg);
|
|
858
855
|
assertSendTextSize(text, o.rtk || o.mark ? "変換後の送信文字列" : "送信文字列");
|
|
859
856
|
const reportedText = text;
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
857
|
+
// Agent composer paste is literal text even if native foreground metadata
|
|
858
|
+
// still reports the startup shell. Keep sanitization, but never encode TUI
|
|
859
|
+
// text as an executable shell command.
|
|
860
|
+
// Original text is validated above. OS queries, stale foreground handling
|
|
861
|
+
// and shell encoding belong to the runtime; common send supplies intent.
|
|
862
|
+
text = adaptShellSubmission(name, text, {
|
|
863
|
+
raw: o.raw, literalPaste: o.bracketedPaste, launchShell: o.launchShell, shell: fg,
|
|
864
|
+
});
|
|
863
865
|
if (o.mark) {
|
|
864
866
|
try {
|
|
865
867
|
fs.writeFileSync(markpath(name), "1"); // waitCompletion に sentinel 完了検出を有効化させる
|
|
@@ -5985,7 +5987,7 @@ function agentVendorSessionEnv(meta) {
|
|
|
5985
5987
|
}
|
|
5986
5988
|
/**
|
|
5987
5989
|
* 席へ渡すAitermの環境変数(名前と値)の唯一の一覧。呼び手が指定した継承分を先に置き、席の控えが無い時は継承分だけ。
|
|
5988
|
-
* shell別の引用はここでは付けず、POSIXの前置き(agentEnvPrefix)とWindowsのPowerShell行(
|
|
5990
|
+
* shell別の引用はここでは付けず、POSIXの前置き(agentEnvPrefix)とWindowsのPowerShell行(windowsAgentLaunchLine)が同じ一覧から作る。
|
|
5989
5991
|
*/
|
|
5990
5992
|
function agentEnvEntries(meta, sid, envVars = []) {
|
|
5991
5993
|
const inherited = envVars.flatMap((name) => {
|
|
@@ -6163,8 +6165,8 @@ function prepareAgentLaunch(kind, opts = {}) {
|
|
|
6163
6165
|
assertClaudeAuthenticationReady(bin);
|
|
6164
6166
|
if (kind === "cursor")
|
|
6165
6167
|
assertCursorAuthenticationReady(bin);
|
|
6166
|
-
// Windows
|
|
6167
|
-
//
|
|
6168
|
+
// Windows agent launches run in a native PowerShell pane. Accepted shebang
|
|
6169
|
+
// wrappers use noninteractive Git Bash in that pane; there is no WSL bridge.
|
|
6168
6170
|
// 未検証リスク: npm グローバル導入の codex.cmd/.bat シムの対話 TUI 描画は実 Windows でしか確認
|
|
6169
6171
|
// できない(CI 非対象。docs/03_audit-sweep-2026-07.md 参照)。native .exe の TUI 描画は
|
|
6170
6172
|
// grok.exe で実測済み(2026-08-15)。
|
|
@@ -6190,8 +6192,9 @@ function prepareAgentLaunch(kind, opts = {}) {
|
|
|
6190
6192
|
return () => {
|
|
6191
6193
|
let sid;
|
|
6192
6194
|
let hint;
|
|
6193
|
-
// Windows
|
|
6194
|
-
|
|
6195
|
+
// Windows launches use native PowerShell input; never type an owned CLI
|
|
6196
|
+
// command through MSYS interactive select/console-master input handling.
|
|
6197
|
+
const paneShell = isWin ? "pwsh" : "bash";
|
|
6195
6198
|
try {
|
|
6196
6199
|
[sid, hint] = openSession(opts.session_name ?? null, paneShell, envVars);
|
|
6197
6200
|
}
|
|
@@ -6238,23 +6241,37 @@ function prepareAgentLaunch(kind, opts = {}) {
|
|
|
6238
6241
|
bindExecutionCreatedLaunch({ session_id: sid, launch_id: meta.launch_id });
|
|
6239
6242
|
launchNote = buildAgentLaunchNote(kind, model, effort, meta);
|
|
6240
6243
|
let full;
|
|
6241
|
-
if (paneShell === "pwsh"
|
|
6242
|
-
|
|
6244
|
+
if (paneShell === "pwsh") {
|
|
6245
|
+
const prompt = opts.prompt ?? null;
|
|
6246
|
+
const argv = kind === "claude" ? claudeAgentArgv(bin, model, effort, prompt, meta)
|
|
6247
|
+
: kind === "codex" ? codexAgentArgv(bin, model, effort, prompt, meta)
|
|
6248
|
+
: kind === "cursor" ? cursorAgentArgv(bin, model, effort, prompt, meta, cursorFast)
|
|
6249
|
+
: grokAgentArgv(kind, bin, model, effort, prompt, meta);
|
|
6250
|
+
full = windowsAgentLaunchLine(cwd, [
|
|
6251
|
+
...(meta?.kind === "grok" ? grokEnvEntries(meta) : []), ...agentEnvEntries(meta, sid, envVars),
|
|
6252
|
+
], windowsAgentArgv(argv, () => resolveWinPaneShell("bash")));
|
|
6243
6253
|
}
|
|
6244
6254
|
else {
|
|
6245
6255
|
const cmd = buildAgentCmd(kind, binForCmd, model, effort, opts.prompt ?? null, meta, cursorFast);
|
|
6246
6256
|
const envPrefix = agentEnvPrefix(meta, sid, envVars);
|
|
6247
|
-
|
|
6257
|
+
const command = cwdForCmd ? `cd ${shq(cwdForCmd)} && ${envPrefix}${cmd}` : `${envPrefix}${cmd}`;
|
|
6258
|
+
// このpaneのbashはAitermが自分で選んだ。sub-agent instructionのLFを含む起動commandは、
|
|
6259
|
+
// 利用者のshell送信と同じknown-shell適合で1物理行にしてから打つ(sanitizeはしない)。
|
|
6260
|
+
// 対話shellの行編集が、埋め込みLFごとに1行ずつ受け付けて継続promptで繋ぐ形に依存しない。
|
|
6261
|
+
// agent TUIへの本文(bracketedPaste)は文字どおりのまま。argv・lineage・metadata・native
|
|
6262
|
+
// admission・receiptの契約は変えない。
|
|
6263
|
+
full = command;
|
|
6248
6264
|
}
|
|
6249
6265
|
if (meta)
|
|
6250
|
-
agentLaunchLines.set(sid, full);
|
|
6251
|
-
// force:true はagent sessionへの手動介入を表す。起動コマンド自体はAiterm
|
|
6266
|
+
agentLaunchLines.set(sid, atomicShellMultiline(full, paneShell));
|
|
6267
|
+
// force:true はagent sessionへの手動介入を表す。起動コマンド自体はAitermが組み立てて、sanitizeせずに送る。
|
|
6252
6268
|
send(sid, full, {
|
|
6253
6269
|
enter: true,
|
|
6254
6270
|
mark: false,
|
|
6255
6271
|
force: true,
|
|
6256
6272
|
rtk: false,
|
|
6257
6273
|
raw: true,
|
|
6274
|
+
launchShell: paneShell,
|
|
6258
6275
|
preserveAgentOperation: meta?.kind === "claude",
|
|
6259
6276
|
});
|
|
6260
6277
|
}
|
|
@@ -70,8 +70,14 @@ export class ParticipantExecutionStore extends FileExecutionStore {
|
|
|
70
70
|
return value;
|
|
71
71
|
}, options);
|
|
72
72
|
}
|
|
73
|
-
transaction(body, options = {}) {
|
|
74
|
-
this.
|
|
73
|
+
async transaction(body, options = {}) {
|
|
74
|
+
if (this.deferEnrollment && !this.registered) {
|
|
75
|
+
this.assertScope();
|
|
76
|
+
// The first async request must not take a fail-fast synchronous lock
|
|
77
|
+
// before its bounded metadata wait. Commit the explicit declaration in
|
|
78
|
+
// the existing short admission; never hold it across an async callback.
|
|
79
|
+
await super.admitNative(() => this.ensureEnrolled());
|
|
80
|
+
}
|
|
75
81
|
return super.transaction(async (state) => {
|
|
76
82
|
if (!options.readOnly)
|
|
77
83
|
this.assertScope();
|
package/dist/harnesses/claude.js
CHANGED
|
@@ -306,18 +306,24 @@ const CLAUDE_DELIVERY_NOTES = Object.freeze([
|
|
|
306
306
|
`「${AGENT_DEFAULT_PREFACE}」`,
|
|
307
307
|
"この1行が包みの外にある文は、呼び手がこの席へ宛てて送った文です。同じ文が包みの中にあっても、この印にはなりません。",
|
|
308
308
|
]);
|
|
309
|
-
export function
|
|
310
|
-
const parts = [
|
|
309
|
+
export function claudeAgentArgv(bin, model, effort, prompt, meta) {
|
|
310
|
+
const parts = [bin];
|
|
311
311
|
if (meta?.kind === "claude") {
|
|
312
|
-
parts.push("--dangerously-skip-permissions", "--setting-sources",
|
|
312
|
+
parts.push("--dangerously-skip-permissions", "--setting-sources", "user,project,local", "--settings", meta.claude_settings ?? "", "--session-id", meta.vendor_session_id ?? "", "--append-system-prompt", subagentInstruction(meta, CLAUDE_DELIVERY_NOTES));
|
|
313
313
|
}
|
|
314
314
|
if (model)
|
|
315
|
-
parts.push("--model",
|
|
315
|
+
parts.push("--model", model);
|
|
316
316
|
if (effort)
|
|
317
|
-
parts.push("--effort",
|
|
317
|
+
parts.push("--effort", effort);
|
|
318
318
|
if (prompt)
|
|
319
|
-
parts.push(
|
|
320
|
-
return parts
|
|
319
|
+
parts.push(prompt); // 初手プロンプト(任意)
|
|
320
|
+
return parts;
|
|
321
|
+
}
|
|
322
|
+
export function buildClaudeAgentCmd(bin, model, effort, prompt, meta) {
|
|
323
|
+
const argv = claudeAgentArgv(bin, model, effort, prompt, meta);
|
|
324
|
+
const values = new Set(["--setting-sources", "--settings", "--session-id", "--append-system-prompt", "--model", "--effort"]);
|
|
325
|
+
return argv.map((arg, index) => index === 0 || values.has(argv[index - 1]) || (prompt && index === argv.length - 1)
|
|
326
|
+
? shq(arg) : arg).join(" ");
|
|
321
327
|
}
|
|
322
328
|
export function claudeLaunchNote(model, effort, meta) {
|
|
323
329
|
const writeScopeNote = writeScopeLaunchNote("claude", meta?.write_scope);
|
package/dist/harnesses/codex.js
CHANGED
|
@@ -745,8 +745,8 @@ export async function observeCodexDone(meta, timeout, requestedCursor, signal) {
|
|
|
745
745
|
await sleep(AGENT_DONE_POLL_MS);
|
|
746
746
|
}
|
|
747
747
|
}
|
|
748
|
-
export function
|
|
749
|
-
const parts = [
|
|
748
|
+
export function codexAgentArgv(bin, model, effort, prompt, meta) {
|
|
749
|
+
const parts = [bin];
|
|
750
750
|
// `codex --help` で確認した実在フラグ。read-only 宣言だけはCLI sandboxへ落とし、
|
|
751
751
|
// launcher自身が実効能力壁を作る。パス説明はCodex CLIに同等のallowlist引数がないため宣言のまま残す。
|
|
752
752
|
if (meta?.kind === "codex" && meta.write_scope === "read-only")
|
|
@@ -759,15 +759,29 @@ export function buildCodexAgentCmd(bin, model, effort, prompt, meta) {
|
|
|
759
759
|
parts.push("-c", "service_tier=default");
|
|
760
760
|
// model/effort は共有configを書き換えず、CLI引数で明示して起動単位に優先する。
|
|
761
761
|
if (model)
|
|
762
|
-
parts.push("-m",
|
|
762
|
+
parts.push("-m", model);
|
|
763
763
|
if (effort)
|
|
764
|
-
parts.push("-c", `model_reasoning_effort=${
|
|
764
|
+
parts.push("-c", `model_reasoning_effort=${effort}`);
|
|
765
765
|
if (meta?.kind === "codex" && meta.hook_route === "shared_codex_home") {
|
|
766
|
-
parts.push("-c", `developer_instructions=${
|
|
766
|
+
parts.push("-c", `developer_instructions=${subagentInstruction(meta)}`);
|
|
767
767
|
}
|
|
768
768
|
if (prompt)
|
|
769
|
-
parts.push(
|
|
770
|
-
return parts
|
|
769
|
+
parts.push(prompt); // 初手プロンプト(任意)
|
|
770
|
+
return parts;
|
|
771
|
+
}
|
|
772
|
+
export function buildCodexAgentCmd(bin, model, effort, prompt, meta) {
|
|
773
|
+
const argv = codexAgentArgv(bin, model, effort, prompt, meta);
|
|
774
|
+
return argv.map((arg, index) => {
|
|
775
|
+
if (index === 0 || argv[index - 1] === "-m" || (prompt && index === argv.length - 1))
|
|
776
|
+
return shq(arg);
|
|
777
|
+
if (argv[index - 1] === "-c") {
|
|
778
|
+
for (const key of ["model_reasoning_effort=", "developer_instructions="]) {
|
|
779
|
+
if (arg.startsWith(key))
|
|
780
|
+
return key + shq(arg.slice(key.length));
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
return arg;
|
|
784
|
+
}).join(" ");
|
|
771
785
|
}
|
|
772
786
|
// 起動応答にモデル/effort の実効値と出所を明示する。codex は端末 config のピン(model /
|
|
773
787
|
// model_reasoning_effort)が対話子へ波及する構造のため、引数・端末config継承・CLI既定の
|
package/dist/harnesses/cursor.js
CHANGED
|
@@ -537,30 +537,7 @@ export function buildCursorAgentCmd(bin, model, effort, prompt, meta, fast = fal
|
|
|
537
537
|
* hookへ渡すJSONの先頭にUTF-8 BOMを付け、BOMを読めない利用者hookが送信を止める(fox実測 2026-09-26:
|
|
538
538
|
* Git Bash配下は全てprompt_historyだけ残りstore.dbが作られず、PowerShell 7 paneからは同じhookで通る)。
|
|
539
539
|
*/
|
|
540
|
-
export
|
|
541
|
-
const psq = (value) => `'${value.replace(/'/g, "''")}'`;
|
|
542
|
-
const parts = [];
|
|
543
|
-
if (cwd)
|
|
544
|
-
parts.push(`Set-Location -LiteralPath ${psq(cwd)}`);
|
|
545
|
-
for (const [name, value] of env) {
|
|
546
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
|
|
547
|
-
throw new AitermError("環境変数名が不正です", 2);
|
|
548
|
-
parts.push(`$env:${name}=${psq(value)}`);
|
|
549
|
-
}
|
|
550
|
-
parts.push(`& ${argv.map(psq).join(" ")}`);
|
|
551
|
-
return parts.join("; ");
|
|
552
|
-
}
|
|
553
|
-
/**
|
|
554
|
-
* PowerShell 7のpaneで走らせるargv。PowerShellが自分のconsoleで走らせるのは .exe・.com・.cmd・.bat・.ps1 だけで、
|
|
555
|
-
* それ以外(受入が許すshebangのscript。拡張子なしも含む)を `&` で呼ぶと、拡張子の関連付けでpaneの外の別の窓に開く
|
|
556
|
-
* (fox実測 2026-10-14: `.sh` は `git-bash.exe` の窓で起き、席を閉じてもprocessが残った)。
|
|
557
|
-
* scriptは、control commandと同じGit Bashをpaneの中で挟んで走らせる。
|
|
558
|
-
*/
|
|
559
|
-
export function cursorPwshArgv(argv, scriptShell) {
|
|
560
|
-
if (/\.(?:exe|com|cmd|bat|ps1)$/i.test(argv[0]))
|
|
561
|
-
return argv;
|
|
562
|
-
return [scriptShell(), argv[0].replace(/\\/g, "/"), ...argv.slice(1)];
|
|
563
|
-
}
|
|
540
|
+
export { windowsAgentLaunchLine as cursorPwshLaunchLine, windowsAgentArgv as cursorPwshArgv } from "../agent-resolver.js";
|
|
564
541
|
export function cursorPromptWithLineage(meta, prompt) {
|
|
565
542
|
return `${subagentInstruction(meta)}\n\n${prompt}`;
|
|
566
543
|
}
|
package/dist/harnesses/grok.js
CHANGED
|
@@ -371,15 +371,15 @@ export async function observeGrokDone(meta, timeout, requestedCursor, detectRate
|
|
|
371
371
|
await sleep(AGENT_DONE_POLL_MS);
|
|
372
372
|
}
|
|
373
373
|
}
|
|
374
|
-
export function
|
|
375
|
-
const parts = [
|
|
374
|
+
export function grokAgentArgv(kind, bin, model, effort, prompt, meta) {
|
|
375
|
+
const parts = [bin];
|
|
376
376
|
parts.push("--no-auto-update");
|
|
377
377
|
// 無人起動の対象cwdはCLIの公式folder trust指定で登録し、確認画面にpromptを消費させない。
|
|
378
378
|
if (meta?.kind === "grok")
|
|
379
379
|
parts.push("--no-alt-screen", "--trust");
|
|
380
|
-
parts.push("--model",
|
|
380
|
+
parts.push("--model", model ?? GROK_MODEL_DEFAULTS[kind]);
|
|
381
381
|
if (effort)
|
|
382
|
-
parts.push("--reasoning-effort",
|
|
382
|
+
parts.push("--reasoning-effort", effort);
|
|
383
383
|
if (meta?.kind === "grok" && meta.write_scope === "read-only") {
|
|
384
384
|
// read-only は sandbox が実効書込み禁止を作るため、MCP ツール許可ダイアログの自動承認を
|
|
385
385
|
// 付けても能力は増えない。無人 subagent が初回 MCP 使用の許可待ちで停止する実障害への対処。
|
|
@@ -387,13 +387,19 @@ export function buildGrokAgentCmd(kind, bin, model, effort, prompt, meta) {
|
|
|
387
387
|
parts.push("--sandbox", "read-only", "--always-approve");
|
|
388
388
|
}
|
|
389
389
|
if (meta?.kind === "grok" && meta.hook_route === "shared_grok_home") {
|
|
390
|
-
parts.push("--session-id",
|
|
390
|
+
parts.push("--session-id", meta.vendor_session_id ?? "", "--rules", subagentInstruction(meta));
|
|
391
391
|
}
|
|
392
392
|
if (meta?.kind === "grok" && prompt)
|
|
393
393
|
parts.push("--verbatim");
|
|
394
394
|
if (prompt)
|
|
395
|
-
parts.push(
|
|
396
|
-
return parts
|
|
395
|
+
parts.push(prompt); // 初手プロンプト(任意)
|
|
396
|
+
return parts;
|
|
397
|
+
}
|
|
398
|
+
export function buildGrokAgentCmd(kind, bin, model, effort, prompt, meta) {
|
|
399
|
+
const argv = grokAgentArgv(kind, bin, model, effort, prompt, meta);
|
|
400
|
+
const values = new Set(["--model", "--reasoning-effort", "--session-id", "--rules"]);
|
|
401
|
+
return argv.map((arg, index) => index === 0 || values.has(argv[index - 1]) || (prompt && index === argv.length - 1)
|
|
402
|
+
? shq(arg) : arg).join(" ");
|
|
397
403
|
}
|
|
398
404
|
export function grokLaunchNote(kind, model, effort, meta) {
|
|
399
405
|
const writeScopeNote = writeScopeLaunchNote(kind, meta?.write_scope);
|
|
@@ -403,10 +409,13 @@ export function grokLaunchNote(kind, model, effort, meta) {
|
|
|
403
409
|
// grok: 検証済み auth 正本をそのままの path 形で渡す。Windows では native 強制により
|
|
404
410
|
// harness は Windows process なので、Windows ドライブパスが正しい形(WSL 形への変換はしない)。
|
|
405
411
|
export function grokEnvTokens(meta) {
|
|
412
|
+
return grokEnvEntries(meta).map(([name, value]) => `${name}=${name === "GROK_AUTH_PATH" ? shq(value) : value}`);
|
|
413
|
+
}
|
|
414
|
+
export function grokEnvEntries(meta) {
|
|
406
415
|
return [
|
|
407
|
-
...(meta.grok_auth_path ? [
|
|
408
|
-
"GROK_DISABLE_AUTOUPDATER
|
|
409
|
-
"GROK_PRIVACY_NOTICE_ROLLOUT
|
|
416
|
+
...(meta.grok_auth_path ? [["GROK_AUTH_PATH", meta.grok_auth_path]] : []),
|
|
417
|
+
["GROK_DISABLE_AUTOUPDATER", "1"],
|
|
418
|
+
["GROK_PRIVACY_NOTICE_ROLLOUT", "0"],
|
|
410
419
|
];
|
|
411
420
|
}
|
|
412
421
|
export function assertGrokSandboxNotRejected(screen) {
|
|
@@ -2,8 +2,9 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import * as net from "node:net";
|
|
3
3
|
import * as os from "node:os";
|
|
4
4
|
import * as path from "node:path";
|
|
5
|
-
// 公開本文64KiB
|
|
6
|
-
|
|
5
|
+
// 公開本文64KiBのBase64に加え、UTF-8初期化文・scriptblock構文・paste markerを含む。
|
|
6
|
+
// 最大本文の変換増分は336byte以内。本文の公開上限は変えず、内部の包みを512byte確保する。
|
|
7
|
+
const MAX_PAYLOAD_BYTES = Math.ceil(64 * 1024 / 3) * 4 + 512;
|
|
7
8
|
const PTY_CHUNK_BYTES = 256;
|
|
8
9
|
const MAX_FINAL_DRAIN_MS = 3_000;
|
|
9
10
|
const SESSION_BASE_RE = /^[A-Za-z0-9_-]{1,160}$/;
|
package/dist/tmux-runtime.js
CHANGED
|
@@ -443,6 +443,14 @@ function tmuxHasSessionEnvironmentFlags(version) {
|
|
|
443
443
|
return Number(match[1]) > 3 || (Number(match[1]) === 3 && Number(match[2]) >= 2);
|
|
444
444
|
}
|
|
445
445
|
export function sessionEnvironmentLaunch(shell, environment, version) {
|
|
446
|
+
// psmux 3.3.8 rebuilds PATH from the registry when creating a pane. Preserve
|
|
447
|
+
// the caller's runtime additions (tool installs, activated environments),
|
|
448
|
+
// without copying other environment values into command arguments.
|
|
449
|
+
if (isWin && !environment.some(entry => /^path=/i.test(entry))) {
|
|
450
|
+
const callerPath = process.env.PATH;
|
|
451
|
+
if (callerPath !== undefined)
|
|
452
|
+
environment = [...environment, `PATH=${callerPath}`];
|
|
453
|
+
}
|
|
446
454
|
const modern = isWin || tmuxHasSessionEnvironmentFlags(version);
|
|
447
455
|
if (modern)
|
|
448
456
|
return { shell, args: environment.flatMap(entry => ["-e", entry]), register_after_start: false };
|
|
@@ -579,9 +587,17 @@ const POSIX_ATOMIC_SHELLS = new Set(["bash", "sh", "zsh", "dash"]);
|
|
|
579
587
|
// OSで仕組みを変えず、同じ一括入力を各shellの構文へ適合させる。
|
|
580
588
|
export function atomicShellMultiline(text, foreground) {
|
|
581
589
|
if (POWERSHELL_COMMANDS.has(foreground)) {
|
|
582
|
-
|
|
590
|
+
// A ConPTY PowerShell can start at CP437 even when its parent uses UTF-8.
|
|
591
|
+
// Send ASCII until the submitted script establishes UTF-8; keep psmux's
|
|
592
|
+
// interactive/profile/CWD initialization and execute in the current scope.
|
|
593
|
+
const encoding = isWin
|
|
594
|
+
? "[Console]::InputEncoding = [Text.UTF8Encoding]::new($false); [Console]::OutputEncoding = [Text.UTF8Encoding]::new($false); $OutputEncoding = [Text.UTF8Encoding]::new($false); "
|
|
595
|
+
: "";
|
|
596
|
+
const encoded = Buffer.from(encoding + text, "utf8").toString("base64");
|
|
583
597
|
return `. ([scriptblock]::Create([Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${encoded}'))))`;
|
|
584
598
|
}
|
|
599
|
+
if (!text.includes("\n"))
|
|
600
|
+
return text;
|
|
585
601
|
if (!POSIX_ATOMIC_SHELLS.has(foreground))
|
|
586
602
|
return text;
|
|
587
603
|
const quoted = text.replace(/\\/g, "\\\\").replace(/\n/g, "\\n")
|
|
@@ -589,14 +605,34 @@ export function atomicShellMultiline(text, foreground) {
|
|
|
589
605
|
// printf %bで本文を復元する。末尾LFの除去はpty_sendのsubmit Enterと同値。
|
|
590
606
|
return `eval "$(command printf '%b' '${quoted}')"`;
|
|
591
607
|
}
|
|
592
|
-
export function markShellCommand(foreground, screen) {
|
|
593
|
-
if (
|
|
608
|
+
export function markShellCommand(foreground, screen, platform = process.platform) {
|
|
609
|
+
if (platform !== "win32" && foreground !== "ssh")
|
|
594
610
|
return foreground;
|
|
611
|
+
// psmuxの前面名はprocess snapshotやOSCの古い値を返しうる。
|
|
612
|
+
// 現在のpromptだけを使い、PowerShell→Git Bashと逆向きの両方を補正する。
|
|
613
|
+
const current = screen.replace(/\x1b\[[0-9;?]*[a-zA-Z]/g, "").trimEnd();
|
|
614
|
+
if (/(?:^|\n)PS [^\r\n]*>$/.test(current))
|
|
615
|
+
return "pwsh";
|
|
616
|
+
if (platform === "win32" && /(?:^|\n)[^\r\n]*\b(?:MINGW(?:32|64)|UCRT64|MSYS)\b[^\r\n]*\r?\n\$\s*$/.test(current))
|
|
617
|
+
return "bash";
|
|
618
|
+
return foreground;
|
|
619
|
+
}
|
|
620
|
+
/** The runtime owns platform foreground queries and shell-dialect reconciliation. */
|
|
621
|
+
export function paneShellForSubmission(name) {
|
|
622
|
+
const r = tmuxCommand(true, "display-message", "-p", "-t", name, "#{pane_current_command}");
|
|
623
|
+
const foreground = r.code === 0 ? normalizePaneCommand(r.stdout.trim()) : "";
|
|
595
624
|
if (!isWin && foreground !== "ssh")
|
|
596
625
|
return foreground;
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
626
|
+
const screen = tmuxCommand(true, "capture-pane", "-p", "-J", "-t", name, "-S", "-4");
|
|
627
|
+
return markShellCommand(foreground, screen.code === 0 ? screen.stdout : "");
|
|
628
|
+
}
|
|
629
|
+
/** Common send code supplies intent; the runtime decides whether/how to encode it. */
|
|
630
|
+
export function adaptShellSubmission(name, text, options = {}) {
|
|
631
|
+
if (options.launchShell)
|
|
632
|
+
return atomicShellMultiline(text, options.launchShell);
|
|
633
|
+
if (options.raw || options.literalPaste || (!isWin && !text.includes("\n")))
|
|
634
|
+
return text;
|
|
635
|
+
return atomicShellMultiline(text, options.shell || paneShellForSubmission(name));
|
|
600
636
|
}
|
|
601
637
|
export function appendMarkSentinel(text, foreground) {
|
|
602
638
|
// 複数行入力の末尾はheredoc/here-string終端になり得るため、独立した次行へ置く。
|
package/docs/DESIGN.md
CHANGED
|
@@ -69,6 +69,9 @@ core入口の再確認と、managed metadata/hook生成・設定model保存は
|
|
|
69
69
|
native作用やawaitをcallbackへ入れず、停止・世代/actor/scope交代・RPC終了後の遅着を拒否する。
|
|
70
70
|
これらの明示接続以外の設定復元や親配送metadata経路はまだ未了であり、既定mainへの有効化条件を満たさない。
|
|
71
71
|
private factoryは同scopeの共有stateへ既存PID/開始identityと役割を宣言し、各受付の同じlock内で欠測を拒否する。
|
|
72
|
+
遅延登録する参加者の最初の非同期要求は、既存の上限付きmetadata受付内で宣言を保存してから進む。
|
|
73
|
+
待機後にもscope/actorを照合し、read-only要求でも宣言だけは独立して保存する。
|
|
74
|
+
同期入口の即時拒否、登録削除後の拒否、停止snapshotの登録不要条件は変えず、入力や要求を再送しない。
|
|
72
75
|
MCP/parent-effectの既存参照とnative identityを読むinventoryはread-onlyで、役割やenvから世代・終了を補完しない。
|
|
73
76
|
開始identity交代や未登録actorを示しても旧slotを消さず、parent受付だけで参照を退役させない。
|
|
74
77
|
全行のidentity一致でも参加者の全発見/native終了fence/全経路の接続を証明せず、coverage incompleteを維持する。
|
|
@@ -103,7 +106,22 @@ sanitize済みの複数行は、POSIX shellでもPowerShellでもscript全体を
|
|
|
103
106
|
`src/tmux-runtime.ts`が改行を持たない1回の入力へ適合させ、POSIXは`eval`、PowerShellは
|
|
104
107
|
UTF-8のBase64を復元したscriptblockのdot-sourceを使う。変数と作業場所は現在のshellに残す。
|
|
105
108
|
生LFをPowerShellへキー入力として流さないため、Windowsの`Ctrl+Enter`による行順の反転を防ぐ。
|
|
109
|
+
WindowsのPowerShell shell向け非raw送信は単行もASCIIのBase64 wrapperを使い、本文の前に
|
|
110
|
+
Console入力・出力とnative pipelineのencodingをUTF-8へ揃える。CP437で起動したConPTYでも
|
|
111
|
+
文字を失わず、psmuxのprofile/PSReadLine/CWD初期化を置換しない。追加の送信やEnterは行わない。
|
|
106
112
|
単一行、`raw:true`、非shell前面は直接PTYへ送る。`enter:false`では後続のEnterまで実行しない。
|
|
113
|
+
Aitermが所有するagent起動は、POSIXではbash、WindowsではPowerShell 7のpaneを使う。
|
|
114
|
+
harnessは未引用のargvを一度組み立て、POSIXの従来の引用とWindowsのPowerShell単引用へ適合する。
|
|
115
|
+
Windowsは既存のUTF-8 Base64 scriptblockへ包み、対話MSYS bashのselect/input-mutexへ起動行を打たない。
|
|
116
|
+
受入済みshebang scriptだけは、既存のcontrol commandと同じGit Bashで非対話実行する。
|
|
117
|
+
POSIXの複数行起動commandは既存のPOSIX適合で1物理行にする。いずれもsanitizeはしない。
|
|
118
|
+
`.lastcmd`と`agentLaunchLines`は実際に打つ1物理行を持ち、公開64KiBは符号化前に検査する。
|
|
119
|
+
argv・lineage・metadata・native admission・receipt・TUI本文は変えず、新queueや再送は作らない。
|
|
120
|
+
|
|
121
|
+
通常送信もmark送信も、shellの取得・現在promptとの補正・構文への適合はtmux-runtimeの
|
|
122
|
+
同じ入口へ渡す。共通sendはraw/TUI/startupという送信意図と符号化前の上限検査を所有し、
|
|
123
|
+
Windowsの前面名だけから方言を決めない。psmuxのprocess snapshot/OSCが古い時は、
|
|
124
|
+
現在のPowerShell又はGit Bash promptで双方向に補正する。過去のpromptは使わない。
|
|
107
125
|
|
|
108
126
|
TUIの準備判定、送信文の入力欄への残存、完了後の画面安定待ちは`agent-screen-observation.ts`が所有する。
|
|
109
127
|
このmoduleはcoreをimportせず、既存harness adapterと渡されたsample・sleep・時計だけで判断する。
|
|
@@ -122,6 +140,8 @@ coreの観測(`pty_observe`)・起動準備・送信口・停止は`kind`を
|
|
|
122
140
|
席へ渡すAitermの環境変数は`agentEnvEntries`の1つの一覧から、POSIXの前置き(`agentEnvPrefix`)とWindowsのPowerShell行
|
|
123
141
|
(`cursorPwshLaunchLine`)の両方を作る。名前と値の一覧とshell別の引用を分け、同じ値を2度定義しない。
|
|
124
142
|
|
|
143
|
+
agent入力欄への`bracketedPaste`は、制御文字の除去後も本文のまま渡す。nativeの前面process名が起動shellを報告していてもshell実行文へ変換しない。shell用のUTF-8初期化・複数行適合はshell送信(利用者のshell送信と、Aiterm自身のbash起動command)だけに適用する。
|
|
144
|
+
|
|
125
145
|
`pty_read`は制御文字除去、反復圧縮、head+tail、command別reducerでcontext量を減らす。
|
|
126
146
|
完了はprocess exit、shell sentinel、literal/regex `until`、shell復帰を伴うquiescence、timeoutを区別する。
|
|
127
147
|
要求されたsentinel/untilを静止判定より優先し、nested shellで証拠がない状態を完了へ丸めない。
|
|
@@ -137,7 +157,9 @@ psmuxが出力した余分な環境値を返さない。通常PTYとagentへ`AIT
|
|
|
137
157
|
全sessionへ配るので、`new-session`の間だけ`update-environment`を差し替えてclientの環境をsessionへ写し、
|
|
138
158
|
共通環境にしか無い変数はsessionで消す。`AITERM_SESSION_ID`・`AITERM_AGENT_*`・`TMUX`・`TMUX_PANE`は継がない。
|
|
139
159
|
sessionの表には環境が丸ごと入るので、名指しで登録した名前をsessionのoption `@aiterm_env_keys`に控え、
|
|
140
|
-
`env_keys`はその名前だけを返す。psmux
|
|
160
|
+
`env_keys`はその名前だけを返す。psmuxは端末ごとに呼び出し元の環境を継ぐが、3.3.8はPATHをregistry値で上書きする。
|
|
161
|
+
Windowsでは呼出元PATHだけをnew-sessionの`-e`で明示し、実行時に追加したtoolの場所を保つ。
|
|
162
|
+
明示済みPATHは大文字小文字を問わず優先し、他の環境値を引数へ追加しない。
|
|
141
163
|
|
|
142
164
|
内部の`killAll`は終了するsocketのsession一覧と、そのsocketのログ等に残るsession名だけを対象にする。
|
|
143
165
|
別socketが同じ`AITERM_STATE_BASE`を使っていても、他のsessionの登録・完了記録・待機lockを削除しない。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiterm-mcp",
|
|
3
|
-
"version": "0.61.
|
|
3
|
+
"version": "0.61.12",
|
|
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": [
|