diff --git a/src/main/services/team/TeamProvisioningService.ts b/src/main/services/team/TeamProvisioningService.ts index 822a857e..96e955fd 100644 --- a/src/main/services/team/TeamProvisioningService.ts +++ b/src/main/services/team/TeamProvisioningService.ts @@ -73,6 +73,7 @@ import { TeamMetaStore } from './TeamMetaStore'; import { TeamSentMessagesStore } from './TeamSentMessagesStore'; import { TeamTaskReader } from './TeamTaskReader'; import { TeamLaunchStateStore } from './TeamLaunchStateStore'; +import { getDesktopPreferredTeammateMode } from './runtimeTeammateMode'; import { createPersistedLaunchSnapshot, snapshotFromRuntimeMemberStatuses, @@ -4356,6 +4357,7 @@ export class TeamProvisioningService { const { env: shellEnv, geminiRuntimeAuth } = await this.buildProvisioningEnv( request.providerId ); + const preferredTeammateMode = await getDesktopPreferredTeammateMode(request.extraCliArgs); let mcpConfigPath: string; try { mcpConfigPath = await this.mcpConfigBuilder.writeConfigFile(request.cwd); @@ -4386,6 +4388,7 @@ export class TeamProvisioningService { ...(request.model ? ['--model', request.model] : []), ...(request.effort ? ['--effort', request.effort] : []), ...(request.worktree ? ['--worktree', request.worktree] : []), + ...(preferredTeammateMode ? ['--teammate-mode', preferredTeammateMode] : []), ...parseCliArgs(request.extraCliArgs), ]; const runtimeWarning = buildRuntimeLaunchWarning(request, shellEnv, { @@ -4859,6 +4862,7 @@ export class TeamProvisioningService { const { env: shellEnv, geminiRuntimeAuth } = await this.buildProvisioningEnv( request.providerId ); + const preferredTeammateMode = await getDesktopPreferredTeammateMode(request.extraCliArgs); let mcpConfigPath: string; try { mcpConfigPath = await this.mcpConfigBuilder.writeConfigFile(request.cwd); @@ -4903,6 +4907,9 @@ export class TeamProvisioningService { if (request.worktree) { launchArgs.push('--worktree', request.worktree); } + if (preferredTeammateMode) { + launchArgs.push('--teammate-mode', preferredTeammateMode); + } launchArgs.push(...parseCliArgs(request.extraCliArgs)); const runtimeWarning = buildRuntimeLaunchWarning(request, shellEnv, { geminiRuntimeAuth, @@ -9653,6 +9660,7 @@ export class TeamProvisioningService { ? { CLAUDE_CONFIG_DIR: getClaudeBasePath() } : {}), CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: '1', + CLAUDE_CODE_ENTRYPOINT: 'claude-desktop', }; applyConfiguredRuntimeBackendsEnv(env); applyProviderRuntimeEnv(env, providerId); diff --git a/src/main/services/team/runtimeTeammateMode.ts b/src/main/services/team/runtimeTeammateMode.ts new file mode 100644 index 00000000..274cfbef --- /dev/null +++ b/src/main/services/team/runtimeTeammateMode.ts @@ -0,0 +1,47 @@ +import { execFile } from 'child_process'; + +import { parseCliArgs } from '@shared/utils/cliArgsParser'; + +let tmuxAvailablePromise: Promise | null = null; + +function execFileAsync(command: string, args: string[], timeout: number): Promise { + return new Promise((resolve, reject) => { + execFile(command, args, { timeout }, (error) => { + if (error) { + reject(error); + return; + } + resolve(); + }); + }); +} + +function hasExplicitTeammateMode(rawExtraCliArgs: string | undefined): boolean { + return parseCliArgs(rawExtraCliArgs).some( + (token) => token === '--teammate-mode' || token.startsWith('--teammate-mode=') + ); +} + +async function isTmuxAvailable(): Promise { + if (!tmuxAvailablePromise) { + tmuxAvailablePromise = execFileAsync('tmux', ['-V'], 3_000) + .then(() => true) + .catch(() => false); + } + + return tmuxAvailablePromise; +} + +export async function getDesktopPreferredTeammateMode( + rawExtraCliArgs: string | undefined +): Promise<'tmux' | null> { + if (process.platform === 'win32') { + return null; + } + + if (hasExplicitTeammateMode(rawExtraCliArgs)) { + return null; + } + + return (await isTmuxAvailable()) ? 'tmux' : null; +} diff --git a/src/shared/utils/cliArgsParser.ts b/src/shared/utils/cliArgsParser.ts index 5a22ac91..bd7ddaa9 100644 --- a/src/shared/utils/cliArgsParser.ts +++ b/src/shared/utils/cliArgsParser.ts @@ -26,6 +26,7 @@ export const PROTECTED_CLI_FLAGS = new Set([ '--verbose', '--model', '--effort', + '--teammate-mode', '--resume', '--permission-mode', '--permission-prompt-tool',