Merge remote-tracking branch 'origin/master' into relprep/pr-510

Brings the 1.33.2 based adoption feature up to master. Conflicts were
resolved by keeping master's intent and re-applying the feature on top:
both sides kept for imports, the script tag and the stylesheet blocks; the
trust-dialog guard keeps master's stopped check plus the adopted refusal;
the Ralph and image watchers keep master's remote branch plus the adopted
skip; the close confirmation keeps master's worktree option plus the
adopted wording.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer committed 2026-11-06 02:51:00 +01:00
commit 57b2dcc466
858 files changed
+173626 -7078

No files matched your search

+80 -9
View File
@@ -20,12 +20,14 @@ import type {
AntigravityConfig,
PiConfig,
GrokConfig,
CopilotConfig,
DeepSeekConfig,
OmpConfig,
SessionRemote,
SessionDocker,
PaneExit,
SessionAdopt,
StatusLineExporter,
} from './types.js';
/**
@@ -65,9 +67,17 @@ export interface MuxSession {
respawnConfig?: PersistedRespawnConfig;
/** Whether Ralph / Todo tracking is enabled */
ralphEnabled?: boolean;
/** Whether the current launch carries the statusLine exporter; set on every create and respawn. */
statusLine?: StatusLineExporter;
/**
* Whether the current launch carries `idleCompaction: false` in its `--settings` JSON (keep-warm
* on at launch, the exporter injected, Claude Code new enough); set on every create and respawn.
*/
idleCompactionOff?: boolean;
/**
* This record was rebuilt from the tmux socket rather than from Codeman's own
* bookkeeping, so everything on it but the name and the pid is a guess. Its
* bookkeeping, so everything on it but the name, the pid and, when tmux
* reported a usable one, the directory is a guess. Its
* synthetic `restored-<fragment>` id cannot find the session's `state.json`
* entry either, which means a remote or docker session rediscovered this way
* arrives with no `remote`/`docker` metadata and looks local. Anything that
@@ -102,7 +112,8 @@ export interface CreateSessionOptions {
* Name pinned on a claude spawn as `--name` (version-gated, sanitized, local only).
* Deliberately NOT `name`: `--name` owns the prompt-box label, the `/resume` picker
* entry and the terminal title, and a pinned title stops Claude generating its own,
* so only a user-chosen name belongs here (see `Session.cliPinnedName`).
* so by default only a user-chosen name belongs here; the opt-in `pinCliSessionName`
* setting pins every tab name (see `Session.cliPinnedName`).
*/
cliName?: string;
niceConfig?: NiceConfig;
@@ -115,6 +126,7 @@ export interface CreateSessionOptions {
antigravityConfig?: AntigravityConfig;
piConfig?: PiConfig;
grokConfig?: GrokConfig;
copilotConfig?: CopilotConfig;
deepSeekConfig?: DeepSeekConfig;
ompConfig?: OmpConfig;
/** When restoring after reboot, resume a previous Claude conversation by its session ID */
@@ -123,6 +135,12 @@ export interface CreateSessionOptions {
envOverrides?: Record<string, string>;
/** Claude CLI effort level, injected as a `--settings` soft default (overridable via /effort in-session) */
effort?: EffortLevel;
/** Claude advisor model, merged into the same `--settings` JSON (overridable via /advisor in-session) */
advisorModel?: string;
/** The session's own prompt-cache keep-warm choice (undefined = app default); decides the `idleCompaction` opt-out. */
keepWarm?: boolean;
/** Spawned by another session: it does not inherit the keep-warm app default (`keepWarmOn`). */
spawnedByAgent?: boolean;
/** tmux history-limit (scrollback lines) allocated when this session is created. */
historyLimit?: number;
/** Remote execution metadata for local tmux sessions wrapping SSH */
@@ -146,7 +164,8 @@ export interface RespawnPaneOptions {
* Name pinned on a respawned claude as `--name` (version-gated, sanitized, local only).
* Deliberately NOT `name`: `--name` owns the prompt-box label, the `/resume` picker
* entry and the terminal title, and a pinned title stops Claude generating its own,
* so only a user-chosen name belongs here (see `Session.cliPinnedName`).
* so by default only a user-chosen name belongs here; the opt-in `pinCliSessionName`
* setting pins every tab name (see `Session.cliPinnedName`).
*/
cliName?: string;
niceConfig?: NiceConfig;
@@ -159,6 +178,7 @@ export interface RespawnPaneOptions {
antigravityConfig?: AntigravityConfig;
piConfig?: PiConfig;
grokConfig?: GrokConfig;
copilotConfig?: CopilotConfig;
deepSeekConfig?: DeepSeekConfig;
ompConfig?: OmpConfig;
/** Resume a previous Claude conversation when respawning */
@@ -174,6 +194,12 @@ export interface RespawnPaneOptions {
unsetEnvKeys?: string[];
/** Claude CLI effort level (preserved across respawns, injected via `--settings`) */
effort?: EffortLevel;
/** Claude advisor model (preserved across respawns, merged into the same `--settings` JSON) */
advisorModel?: string;
/** The session's own prompt-cache keep-warm choice, re-read at every relaunch (see CreateSessionOptions). */
keepWarm?: boolean;
/** Spawned by another session (see CreateSessionOptions). */
spawnedByAgent?: boolean;
/** Original tmux history-limit retained for config parity; respawn cannot resize the existing pane. */
historyLimit?: number;
/** Remote execution metadata for local tmux sessions wrapping SSH */
@@ -197,6 +223,21 @@ export interface PaneCaptureOptions {
fullHistory?: boolean;
/** Bound the full-history capture to this many scrollback lines (`-S -<N>`). */
historyLimitLines?: number;
/**
* Full-history only: scrollback rows read from somewhere other than this pane
* (raw `capture-pane -p -e -J` text, oldest first). The pane then contributes
* only its visible frame and caret, and its own history is not read. A remote
* session's real history lives in the REMOTE tmux (`remote-pane-history.ts`).
*/
scrollbackOverride?: string;
/**
* With `scrollbackOverride`: the screen rows of the pane that history came
* from, read right after it. The frame this pane captures later can have
* scrolled past some of them, or show only part of a taller screen, so the
* rows above where the frame's top overlaps them are kept between the
* scrollback and the frame (`joinScrollbackAndFrame`).
*/
scrollbackOverrideScreen?: string;
/**
* Byte cap the consumer will keep from the capture. Sizes the child-process
* stdout buffer (with slack) so multi-MB scrollback dumps aren't killed by
@@ -212,6 +253,24 @@ export interface PaneCaptureOptions {
* rendering it needs the real height to know the frame fits.
*/
capturedGeometry?: { cols: number; rows: number };
/**
* Filled in by the implementation with the number of rows the pane holds in
* scrollback ABOVE the visible frame (tmux `#{history_size}`), read in the
* same query as the geometry. 0 means a full-history capture can return
* nothing beyond the visible frame: a pane in the alternate screen (a
* fullscreen CLI that keeps its transcript itself) never accumulates any.
* A full-history capture bounded by `historyLimitLines` below this depth
* left older lines behind in the multiplexer, which the caller must report
* as recoverable. Absent when the pane could not be queried.
*/
capturedHistoryLines?: number;
/**
* Filled in by the implementation with whether the pane was in the alternate
* screen at capture time, when it can tell. tmux keeps no history for such a
* pane (a nested tmux client puts it there), so a full-history capture of it
* holds one screen plus whatever the pane held before.
*/
capturedAlternateOn?: boolean;
}
/**
@@ -224,7 +283,7 @@ export interface PaneCaptureOptions {
* - `sessionKilled` (data: { sessionId: string }) - Session terminated
* - `sessionDied` (data: { sessionId: string }) - Session died unexpectedly
* - `statsUpdated` (sessions: MuxSessionWithStats[]) - Stats refreshed
* - `paneExitsUpdated` () - A pane read finished; ask `getPaneExit()` per session
* - `paneExitsUpdated` () - A pane read finished; ask `getPaneExit()` (and `getPaneCurrentPath()`) per session
*/
export interface TerminalMultiplexer extends EventEmitter {
/** Which backend this instance uses */
@@ -267,9 +326,10 @@ export interface TerminalMultiplexer extends EventEmitter {
// ========== Input ==========
/**
* Send input to a session via tmux send-keys.
* Send input to a session via tmux send-keys. The optional internal Enter-only
* guard runs synchronously immediately before transport dispatch.
*/
sendInput(sessionId: string, input: string): Promise<boolean>;
sendInput(sessionId: string, input: string, options?: { beforeDispatch?: () => boolean }): Promise<boolean>;
// ========== Metadata ==========
@@ -348,6 +408,16 @@ export interface TerminalMultiplexer extends EventEmitter {
*/
getPaneExit?(muxName: string): PaneExit | undefined;
/**
* The directory the session's pane was in at the last pane read
* (`#{pane_current_path}`), or `undefined` when unknown. Read from the same
* batched watcher as {@link getPaneExit}, so it costs no tmux call. A relative
* path printed in the terminal resolves against it; it is never a
* confinement root. A multiplexer without it leaves relative paths resolving
* against `workingDir`.
*/
getPaneCurrentPath?(muxName: string): string | undefined;
/**
* How many authoritative pane reads have agreed on the exit `getPaneExit()`
* reports, or 0 when it reports none. The exited-agent sweep closes a session
@@ -382,11 +452,12 @@ export interface TerminalMultiplexer extends EventEmitter {
captureActivePaneBuffer?(muxName: string, opts?: PaneCaptureOptions): string | null;
/**
* Plain text of the visible frame: no styles, no cursor query, no repaint
* reconstruction. Deliberately cheaper than `capturePaneBuffer` because idle
* Plain text of the visible frame: no cursor query, no repaint
* reconstruction, and no styles unless `styles` asks for them (SGR only, lines
* still `\n`-separated). Deliberately cheaper than `capturePaneBuffer` because idle
* detection calls it on a timer: it only needs to read what the CLI is
* currently rendering, never to replay it into an xterm. Returns null when the
* pane cannot be read.
*/
capturePaneText?(muxName: string, paneTarget?: string): string | null;
capturePaneText?(muxName: string, paneTarget?: string, opts?: { styles?: boolean }): string | null;
}