fix(team): prefer tmux teammates for desktop launches

This commit is contained in:
iliya 2026-04-06 15:13:03 +03:00
parent cf8df6b306
commit d549006aaf
3 changed files with 56 additions and 0 deletions

View file

@ -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);

View file

@ -0,0 +1,47 @@
import { execFile } from 'child_process';
import { parseCliArgs } from '@shared/utils/cliArgsParser';
let tmuxAvailablePromise: Promise<boolean> | null = null;
function execFileAsync(command: string, args: string[], timeout: number): Promise<void> {
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<boolean> {
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;
}

View file

@ -26,6 +26,7 @@ export const PROTECTED_CLI_FLAGS = new Set([
'--verbose',
'--model',
'--effort',
'--teammate-mode',
'--resume',
'--permission-mode',
'--permission-prompt-tool',