fix(ci): restore dev validation gates
This commit is contained in:
parent
b92c8c2f54
commit
92a1c2067b
33 changed files with 106 additions and 69 deletions
|
|
@ -120,6 +120,7 @@ import {
|
||||||
import { startEventLoopLagMonitor } from './services/infrastructure/EventLoopLagMonitor';
|
import { startEventLoopLagMonitor } from './services/infrastructure/EventLoopLagMonitor';
|
||||||
import { HttpServer } from './services/infrastructure/HttpServer';
|
import { HttpServer } from './services/infrastructure/HttpServer';
|
||||||
import { clearAutoResumeService } from './services/team/AutoResumeService';
|
import { clearAutoResumeService } from './services/team/AutoResumeService';
|
||||||
|
import { LaunchIoGovernor } from './services/team/LaunchIoGovernor';
|
||||||
import { OpenCodeBridgeCommandClient } from './services/team/opencode/bridge/OpenCodeBridgeCommandClient';
|
import { OpenCodeBridgeCommandClient } from './services/team/opencode/bridge/OpenCodeBridgeCommandClient';
|
||||||
import {
|
import {
|
||||||
createOpenCodeBridgeCommandLeaseStore,
|
createOpenCodeBridgeCommandLeaseStore,
|
||||||
|
|
@ -136,16 +137,15 @@ import {
|
||||||
clearTeamControlApiState,
|
clearTeamControlApiState,
|
||||||
writeTeamControlApiState,
|
writeTeamControlApiState,
|
||||||
} from './services/team/TeamControlApiState';
|
} from './services/team/TeamControlApiState';
|
||||||
import { TeamInboxReader } from './services/team/TeamInboxReader';
|
|
||||||
import { getTeamDataWorkerClient } from './services/team/TeamDataWorkerClient';
|
import { getTeamDataWorkerClient } from './services/team/TeamDataWorkerClient';
|
||||||
import { getTeamFsWorkerClient } from './services/team/TeamFsWorkerClient';
|
import { getTeamFsWorkerClient } from './services/team/TeamFsWorkerClient';
|
||||||
|
import { TeamInboxReader } from './services/team/TeamInboxReader';
|
||||||
import { TeamMemberRuntimeAdvisoryService } from './services/team/TeamMemberRuntimeAdvisoryService';
|
import { TeamMemberRuntimeAdvisoryService } from './services/team/TeamMemberRuntimeAdvisoryService';
|
||||||
import {
|
import {
|
||||||
createTeamReconcileDrainScheduler,
|
createTeamReconcileDrainScheduler,
|
||||||
type TeamReconcileTrigger,
|
type TeamReconcileTrigger,
|
||||||
} from './services/team/TeamReconcileDrainScheduler';
|
} from './services/team/TeamReconcileDrainScheduler';
|
||||||
import { TeamSentMessagesStore } from './services/team/TeamSentMessagesStore';
|
import { TeamSentMessagesStore } from './services/team/TeamSentMessagesStore';
|
||||||
import { LaunchIoGovernor } from './services/team/LaunchIoGovernor';
|
|
||||||
import { getAppIconPath } from './utils/appIcon';
|
import { getAppIconPath } from './utils/appIcon';
|
||||||
import {
|
import {
|
||||||
getClaudeBasePath,
|
getClaudeBasePath,
|
||||||
|
|
@ -647,7 +647,7 @@ async function runStartupJobsBounded<T>(
|
||||||
if (isShutdownStarted()) {
|
if (isShutdownStarted()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await run(items[index]!);
|
await run(items[index]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await Promise.allSettled(workers);
|
await Promise.allSettled(workers);
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,10 @@ import {
|
||||||
initializeAutoResumeService,
|
initializeAutoResumeService,
|
||||||
planRateLimitAutoResume,
|
planRateLimitAutoResume,
|
||||||
} from '../services/team/AutoResumeService';
|
} from '../services/team/AutoResumeService';
|
||||||
|
import {
|
||||||
|
cloneLaunchIoGovernorPayload,
|
||||||
|
type LaunchIoGovernor,
|
||||||
|
} from '../services/team/LaunchIoGovernor';
|
||||||
import {
|
import {
|
||||||
buildReplaceMembersDiff,
|
buildReplaceMembersDiff,
|
||||||
buildReplaceMembersSummaryMessage,
|
buildReplaceMembersSummaryMessage,
|
||||||
|
|
@ -136,10 +140,6 @@ import { TeamMetaStore } from '../services/team/TeamMetaStore';
|
||||||
import { buildAddMemberSpawnMessage } from '../services/team/TeamProvisioningService';
|
import { buildAddMemberSpawnMessage } from '../services/team/TeamProvisioningService';
|
||||||
import { TeamTaskAttachmentStore } from '../services/team/TeamTaskAttachmentStore';
|
import { TeamTaskAttachmentStore } from '../services/team/TeamTaskAttachmentStore';
|
||||||
import { TeamWorktreeGitService } from '../services/team/TeamWorktreeGitService';
|
import { TeamWorktreeGitService } from '../services/team/TeamWorktreeGitService';
|
||||||
import {
|
|
||||||
cloneLaunchIoGovernorPayload,
|
|
||||||
type LaunchIoGovernor,
|
|
||||||
} from '../services/team/LaunchIoGovernor';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
validateFromField,
|
validateFromField,
|
||||||
|
|
@ -983,7 +983,6 @@ async function handleGetData(
|
||||||
} else {
|
} else {
|
||||||
noteHeavyTeamDataWorkerFallback('teams:getData');
|
noteHeavyTeamDataWorkerFallback('teams:getData');
|
||||||
data = await getTeamDataService().getTeamData(tn);
|
data = await getTeamDataService().getTeamData(tn);
|
||||||
dataSource = 'main-unavailable';
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const message = error instanceof Error ? error.message : String(error);
|
const message = error instanceof Error ? error.message : String(error);
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import { stripAgentBlocks } from '@shared/constants/agentBlocks';
|
||||||
import { getMemberColorByName, MEMBER_COLOR_HUE } from '@shared/constants/memberColors';
|
import { getMemberColorByName, MEMBER_COLOR_HUE } from '@shared/constants/memberColors';
|
||||||
import { isLeadMember } from '@shared/utils/leadDetection';
|
import { isLeadMember } from '@shared/utils/leadDetection';
|
||||||
import { createLogger } from '@shared/utils/logger';
|
import { createLogger } from '@shared/utils/logger';
|
||||||
import { Notification as ElectronNotification, nativeImage } from 'electron';
|
import { nativeImage, Notification as ElectronNotification } from 'electron';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
||||||
import * as fsp from 'fs/promises';
|
import * as fsp from 'fs/promises';
|
||||||
|
|
@ -279,7 +279,7 @@ function truncateNotificationText(value: string, maxLength: number): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractTaskRef(summary: string): string | null {
|
function extractTaskRef(summary: string): string | null {
|
||||||
const match = summary.match(/#([A-Za-z0-9][A-Za-z0-9-]*)/);
|
const match = /#([A-Za-z0-9][A-Za-z0-9-]*)/.exec(summary);
|
||||||
return match ? `#${match[1]}` : null;
|
return match ? `#${match[1]}` : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
import { randomUUID } from 'crypto';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { randomUUID } from 'crypto';
|
|
||||||
|
|
||||||
import { mergeJsonSettingsObjects, parseJsonSettingsObject } from './cliSettingsArgs';
|
import { mergeJsonSettingsObjects, parseJsonSettingsObject } from './cliSettingsArgs';
|
||||||
|
|
||||||
|
|
@ -24,7 +24,8 @@ export function splitSettingsJsonArgs(args: string[]): SplitSettingsJsonArgsResu
|
||||||
const settingsFragments: TeamRuntimeSettingsJson[] = [];
|
const settingsFragments: TeamRuntimeSettingsJson[] = [];
|
||||||
const passthroughArgs: string[] = [];
|
const passthroughArgs: string[] = [];
|
||||||
|
|
||||||
for (let index = 0; index < args.length; index += 1) {
|
let index = 0;
|
||||||
|
while (index < args.length) {
|
||||||
const arg = args[index];
|
const arg = args[index];
|
||||||
if (arg === '--settings') {
|
if (arg === '--settings') {
|
||||||
const value = args[index + 1];
|
const value = args[index + 1];
|
||||||
|
|
@ -32,11 +33,11 @@ export function splitSettingsJsonArgs(args: string[]): SplitSettingsJsonArgsResu
|
||||||
const parsed = parseJsonSettingsObject(value);
|
const parsed = parseJsonSettingsObject(value);
|
||||||
if (parsed) {
|
if (parsed) {
|
||||||
settingsFragments.push(parsed);
|
settingsFragments.push(parsed);
|
||||||
index += 1;
|
index += 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
passthroughArgs.push(arg, value);
|
passthroughArgs.push(arg, value);
|
||||||
index += 1;
|
index += 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -52,6 +53,7 @@ export function splitSettingsJsonArgs(args: string[]): SplitSettingsJsonArgsResu
|
||||||
}
|
}
|
||||||
|
|
||||||
passthroughArgs.push(arg);
|
passthroughArgs.push(arg);
|
||||||
|
index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { settingsFragments, passthroughArgs };
|
return { settingsFragments, passthroughArgs };
|
||||||
|
|
@ -119,7 +121,7 @@ async function writeSettingsFile(
|
||||||
export async function materializeTeamRuntimeSettingsBundle(input: {
|
export async function materializeTeamRuntimeSettingsBundle(input: {
|
||||||
teamName: string;
|
teamName: string;
|
||||||
providerId: TeamProviderId;
|
providerId: TeamProviderId;
|
||||||
baseSettings?: Array<TeamRuntimeSettingsJson | null | undefined>;
|
baseSettings?: (TeamRuntimeSettingsJson | null | undefined)[];
|
||||||
anthropicHelper?: AnthropicTeamApiKeyHelperMaterial | null;
|
anthropicHelper?: AnthropicTeamApiKeyHelperMaterial | null;
|
||||||
}): Promise<TeamRuntimeSettingsBundle | null> {
|
}): Promise<TeamRuntimeSettingsBundle | null> {
|
||||||
const fragments = [...(input.baseSettings ?? [])].filter(
|
const fragments = [...(input.baseSettings ?? [])].filter(
|
||||||
|
|
|
||||||
|
|
@ -198,12 +198,8 @@ export class TeamFsWorkerClient {
|
||||||
)}`
|
)}`
|
||||||
);
|
);
|
||||||
this.failWorker(worker, timeoutError);
|
this.failWorker(worker, timeoutError);
|
||||||
try {
|
// Terminate and recreate on next call - worker may be stuck in native IO.
|
||||||
// Terminate and recreate on next call - worker may be stuck in native IO.
|
void worker.terminate().catch(() => undefined);
|
||||||
worker.terminate().catch(() => undefined);
|
|
||||||
} catch {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
reject(timeoutError);
|
reject(timeoutError);
|
||||||
}, WORKER_CALL_TIMEOUT_MS);
|
}, WORKER_CALL_TIMEOUT_MS);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,13 @@ import {
|
||||||
BOARD_TASK_CHANGES_DIRNAME,
|
BOARD_TASK_CHANGES_DIRNAME,
|
||||||
BOARD_TASK_LOG_FRESHNESS_DIRNAME,
|
BOARD_TASK_LOG_FRESHNESS_DIRNAME,
|
||||||
BOARD_TASK_LOG_FRESHNESS_FILE_SUFFIX,
|
BOARD_TASK_LOG_FRESHNESS_FILE_SUFFIX,
|
||||||
MAX_PENDING_UNKNOWN_ROOT_REFRESH_ATTEMPTS,
|
|
||||||
MAX_PENDING_UNKNOWN_ROOT_SESSIONS,
|
|
||||||
PENDING_UNKNOWN_ROOT_SESSION_TTL_MS,
|
|
||||||
classifyLogSourceWatcherEvent,
|
classifyLogSourceWatcherEvent,
|
||||||
getRelativeLogSourceParts,
|
getRelativeLogSourceParts,
|
||||||
isAgentTranscriptFileName,
|
isAgentTranscriptFileName,
|
||||||
|
MAX_PENDING_UNKNOWN_ROOT_REFRESH_ATTEMPTS,
|
||||||
|
MAX_PENDING_UNKNOWN_ROOT_SESSIONS,
|
||||||
normalizeLogSourceSessionId,
|
normalizeLogSourceSessionId,
|
||||||
|
PENDING_UNKNOWN_ROOT_SESSION_TTL_MS,
|
||||||
} from './teamLogSourceWatchScope';
|
} from './teamLogSourceWatchScope';
|
||||||
|
|
||||||
import type { TeamLogSourceLiveContext, TeamMemberLogsFinder } from './TeamMemberLogsFinder';
|
import type { TeamLogSourceLiveContext, TeamMemberLogsFinder } from './TeamMemberLogsFinder';
|
||||||
|
|
@ -420,18 +420,21 @@ export class TeamLogSourceTracker {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (action.kind === 'task-freshness') {
|
if (action.kind === 'task-freshness') {
|
||||||
this.handleTaskFreshnessSignalChange(
|
if (
|
||||||
teamName,
|
!this.handleTaskFreshnessSignalChange(
|
||||||
current.projectDir,
|
teamName,
|
||||||
changedPath,
|
current.projectDir,
|
||||||
BOARD_TASK_LOG_FRESHNESS_DIRNAME
|
changedPath,
|
||||||
) ||
|
BOARD_TASK_LOG_FRESHNESS_DIRNAME
|
||||||
|
)
|
||||||
|
) {
|
||||||
this.handleTaskFreshnessSignalChange(
|
this.handleTaskFreshnessSignalChange(
|
||||||
teamName,
|
teamName,
|
||||||
current.projectDir,
|
current.projectDir,
|
||||||
changedPath,
|
changedPath,
|
||||||
BOARD_TASK_CHANGE_FRESHNESS_DIRNAME
|
BOARD_TASK_CHANGE_FRESHNESS_DIRNAME
|
||||||
);
|
);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,15 +11,15 @@ import {
|
||||||
lineHasAgentTeamsTaskBoundaryToolName,
|
lineHasAgentTeamsTaskBoundaryToolName,
|
||||||
} from './agentTeamsToolNames';
|
} from './agentTeamsToolNames';
|
||||||
import {
|
import {
|
||||||
readBootstrapLaunchSnapshot,
|
|
||||||
choosePreferredLaunchSnapshot,
|
choosePreferredLaunchSnapshot,
|
||||||
|
readBootstrapLaunchSnapshot,
|
||||||
} from './TeamBootstrapStateReader';
|
} from './TeamBootstrapStateReader';
|
||||||
import { TeamConfigReader } from './TeamConfigReader';
|
import { TeamConfigReader } from './TeamConfigReader';
|
||||||
import { TeamInboxReader } from './TeamInboxReader';
|
import { TeamInboxReader } from './TeamInboxReader';
|
||||||
import { TeamLaunchStateStore } from './TeamLaunchStateStore';
|
import { TeamLaunchStateStore } from './TeamLaunchStateStore';
|
||||||
|
import { buildTeamLogWatchSessionIds, extractRuntimeSessionIds } from './teamLogSourceWatchScope';
|
||||||
import { TeamMembersMetaStore } from './TeamMembersMetaStore';
|
import { TeamMembersMetaStore } from './TeamMembersMetaStore';
|
||||||
import { TeamTranscriptProjectResolver } from './TeamTranscriptProjectResolver';
|
import { TeamTranscriptProjectResolver } from './TeamTranscriptProjectResolver';
|
||||||
import { buildTeamLogWatchSessionIds, extractRuntimeSessionIds } from './teamLogSourceWatchScope';
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
MemberLogSummary,
|
MemberLogSummary,
|
||||||
|
|
|
||||||
|
|
@ -109,20 +109,20 @@ import * as path from 'path';
|
||||||
import pidusage from 'pidusage';
|
import pidusage from 'pidusage';
|
||||||
import * as readline from 'readline';
|
import * as readline from 'readline';
|
||||||
|
|
||||||
import { mergeJsonSettingsArgs, parseJsonSettingsObject } from '../runtime/cliSettingsArgs';
|
|
||||||
import {
|
import {
|
||||||
ANTHROPIC_HELPER_MODE_COMPETING_AUTH_ENV_KEYS,
|
ANTHROPIC_HELPER_MODE_COMPETING_AUTH_ENV_KEYS,
|
||||||
|
type AnthropicTeamApiKeyHelperMaterial,
|
||||||
CLAUDE_TEAM_ANTHROPIC_API_KEY_HELPER_SETTINGS_PATH_ENV,
|
CLAUDE_TEAM_ANTHROPIC_API_KEY_HELPER_SETTINGS_PATH_ENV,
|
||||||
CLAUDE_TEAM_ANTHROPIC_AUTH_MODE_API_KEY_HELPER,
|
CLAUDE_TEAM_ANTHROPIC_AUTH_MODE_API_KEY_HELPER,
|
||||||
CLAUDE_TEAM_ANTHROPIC_AUTH_MODE_ENV,
|
CLAUDE_TEAM_ANTHROPIC_AUTH_MODE_ENV,
|
||||||
DISABLE_ANTHROPIC_TEAM_API_KEY_HELPER_ENV,
|
|
||||||
cleanupAnthropicTeamApiKeyHelperForTeam,
|
cleanupAnthropicTeamApiKeyHelperForTeam,
|
||||||
cleanupAnthropicTeamApiKeyHelperMaterial,
|
cleanupAnthropicTeamApiKeyHelperMaterial,
|
||||||
cleanupStaleAnthropicTeamApiKeyHelpers,
|
cleanupStaleAnthropicTeamApiKeyHelpers,
|
||||||
|
DISABLE_ANTHROPIC_TEAM_API_KEY_HELPER_ENV,
|
||||||
materializeAnthropicTeamApiKeyHelper,
|
materializeAnthropicTeamApiKeyHelper,
|
||||||
verifyAnthropicTeamApiKeyHelperMaterial,
|
verifyAnthropicTeamApiKeyHelperMaterial,
|
||||||
type AnthropicTeamApiKeyHelperMaterial,
|
|
||||||
} from '../runtime/anthropicTeamApiKeyHelper';
|
} from '../runtime/anthropicTeamApiKeyHelper';
|
||||||
|
import { mergeJsonSettingsArgs, parseJsonSettingsObject } from '../runtime/cliSettingsArgs';
|
||||||
import {
|
import {
|
||||||
type GeminiRuntimeAuthState,
|
type GeminiRuntimeAuthState,
|
||||||
resolveGeminiRuntimeAuth,
|
resolveGeminiRuntimeAuth,
|
||||||
|
|
@ -359,9 +359,9 @@ import type {
|
||||||
LeadContextUsage,
|
LeadContextUsage,
|
||||||
MemberLaunchState,
|
MemberLaunchState,
|
||||||
MemberSpawnLivenessSource,
|
MemberSpawnLivenessSource,
|
||||||
MemberSpawnStatusesSnapshot,
|
|
||||||
MemberSpawnStatus,
|
MemberSpawnStatus,
|
||||||
MemberSpawnStatusEntry,
|
MemberSpawnStatusEntry,
|
||||||
|
MemberSpawnStatusesSnapshot,
|
||||||
PersistedTeamLaunchMemberState,
|
PersistedTeamLaunchMemberState,
|
||||||
PersistedTeamLaunchPhase,
|
PersistedTeamLaunchPhase,
|
||||||
PersistedTeamLaunchSnapshot,
|
PersistedTeamLaunchSnapshot,
|
||||||
|
|
@ -1100,22 +1100,26 @@ function filterOutSettingsPathArgs(
|
||||||
return [...args];
|
return [...args];
|
||||||
}
|
}
|
||||||
const filtered: string[] = [];
|
const filtered: string[] = [];
|
||||||
for (let index = 0; index < args.length; index += 1) {
|
let index = 0;
|
||||||
|
while (index < args.length) {
|
||||||
const arg = args[index];
|
const arg = args[index];
|
||||||
if (arg === '--settings' && args[index + 1] === settingsPath) {
|
if (arg === '--settings' && args[index + 1] === settingsPath) {
|
||||||
index += 1;
|
index += 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (arg === `--settings=${settingsPath}`) {
|
if (arg === `--settings=${settingsPath}`) {
|
||||||
|
index += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
filtered.push(arg);
|
filtered.push(arg);
|
||||||
|
index += 1;
|
||||||
}
|
}
|
||||||
return filtered;
|
return filtered;
|
||||||
}
|
}
|
||||||
|
|
||||||
function hasPathBasedSettingsArgs(args: string[]): boolean {
|
function hasPathBasedSettingsArgs(args: string[]): boolean {
|
||||||
for (let index = 0; index < args.length; index += 1) {
|
let index = 0;
|
||||||
|
while (index < args.length) {
|
||||||
const arg = args[index];
|
const arg = args[index];
|
||||||
if (arg === '--settings') {
|
if (arg === '--settings') {
|
||||||
const value = args[index + 1];
|
const value = args[index + 1];
|
||||||
|
|
@ -1123,17 +1127,20 @@ function hasPathBasedSettingsArgs(args: string[]): boolean {
|
||||||
if (!parseJsonSettingsObject(value)) {
|
if (!parseJsonSettingsObject(value)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
index += 1;
|
index += 2;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if (typeof value !== 'string') {
|
if (typeof value !== 'string') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
index += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const prefix = '--settings=';
|
const prefix = '--settings=';
|
||||||
if (arg.startsWith(prefix) && !parseJsonSettingsObject(arg.slice(prefix.length))) {
|
if (arg.startsWith(prefix) && !parseJsonSettingsObject(arg.slice(prefix.length))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
index += 1;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -4989,6 +4996,10 @@ export class TeamProvisioningService {
|
||||||
this.transcriptProjectResolver = new TeamTranscriptProjectResolver({
|
this.transcriptProjectResolver = new TeamTranscriptProjectResolver({
|
||||||
getConfig: (teamName) => this.configReader.getConfigSnapshot(teamName),
|
getConfig: (teamName) => this.configReader.getConfigSnapshot(teamName),
|
||||||
});
|
});
|
||||||
|
this.scheduleStaleAnthropicTeamApiKeyHelperCleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private scheduleStaleAnthropicTeamApiKeyHelperCleanup(): void {
|
||||||
void cleanupStaleAnthropicTeamApiKeyHelpers({
|
void cleanupStaleAnthropicTeamApiKeyHelpers({
|
||||||
baseClaudeDir: getClaudeBasePath(),
|
baseClaudeDir: getClaudeBasePath(),
|
||||||
maxAgeMs: 14 * 24 * 60 * 60 * 1000,
|
maxAgeMs: 14 * 24 * 60 * 60 * 1000,
|
||||||
|
|
@ -11090,8 +11101,7 @@ export class TeamProvisioningService {
|
||||||
|
|
||||||
const existingRequest = this.memberSpawnStatusesInFlightByTeam.get(teamName);
|
const existingRequest = this.memberSpawnStatusesInFlightByTeam.get(teamName);
|
||||||
if (
|
if (
|
||||||
existingRequest &&
|
existingRequest?.generationAtStart === generationAtStart &&
|
||||||
existingRequest.generationAtStart === generationAtStart &&
|
|
||||||
existingRequest.runIdAtStart === run.runId
|
existingRequest.runIdAtStart === run.runId
|
||||||
) {
|
) {
|
||||||
const snapshot = await existingRequest.promise;
|
const snapshot = await existingRequest.promise;
|
||||||
|
|
@ -11201,8 +11211,7 @@ export class TeamProvisioningService {
|
||||||
const generationAtStart = this.getRuntimeSnapshotCacheGeneration(teamName);
|
const generationAtStart = this.getRuntimeSnapshotCacheGeneration(teamName);
|
||||||
const existingRequest = this.agentRuntimeSnapshotInFlightByTeam.get(teamName);
|
const existingRequest = this.agentRuntimeSnapshotInFlightByTeam.get(teamName);
|
||||||
if (
|
if (
|
||||||
existingRequest &&
|
existingRequest?.generationAtStart === generationAtStart &&
|
||||||
existingRequest.generationAtStart === generationAtStart &&
|
|
||||||
existingRequest.runIdAtStart === runId
|
existingRequest.runIdAtStart === runId
|
||||||
) {
|
) {
|
||||||
return existingRequest.promise;
|
return existingRequest.promise;
|
||||||
|
|
@ -18732,8 +18741,7 @@ export class TeamProvisioningService {
|
||||||
const generationAtStart = this.getRuntimeSnapshotCacheGeneration(teamName);
|
const generationAtStart = this.getRuntimeSnapshotCacheGeneration(teamName);
|
||||||
const existingRequest = this.liveTeamAgentRuntimeMetadataInFlightByTeam.get(teamName);
|
const existingRequest = this.liveTeamAgentRuntimeMetadataInFlightByTeam.get(teamName);
|
||||||
if (
|
if (
|
||||||
existingRequest &&
|
existingRequest?.generationAtStart === generationAtStart &&
|
||||||
existingRequest.generationAtStart === generationAtStart &&
|
|
||||||
existingRequest.runIdAtStart === runId
|
existingRequest.runIdAtStart === runId
|
||||||
) {
|
) {
|
||||||
return this.cloneLiveTeamAgentRuntimeMetadata(await existingRequest.promise);
|
return this.cloneLiveTeamAgentRuntimeMetadata(await existingRequest.promise);
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@ import { createHash, randomUUID } from 'crypto';
|
||||||
import { promises as fs } from 'fs';
|
import { promises as fs } from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
import type { FileLockOptions } from '../../fileLock';
|
|
||||||
|
|
||||||
import { VersionedJsonStore, VersionedJsonStoreError } from './VersionedJsonStore';
|
import { VersionedJsonStore, VersionedJsonStoreError } from './VersionedJsonStore';
|
||||||
|
|
||||||
|
import type { FileLockOptions } from '../../fileLock';
|
||||||
|
|
||||||
export const OPENCODE_RUNTIME_STORE_MANIFEST_SCHEMA_VERSION = 1;
|
export const OPENCODE_RUNTIME_STORE_MANIFEST_SCHEMA_VERSION = 1;
|
||||||
export const OPENCODE_RUNTIME_STORE_RECEIPT_SCHEMA_VERSION = 1;
|
export const OPENCODE_RUNTIME_STORE_RECEIPT_SCHEMA_VERSION = 1;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -148,8 +148,8 @@ interface TeamSummaryCacheEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
type CachedTaskReadResult =
|
type CachedTaskReadResult =
|
||||||
| { task: Record<string, unknown>; skipReason?: undefined }
|
| { task: Record<string, unknown>; skipReason?: never }
|
||||||
| { task?: undefined; skipReason: string };
|
| { task?: never; skipReason: string };
|
||||||
|
|
||||||
interface TaskFileCacheEntry {
|
interface TaskFileCacheEntry {
|
||||||
fingerprint: string;
|
fingerprint: string;
|
||||||
|
|
|
||||||
|
|
@ -216,3 +216,5 @@ export const BaseItem = memo(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
BaseItem.displayName = 'BaseItem';
|
||||||
|
|
|
||||||
|
|
@ -282,3 +282,5 @@ export const ExecutionTrace: React.FC<ExecutionTraceProps> = React.memo(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ExecutionTrace.displayName = 'ExecutionTrace';
|
||||||
|
|
|
||||||
|
|
@ -236,3 +236,5 @@ export const LinkedToolItem = memo(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
LinkedToolItem.displayName = 'LinkedToolItem';
|
||||||
|
|
|
||||||
|
|
@ -215,3 +215,5 @@ export const MetricsPill = memo(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
MetricsPill.displayName = 'MetricsPill';
|
||||||
|
|
|
||||||
|
|
@ -81,3 +81,5 @@ export const SlashItem = memo(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
SlashItem.displayName = 'SlashItem';
|
||||||
|
|
|
||||||
|
|
@ -598,3 +598,5 @@ export const SubagentItem: React.FC<SubagentItemProps> = React.memo(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
SubagentItem.displayName = 'SubagentItem';
|
||||||
|
|
|
||||||
|
|
@ -264,3 +264,5 @@ export const TeammateMessageItem = memo(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TeammateMessageItem.displayName = 'TeammateMessageItem';
|
||||||
|
|
|
||||||
|
|
@ -82,3 +82,5 @@ export const TextItem: React.FC<TextItemProps> = React.memo(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TextItem.displayName = 'TextItem';
|
||||||
|
|
|
||||||
|
|
@ -82,3 +82,5 @@ export const ThinkingItem: React.FC<ThinkingItemProps> = React.memo(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ThinkingItem.displayName = 'ThinkingItem';
|
||||||
|
|
|
||||||
|
|
@ -59,3 +59,5 @@ export const CollapsibleOutputSection = memo(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CollapsibleOutputSection.displayName = 'CollapsibleOutputSection';
|
||||||
|
|
|
||||||
|
|
@ -1112,3 +1112,5 @@ export const DateGroupedSessions = memo((): React.JSX.Element => {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
DateGroupedSessions.displayName = 'DateGroupedSessions';
|
||||||
|
|
|
||||||
|
|
@ -117,3 +117,5 @@ export const MemberBadge = memo(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
MemberBadge.displayName = 'MemberBadge';
|
||||||
|
|
|
||||||
|
|
@ -128,12 +128,12 @@ import {
|
||||||
} from './sidebar/teamSidebarUiState';
|
} from './sidebar/teamSidebarUiState';
|
||||||
import { ClaudeLogsSection } from './ClaudeLogsSection';
|
import { ClaudeLogsSection } from './ClaudeLogsSection';
|
||||||
import { CollapsibleTeamSection } from './CollapsibleTeamSection';
|
import { CollapsibleTeamSection } from './CollapsibleTeamSection';
|
||||||
import { ProcessesSection } from './ProcessesSection';
|
|
||||||
import { getLaunchJoinMilestonesFromMembers, getLaunchJoinState } from './provisioningSteps';
|
|
||||||
import { TeamProvisioningBanner } from './TeamProvisioningBanner';
|
|
||||||
import { deriveLeadContextButtonLabel } from './leadContextLoadGuards';
|
import { deriveLeadContextButtonLabel } from './leadContextLoadGuards';
|
||||||
import { LeadSessionDetailGate } from './LeadSessionDetailGate';
|
import { LeadSessionDetailGate } from './LeadSessionDetailGate';
|
||||||
import { LiveRuntimeStatusBridge } from './LiveRuntimeStatusBridge';
|
import { LiveRuntimeStatusBridge } from './LiveRuntimeStatusBridge';
|
||||||
|
import { ProcessesSection } from './ProcessesSection';
|
||||||
|
import { getLaunchJoinMilestonesFromMembers, getLaunchJoinState } from './provisioningSteps';
|
||||||
|
import { TeamProvisioningBanner } from './TeamProvisioningBanner';
|
||||||
import { loadTeamSessionMetadata } from './teamSessionFetchGuards';
|
import { loadTeamSessionMetadata } from './teamSessionFetchGuards';
|
||||||
import { TeamSessionsSection } from './TeamSessionsSection';
|
import { TeamSessionsSection } from './TeamSessionsSection';
|
||||||
|
|
||||||
|
|
@ -1847,7 +1847,7 @@ export const TeamDetailView = memo(function TeamDetailView({
|
||||||
const pendingTeamSectionFocus = useStore((s) => s.pendingTeamSectionFocus);
|
const pendingTeamSectionFocus = useStore((s) => s.pendingTeamSectionFocus);
|
||||||
const clearTeamSectionFocus = useStore((s) => s.clearTeamSectionFocus);
|
const clearTeamSectionFocus = useStore((s) => s.clearTeamSectionFocus);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!pendingTeamSectionFocus || pendingTeamSectionFocus.teamName !== teamName) return;
|
if (pendingTeamSectionFocus?.teamName !== teamName) return;
|
||||||
|
|
||||||
const sectionId =
|
const sectionId =
|
||||||
pendingTeamSectionFocus.section === 'members'
|
pendingTeamSectionFocus.section === 'members'
|
||||||
|
|
|
||||||
|
|
@ -79,3 +79,5 @@ export const ReplyQuoteBlock = memo(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ReplyQuoteBlock.displayName = 'ReplyQuoteBlock';
|
||||||
|
|
|
||||||
|
|
@ -458,5 +458,7 @@ export const KanbanGridLayout = memo(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
KanbanGridLayout.displayName = 'KanbanGridLayout';
|
||||||
|
|
||||||
export { SKELETON_HIDE_DELAY_MS, SKELETON_HIDE_DELAY_MS_ON_MODE_SWITCH };
|
export { SKELETON_HIDE_DELAY_MS, SKELETON_HIDE_DELAY_MS_ON_MODE_SWITCH };
|
||||||
/* eslint-enable tailwindcss/no-custom-classname -- stable class hooks remain scoped to this file. */
|
/* eslint-enable tailwindcss/no-custom-classname -- stable class hooks remain scoped to this file. */
|
||||||
|
|
|
||||||
|
|
@ -58,3 +58,5 @@ export const CurrentTaskIndicator = memo(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CurrentTaskIndicator.displayName = 'CurrentTaskIndicator';
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,5 @@ export const MemberPresenceDot = memo(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
MemberPresenceDot.displayName = 'MemberPresenceDot';
|
||||||
|
|
|
||||||
|
|
@ -36,11 +36,11 @@ export interface TeamRuntimeDisplayRow {
|
||||||
actionsAllowed: false;
|
actionsAllowed: false;
|
||||||
}
|
}
|
||||||
|
|
||||||
type SpawnDegradation = {
|
interface SpawnDegradation {
|
||||||
reason: string;
|
reason: string;
|
||||||
diagnostic?: string;
|
diagnostic?: string;
|
||||||
diagnosticSeverity: TeamAgentRuntimeDiagnosticSeverity;
|
diagnosticSeverity: TeamAgentRuntimeDiagnosticSeverity;
|
||||||
};
|
}
|
||||||
|
|
||||||
const ACTIVE_SPAWN_STATUSES = new Set(['waiting', 'spawning']);
|
const ACTIVE_SPAWN_STATUSES = new Set(['waiting', 'spawning']);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,8 @@ import {
|
||||||
isTeamDataRefreshPending,
|
isTeamDataRefreshPending,
|
||||||
selectTeamDataForName,
|
selectTeamDataForName,
|
||||||
} from './slices/teamSlice';
|
} from './slices/teamSlice';
|
||||||
|
import { createUISlice } from './slices/uiSlice';
|
||||||
|
import { createUpdateSlice } from './slices/updateSlice';
|
||||||
import {
|
import {
|
||||||
decideProcessFanoutDryRun,
|
decideProcessFanoutDryRun,
|
||||||
decideProcessFanoutMode,
|
decideProcessFanoutMode,
|
||||||
|
|
@ -58,8 +60,6 @@ import {
|
||||||
noteTeamRefreshFanout,
|
noteTeamRefreshFanout,
|
||||||
type TeamRefreshFanoutOperation,
|
type TeamRefreshFanoutOperation,
|
||||||
} from './teamRefreshFanoutDiagnostics';
|
} from './teamRefreshFanoutDiagnostics';
|
||||||
import { createUISlice } from './slices/uiSlice';
|
|
||||||
import { createUpdateSlice } from './slices/updateSlice';
|
|
||||||
|
|
||||||
import type { DetectedError } from '../types/data';
|
import type { DetectedError } from '../types/data';
|
||||||
import type { AppState } from './types';
|
import type { AppState } from './types';
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ export interface TeamRefreshFanoutStructuredCount {
|
||||||
phase: TeamRefreshFanoutPhase;
|
phase: TeamRefreshFanoutPhase;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TeamRefreshFanoutSummaryRow extends TeamRefreshFanoutStructuredCount {}
|
export type TeamRefreshFanoutSummaryRow = TeamRefreshFanoutStructuredCount;
|
||||||
|
|
||||||
export interface TeamRefreshFanoutSummary {
|
export interface TeamRefreshFanoutSummary {
|
||||||
generatedAt: number;
|
generatedAt: number;
|
||||||
|
|
@ -92,7 +92,7 @@ function createEmptyBucket(): TeamRefreshFanoutBucket {
|
||||||
|
|
||||||
function ensureTeamBucket(teamName: string): TeamRefreshFanoutBucket {
|
function ensureTeamBucket(teamName: string): TeamRefreshFanoutBucket {
|
||||||
if (!buckets.has(teamName) && buckets.size >= MAX_TEAM_REFRESH_DIAGNOSTIC_TEAMS) {
|
if (!buckets.has(teamName) && buckets.size >= MAX_TEAM_REFRESH_DIAGNOSTIC_TEAMS) {
|
||||||
const oldestKey = buckets.keys().next().value as string | undefined;
|
const oldestKey = buckets.keys().next().value;
|
||||||
if (oldestKey) {
|
if (oldestKey) {
|
||||||
buckets.delete(oldestKey);
|
buckets.delete(oldestKey);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import type { EnhancedChunk } from '@main/types';
|
|
||||||
import type { NotificationTarget, TeamEventType } from './notifications';
|
import type { NotificationTarget, TeamEventType } from './notifications';
|
||||||
|
import type { EnhancedChunk } from '@main/types';
|
||||||
|
|
||||||
export interface TeamMember {
|
export interface TeamMember {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
|
||||||
|
|
@ -235,10 +235,7 @@ liveDescribe('Mixed provider team launch live e2e', () => {
|
||||||
|
|
||||||
await waitUntilWithDiagnostics(async () => {
|
await waitUntilWithDiagnostics(async () => {
|
||||||
const status = await harness!.svc.getMemberSpawnStatuses(teamName!);
|
const status = await harness!.svc.getMemberSpawnStatuses(teamName!);
|
||||||
if (
|
if (status.teamLaunchState === 'partial_failure') {
|
||||||
status.teamLaunchState === 'failed' ||
|
|
||||||
status.teamLaunchState === 'partial_failure'
|
|
||||||
) {
|
|
||||||
throw new Error(await formatMixedLaunchDiagnostics(harness!, teamName!, progressEvents));
|
throw new Error(await formatMixedLaunchDiagnostics(harness!, teamName!, progressEvents));
|
||||||
}
|
}
|
||||||
for (const memberName of ['alice', 'cody', 'oscar'] as const) {
|
for (const memberName of ['alice', 'cody', 'oscar'] as const) {
|
||||||
|
|
@ -268,8 +265,8 @@ liveDescribe('Mixed provider team launch live e2e', () => {
|
||||||
|
|
||||||
const laneIndex = await readOpenCodeRuntimeLaneIndex(getTeamsBasePath(), teamName);
|
const laneIndex = await readOpenCodeRuntimeLaneIndex(getTeamsBasePath(), teamName);
|
||||||
expect(
|
expect(
|
||||||
Object.values(laneIndex.lanes).some(
|
Object.entries(laneIndex.lanes).some(
|
||||||
(lane) => lane.state === 'active' && lane.memberName === 'oscar'
|
([laneId, lane]) => lane.state === 'active' && laneId === 'secondary:opencode:oscar'
|
||||||
)
|
)
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ vi.mock('@main/services/team/ClaudeBinaryResolver', () => ({
|
||||||
|
|
||||||
vi.mock('@main/utils/childProcess', () => ({
|
vi.mock('@main/utils/childProcess', () => ({
|
||||||
execCli: vi.fn(async (_binaryPath: string | null, args: string[]) => {
|
execCli: vi.fn(async (_binaryPath: string | null, args: string[]) => {
|
||||||
if (args[0] === 'model') {
|
if (args.includes('model') && args.includes('list')) {
|
||||||
return {
|
return {
|
||||||
stdout: JSON.stringify({
|
stdout: JSON.stringify({
|
||||||
schemaVersion: 1,
|
schemaVersion: 1,
|
||||||
|
|
@ -54,7 +54,7 @@ vi.mock('@main/utils/childProcess', () => ({
|
||||||
stderr: '',
|
stderr: '',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (args[0] === 'runtime') {
|
if (args.includes('runtime') && args.includes('status')) {
|
||||||
return {
|
return {
|
||||||
stdout: JSON.stringify({
|
stdout: JSON.stringify({
|
||||||
providers: {
|
providers: {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue