[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
This commit is contained in:
121
application/state/terminalConnectionReuse.ts
Normal file
121
application/state/terminalConnectionReuse.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import type { TerminalSession } from "../../domain/models";
|
||||
|
||||
type SftpReuseCandidate = Pick<
|
||||
TerminalSession,
|
||||
"protocol" | "moshEnabled" | "etEnabled"
|
||||
>;
|
||||
|
||||
/** SSH (non-mosh/et) sessions that can back SFTP once the transport is up. */
|
||||
export function isTerminalSessionEligibleForSftpReuse(session: SftpReuseCandidate): boolean {
|
||||
return (
|
||||
(session.protocol === "ssh" || session.protocol === undefined)
|
||||
&& !session.moshEnabled
|
||||
&& !session.etEnabled
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveSftpReuseSourceSessionId(
|
||||
session: SftpReuseCandidate,
|
||||
sessionId: string,
|
||||
): string | undefined {
|
||||
return isTerminalSessionEligibleForSftpReuse(session)
|
||||
? sessionId
|
||||
: undefined;
|
||||
}
|
||||
|
||||
export function canReuseTerminalConnection(session: TerminalSession): boolean {
|
||||
return isTerminalSessionEligibleForSftpReuse(session) && session.status === "connected";
|
||||
}
|
||||
|
||||
type CloneSessionOptions = {
|
||||
id: string;
|
||||
localShellType?: TerminalSession["shellType"];
|
||||
workspaceId?: string;
|
||||
inheritedCwd?: string;
|
||||
/**
|
||||
* When false, the clone never reuses the source's established SSH channel and
|
||||
* instead opens a brand-new connection (fresh auth; e.g. a new bastion login).
|
||||
* Defaults to true (reuse when possible).
|
||||
*/
|
||||
reuseConnection?: boolean;
|
||||
};
|
||||
|
||||
function getClonedShellType(
|
||||
session: TerminalSession,
|
||||
localShellType?: TerminalSession["shellType"],
|
||||
): TerminalSession["shellType"] {
|
||||
return session.protocol === "local" ? localShellType : session.shellType;
|
||||
}
|
||||
|
||||
function createTerminalSessionClone(
|
||||
session: TerminalSession,
|
||||
options: CloneSessionOptions,
|
||||
): TerminalSession {
|
||||
const isLocal = session.protocol === "local";
|
||||
// Only ssh/undefined (non-mosh/et) sessions inject an inherited `cd`; setting
|
||||
// pendingInitialCwd for telnet/serial/mosh/et would be dead, never-cleared
|
||||
// state (those protocols don't track cwd, so it's never consumed or cleared).
|
||||
const injectsInheritedCwd =
|
||||
options.reuseConnection !== false
|
||||
&& (session.protocol === "ssh" || session.protocol === undefined)
|
||||
&& !session.moshEnabled
|
||||
&& !session.etEnabled;
|
||||
const clonedSession: TerminalSession = {
|
||||
id: options.id,
|
||||
hostId: session.hostId,
|
||||
hostLabel: session.hostLabel,
|
||||
hostname: session.hostname,
|
||||
username: session.username,
|
||||
status: "connecting",
|
||||
protocol: session.protocol,
|
||||
pluginConnection: session.pluginConnection == null
|
||||
? undefined
|
||||
: structuredClone(session.pluginConnection),
|
||||
port: session.port,
|
||||
moshEnabled: session.moshEnabled,
|
||||
etEnabled: session.etEnabled,
|
||||
shellType: getClonedShellType(session, options.localShellType),
|
||||
charset: session.charset,
|
||||
localShell: session.localShell,
|
||||
localShellArgs: session.localShellArgs,
|
||||
localShellName: session.localShellName,
|
||||
localShellIcon: session.localShellIcon,
|
||||
localStartDir: isLocal && options.inheritedCwd ? options.inheritedCwd : session.localStartDir,
|
||||
fontSize: session.fontSize,
|
||||
fontSizeOverride: session.fontSizeOverride,
|
||||
...(session.ephemeralHost ? { ephemeralHost: true } : {}),
|
||||
...(injectsInheritedCwd && options.inheritedCwd ? { pendingInitialCwd: options.inheritedCwd } : {}),
|
||||
// Clearing `reuseConnectionFromSessionId` only disables source-specific
|
||||
// reuse; without an explicit fresh-connection flag the bridge would still
|
||||
// be eligible for general endpoint/idle transport reuse (e.g. borrowing
|
||||
// the source's live transport). Flag the clone so the starter sends
|
||||
// `reuseTransport: false` and the session truly dials fresh.
|
||||
...(options.reuseConnection === false ? { requireFreshConnection: true } : {}),
|
||||
reuseConnectionFromSessionId: options.reuseConnection === false
|
||||
? undefined
|
||||
: (canReuseTerminalConnection(session) ? session.id : undefined),
|
||||
};
|
||||
|
||||
if (options.workspaceId) {
|
||||
clonedSession.workspaceId = options.workspaceId;
|
||||
}
|
||||
|
||||
return clonedSession;
|
||||
}
|
||||
|
||||
export function createSplitTerminalSessionClone(
|
||||
session: TerminalSession,
|
||||
options: CloneSessionOptions,
|
||||
): TerminalSession {
|
||||
return createTerminalSessionClone(session, options);
|
||||
}
|
||||
|
||||
export function createCopiedTerminalSessionClone(
|
||||
session: TerminalSession,
|
||||
options: CloneSessionOptions,
|
||||
): TerminalSession {
|
||||
return {
|
||||
...createTerminalSessionClone(session, options),
|
||||
serialConfig: session.serialConfig,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user