fix(team): narrow process teammate override
This commit is contained in:
parent
d549006aaf
commit
5402ddfe97
2 changed files with 90 additions and 18 deletions
|
|
@ -73,7 +73,7 @@ import { TeamMetaStore } from './TeamMetaStore';
|
||||||
import { TeamSentMessagesStore } from './TeamSentMessagesStore';
|
import { TeamSentMessagesStore } from './TeamSentMessagesStore';
|
||||||
import { TeamTaskReader } from './TeamTaskReader';
|
import { TeamTaskReader } from './TeamTaskReader';
|
||||||
import { TeamLaunchStateStore } from './TeamLaunchStateStore';
|
import { TeamLaunchStateStore } from './TeamLaunchStateStore';
|
||||||
import { getDesktopPreferredTeammateMode } from './runtimeTeammateMode';
|
import { resolveDesktopTeammateModeDecision } from './runtimeTeammateMode';
|
||||||
import {
|
import {
|
||||||
createPersistedLaunchSnapshot,
|
createPersistedLaunchSnapshot,
|
||||||
snapshotFromRuntimeMemberStatuses,
|
snapshotFromRuntimeMemberStatuses,
|
||||||
|
|
@ -4357,7 +4357,10 @@ export class TeamProvisioningService {
|
||||||
const { env: shellEnv, geminiRuntimeAuth } = await this.buildProvisioningEnv(
|
const { env: shellEnv, geminiRuntimeAuth } = await this.buildProvisioningEnv(
|
||||||
request.providerId
|
request.providerId
|
||||||
);
|
);
|
||||||
const preferredTeammateMode = await getDesktopPreferredTeammateMode(request.extraCliArgs);
|
const teammateModeDecision = await resolveDesktopTeammateModeDecision(request.extraCliArgs);
|
||||||
|
if (teammateModeDecision.forceProcessTeammates) {
|
||||||
|
shellEnv.CLAUDE_TEAM_FORCE_PROCESS_TEAMMATES = '1';
|
||||||
|
}
|
||||||
let mcpConfigPath: string;
|
let mcpConfigPath: string;
|
||||||
try {
|
try {
|
||||||
mcpConfigPath = await this.mcpConfigBuilder.writeConfigFile(request.cwd);
|
mcpConfigPath = await this.mcpConfigBuilder.writeConfigFile(request.cwd);
|
||||||
|
|
@ -4388,7 +4391,9 @@ export class TeamProvisioningService {
|
||||||
...(request.model ? ['--model', request.model] : []),
|
...(request.model ? ['--model', request.model] : []),
|
||||||
...(request.effort ? ['--effort', request.effort] : []),
|
...(request.effort ? ['--effort', request.effort] : []),
|
||||||
...(request.worktree ? ['--worktree', request.worktree] : []),
|
...(request.worktree ? ['--worktree', request.worktree] : []),
|
||||||
...(preferredTeammateMode ? ['--teammate-mode', preferredTeammateMode] : []),
|
...(teammateModeDecision.injectedTeammateMode
|
||||||
|
? ['--teammate-mode', teammateModeDecision.injectedTeammateMode]
|
||||||
|
: []),
|
||||||
...parseCliArgs(request.extraCliArgs),
|
...parseCliArgs(request.extraCliArgs),
|
||||||
];
|
];
|
||||||
const runtimeWarning = buildRuntimeLaunchWarning(request, shellEnv, {
|
const runtimeWarning = buildRuntimeLaunchWarning(request, shellEnv, {
|
||||||
|
|
@ -4862,7 +4867,10 @@ export class TeamProvisioningService {
|
||||||
const { env: shellEnv, geminiRuntimeAuth } = await this.buildProvisioningEnv(
|
const { env: shellEnv, geminiRuntimeAuth } = await this.buildProvisioningEnv(
|
||||||
request.providerId
|
request.providerId
|
||||||
);
|
);
|
||||||
const preferredTeammateMode = await getDesktopPreferredTeammateMode(request.extraCliArgs);
|
const teammateModeDecision = await resolveDesktopTeammateModeDecision(request.extraCliArgs);
|
||||||
|
if (teammateModeDecision.forceProcessTeammates) {
|
||||||
|
shellEnv.CLAUDE_TEAM_FORCE_PROCESS_TEAMMATES = '1';
|
||||||
|
}
|
||||||
let mcpConfigPath: string;
|
let mcpConfigPath: string;
|
||||||
try {
|
try {
|
||||||
mcpConfigPath = await this.mcpConfigBuilder.writeConfigFile(request.cwd);
|
mcpConfigPath = await this.mcpConfigBuilder.writeConfigFile(request.cwd);
|
||||||
|
|
@ -4907,8 +4915,8 @@ export class TeamProvisioningService {
|
||||||
if (request.worktree) {
|
if (request.worktree) {
|
||||||
launchArgs.push('--worktree', request.worktree);
|
launchArgs.push('--worktree', request.worktree);
|
||||||
}
|
}
|
||||||
if (preferredTeammateMode) {
|
if (teammateModeDecision.injectedTeammateMode) {
|
||||||
launchArgs.push('--teammate-mode', preferredTeammateMode);
|
launchArgs.push('--teammate-mode', teammateModeDecision.injectedTeammateMode);
|
||||||
}
|
}
|
||||||
launchArgs.push(...parseCliArgs(request.extraCliArgs));
|
launchArgs.push(...parseCliArgs(request.extraCliArgs));
|
||||||
const runtimeWarning = buildRuntimeLaunchWarning(request, shellEnv, {
|
const runtimeWarning = buildRuntimeLaunchWarning(request, shellEnv, {
|
||||||
|
|
@ -9660,7 +9668,6 @@ export class TeamProvisioningService {
|
||||||
? { CLAUDE_CONFIG_DIR: getClaudeBasePath() }
|
? { CLAUDE_CONFIG_DIR: getClaudeBasePath() }
|
||||||
: {}),
|
: {}),
|
||||||
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: '1',
|
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: '1',
|
||||||
CLAUDE_CODE_ENTRYPOINT: 'claude-desktop',
|
|
||||||
};
|
};
|
||||||
applyConfiguredRuntimeBackendsEnv(env);
|
applyConfiguredRuntimeBackendsEnv(env);
|
||||||
applyProviderRuntimeEnv(env, providerId);
|
applyProviderRuntimeEnv(env, providerId);
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,14 @@ import { execFile } from 'child_process';
|
||||||
|
|
||||||
import { parseCliArgs } from '@shared/utils/cliArgsParser';
|
import { parseCliArgs } from '@shared/utils/cliArgsParser';
|
||||||
|
|
||||||
|
const TMUX_AVAILABILITY_CACHE_TTL_MS = 10_000;
|
||||||
|
|
||||||
|
type DesktopTeammateModeDecision = {
|
||||||
|
injectedTeammateMode: 'tmux' | null;
|
||||||
|
forceProcessTeammates: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
let tmuxAvailabilityCache: { value: boolean; at: number } | null = null;
|
||||||
let tmuxAvailablePromise: Promise<boolean> | null = null;
|
let tmuxAvailablePromise: Promise<boolean> | null = null;
|
||||||
|
|
||||||
function execFileAsync(command: string, args: string[], timeout: number): Promise<void> {
|
function execFileAsync(command: string, args: string[], timeout: number): Promise<void> {
|
||||||
|
|
@ -16,32 +24,89 @@ function execFileAsync(command: string, args: string[], timeout: number): Promis
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasExplicitTeammateMode(rawExtraCliArgs: string | undefined): boolean {
|
function getExplicitTeammateMode(
|
||||||
return parseCliArgs(rawExtraCliArgs).some(
|
rawExtraCliArgs: string | undefined
|
||||||
(token) => token === '--teammate-mode' || token.startsWith('--teammate-mode=')
|
): 'auto' | 'tmux' | 'in-process' | null {
|
||||||
);
|
const tokens = parseCliArgs(rawExtraCliArgs);
|
||||||
|
for (let i = 0; i < tokens.length; i += 1) {
|
||||||
|
const token = tokens[i];
|
||||||
|
if (token === '--teammate-mode') {
|
||||||
|
const next = tokens[i + 1];
|
||||||
|
if (next === 'auto' || next === 'tmux' || next === 'in-process') {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (token.startsWith('--teammate-mode=')) {
|
||||||
|
const value = token.slice('--teammate-mode='.length);
|
||||||
|
if (value === 'auto' || value === 'tmux' || value === 'in-process') {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function isTmuxAvailable(): Promise<boolean> {
|
async function isTmuxAvailable(): Promise<boolean> {
|
||||||
|
if (
|
||||||
|
tmuxAvailabilityCache &&
|
||||||
|
Date.now() - tmuxAvailabilityCache.at < TMUX_AVAILABILITY_CACHE_TTL_MS
|
||||||
|
) {
|
||||||
|
return tmuxAvailabilityCache.value;
|
||||||
|
}
|
||||||
|
|
||||||
if (!tmuxAvailablePromise) {
|
if (!tmuxAvailablePromise) {
|
||||||
tmuxAvailablePromise = execFileAsync('tmux', ['-V'], 3_000)
|
tmuxAvailablePromise = execFileAsync('tmux', ['-V'], 3_000)
|
||||||
.then(() => true)
|
.then(() => true)
|
||||||
.catch(() => false);
|
.catch(() => false)
|
||||||
|
.then((value) => {
|
||||||
|
tmuxAvailabilityCache = { value, at: Date.now() };
|
||||||
|
return value;
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
tmuxAvailablePromise = null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return tmuxAvailablePromise;
|
return tmuxAvailablePromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getDesktopPreferredTeammateMode(
|
export async function resolveDesktopTeammateModeDecision(
|
||||||
rawExtraCliArgs: string | undefined
|
rawExtraCliArgs: string | undefined
|
||||||
): Promise<'tmux' | null> {
|
): Promise<DesktopTeammateModeDecision> {
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
return null;
|
return {
|
||||||
|
injectedTeammateMode: null,
|
||||||
|
forceProcessTeammates: false,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasExplicitTeammateMode(rawExtraCliArgs)) {
|
const explicitMode = getExplicitTeammateMode(rawExtraCliArgs);
|
||||||
return null;
|
if (explicitMode === 'tmux') {
|
||||||
|
return {
|
||||||
|
injectedTeammateMode: null,
|
||||||
|
forceProcessTeammates: true,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return (await isTmuxAvailable()) ? 'tmux' : null;
|
if (explicitMode === 'auto' || explicitMode === 'in-process') {
|
||||||
|
return {
|
||||||
|
injectedTeammateMode: null,
|
||||||
|
forceProcessTeammates: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await isTmuxAvailable())) {
|
||||||
|
return {
|
||||||
|
injectedTeammateMode: null,
|
||||||
|
forceProcessTeammates: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
injectedTeammateMode: 'tmux',
|
||||||
|
forceProcessTeammates: true,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue