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
107 lines
3.7 KiB
TypeScript
107 lines
3.7 KiB
TypeScript
import { classifyDistroId, resolveHostOs } from './host';
|
|
import type { PortForwardingRule } from './models';
|
|
import type { Host, TerminalSession } from '../types';
|
|
|
|
export type AITerminalSessionInfo = {
|
|
sessionId: string;
|
|
hostId: string;
|
|
hostname: string;
|
|
label: string;
|
|
os?: string;
|
|
username?: string;
|
|
protocol?: string;
|
|
shellType?: string;
|
|
deviceType?: string;
|
|
connected: boolean;
|
|
hostChain?: Array<{ hostId: string; label?: string; hostname?: string }>;
|
|
activePortForwards?: Array<{
|
|
ruleId: string;
|
|
label?: string;
|
|
type?: string;
|
|
localPort?: number;
|
|
status?: string;
|
|
}>;
|
|
};
|
|
|
|
function summarizeHostChain(
|
|
host: Host | undefined,
|
|
allHosts: Host[],
|
|
): AITerminalSessionInfo['hostChain'] | undefined {
|
|
if (!host?.hostChain?.hostIds?.length) return undefined;
|
|
return host.hostChain.hostIds.map((hostId) => {
|
|
const jumpHost = allHosts.find((entry) => entry.id === hostId);
|
|
return {
|
|
hostId,
|
|
label: jumpHost?.label,
|
|
hostname: jumpHost?.hostname,
|
|
};
|
|
});
|
|
}
|
|
|
|
export const buildAITerminalSessionInfo = (
|
|
session: TerminalSession | undefined,
|
|
host: Host | undefined,
|
|
localOs: 'linux' | 'macos' | 'windows',
|
|
options?: {
|
|
allHosts?: Host[];
|
|
portForwardingRules?: PortForwardingRule[];
|
|
},
|
|
): AITerminalSessionInfo => {
|
|
const protocol = session?.protocol || host?.protocol;
|
|
const isLocalSession = protocol === 'local' || session?.hostId?.startsWith('local-');
|
|
const allHosts = options?.allHosts ?? (host ? [host] : []);
|
|
const hostChain = summarizeHostChain(host, allHosts);
|
|
const activePortForwards = host?.id && options?.portForwardingRules
|
|
? options.portForwardingRules
|
|
.filter((rule) => rule.hostId === host.id && (rule.status === 'active' || rule.status === 'connecting'))
|
|
.map((rule) => ({
|
|
ruleId: rule.id,
|
|
label: rule.label,
|
|
type: rule.type,
|
|
localPort: rule.localPort,
|
|
status: rule.status,
|
|
}))
|
|
: undefined;
|
|
// Mosh / ET sessions always run over a shell-backed PTY and cannot reach a
|
|
// vendor CLI, so network device mode never applies to them.
|
|
const isMoshOrEt = Boolean(
|
|
session?.moshEnabled || host?.moshEnabled || session?.etEnabled || host?.etEnabled,
|
|
);
|
|
// Report 'network' when the host is explicitly a network device OR when the
|
|
// detected distro/vendor classifies as one (Huawei VRP, Cisco IOS, ...). This
|
|
// mirrors the terminal's own gating (Terminal.tsx / systemTarget.ts) so AI
|
|
// exec skips shell wrapping (routing to the raw-PTY path) and the system
|
|
// prompt gets vendor-CLI guidance even before the user manually flips
|
|
// Network Device Mode (#2367).
|
|
const isNetworkDevice = host?.deviceType === 'network'
|
|
|| classifyDistroId(host?.distro) === 'network-device';
|
|
const deviceType = isMoshOrEt
|
|
? undefined
|
|
: (isNetworkDevice ? 'network' : host?.deviceType);
|
|
return {
|
|
sessionId: session?.id || '',
|
|
hostId: session?.hostId || '',
|
|
hostname: host?.hostname || session?.hostname || '',
|
|
label: host?.label || session?.hostLabel || '',
|
|
os: isLocalSession ? localOs : resolveHostOs(host),
|
|
username: host?.username || session?.username,
|
|
protocol,
|
|
shellType: session?.shellType && session.shellType !== 'unknown' ? session.shellType : undefined,
|
|
deviceType,
|
|
connected: session?.status === 'connected',
|
|
...(hostChain?.length ? { hostChain } : {}),
|
|
...(activePortForwards?.length ? { activePortForwards } : {}),
|
|
};
|
|
};
|
|
|
|
|
|
export type AIPanelContext = {
|
|
scopeType: 'terminal' | 'workspace';
|
|
scopeTargetId?: string;
|
|
scopeHostIds: string[];
|
|
scopeLabel: string;
|
|
/** Focused pane in a workspace; used to inherit AI chat after terminal merge. */
|
|
focusedSessionId?: string;
|
|
terminalSessions: AITerminalSessionInfo[];
|
|
};
|