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
91 lines
3.3 KiB
TypeScript
91 lines
3.3 KiB
TypeScript
import type { DiscoveredAgent, ExternalAgentConfig } from './types';
|
|
import { getCommandBasename, isPathLikeCommand } from './shared/pathLikeCommand';
|
|
|
|
export { isPathLikeCommand, getCommandBasename };
|
|
|
|
export type ManagedAgentKey = 'codex' | 'claude' | 'copilot' | 'cursor' | 'codebuddy' | 'opencode' | 'grok';
|
|
|
|
const MANAGED_AGENT_META: Record<ManagedAgentKey, { commandNames: string[]; sdkBackend: string }> = {
|
|
codex: { commandNames: ['codex'], sdkBackend: 'codex' },
|
|
claude: { commandNames: ['claude'], sdkBackend: 'claude' },
|
|
copilot: { commandNames: ['copilot'], sdkBackend: 'copilot' },
|
|
cursor: { commandNames: ['cursor'], sdkBackend: 'cursor' },
|
|
codebuddy: { commandNames: ['codebuddy'], sdkBackend: 'codebuddy' },
|
|
opencode: { commandNames: ['opencode'], sdkBackend: 'opencode' },
|
|
grok: { commandNames: ['grok'], sdkBackend: 'grok' },
|
|
};
|
|
|
|
function matchesPrimaryCliBasename(command: string | undefined, agentKey: ManagedAgentKey): boolean {
|
|
const basename = getCommandBasename(command);
|
|
return basename === agentKey || basename.startsWith(`${agentKey}.`);
|
|
}
|
|
|
|
export function isSettingsManagedDiscoveredAgent(
|
|
agent: Pick<DiscoveredAgent, 'command'>,
|
|
): agent is Pick<DiscoveredAgent, 'command'> & { command: ManagedAgentKey } {
|
|
return agent.command === 'codex'
|
|
|| agent.command === 'claude'
|
|
|| agent.command === 'copilot'
|
|
|| agent.command === 'cursor'
|
|
|| agent.command === 'codebuddy'
|
|
|| agent.command === 'opencode'
|
|
|| agent.command === 'grok';
|
|
}
|
|
|
|
export function matchesManagedAgentConfig(
|
|
agent: Pick<ExternalAgentConfig, 'id' | 'command' | 'sdkBackend' | 'acpCommand'>,
|
|
agentKey: ManagedAgentKey,
|
|
): boolean {
|
|
const meta = MANAGED_AGENT_META[agentKey];
|
|
const basename = getCommandBasename(agent.command);
|
|
if (agentKey === 'claude') {
|
|
return (
|
|
agent.id === 'discovered_claude' ||
|
|
basename === 'claude' ||
|
|
basename.startsWith('claude.')
|
|
);
|
|
}
|
|
return (
|
|
agent.id === `discovered_${agentKey}` ||
|
|
getExternalAgentSdkBackend(agent) === meta.sdkBackend ||
|
|
meta.commandNames.some((commandName) => basename === commandName || basename.startsWith(`${commandName}.`))
|
|
);
|
|
}
|
|
|
|
export function getExternalAgentSdkBackend(
|
|
agent: Pick<ExternalAgentConfig, 'sdkBackend' | 'acpCommand'> | undefined,
|
|
): string | undefined {
|
|
return agent?.sdkBackend || agent?.acpCommand || undefined;
|
|
}
|
|
|
|
export function getManagedAgentStoredPath(
|
|
agents: ExternalAgentConfig[],
|
|
agentKey: ManagedAgentKey,
|
|
): string | null {
|
|
const managedId = `discovered_${agentKey}`;
|
|
const preferredAgent = agents.find(
|
|
(agent) =>
|
|
agent.id === managedId &&
|
|
isPathLikeCommand(agent.command) &&
|
|
matchesPrimaryCliBasename(agent.command, agentKey),
|
|
);
|
|
if (preferredAgent) {
|
|
return preferredAgent.command;
|
|
}
|
|
|
|
const fallbackAgent = agents.find(
|
|
(agent) =>
|
|
matchesManagedAgentConfig(agent, agentKey) &&
|
|
isPathLikeCommand(agent.command) &&
|
|
matchesPrimaryCliBasename(agent.command, agentKey),
|
|
);
|
|
return fallbackAgent?.command ?? null;
|
|
}
|
|
|
|
export function getManualAgentCommand(
|
|
config: Pick<ExternalAgentConfig, 'command' | 'commandSource'> | null | undefined,
|
|
): string | undefined {
|
|
const command = String(config?.command || '').trim();
|
|
return config?.commandSource === 'manual' && command ? command : undefined;
|
|
}
|