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
130 lines
3.8 KiB
TypeScript
130 lines
3.8 KiB
TypeScript
import { CODING_CLI_PROVIDERS, getCodingCliProvider, type CodingCliProvider } from './codingCliProviders';
|
|
import {
|
|
inferCodingCliProviderFromTitleSignals,
|
|
titleIncludesPhrase,
|
|
} from './codingCliTitleParse';
|
|
import type { Host, TerminalSession } from '../types';
|
|
|
|
export type SessionCodingCliSource = Pick<
|
|
TerminalSession,
|
|
| 'dynamicTitle'
|
|
| 'startupCommand'
|
|
| 'customName'
|
|
| 'hostLabel'
|
|
| 'localShell'
|
|
| 'localShellName'
|
|
| 'codingCliProviderId'
|
|
> & {
|
|
hostStartupCommand?: Host['startupCommand'];
|
|
};
|
|
|
|
export function getCodingCliCommandBasename(commandLine: string): string {
|
|
const trimmed = commandLine.trim();
|
|
if (!trimmed) return '';
|
|
const firstToken = trimmed.split(/\s+/)[0] ?? '';
|
|
const segments = firstToken.split(/[\\/]/);
|
|
const basename = (segments.pop() || '').toLowerCase();
|
|
return basename.replace(/\.(exe|cmd|bat|ps1)$/i, '');
|
|
}
|
|
|
|
export function matchCodingCliProviderFromCommand(commandLine: string): CodingCliProvider | undefined {
|
|
const basename = getCodingCliCommandBasename(commandLine);
|
|
if (!basename) return undefined;
|
|
|
|
return CODING_CLI_PROVIDERS.find((provider) => (
|
|
provider.command === basename
|
|
|| provider.aliases?.some((alias) => alias === basename)
|
|
));
|
|
}
|
|
|
|
export function matchCodingCliProviderFromTitle(title: string): CodingCliProvider | undefined {
|
|
const inferredId = inferCodingCliProviderFromTitleSignals(title);
|
|
if (inferredId) {
|
|
return getCodingCliProvider(inferredId);
|
|
}
|
|
|
|
const normalized = title.toLowerCase();
|
|
if (!normalized.trim()) return undefined;
|
|
|
|
const ranked = [...CODING_CLI_PROVIDERS].sort((left, right) => {
|
|
const leftHints = [
|
|
...(left.titleHints ?? []),
|
|
left.label,
|
|
left.command,
|
|
...(left.aliases ?? []),
|
|
];
|
|
const rightHints = [
|
|
...(right.titleHints ?? []),
|
|
right.label,
|
|
right.command,
|
|
...(right.aliases ?? []),
|
|
];
|
|
const leftMax = Math.max(...leftHints.map((hint) => hint.length), 0);
|
|
const rightMax = Math.max(...rightHints.map((hint) => hint.length), 0);
|
|
return rightMax - leftMax;
|
|
});
|
|
|
|
for (const provider of ranked) {
|
|
const hints = [
|
|
...(provider.titleHints ?? []),
|
|
provider.label,
|
|
provider.command,
|
|
...(provider.aliases ?? []),
|
|
];
|
|
if (hints.some((hint) => titleIncludesPhrase(normalized, hint))) {
|
|
return provider;
|
|
}
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
/**
|
|
* Resolve the active coding CLI for a terminal session from launch commands
|
|
* and shell-reported window titles.
|
|
*/
|
|
export function resolveCodingCliProviderFromCommandCandidates(
|
|
source: Pick<SessionCodingCliSource, 'startupCommand' | 'localShell'>,
|
|
host?: Pick<Host, 'startupCommand'>,
|
|
): CodingCliProvider | undefined {
|
|
const commandCandidates = [
|
|
source.startupCommand,
|
|
host?.startupCommand,
|
|
source.localShell,
|
|
].filter((value): value is string => Boolean(value?.trim()));
|
|
|
|
for (const commandLine of commandCandidates) {
|
|
const provider = matchCodingCliProviderFromCommand(commandLine);
|
|
if (provider) return provider;
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
export function resolveSessionCodingCliProvider(
|
|
source: SessionCodingCliSource,
|
|
host?: Pick<Host, 'startupCommand'>,
|
|
): CodingCliProvider | undefined {
|
|
if (source.codingCliProviderId) {
|
|
const sticky = getCodingCliProvider(source.codingCliProviderId);
|
|
if (sticky) return sticky;
|
|
}
|
|
|
|
const commandProvider = resolveCodingCliProviderFromCommandCandidates(source, host);
|
|
if (commandProvider) return commandProvider;
|
|
|
|
if (!source.customName) {
|
|
const dynamicTitle = source.dynamicTitle?.trim();
|
|
if (dynamicTitle) {
|
|
const provider = matchCodingCliProviderFromTitle(dynamicTitle);
|
|
if (provider) return provider;
|
|
}
|
|
}
|
|
|
|
if (source.localShellName) {
|
|
return matchCodingCliProviderFromTitle(source.localShellName);
|
|
}
|
|
|
|
return undefined;
|
|
}
|