fix(ci): restore dev validation
This commit is contained in:
parent
6c43380846
commit
a8d53ca5cb
51 changed files with 298 additions and 129 deletions
|
|
@ -1353,6 +1353,7 @@ describe('agent-teams-mcp tools', () => {
|
||||||
members: [
|
members: [
|
||||||
{ name: 'lead', role: 'team-lead' },
|
{ name: 'lead', role: 'team-lead' },
|
||||||
{ name: 'alice', role: 'developer' },
|
{ name: 'alice', role: 'developer' },
|
||||||
|
{ name: 'bob', role: 'reviewer' },
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
"opencode:prove-team-provisioning": "node ./scripts/prove-opencode-team-provisioning.mjs",
|
"opencode:prove-team-provisioning": "node ./scripts/prove-opencode-team-provisioning.mjs",
|
||||||
"team:prove-launch-matrix": "pnpm exec vitest run --maxWorkers 1 --minWorkers 1 test/main/services/team/TeamAgentLaunchMatrix.safe-e2e.test.ts",
|
"team:prove-launch-matrix": "pnpm exec vitest run --maxWorkers 1 --minWorkers 1 test/main/services/team/TeamAgentLaunchMatrix.safe-e2e.test.ts",
|
||||||
"prebuild": "tsx scripts/fetch-pricing-data.ts && pnpm --filter agent-teams-controller build && pnpm --filter agent-teams-mcp build",
|
"prebuild": "tsx scripts/fetch-pricing-data.ts && pnpm --filter agent-teams-controller build && pnpm --filter agent-teams-mcp build",
|
||||||
"build": "electron-vite build",
|
"build": "node --max-old-space-size=8192 ./node_modules/electron-vite/bin/electron-vite.js build",
|
||||||
"dist": "electron-builder --mac --win --linux",
|
"dist": "electron-builder --mac --win --linux",
|
||||||
"dist:mac": "electron-builder --mac",
|
"dist:mac": "electron-builder --mac",
|
||||||
"dist:mac:arm64": "electron-builder --mac --arm64",
|
"dist:mac:arm64": "electron-builder --mac --arm64",
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ import type {
|
||||||
RuntimeProviderManagementDirectoryResponse,
|
RuntimeProviderManagementDirectoryResponse,
|
||||||
RuntimeProviderManagementForgetInput,
|
RuntimeProviderManagementForgetInput,
|
||||||
RuntimeProviderManagementLoadDirectoryInput,
|
RuntimeProviderManagementLoadDirectoryInput,
|
||||||
|
RuntimeProviderManagementLoadModelsInput,
|
||||||
RuntimeProviderManagementLoadSetupFormInput,
|
RuntimeProviderManagementLoadSetupFormInput,
|
||||||
RuntimeProviderManagementLoadViewInput,
|
RuntimeProviderManagementLoadViewInput,
|
||||||
RuntimeProviderManagementLoadModelsInput,
|
|
||||||
RuntimeProviderManagementModelTestResponse,
|
|
||||||
RuntimeProviderManagementModelsResponse,
|
RuntimeProviderManagementModelsResponse,
|
||||||
|
RuntimeProviderManagementModelTestResponse,
|
||||||
RuntimeProviderManagementProviderResponse,
|
RuntimeProviderManagementProviderResponse,
|
||||||
RuntimeProviderManagementSetDefaultModelInput,
|
RuntimeProviderManagementSetDefaultModelInput,
|
||||||
RuntimeProviderManagementSetupFormResponse,
|
RuntimeProviderManagementSetupFormResponse,
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@ import type {
|
||||||
RuntimeProviderManagementDirectoryResponse,
|
RuntimeProviderManagementDirectoryResponse,
|
||||||
RuntimeProviderManagementForgetInput,
|
RuntimeProviderManagementForgetInput,
|
||||||
RuntimeProviderManagementLoadDirectoryInput,
|
RuntimeProviderManagementLoadDirectoryInput,
|
||||||
RuntimeProviderManagementLoadSetupFormInput,
|
|
||||||
RuntimeProviderManagementLoadModelsInput,
|
RuntimeProviderManagementLoadModelsInput,
|
||||||
|
RuntimeProviderManagementLoadSetupFormInput,
|
||||||
RuntimeProviderManagementLoadViewInput,
|
RuntimeProviderManagementLoadViewInput,
|
||||||
RuntimeProviderManagementModelTestResponse,
|
|
||||||
RuntimeProviderManagementModelsResponse,
|
RuntimeProviderManagementModelsResponse,
|
||||||
|
RuntimeProviderManagementModelTestResponse,
|
||||||
RuntimeProviderManagementProviderResponse,
|
RuntimeProviderManagementProviderResponse,
|
||||||
RuntimeProviderManagementSetDefaultModelInput,
|
RuntimeProviderManagementSetDefaultModelInput,
|
||||||
RuntimeProviderManagementSetupFormResponse,
|
RuntimeProviderManagementSetupFormResponse,
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,11 @@ import type {
|
||||||
RuntimeProviderManagementDirectoryResponse,
|
RuntimeProviderManagementDirectoryResponse,
|
||||||
RuntimeProviderManagementForgetInput,
|
RuntimeProviderManagementForgetInput,
|
||||||
RuntimeProviderManagementLoadDirectoryInput,
|
RuntimeProviderManagementLoadDirectoryInput,
|
||||||
RuntimeProviderManagementLoadSetupFormInput,
|
|
||||||
RuntimeProviderManagementLoadModelsInput,
|
RuntimeProviderManagementLoadModelsInput,
|
||||||
|
RuntimeProviderManagementLoadSetupFormInput,
|
||||||
RuntimeProviderManagementLoadViewInput,
|
RuntimeProviderManagementLoadViewInput,
|
||||||
RuntimeProviderManagementModelTestResponse,
|
|
||||||
RuntimeProviderManagementModelsResponse,
|
RuntimeProviderManagementModelsResponse,
|
||||||
|
RuntimeProviderManagementModelTestResponse,
|
||||||
RuntimeProviderManagementProviderResponse,
|
RuntimeProviderManagementProviderResponse,
|
||||||
RuntimeProviderManagementSetDefaultModelInput,
|
RuntimeProviderManagementSetDefaultModelInput,
|
||||||
RuntimeProviderManagementSetupFormResponse,
|
RuntimeProviderManagementSetupFormResponse,
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@ import type {
|
||||||
RuntimeProviderManagementDirectoryResponse,
|
RuntimeProviderManagementDirectoryResponse,
|
||||||
RuntimeProviderManagementForgetInput,
|
RuntimeProviderManagementForgetInput,
|
||||||
RuntimeProviderManagementLoadDirectoryInput,
|
RuntimeProviderManagementLoadDirectoryInput,
|
||||||
RuntimeProviderManagementLoadSetupFormInput,
|
|
||||||
RuntimeProviderManagementLoadModelsInput,
|
RuntimeProviderManagementLoadModelsInput,
|
||||||
|
RuntimeProviderManagementLoadSetupFormInput,
|
||||||
RuntimeProviderManagementLoadViewInput,
|
RuntimeProviderManagementLoadViewInput,
|
||||||
RuntimeProviderManagementModelTestResponse,
|
|
||||||
RuntimeProviderManagementModelsResponse,
|
RuntimeProviderManagementModelsResponse,
|
||||||
|
RuntimeProviderManagementModelTestResponse,
|
||||||
RuntimeProviderManagementProviderResponse,
|
RuntimeProviderManagementProviderResponse,
|
||||||
RuntimeProviderManagementSetDefaultModelInput,
|
RuntimeProviderManagementSetDefaultModelInput,
|
||||||
RuntimeProviderManagementSetupFormResponse,
|
RuntimeProviderManagementSetupFormResponse,
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ import type {
|
||||||
RuntimeProviderManagementErrorDto,
|
RuntimeProviderManagementErrorDto,
|
||||||
RuntimeProviderManagementForgetInput,
|
RuntimeProviderManagementForgetInput,
|
||||||
RuntimeProviderManagementLoadDirectoryInput,
|
RuntimeProviderManagementLoadDirectoryInput,
|
||||||
RuntimeProviderManagementLoadSetupFormInput,
|
|
||||||
RuntimeProviderManagementLoadModelsInput,
|
RuntimeProviderManagementLoadModelsInput,
|
||||||
|
RuntimeProviderManagementLoadSetupFormInput,
|
||||||
RuntimeProviderManagementLoadViewInput,
|
RuntimeProviderManagementLoadViewInput,
|
||||||
RuntimeProviderManagementModelsResponse,
|
RuntimeProviderManagementModelsResponse,
|
||||||
RuntimeProviderManagementModelTestResponse,
|
RuntimeProviderManagementModelTestResponse,
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,11 @@ import type {
|
||||||
RuntimeProviderManagementDirectoryResponse,
|
RuntimeProviderManagementDirectoryResponse,
|
||||||
RuntimeProviderManagementForgetInput,
|
RuntimeProviderManagementForgetInput,
|
||||||
RuntimeProviderManagementLoadDirectoryInput,
|
RuntimeProviderManagementLoadDirectoryInput,
|
||||||
RuntimeProviderManagementLoadSetupFormInput,
|
|
||||||
RuntimeProviderManagementLoadModelsInput,
|
RuntimeProviderManagementLoadModelsInput,
|
||||||
|
RuntimeProviderManagementLoadSetupFormInput,
|
||||||
RuntimeProviderManagementLoadViewInput,
|
RuntimeProviderManagementLoadViewInput,
|
||||||
RuntimeProviderManagementModelTestResponse,
|
|
||||||
RuntimeProviderManagementModelsResponse,
|
RuntimeProviderManagementModelsResponse,
|
||||||
|
RuntimeProviderManagementModelTestResponse,
|
||||||
RuntimeProviderManagementProviderResponse,
|
RuntimeProviderManagementProviderResponse,
|
||||||
RuntimeProviderManagementSetDefaultModelInput,
|
RuntimeProviderManagementSetDefaultModelInput,
|
||||||
RuntimeProviderManagementSetupFormResponse,
|
RuntimeProviderManagementSetupFormResponse,
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ interface ProviderRowProps {
|
||||||
readonly actions: RuntimeProviderManagementActions;
|
readonly actions: RuntimeProviderManagementActions;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DIRECTORY_FILTERS: Array<{ id: RuntimeProviderDirectoryFilterDto; label: string }> = [
|
const DIRECTORY_FILTERS: { id: RuntimeProviderDirectoryFilterDto; label: string }[] = [
|
||||||
{ id: 'all', label: 'All' },
|
{ id: 'all', label: 'All' },
|
||||||
{ id: 'connectable', label: 'Connectable' },
|
{ id: 'connectable', label: 'Connectable' },
|
||||||
{ id: 'connected', label: 'Connected' },
|
{ id: 'connected', label: 'Connected' },
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@ import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
import type { CSSProperties, JSX } from 'react';
|
import type { CSSProperties, JSX } from 'react';
|
||||||
|
|
||||||
type ProviderBrand = {
|
interface ProviderBrand {
|
||||||
providerId: string;
|
providerId: string;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
interface SvgPath {
|
interface SvgPath {
|
||||||
d: string;
|
d: string;
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ import {
|
||||||
TEAM_ALIVE_LIST,
|
TEAM_ALIVE_LIST,
|
||||||
TEAM_CANCEL_PROVISIONING,
|
TEAM_CANCEL_PROVISIONING,
|
||||||
TEAM_CREATE,
|
TEAM_CREATE,
|
||||||
TEAM_CREATE_INITIAL_GIT_COMMIT,
|
|
||||||
TEAM_CREATE_CONFIG,
|
TEAM_CREATE_CONFIG,
|
||||||
|
TEAM_CREATE_INITIAL_GIT_COMMIT,
|
||||||
TEAM_CREATE_TASK,
|
TEAM_CREATE_TASK,
|
||||||
TEAM_DELETE_DRAFT,
|
TEAM_DELETE_DRAFT,
|
||||||
TEAM_DELETE_TASK_ATTACHMENT,
|
TEAM_DELETE_TASK_ATTACHMENT,
|
||||||
|
|
@ -209,8 +209,8 @@ import type {
|
||||||
TeamTask,
|
TeamTask,
|
||||||
TeamTaskStatus,
|
TeamTaskStatus,
|
||||||
TeamUpdateConfigRequest,
|
TeamUpdateConfigRequest,
|
||||||
TeamWorktreeGitStatus,
|
|
||||||
TeamViewSnapshot,
|
TeamViewSnapshot,
|
||||||
|
TeamWorktreeGitStatus,
|
||||||
ToolApprovalFileContent,
|
ToolApprovalFileContent,
|
||||||
ToolApprovalSettings,
|
ToolApprovalSettings,
|
||||||
UpdateKanbanPatch,
|
UpdateKanbanPatch,
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,10 @@ import { countTokens } from '@main/utils/tokenizer';
|
||||||
import { createLogger } from '@shared/utils/logger';
|
import { createLogger } from '@shared/utils/logger';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
import { buildSemanticStepGroups } from './SemanticStepGrouper';
|
|
||||||
import { resolveProjectStorageDir } from '../discovery/projectStorageDir';
|
import { resolveProjectStorageDir } from '../discovery/projectStorageDir';
|
||||||
|
|
||||||
|
import { buildSemanticStepGroups } from './SemanticStepGrouper';
|
||||||
|
|
||||||
import type { SubagentResolver } from '../discovery/SubagentResolver';
|
import type { SubagentResolver } from '../discovery/SubagentResolver';
|
||||||
import type { FileSystemProvider } from '../infrastructure/FileSystemProvider';
|
import type { FileSystemProvider } from '../infrastructure/FileSystemProvider';
|
||||||
import type { SessionParser } from '../parsing/SessionParser';
|
import type { SessionParser } from '../parsing/SessionParser';
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,9 @@ import * as path from 'path';
|
||||||
|
|
||||||
import { startMainSpan } from '../../sentry';
|
import { startMainSpan } from '../../sentry';
|
||||||
|
|
||||||
|
import { resolveProjectStorageDir } from './projectStorageDir';
|
||||||
import { SearchTextCache } from './SearchTextCache';
|
import { SearchTextCache } from './SearchTextCache';
|
||||||
import { extractSearchableEntries } from './SearchTextExtractor';
|
import { extractSearchableEntries } from './SearchTextExtractor';
|
||||||
import { resolveProjectStorageDir } from './projectStorageDir';
|
|
||||||
import { subprojectRegistry } from './SubprojectRegistry';
|
import { subprojectRegistry } from './SubprojectRegistry';
|
||||||
|
|
||||||
import type { SearchableEntry } from './SearchTextExtractor';
|
import type { SearchableEntry } from './SearchTextExtractor';
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
// @vitest-environment node
|
// @vitest-environment node
|
||||||
import { constants as fsConstants } from 'node:fs';
|
import { constants as fsConstants } from 'node:fs';
|
||||||
import type { PathLike } from 'node:fs';
|
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
|
|
||||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||||
|
|
||||||
|
import type { PathLike } from 'node:fs';
|
||||||
|
|
||||||
const accessMock = vi.fn<(filePath: PathLike, mode?: number) => Promise<void>>();
|
const accessMock = vi.fn<(filePath: PathLike, mode?: number) => Promise<void>>();
|
||||||
|
|
||||||
vi.mock('node:fs/promises', () => ({
|
vi.mock('node:fs/promises', () => ({
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { getTasksBasePath, getTeamsBasePath } from '@main/utils/pathDecoder';
|
|
||||||
import { appendOpenCodeTaskChangeDiag } from '@main/utils/openCodeTaskChangeDiagLog';
|
import { appendOpenCodeTaskChangeDiag } from '@main/utils/openCodeTaskChangeDiagLog';
|
||||||
|
import { getTasksBasePath, getTeamsBasePath } from '@main/utils/pathDecoder';
|
||||||
import { createLogger } from '@shared/utils/logger';
|
import { createLogger } from '@shared/utils/logger';
|
||||||
import { resolveTaskChangePresenceFromResult } from '@shared/utils/taskChangePresence';
|
import { resolveTaskChangePresenceFromResult } from '@shared/utils/taskChangePresence';
|
||||||
import {
|
import {
|
||||||
|
|
@ -9,19 +9,18 @@ import {
|
||||||
} from '@shared/utils/taskChangeState';
|
} from '@shared/utils/taskChangeState';
|
||||||
import { createHash } from 'crypto';
|
import { createHash } from 'crypto';
|
||||||
import { existsSync } from 'fs';
|
import { existsSync } from 'fs';
|
||||||
import { mkdtemp, readFile, readdir, rm, stat, writeFile } from 'fs/promises';
|
import { mkdtemp, readdir, readFile, rm, stat, writeFile } from 'fs/promises';
|
||||||
import * as os from 'os';
|
import * as os from 'os';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
import { JsonTaskChangeSummaryCacheRepository } from './cache/JsonTaskChangeSummaryCacheRepository';
|
import { JsonTaskChangeSummaryCacheRepository } from './cache/JsonTaskChangeSummaryCacheRepository';
|
||||||
import { TeamMetaStore } from './TeamMetaStore';
|
|
||||||
import { TaskChangeComputer } from './TaskChangeComputer';
|
|
||||||
import { TaskChangeLedgerReader } from './TaskChangeLedgerReader';
|
|
||||||
import {
|
import {
|
||||||
getOpenCodeLaneScopedRuntimeFilePath,
|
getOpenCodeLaneScopedRuntimeFilePath,
|
||||||
getOpenCodeTeamRuntimeDirectory,
|
getOpenCodeTeamRuntimeDirectory,
|
||||||
readOpenCodeRuntimeLaneIndex,
|
readOpenCodeRuntimeLaneIndex,
|
||||||
} from './opencode/store/OpenCodeRuntimeManifestEvidenceReader';
|
} from './opencode/store/OpenCodeRuntimeManifestEvidenceReader';
|
||||||
|
import { TaskChangeComputer } from './TaskChangeComputer';
|
||||||
|
import { TaskChangeLedgerReader } from './TaskChangeLedgerReader';
|
||||||
import {
|
import {
|
||||||
buildTaskChangePresenceDescriptor,
|
buildTaskChangePresenceDescriptor,
|
||||||
computeTaskChangePresenceProjectFingerprint,
|
computeTaskChangePresenceProjectFingerprint,
|
||||||
|
|
@ -34,14 +33,15 @@ import {
|
||||||
type TaskChangeTaskMeta,
|
type TaskChangeTaskMeta,
|
||||||
} from './taskChangeWorkerTypes';
|
} from './taskChangeWorkerTypes';
|
||||||
import { TeamConfigReader } from './TeamConfigReader';
|
import { TeamConfigReader } from './TeamConfigReader';
|
||||||
|
import { TeamMetaStore } from './TeamMetaStore';
|
||||||
|
|
||||||
import type { TaskChangePresenceRepository } from './cache/TaskChangePresenceRepository';
|
import type { TaskChangePresenceRepository } from './cache/TaskChangePresenceRepository';
|
||||||
|
import type { OpenCodeLedgerBackfillPort } from './opencode/bridge/OpenCodeReadinessBridge';
|
||||||
|
import type { OpenCodePromptDeliveryLedgerRecord } from './opencode/delivery/OpenCodePromptDeliveryLedger';
|
||||||
import type { TaskBoundaryParser } from './TaskBoundaryParser';
|
import type { TaskBoundaryParser } from './TaskBoundaryParser';
|
||||||
import type { TaskChangeWorkerClient } from './TaskChangeWorkerClient';
|
import type { TaskChangeWorkerClient } from './TaskChangeWorkerClient';
|
||||||
import type { TeamLogSourceTracker } from './TeamLogSourceTracker';
|
import type { TeamLogSourceTracker } from './TeamLogSourceTracker';
|
||||||
import type { TeamMemberLogsFinder } from './TeamMemberLogsFinder';
|
import type { TeamMemberLogsFinder } from './TeamMemberLogsFinder';
|
||||||
import type { OpenCodeLedgerBackfillPort } from './opencode/bridge/OpenCodeReadinessBridge';
|
|
||||||
import type { OpenCodePromptDeliveryLedgerRecord } from './opencode/delivery/OpenCodePromptDeliveryLedger';
|
|
||||||
import type { AgentChangeSet, ChangeStats, TaskChangeSetV2 } from '@shared/types';
|
import type { AgentChangeSet, ChangeStats, TaskChangeSetV2 } from '@shared/types';
|
||||||
|
|
||||||
const logger = createLogger('Service:ChangeExtractorService');
|
const logger = createLogger('Service:ChangeExtractorService');
|
||||||
|
|
@ -678,7 +678,7 @@ export class ChangeExtractorService {
|
||||||
teamName: string,
|
teamName: string,
|
||||||
taskId: string
|
taskId: string
|
||||||
): Promise<
|
): Promise<
|
||||||
Array<{
|
{
|
||||||
memberName: string;
|
memberName: string;
|
||||||
laneId?: string;
|
laneId?: string;
|
||||||
runtimeSessionId: string | null;
|
runtimeSessionId: string | null;
|
||||||
|
|
@ -687,8 +687,8 @@ export class ChangeExtractorService {
|
||||||
observedAssistantMessageId: string | null;
|
observedAssistantMessageId: string | null;
|
||||||
prePromptCursor: string | null;
|
prePromptCursor: string | null;
|
||||||
postPromptCursor: string | null;
|
postPromptCursor: string | null;
|
||||||
taskRefs: Array<{ taskId: string; displayId: string; teamName: string }>;
|
taskRefs: { taskId: string; displayId: string; teamName: string }[];
|
||||||
}>
|
}[]
|
||||||
> {
|
> {
|
||||||
const teamsBasePath = getTeamsBasePath();
|
const teamsBasePath = getTeamsBasePath();
|
||||||
const laneIds = new Set<string>(['primary']);
|
const laneIds = new Set<string>(['primary']);
|
||||||
|
|
@ -704,7 +704,7 @@ export class ChangeExtractorService {
|
||||||
laneIds.add(laneId);
|
laneIds.add(laneId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const records: Array<{
|
const records: {
|
||||||
memberName: string;
|
memberName: string;
|
||||||
laneId?: string;
|
laneId?: string;
|
||||||
runtimeSessionId: string | null;
|
runtimeSessionId: string | null;
|
||||||
|
|
@ -713,8 +713,8 @@ export class ChangeExtractorService {
|
||||||
observedAssistantMessageId: string | null;
|
observedAssistantMessageId: string | null;
|
||||||
prePromptCursor: string | null;
|
prePromptCursor: string | null;
|
||||||
postPromptCursor: string | null;
|
postPromptCursor: string | null;
|
||||||
taskRefs: Array<{ taskId: string; displayId: string; teamName: string }>;
|
taskRefs: { taskId: string; displayId: string; teamName: string }[];
|
||||||
}> = [];
|
}[] = [];
|
||||||
|
|
||||||
for (const laneId of laneIds) {
|
for (const laneId of laneIds) {
|
||||||
const filePath = getOpenCodeLaneScopedRuntimeFilePath({
|
const filePath = getOpenCodeLaneScopedRuntimeFilePath({
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { getAppDataPath, getClaudeBasePath } from '@main/utils/pathDecoder';
|
import { getAppDataPath, getClaudeBasePath } from '@main/utils/pathDecoder';
|
||||||
import { createHash } from 'crypto';
|
|
||||||
import { execFile } from 'child_process';
|
import { execFile } from 'child_process';
|
||||||
|
import { createHash } from 'crypto';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3959,10 +3959,10 @@ export class TeamProvisioningService {
|
||||||
Promise<OpenCodeMemberInboxRelayResult>
|
Promise<OpenCodeMemberInboxRelayResult>
|
||||||
>();
|
>();
|
||||||
private readonly openCodePromptDeliveryWatchdogTimers = new Map<string, NodeJS.Timeout>();
|
private readonly openCodePromptDeliveryWatchdogTimers = new Map<string, NodeJS.Timeout>();
|
||||||
private readonly openCodePromptDeliveryWatchdogQueue: Array<{
|
private readonly openCodePromptDeliveryWatchdogQueue: {
|
||||||
teamName: string;
|
teamName: string;
|
||||||
run: () => Promise<void>;
|
run: () => Promise<void>;
|
||||||
}> = [];
|
}[] = [];
|
||||||
private openCodePromptDeliveryWatchdogInFlight = 0;
|
private openCodePromptDeliveryWatchdogInFlight = 0;
|
||||||
private openCodePromptDeliveryWatchdogDisabledLogged = false;
|
private openCodePromptDeliveryWatchdogDisabledLogged = false;
|
||||||
private readonly openCodePromptDeliveryWatchdogInFlightByTeam = new Map<string, number>();
|
private readonly openCodePromptDeliveryWatchdogInFlightByTeam = new Map<string, number>();
|
||||||
|
|
@ -13625,7 +13625,7 @@ export class TeamProvisioningService {
|
||||||
(config) => config?.members?.find((member) => isLeadMember(member))?.name?.trim() || null
|
(config) => config?.members?.find((member) => isLeadMember(member))?.name?.trim() || null
|
||||||
)
|
)
|
||||||
.catch(() => null);
|
.catch(() => null);
|
||||||
if (leadName && inboxName.trim().toLowerCase() === leadName.toLowerCase()) {
|
if (inboxName.trim().toLowerCase() === leadName?.toLowerCase()) {
|
||||||
if (await this.isOpenCodeRuntimeRecipient(teamName, inboxName)) {
|
if (await this.isOpenCodeRuntimeRecipient(teamName, inboxName)) {
|
||||||
const diagnostic =
|
const diagnostic =
|
||||||
'opencode_lead_runtime_session_missing: OpenCode lead inbox relay is unsupported in v1; leaving inbox unread for durable retry/diagnostics.';
|
'opencode_lead_runtime_session_missing: OpenCode lead inbox relay is unsupported in v1; leaving inbox unread for durable retry/diagnostics.';
|
||||||
|
|
@ -18154,7 +18154,7 @@ export class TeamProvisioningService {
|
||||||
? this.runs.get(this.getTrackedRunId(teamName)!)?.child?.pid
|
? this.runs.get(this.getTrackedRunId(teamName)!)?.child?.pid
|
||||||
: undefined;
|
: undefined;
|
||||||
const pids = new Set<number>();
|
const pids = new Set<number>();
|
||||||
const rows: Array<{ pid: number; command: string }> = [];
|
const rows: { pid: number; command: string }[] = [];
|
||||||
|
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ export interface OpenCodeCleanupHostsCommandBody {
|
||||||
export interface OpenCodeCleanupHostsCommandData {
|
export interface OpenCodeCleanupHostsCommandData {
|
||||||
cleaned: number;
|
cleaned: number;
|
||||||
remaining: number;
|
remaining: number;
|
||||||
hosts: Array<{
|
hosts: {
|
||||||
hostKey: string;
|
hostKey: string;
|
||||||
projectPath: string;
|
projectPath: string;
|
||||||
pid: number;
|
pid: number;
|
||||||
|
|
@ -146,7 +146,7 @@ export interface OpenCodeCleanupHostsCommandData {
|
||||||
| 'failed';
|
| 'failed';
|
||||||
reason: string;
|
reason: string;
|
||||||
leaseCount: number;
|
leaseCount: number;
|
||||||
}>;
|
}[];
|
||||||
diagnostics: string[];
|
diagnostics: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -270,7 +270,7 @@ export interface OpenCodeBackfillTaskLedgerCommandData {
|
||||||
importedEvents: number;
|
importedEvents: number;
|
||||||
skippedEvents: number;
|
skippedEvents: number;
|
||||||
outcome: OpenCodeBackfillTaskLedgerOutcome;
|
outcome: OpenCodeBackfillTaskLedgerOutcome;
|
||||||
notices: Array<{ severity: 'warning'; message: string; code: string }>;
|
notices: { severity: 'warning'; message: string; code: string }[];
|
||||||
diagnostics: string[];
|
diagnostics: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,13 @@ import type {
|
||||||
OpenCodeTeamLaunchReadinessState,
|
OpenCodeTeamLaunchReadinessState,
|
||||||
} from '../readiness/OpenCodeTeamLaunchReadiness';
|
} from '../readiness/OpenCodeTeamLaunchReadiness';
|
||||||
import type {
|
import type {
|
||||||
|
OpenCodeBackfillTaskLedgerCommandBody,
|
||||||
|
OpenCodeBackfillTaskLedgerCommandData,
|
||||||
OpenCodeBridgeCommandName,
|
OpenCodeBridgeCommandName,
|
||||||
OpenCodeBridgeDiagnosticEvent,
|
OpenCodeBridgeDiagnosticEvent,
|
||||||
OpenCodeBridgeFailureKind,
|
OpenCodeBridgeFailureKind,
|
||||||
OpenCodeBridgeResult,
|
OpenCodeBridgeResult,
|
||||||
OpenCodeBridgeRuntimeSnapshot,
|
OpenCodeBridgeRuntimeSnapshot,
|
||||||
OpenCodeBackfillTaskLedgerCommandBody,
|
|
||||||
OpenCodeBackfillTaskLedgerCommandData,
|
|
||||||
OpenCodeCleanupHostsCommandBody,
|
OpenCodeCleanupHostsCommandBody,
|
||||||
OpenCodeCleanupHostsCommandData,
|
OpenCodeCleanupHostsCommandData,
|
||||||
OpenCodeLaunchTeamCommandBody,
|
OpenCodeLaunchTeamCommandBody,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import { stableHash } from '../bridge/OpenCodeBridgeCommandContract';
|
import { stableHash } from '../bridge/OpenCodeBridgeCommandContract';
|
||||||
import { VersionedJsonStore, VersionedJsonStoreError } from '../store/VersionedJsonStore';
|
import { VersionedJsonStore, VersionedJsonStoreError } from '../store/VersionedJsonStore';
|
||||||
|
|
||||||
import type { AgentActionMode, TaskRef } from '@shared/types/team';
|
|
||||||
import type {
|
import type {
|
||||||
OpenCodeDeliveryResponseObservation,
|
OpenCodeDeliveryResponseObservation,
|
||||||
OpenCodeDeliveryResponseState,
|
OpenCodeDeliveryResponseState,
|
||||||
OpenCodeDeliveryVisibleReplyCorrelation,
|
OpenCodeDeliveryVisibleReplyCorrelation,
|
||||||
} from '../bridge/OpenCodeBridgeCommandContract';
|
} from '../bridge/OpenCodeBridgeCommandContract';
|
||||||
|
import type { AgentActionMode, TaskRef } from '@shared/types/team';
|
||||||
|
|
||||||
export const OPENCODE_PROMPT_DELIVERY_LEDGER_SCHEMA_VERSION = 1;
|
export const OPENCODE_PROMPT_DELIVERY_LEDGER_SCHEMA_VERSION = 1;
|
||||||
export const OPENCODE_PROMPT_DELIVERY_RESPONDED_RETENTION_MS = 7 * 24 * 60 * 60 * 1000;
|
export const OPENCODE_PROMPT_DELIVERY_RESPONDED_RETENTION_MS = 7 * 24 * 60 * 60 * 1000;
|
||||||
|
|
@ -603,7 +603,7 @@ export function hashOpenCodePromptDeliveryPayload(input: {
|
||||||
replyRecipient: string;
|
replyRecipient: string;
|
||||||
actionMode?: AgentActionMode | null;
|
actionMode?: AgentActionMode | null;
|
||||||
taskRefs?: TaskRef[];
|
taskRefs?: TaskRef[];
|
||||||
attachments?: Array<{ id?: string; filename?: string; mimeType?: string; size?: number }>;
|
attachments?: { id?: string; filename?: string; mimeType?: string; size?: number }[];
|
||||||
source?: string;
|
source?: string;
|
||||||
}): string {
|
}): string {
|
||||||
return `sha256:${stableHash({
|
return `sha256:${stableHash({
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import type { AgentActionMode, InboxMessage, TaskRef } from '@shared/types/team';
|
|
||||||
import type { OpenCodeDeliveryResponseState } from '../bridge/OpenCodeBridgeCommandContract';
|
import type { OpenCodeDeliveryResponseState } from '../bridge/OpenCodeBridgeCommandContract';
|
||||||
import type { OpenCodePromptDeliveryStatus } from './OpenCodePromptDeliveryLedger';
|
import type { OpenCodePromptDeliveryStatus } from './OpenCodePromptDeliveryLedger';
|
||||||
|
import type { AgentActionMode, InboxMessage, TaskRef } from '@shared/types/team';
|
||||||
|
|
||||||
export const OPENCODE_PROMPT_DELIVERY_OBSERVE_DELAY_MS = 3_000;
|
export const OPENCODE_PROMPT_DELIVERY_OBSERVE_DELAY_MS = 3_000;
|
||||||
export const OPENCODE_PROMPT_DELIVERY_RETRY_DELAY_MS = 15_000;
|
export const OPENCODE_PROMPT_DELIVERY_RETRY_DELAY_MS = 15_000;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
import { ClaudeMultimodelBridgeService } from '../../runtime/ClaudeMultimodelBridgeService';
|
||||||
import { canonicalizeAgentTeamsToolName } from '../agentTeamsToolNames';
|
import { canonicalizeAgentTeamsToolName } from '../agentTeamsToolNames';
|
||||||
import { ClaudeBinaryResolver } from '../ClaudeBinaryResolver';
|
import { ClaudeBinaryResolver } from '../ClaudeBinaryResolver';
|
||||||
import { ClaudeMultimodelBridgeService } from '../../runtime/ClaudeMultimodelBridgeService';
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
OpenCodeRuntimeTranscriptLogMessage,
|
OpenCodeRuntimeTranscriptLogMessage,
|
||||||
|
|
|
||||||
|
|
@ -15,28 +15,185 @@ export interface TaskProgressTouchClassification {
|
||||||
reason: string;
|
reason: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const CONCRETE_FILE_OR_PATH_RE =
|
const FILE_EXTENSIONS = [
|
||||||
/(?:^|\s)(?:\.{1,2}\/|~\/|\/|\w[\w.-]*\/)[\w./\s-]+|\b[\w.-]+\.(?:[cm]?[tj]sx?|json|md|css|scss|py|go|rs|java|kt|swift|ya?ml|toml|lock|sh|sql)\b/i;
|
'.ts',
|
||||||
const TASK_OR_ISSUE_REF_RE = /#[a-f0-9]{6,}|\btask-[\w-]+/i;
|
'.tsx',
|
||||||
const TEST_OR_BUILD_RESULT_RE =
|
'.js',
|
||||||
/\b(?:test(?:s|ed|ing)?|vitest|jest|playwright|pnpm|npm|bun|build|typecheck|lint|passed|failed|green|red|error|exception|stack trace)\b|тест|сборк|линт|ошибк|упал|прош[её]л/i;
|
'.jsx',
|
||||||
const SUBSTANTIVE_WORK_RE =
|
'.cts',
|
||||||
/\b(?:implemented|fixed|added|updated|changed|removed|found|verified|confirmed|completed|created|refactored|patched|root cause|next step)\b|исправ|добав|обнов|измен|удал|наш[её]л|подтверд|готово|сделал|сделана|причин|следующ/i;
|
'.mts',
|
||||||
const BLOCKER_OR_CLARIFICATION_RE =
|
'.ctsx',
|
||||||
/\?|(?:^|\b)(?:blocked|blocker|cannot|can't|need|needs|waiting|clarification|question|permission|access denied|not enough context)\b|не могу|не получается|нужн|жду|блок|уточн|вопрос|нет доступа|недостаточно контекст/i;
|
'.mtsx',
|
||||||
const WEAK_START_ONLY_RE =
|
'.json',
|
||||||
/^(?:я\s+)?(?:начинаю(?:\s+работу)?|начну|приступаю(?:\s+к\s+работе)?|беру\s+в\s+работу|проверю|сейчас\s+проверю|посмотрю|разберусь|готов(?:а)?\s+приступить|готов(?:а)?\s+к\s+работе|will\s+start|starting\s+work|starting|taking\s+this|i(?:'|’)?ll\s+start|i\s+will\s+start|i\s+am\s+starting|i(?:'|’)?ll\s+check|i\s+will\s+check|checking\s+now|on\s+it)(?:[.!…\s]*)$/i;
|
'.md',
|
||||||
|
'.css',
|
||||||
|
'.scss',
|
||||||
|
'.py',
|
||||||
|
'.go',
|
||||||
|
'.rs',
|
||||||
|
'.java',
|
||||||
|
'.kt',
|
||||||
|
'.swift',
|
||||||
|
'.yaml',
|
||||||
|
'.yml',
|
||||||
|
'.toml',
|
||||||
|
'.lock',
|
||||||
|
'.sh',
|
||||||
|
'.sql',
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const TEST_OR_BUILD_KEYWORDS = [
|
||||||
|
'test',
|
||||||
|
'tests',
|
||||||
|
'tested',
|
||||||
|
'testing',
|
||||||
|
'vitest',
|
||||||
|
'jest',
|
||||||
|
'playwright',
|
||||||
|
'pnpm',
|
||||||
|
'npm',
|
||||||
|
'bun',
|
||||||
|
'build',
|
||||||
|
'typecheck',
|
||||||
|
'lint',
|
||||||
|
'passed',
|
||||||
|
'failed',
|
||||||
|
'green',
|
||||||
|
'red',
|
||||||
|
'error',
|
||||||
|
'exception',
|
||||||
|
'stack trace',
|
||||||
|
'тест',
|
||||||
|
'сборк',
|
||||||
|
'линт',
|
||||||
|
'ошибк',
|
||||||
|
'упал',
|
||||||
|
'прошел',
|
||||||
|
'прошёл',
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const SUBSTANTIVE_WORK_KEYWORDS = [
|
||||||
|
'implemented',
|
||||||
|
'fixed',
|
||||||
|
'added',
|
||||||
|
'updated',
|
||||||
|
'changed',
|
||||||
|
'removed',
|
||||||
|
'found',
|
||||||
|
'verified',
|
||||||
|
'confirmed',
|
||||||
|
'completed',
|
||||||
|
'created',
|
||||||
|
'refactored',
|
||||||
|
'patched',
|
||||||
|
'root cause',
|
||||||
|
'next step',
|
||||||
|
'исправ',
|
||||||
|
'добав',
|
||||||
|
'обнов',
|
||||||
|
'измен',
|
||||||
|
'удал',
|
||||||
|
'нашел',
|
||||||
|
'нашёл',
|
||||||
|
'подтверд',
|
||||||
|
'готово',
|
||||||
|
'сделал',
|
||||||
|
'сделана',
|
||||||
|
'причин',
|
||||||
|
'следующ',
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const BLOCKER_OR_CLARIFICATION_KEYWORDS = [
|
||||||
|
'blocked',
|
||||||
|
'blocker',
|
||||||
|
'cannot',
|
||||||
|
"can't",
|
||||||
|
'need',
|
||||||
|
'needs',
|
||||||
|
'waiting',
|
||||||
|
'clarification',
|
||||||
|
'question',
|
||||||
|
'permission',
|
||||||
|
'access denied',
|
||||||
|
'not enough context',
|
||||||
|
'не могу',
|
||||||
|
'не получается',
|
||||||
|
'нужн',
|
||||||
|
'жду',
|
||||||
|
'блок',
|
||||||
|
'уточн',
|
||||||
|
'вопрос',
|
||||||
|
'нет доступа',
|
||||||
|
'недостаточно контекст',
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
const WEAK_START_ONLY_PHRASES = [
|
||||||
|
'начинаю',
|
||||||
|
'начинаю работу',
|
||||||
|
'начну',
|
||||||
|
'приступаю',
|
||||||
|
'приступаю к работе',
|
||||||
|
'беру в работу',
|
||||||
|
'проверю',
|
||||||
|
'сейчас проверю',
|
||||||
|
'посмотрю',
|
||||||
|
'разберусь',
|
||||||
|
'готов приступить',
|
||||||
|
'готова приступить',
|
||||||
|
'готов к работе',
|
||||||
|
'готова к работе',
|
||||||
|
'will start',
|
||||||
|
'starting work',
|
||||||
|
'starting',
|
||||||
|
'taking this',
|
||||||
|
"i'll start",
|
||||||
|
'i’ll start',
|
||||||
|
'i will start',
|
||||||
|
'i am starting',
|
||||||
|
"i'll check",
|
||||||
|
'i’ll check',
|
||||||
|
'i will check',
|
||||||
|
'checking now',
|
||||||
|
'on it',
|
||||||
|
] as const;
|
||||||
|
|
||||||
function normalizeCommentText(text: string): string {
|
function normalizeCommentText(text: string): string {
|
||||||
return stripAgentBlocks(text).replace(/\s+/g, ' ').trim();
|
return stripAgentBlocks(text).replace(/\s+/g, ' ').trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function includesAnyKeyword(text: string, keywords: readonly string[]): boolean {
|
||||||
|
return keywords.some((keyword) => text.includes(keyword));
|
||||||
|
}
|
||||||
|
|
||||||
|
function containsTaskOrIssueRef(text: string): boolean {
|
||||||
|
return text.includes('task-') || /#[a-f0-9]{6,}/i.test(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
function containsConcreteFileOrPath(text: string): boolean {
|
||||||
|
const parts = text.split(/\s+/);
|
||||||
|
return (
|
||||||
|
parts.some(
|
||||||
|
(part) => part.startsWith('./') || part.startsWith('../') || part.startsWith('~/')
|
||||||
|
) ||
|
||||||
|
parts.some((part) => part.includes('/') && /[a-z0-9_]/i.test(part)) ||
|
||||||
|
FILE_EXTENSIONS.some((extension) => text.includes(extension))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isWeakStartOnly(text: string): boolean {
|
||||||
|
const normalized = text
|
||||||
|
.replace(/[.!…\s]+$/g, '')
|
||||||
|
.replace(/^я\s+/, '')
|
||||||
|
.trim();
|
||||||
|
return WEAK_START_ONLY_PHRASES.includes(normalized as (typeof WEAK_START_ONLY_PHRASES)[number]);
|
||||||
|
}
|
||||||
|
|
||||||
function isConcreteProgress(text: string): boolean {
|
function isConcreteProgress(text: string): boolean {
|
||||||
return (
|
return (
|
||||||
CONCRETE_FILE_OR_PATH_RE.test(text) ||
|
containsConcreteFileOrPath(text) ||
|
||||||
TASK_OR_ISSUE_REF_RE.test(text) ||
|
containsTaskOrIssueRef(text) ||
|
||||||
TEST_OR_BUILD_RESULT_RE.test(text) ||
|
includesAnyKeyword(text, TEST_OR_BUILD_KEYWORDS) ||
|
||||||
SUBSTANTIVE_WORK_RE.test(text)
|
includesAnyKeyword(text, SUBSTANTIVE_WORK_KEYWORDS)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -46,18 +203,20 @@ function classifyTaskCommentText(text: string): TaskProgressTouchClassification
|
||||||
return { signal: 'unknown', reason: 'comment_text_empty' };
|
return { signal: 'unknown', reason: 'comment_text_empty' };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BLOCKER_OR_CLARIFICATION_RE.test(normalized)) {
|
const lowerText = normalized.toLowerCase();
|
||||||
|
|
||||||
|
if (lowerText.includes('?') || includesAnyKeyword(lowerText, BLOCKER_OR_CLARIFICATION_KEYWORDS)) {
|
||||||
return {
|
return {
|
||||||
signal: 'blocker_or_clarification',
|
signal: 'blocker_or_clarification',
|
||||||
reason: 'comment_mentions_blocker_or_clarification',
|
reason: 'comment_mentions_blocker_or_clarification',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isConcreteProgress(normalized)) {
|
if (isConcreteProgress(lowerText)) {
|
||||||
return { signal: 'strong_progress', reason: 'comment_contains_concrete_progress' };
|
return { signal: 'strong_progress', reason: 'comment_contains_concrete_progress' };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalized.length <= 120 && WEAK_START_ONLY_RE.test(normalized)) {
|
if (lowerText.length <= 120 && isWeakStartOnly(lowerText)) {
|
||||||
return { signal: 'weak_start_only', reason: 'comment_is_start_only' };
|
return { signal: 'weak_start_only', reason: 'comment_is_start_only' };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { formatTaskDisplayLabel } from '@shared/utils/taskIdentity';
|
|
||||||
import { createLogger } from '@shared/utils/logger';
|
import { createLogger } from '@shared/utils/logger';
|
||||||
|
import { formatTaskDisplayLabel } from '@shared/utils/taskIdentity';
|
||||||
|
|
||||||
import { TeamInboxReader } from '../TeamInboxReader';
|
import { TeamInboxReader } from '../TeamInboxReader';
|
||||||
import { TeamInboxWriter } from '../TeamInboxWriter';
|
import { TeamInboxWriter } from '../TeamInboxWriter';
|
||||||
|
|
||||||
import type { TeamDataService } from '../TeamDataService';
|
import type { TeamDataService } from '../TeamDataService';
|
||||||
import type { TeamProvisioningService } from '../TeamProvisioningService';
|
import type { TeamProvisioningService } from '../TeamProvisioningService';
|
||||||
import type { TaskStallAlert } from './TeamTaskStallTypes';
|
import type { TaskStallAlert } from './TeamTaskStallTypes';
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import type { BoardTaskActivityRecord } from '../taskLogs/activity/BoardTaskActivityRecord';
|
import { getOpenCodeWeakStartStallThresholdMs } from './featureGates';
|
||||||
import { classifyTaskProgressTouch, type TaskProgressSignal } from './TaskProgressSignalClassifier';
|
import { classifyTaskProgressTouch, type TaskProgressSignal } from './TaskProgressSignalClassifier';
|
||||||
|
|
||||||
|
import type { BoardTaskActivityRecord } from '../taskLogs/activity/BoardTaskActivityRecord';
|
||||||
import type {
|
import type {
|
||||||
ReviewTaskContext,
|
ReviewTaskContext,
|
||||||
TaskStallBranch,
|
TaskStallBranch,
|
||||||
|
|
@ -9,7 +11,6 @@ import type {
|
||||||
TeamTaskStallSnapshot,
|
TeamTaskStallSnapshot,
|
||||||
WorkTaskContext,
|
WorkTaskContext,
|
||||||
} from './TeamTaskStallTypes';
|
} from './TeamTaskStallTypes';
|
||||||
import { getOpenCodeWeakStartStallThresholdMs } from './featureGates';
|
|
||||||
import type { TaskHistoryEvent, TaskWorkInterval, TeamTask } from '@shared/types';
|
import type { TaskHistoryEvent, TaskWorkInterval, TeamTask } from '@shared/types';
|
||||||
|
|
||||||
const WORK_TOUCH_TOOLS = new Set(['task_start', 'task_add_comment', 'task_set_status']);
|
const WORK_TOUCH_TOOLS = new Set(['task_start', 'task_add_comment', 'task_set_status']);
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,21 @@
|
||||||
|
import {
|
||||||
|
inferTeamProviderIdFromModel,
|
||||||
|
normalizeOptionalTeamProviderId,
|
||||||
|
} from '@shared/utils/teamProvider';
|
||||||
|
|
||||||
import { BoardTaskActivityTranscriptReader } from '../taskLogs/activity/BoardTaskActivityTranscriptReader';
|
import { BoardTaskActivityTranscriptReader } from '../taskLogs/activity/BoardTaskActivityTranscriptReader';
|
||||||
import { isBoardTaskActivityReadEnabled } from '../taskLogs/activity/featureGates';
|
import { isBoardTaskActivityReadEnabled } from '../taskLogs/activity/featureGates';
|
||||||
import { TeamTranscriptSourceLocator } from '../taskLogs/discovery/TeamTranscriptSourceLocator';
|
import { TeamTranscriptSourceLocator } from '../taskLogs/discovery/TeamTranscriptSourceLocator';
|
||||||
import { isBoardTaskExactLogsReadEnabled } from '../taskLogs/exact/featureGates';
|
import { isBoardTaskExactLogsReadEnabled } from '../taskLogs/exact/featureGates';
|
||||||
import { TeamKanbanManager } from '../TeamKanbanManager';
|
import { TeamKanbanManager } from '../TeamKanbanManager';
|
||||||
import { TeamTaskReader } from '../TeamTaskReader';
|
|
||||||
import { TeamMembersMetaStore } from '../TeamMembersMetaStore';
|
import { TeamMembersMetaStore } from '../TeamMembersMetaStore';
|
||||||
|
import { TeamTaskReader } from '../TeamTaskReader';
|
||||||
|
|
||||||
import { BoardTaskActivityBatchIndexer } from './BoardTaskActivityBatchIndexer';
|
import { BoardTaskActivityBatchIndexer } from './BoardTaskActivityBatchIndexer';
|
||||||
import { OpenCodeTaskStallEvidenceSource } from './OpenCodeTaskStallEvidenceSource';
|
import { OpenCodeTaskStallEvidenceSource } from './OpenCodeTaskStallEvidenceSource';
|
||||||
import { buildResolvedReviewerIndex } from './reviewerResolution';
|
import { buildResolvedReviewerIndex } from './reviewerResolution';
|
||||||
import { TeamTaskLogFreshnessReader } from './TeamTaskLogFreshnessReader';
|
import { TeamTaskLogFreshnessReader } from './TeamTaskLogFreshnessReader';
|
||||||
import { TeamTaskStallExactRowReader } from './TeamTaskStallExactRowReader';
|
import { TeamTaskStallExactRowReader } from './TeamTaskStallExactRowReader';
|
||||||
import {
|
|
||||||
inferTeamProviderIdFromModel,
|
|
||||||
normalizeOptionalTeamProviderId,
|
|
||||||
} from '@shared/utils/teamProvider';
|
|
||||||
|
|
||||||
import type { BoardTaskActivityRecord } from '../taskLogs/activity/BoardTaskActivityRecord';
|
import type { BoardTaskActivityRecord } from '../taskLogs/activity/BoardTaskActivityRecord';
|
||||||
import type { TeamTaskStallExactRow, TeamTaskStallSnapshot } from './TeamTaskStallTypes';
|
import type { TeamTaskStallExactRow, TeamTaskStallSnapshot } from './TeamTaskStallTypes';
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ async function mapLimit<T, R>(
|
||||||
if (currentIndex >= items.length) {
|
if (currentIndex >= items.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
results[currentIndex] = await fn(items[currentIndex]!);
|
results[currentIndex] = await fn(items[currentIndex]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await Promise.all(workers);
|
await Promise.all(workers);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
|
import { createLogger } from '@shared/utils/logger';
|
||||||
import * as fs from 'fs/promises';
|
import * as fs from 'fs/promises';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
import { createLogger } from '@shared/utils/logger';
|
|
||||||
|
|
||||||
import { TeamTranscriptProjectResolver } from '../../TeamTranscriptProjectResolver';
|
import { TeamTranscriptProjectResolver } from '../../TeamTranscriptProjectResolver';
|
||||||
|
|
||||||
import type { TeamConfig } from '@shared/types';
|
import type { TeamConfig } from '@shared/types';
|
||||||
|
|
@ -35,7 +34,7 @@ async function mapLimit<T, R>(
|
||||||
if (currentIndex >= items.length) {
|
if (currentIndex >= items.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
results[currentIndex] = await fn(items[currentIndex]!);
|
results[currentIndex] = await fn(items[currentIndex]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await Promise.all(workers);
|
await Promise.all(workers);
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ async function mapLimit<T, R>(
|
||||||
if (currentIndex >= items.length) {
|
if (currentIndex >= items.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
results[currentIndex] = await fn(items[currentIndex]!);
|
results[currentIndex] = await fn(items[currentIndex]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await Promise.all(workers);
|
await Promise.all(workers);
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ async function mapLimit<T, R>(
|
||||||
if (currentIndex >= items.length) {
|
if (currentIndex >= items.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
results[currentIndex] = await fn(items[currentIndex]!);
|
results[currentIndex] = await fn(items[currentIndex]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await Promise.all(workers);
|
await Promise.all(workers);
|
||||||
|
|
|
||||||
|
|
@ -1487,7 +1487,7 @@ function mergeSegments(
|
||||||
|
|
||||||
function chooseDefaultFilter(participants: BoardTaskLogParticipant[]): 'all' | string {
|
function chooseDefaultFilter(participants: BoardTaskLogParticipant[]): 'all' | string {
|
||||||
const namedParticipants = participants.filter((participant) => !participant.isLead);
|
const namedParticipants = participants.filter((participant) => !participant.isLead);
|
||||||
return namedParticipants.length === 1 ? namedParticipants[0]!.key : 'all';
|
return namedParticipants.length === 1 ? namedParticipants[0].key : 'all';
|
||||||
}
|
}
|
||||||
|
|
||||||
function mergeRuntimeFallbackResponse(
|
function mergeRuntimeFallbackResponse(
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { createLogger } from '@shared/utils/logger';
|
|
||||||
import { sanitizeDisplayContent } from '@shared/utils/contentSanitizer';
|
import { sanitizeDisplayContent } from '@shared/utils/contentSanitizer';
|
||||||
|
import { createLogger } from '@shared/utils/logger';
|
||||||
|
|
||||||
import { ClaudeMultimodelBridgeService } from '../../../runtime/ClaudeMultimodelBridgeService';
|
import { ClaudeMultimodelBridgeService } from '../../../runtime/ClaudeMultimodelBridgeService';
|
||||||
import { canonicalizeAgentTeamsToolName } from '../../agentTeamsToolNames';
|
import { canonicalizeAgentTeamsToolName } from '../../agentTeamsToolNames';
|
||||||
|
|
|
||||||
|
|
@ -118,8 +118,8 @@ import {
|
||||||
TEAM_CANCEL_PROVISIONING,
|
TEAM_CANCEL_PROVISIONING,
|
||||||
TEAM_CHANGE,
|
TEAM_CHANGE,
|
||||||
TEAM_CREATE,
|
TEAM_CREATE,
|
||||||
TEAM_CREATE_INITIAL_GIT_COMMIT,
|
|
||||||
TEAM_CREATE_CONFIG,
|
TEAM_CREATE_CONFIG,
|
||||||
|
TEAM_CREATE_INITIAL_GIT_COMMIT,
|
||||||
TEAM_CREATE_TASK,
|
TEAM_CREATE_TASK,
|
||||||
TEAM_DELETE_DRAFT,
|
TEAM_DELETE_DRAFT,
|
||||||
TEAM_DELETE_TASK_ATTACHMENT,
|
TEAM_DELETE_TASK_ATTACHMENT,
|
||||||
|
|
|
||||||
|
|
@ -67,12 +67,12 @@ import type {
|
||||||
TeamProvisioningModelVerificationMode,
|
TeamProvisioningModelVerificationMode,
|
||||||
TeamProvisioningPrepareResult,
|
TeamProvisioningPrepareResult,
|
||||||
TeamProvisioningProgress,
|
TeamProvisioningProgress,
|
||||||
TeamWorktreeGitStatus,
|
|
||||||
TeamsAPI,
|
TeamsAPI,
|
||||||
TeamSummary,
|
TeamSummary,
|
||||||
TeamTask,
|
TeamTask,
|
||||||
TeamTaskStatus,
|
TeamTaskStatus,
|
||||||
TeamViewSnapshot,
|
TeamViewSnapshot,
|
||||||
|
TeamWorktreeGitStatus,
|
||||||
TmuxAPI,
|
TmuxAPI,
|
||||||
TmuxStatus,
|
TmuxStatus,
|
||||||
TriggerTestResult,
|
TriggerTestResult,
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ import { buildReplyBlock } from '@renderer/utils/agentMessageFormatting';
|
||||||
import { removeChipTokenFromText } from '@renderer/utils/chipUtils';
|
import { removeChipTokenFromText } from '@renderer/utils/chipUtils';
|
||||||
import { formatAgentRole } from '@renderer/utils/formatAgentRole';
|
import { formatAgentRole } from '@renderer/utils/formatAgentRole';
|
||||||
import { buildMemberColorMap } from '@renderer/utils/memberHelpers';
|
import { buildMemberColorMap } from '@renderer/utils/memberHelpers';
|
||||||
import type { OpenCodeRuntimeDeliveryDebugDetails } from '@renderer/utils/openCodeRuntimeDeliveryDiagnostics';
|
|
||||||
import {
|
import {
|
||||||
extractTaskRefsFromText,
|
extractTaskRefsFromText,
|
||||||
stripEncodedTaskReferenceMetadata,
|
stripEncodedTaskReferenceMetadata,
|
||||||
|
|
@ -41,6 +40,7 @@ import { MemberBadge } from '../MemberBadge';
|
||||||
import type { ActionMode } from '@renderer/components/team/messages/ActionModeSelector';
|
import type { ActionMode } from '@renderer/components/team/messages/ActionModeSelector';
|
||||||
import type { InlineChip } from '@renderer/types/inlineChip';
|
import type { InlineChip } from '@renderer/types/inlineChip';
|
||||||
import type { MentionSuggestion } from '@renderer/types/mention';
|
import type { MentionSuggestion } from '@renderer/types/mention';
|
||||||
|
import type { OpenCodeRuntimeDeliveryDebugDetails } from '@renderer/utils/openCodeRuntimeDeliveryDiagnostics';
|
||||||
import type {
|
import type {
|
||||||
AttachmentPayload,
|
AttachmentPayload,
|
||||||
ResolvedTeamMember,
|
ResolvedTeamMember,
|
||||||
|
|
|
||||||
|
|
@ -147,13 +147,13 @@ export function getWorktreeGitControlDisabledReason(
|
||||||
return state.status.canUseWorktrees ? null : (state.status.message ?? null);
|
return state.status.canUseWorktrees ? null : (state.status.message ?? null);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function WorktreeGitReadinessBanner({
|
export const WorktreeGitReadinessBanner = ({
|
||||||
state,
|
state,
|
||||||
showReady = false,
|
showReady = false,
|
||||||
}: {
|
}: {
|
||||||
state: WorktreeGitReadinessState;
|
state: WorktreeGitReadinessState;
|
||||||
showReady?: boolean;
|
showReady?: boolean;
|
||||||
}): React.JSX.Element | null {
|
}): React.JSX.Element | null => {
|
||||||
const { status, loading, actionLoading, error, initializeRepository, createInitialCommit } =
|
const { status, loading, actionLoading, error, initializeRepository, createInitialCommit } =
|
||||||
state;
|
state;
|
||||||
|
|
||||||
|
|
@ -240,4 +240,4 @@ export function WorktreeGitReadinessBanner({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { formatTaskDisplayLabel } from '@shared/utils/taskIdentity';
|
|
||||||
import { SyncedLoader2 } from '@renderer/components/ui/SyncedLoader2';
|
import { SyncedLoader2 } from '@renderer/components/ui/SyncedLoader2';
|
||||||
|
import { formatTaskDisplayLabel } from '@shared/utils/taskIdentity';
|
||||||
|
|
||||||
import type { TeamTaskWithKanban } from '@shared/types';
|
import type { TeamTaskWithKanban } from '@shared/types';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import { useMemo, useState } from 'react';
|
import { useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { Badge } from '@renderer/components/ui/badge';
|
import { Badge } from '@renderer/components/ui/badge';
|
||||||
|
import { SyncedLoader2 } from '@renderer/components/ui/SyncedLoader2';
|
||||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip';
|
import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip';
|
||||||
import { getTeamColorSet } from '@renderer/constants/teamColors';
|
import { getTeamColorSet } from '@renderer/constants/teamColors';
|
||||||
import { useTheme } from '@renderer/hooks/useTheme';
|
import { useTheme } from '@renderer/hooks/useTheme';
|
||||||
import { useStore } from '@renderer/store';
|
import { useStore } from '@renderer/store';
|
||||||
import { selectResolvedMembersForTeamName } from '@renderer/store/slices/teamSlice';
|
import { selectResolvedMembersForTeamName } from '@renderer/store/slices/teamSlice';
|
||||||
import { SyncedLoader2 } from '@renderer/components/ui/SyncedLoader2';
|
|
||||||
import { formatAgentRole } from '@renderer/utils/formatAgentRole';
|
import { formatAgentRole } from '@renderer/utils/formatAgentRole';
|
||||||
import {
|
import {
|
||||||
agentAvatarUrl,
|
agentAvatarUrl,
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ import {
|
||||||
import { isLeadMember } from '@shared/utils/leadDetection';
|
import { isLeadMember } from '@shared/utils/leadDetection';
|
||||||
import { Pencil } from 'lucide-react';
|
import { Pencil } from 'lucide-react';
|
||||||
|
|
||||||
import { MemberRoleEditor } from './MemberRoleEditor';
|
|
||||||
import { MemberPresenceDot } from './MemberPresenceDot';
|
import { MemberPresenceDot } from './MemberPresenceDot';
|
||||||
|
import { MemberRoleEditor } from './MemberRoleEditor';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
LeadActivityState,
|
LeadActivityState,
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,10 @@ interface MemberPresenceDotProps {
|
||||||
label: string;
|
label: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MemberPresenceDot({ className, label }: MemberPresenceDotProps): React.JSX.Element {
|
export const MemberPresenceDot = ({
|
||||||
|
className,
|
||||||
|
label,
|
||||||
|
}: MemberPresenceDotProps): React.JSX.Element => {
|
||||||
const shouldSyncPulse = className?.includes('animate-pulse') === true;
|
const shouldSyncPulse = className?.includes('animate-pulse') === true;
|
||||||
const syncedPulseStyle = useSyncedAnimationStyle(shouldSyncPulse, PULSE_DURATION_MS);
|
const syncedPulseStyle = useSyncedAnimationStyle(shouldSyncPulse, PULSE_DURATION_MS);
|
||||||
|
|
||||||
|
|
@ -22,4 +25,4 @@ export function MemberPresenceDot({ className, label }: MemberPresenceDotProps):
|
||||||
aria-label={label}
|
aria-label={label}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ import { isTeamProvisioningActive } from '@renderer/store/slices/teamSlice';
|
||||||
import { serializeChipsWithText } from '@renderer/types/inlineChip';
|
import { serializeChipsWithText } from '@renderer/types/inlineChip';
|
||||||
import { formatAgentRole } from '@renderer/utils/formatAgentRole';
|
import { formatAgentRole } from '@renderer/utils/formatAgentRole';
|
||||||
import { buildMemberColorMap } from '@renderer/utils/memberHelpers';
|
import { buildMemberColorMap } from '@renderer/utils/memberHelpers';
|
||||||
import type { OpenCodeRuntimeDeliveryDebugDetails } from '@renderer/utils/openCodeRuntimeDeliveryDiagnostics';
|
|
||||||
import { nameColorSet } from '@renderer/utils/projectColor';
|
import { nameColorSet } from '@renderer/utils/projectColor';
|
||||||
import { getSuggestedSlashCommandsForProvider } from '@renderer/utils/providerSlashCommands';
|
import { getSuggestedSlashCommandsForProvider } from '@renderer/utils/providerSlashCommands';
|
||||||
import { buildSlashCommandSuggestions } from '@renderer/utils/skillCommandSuggestions';
|
import { buildSlashCommandSuggestions } from '@renderer/utils/skillCommandSuggestions';
|
||||||
|
|
@ -39,6 +38,7 @@ import { useShallow } from 'zustand/react/shallow';
|
||||||
|
|
||||||
import type { ActionMode } from '@renderer/components/team/messages/ActionModeSelector';
|
import type { ActionMode } from '@renderer/components/team/messages/ActionModeSelector';
|
||||||
import type { MentionSuggestion } from '@renderer/types/mention';
|
import type { MentionSuggestion } from '@renderer/types/mention';
|
||||||
|
import type { OpenCodeRuntimeDeliveryDebugDetails } from '@renderer/utils/openCodeRuntimeDeliveryDiagnostics';
|
||||||
import type {
|
import type {
|
||||||
AttachmentPayload,
|
AttachmentPayload,
|
||||||
ResolvedTeamMember,
|
ResolvedTeamMember,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ import { useTeamMessagesExpanded } from '@renderer/hooks/useTeamMessagesExpanded
|
||||||
import { useTeamMessagesRead } from '@renderer/hooks/useTeamMessagesRead';
|
import { useTeamMessagesRead } from '@renderer/hooks/useTeamMessagesRead';
|
||||||
import { useStore } from '@renderer/store';
|
import { useStore } from '@renderer/store';
|
||||||
import { selectTeamMessages } from '@renderer/store/slices/teamSlice';
|
import { selectTeamMessages } from '@renderer/store/slices/teamSlice';
|
||||||
import type { OpenCodeRuntimeDeliveryDebugDetails } from '@renderer/utils/openCodeRuntimeDeliveryDiagnostics';
|
|
||||||
import { filterTeamMessages } from '@renderer/utils/teamMessageFiltering';
|
import { filterTeamMessages } from '@renderer/utils/teamMessageFiltering';
|
||||||
import { toMessageKey } from '@renderer/utils/teamMessageKey';
|
import { toMessageKey } from '@renderer/utils/teamMessageKey';
|
||||||
import { shouldExcludeInboxTextFromReplyCandidates } from '@shared/utils/idleNotificationSemantics';
|
import { shouldExcludeInboxTextFromReplyCandidates } from '@shared/utils/idleNotificationSemantics';
|
||||||
|
|
@ -59,6 +58,7 @@ import type { TimelineItem } from '../activity/LeadThoughtsGroup';
|
||||||
import type { ActionMode } from './ActionModeSelector';
|
import type { ActionMode } from './ActionModeSelector';
|
||||||
import type { MessagesFilterState } from './MessagesFilterPopover';
|
import type { MessagesFilterState } from './MessagesFilterPopover';
|
||||||
import type { TeamMessagesPanelMode } from '@renderer/types/teamMessagesPanelMode';
|
import type { TeamMessagesPanelMode } from '@renderer/types/teamMessagesPanelMode';
|
||||||
|
import type { OpenCodeRuntimeDeliveryDebugDetails } from '@renderer/utils/openCodeRuntimeDeliveryDiagnostics';
|
||||||
import type { InboxMessage, ResolvedTeamMember, TaskRef, TeamTaskWithKanban } from '@shared/types';
|
import type { InboxMessage, ResolvedTeamMember, TaskRef, TeamTaskWithKanban } from '@shared/types';
|
||||||
|
|
||||||
interface TimeWindow {
|
interface TimeWindow {
|
||||||
|
|
@ -186,8 +186,7 @@ export function hasVisibleReplyForSendMessageDiagnostics(
|
||||||
|
|
||||||
const sentMessage = messages.find((message) => message.messageId === messageId);
|
const sentMessage = messages.find((message) => message.messageId === messageId);
|
||||||
if (
|
if (
|
||||||
!sentMessage ||
|
sentMessage?.from !== 'user' ||
|
||||||
sentMessage.from !== 'user' ||
|
|
||||||
typeof sentMessage.to !== 'string' ||
|
typeof sentMessage.to !== 'string' ||
|
||||||
sentMessage.to.length === 0
|
sentMessage.to.length === 0
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,11 @@ interface OpenCodeDeliveryWarningProps {
|
||||||
pendingDelayMs?: number;
|
pendingDelayMs?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OpenCodeDeliveryWarning({
|
export const OpenCodeDeliveryWarning = ({
|
||||||
warning,
|
warning,
|
||||||
debugDetails,
|
debugDetails,
|
||||||
pendingDelayMs = 10_000,
|
pendingDelayMs = 10_000,
|
||||||
}: OpenCodeDeliveryWarningProps): JSX.Element | null {
|
}: OpenCodeDeliveryWarningProps): JSX.Element | null => {
|
||||||
const detailsKey = `${warning ?? ''}:${debugDetails?.messageId ?? ''}`;
|
const detailsKey = `${warning ?? ''}:${debugDetails?.messageId ?? ''}`;
|
||||||
const delayPendingWarning =
|
const delayPendingWarning =
|
||||||
debugDetails?.responsePending === true && debugDetails.delivered !== false;
|
debugDetails?.responsePending === true && debugDetails.delivered !== false;
|
||||||
|
|
@ -148,4 +148,4 @@ export function OpenCodeDeliveryWarning({
|
||||||
) : null}
|
) : null}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,12 @@ export type SyncedLoader2Props = ComponentProps<typeof Loader2> & {
|
||||||
spinDurationMs?: number;
|
spinDurationMs?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function SyncedLoader2({
|
export const SyncedLoader2 = ({
|
||||||
className,
|
className,
|
||||||
style,
|
style,
|
||||||
spinDurationMs = DEFAULT_SPIN_DURATION_MS,
|
spinDurationMs = DEFAULT_SPIN_DURATION_MS,
|
||||||
...props
|
...props
|
||||||
}: SyncedLoader2Props): React.JSX.Element {
|
}: SyncedLoader2Props): React.JSX.Element => {
|
||||||
const syncedStyle = useSyncedAnimationStyle(true, spinDurationMs);
|
const syncedStyle = useSyncedAnimationStyle(true, spinDurationMs);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -25,4 +25,4 @@ export function SyncedLoader2({
|
||||||
style={{ ...syncedStyle, ...style }}
|
style={{ ...syncedStyle, ...style }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ export function isEditableShortcutTarget(target: EventTarget | null): boolean {
|
||||||
}
|
}
|
||||||
|
|
||||||
const contentEditable = editableElement.getAttribute('contenteditable');
|
const contentEditable = editableElement.getAttribute('contenteditable');
|
||||||
return contentEditable == null || contentEditable.toLowerCase() !== 'false';
|
return contentEditable?.toLowerCase() !== 'false';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useKeyboardShortcuts(): void {
|
export function useKeyboardShortcuts(): void {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { api } from '@renderer/api';
|
import { api } from '@renderer/api';
|
||||||
import { mergeTeamMessages } from '@renderer/utils/mergeTeamMessages';
|
import { mergeTeamMessages } from '@renderer/utils/mergeTeamMessages';
|
||||||
|
import { buildOpenCodeRuntimeDeliveryDiagnostics } from '@renderer/utils/openCodeRuntimeDeliveryDiagnostics';
|
||||||
import { normalizePath } from '@renderer/utils/pathNormalize';
|
import { normalizePath } from '@renderer/utils/pathNormalize';
|
||||||
import {
|
import {
|
||||||
buildTaskChangePresenceKey,
|
buildTaskChangePresenceKey,
|
||||||
|
|
@ -10,7 +11,6 @@ import {
|
||||||
import { toMessageKey } from '@renderer/utils/teamMessageKey';
|
import { toMessageKey } from '@renderer/utils/teamMessageKey';
|
||||||
import { extractProviderScopedBaseModel } from '@renderer/utils/teamModelContext';
|
import { extractProviderScopedBaseModel } from '@renderer/utils/teamModelContext';
|
||||||
import { IpcError, unwrapIpc } from '@renderer/utils/unwrapIpc';
|
import { IpcError, unwrapIpc } from '@renderer/utils/unwrapIpc';
|
||||||
import { buildOpenCodeRuntimeDeliveryDiagnostics } from '@renderer/utils/openCodeRuntimeDeliveryDiagnostics';
|
|
||||||
import { stripAgentBlocks } from '@shared/constants/agentBlocks';
|
import { stripAgentBlocks } from '@shared/constants/agentBlocks';
|
||||||
import { DEFAULT_TOOL_APPROVAL_SETTINGS } from '@shared/types/team';
|
import { DEFAULT_TOOL_APPROVAL_SETTINGS } from '@shared/types/team';
|
||||||
import { isLeadMember } from '@shared/utils/leadDetection';
|
import { isLeadMember } from '@shared/utils/leadDetection';
|
||||||
|
|
@ -25,8 +25,8 @@ import { getWorktreeNavigationState } from '../utils/stateResetHelpers';
|
||||||
import type { AppState } from '../types';
|
import type { AppState } from '../types';
|
||||||
import type { GraphLayoutMode, GraphOwnerSlotAssignment } from '@claude-teams/agent-graph';
|
import type { GraphLayoutMode, GraphOwnerSlotAssignment } from '@claude-teams/agent-graph';
|
||||||
import type { AppConfig } from '@renderer/types/data';
|
import type { AppConfig } from '@renderer/types/data';
|
||||||
import type { OpenCodeRuntimeDeliveryDebugDetails } from '@renderer/utils/openCodeRuntimeDeliveryDiagnostics';
|
|
||||||
import type { TeamMessagesPanelMode } from '@renderer/types/teamMessagesPanelMode';
|
import type { TeamMessagesPanelMode } from '@renderer/types/teamMessagesPanelMode';
|
||||||
|
import type { OpenCodeRuntimeDeliveryDebugDetails } from '@renderer/utils/openCodeRuntimeDeliveryDiagnostics';
|
||||||
import type {
|
import type {
|
||||||
ActiveToolCall,
|
ActiveToolCall,
|
||||||
AddMemberRequest,
|
AddMemberRequest,
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ function boundedNumber(value: number | undefined): number | undefined {
|
||||||
}
|
}
|
||||||
|
|
||||||
function uniqueDiagnostics(
|
function uniqueDiagnostics(
|
||||||
...groups: Array<readonly (string | undefined)[] | undefined>
|
...groups: (readonly (string | undefined)[] | undefined)[]
|
||||||
): string[] | undefined {
|
): string[] | undefined {
|
||||||
const seen = new Set<string>();
|
const seen = new Set<string>();
|
||||||
const diagnostics: string[] = [];
|
const diagnostics: string[] = [];
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ export function buildOpenCodeRuntimeDeliveryDiagnostics(
|
||||||
result: SendMessageResult
|
result: SendMessageResult
|
||||||
): OpenCodeRuntimeDeliveryDiagnostics {
|
): OpenCodeRuntimeDeliveryDiagnostics {
|
||||||
const runtimeDelivery = result.runtimeDelivery;
|
const runtimeDelivery = result.runtimeDelivery;
|
||||||
if (!runtimeDelivery || runtimeDelivery.attempted !== true) {
|
if (runtimeDelivery?.attempted !== true) {
|
||||||
return { warning: null, debugDetails: null };
|
return { warning: null, debugDetails: null };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ interface ContentBlock {
|
||||||
input?: Record<string, unknown>;
|
input?: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
type CodexNativeJsonEvent = {
|
interface CodexNativeJsonEvent {
|
||||||
type?: string;
|
type?: string;
|
||||||
thread_id?: string;
|
thread_id?: string;
|
||||||
item?: {
|
item?: {
|
||||||
|
|
@ -70,16 +70,16 @@ type CodexNativeJsonEvent = {
|
||||||
cached_input_tokens?: number;
|
cached_input_tokens?: number;
|
||||||
output_tokens?: number;
|
output_tokens?: number;
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
type CodexNativeProjectedSystemEvent = {
|
interface CodexNativeProjectedSystemEvent {
|
||||||
type?: string;
|
type?: string;
|
||||||
subtype?: string;
|
subtype?: string;
|
||||||
content?: string;
|
content?: string;
|
||||||
level?: string;
|
level?: string;
|
||||||
codexNativeThreadStatus?: string;
|
codexNativeThreadStatus?: string;
|
||||||
codexNativeThreadId?: string;
|
codexNativeThreadId?: string;
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Content-based hash for deterministic fallback IDs that survive
|
* Content-based hash for deterministic fallback IDs that survive
|
||||||
|
|
@ -265,7 +265,7 @@ function codexNativeProjectedSystemToDisplayItems(
|
||||||
timestamp: Date
|
timestamp: Date
|
||||||
): AIGroupDisplayItem[] | null {
|
): AIGroupDisplayItem[] | null {
|
||||||
const event = asRecord(parsed) as CodexNativeProjectedSystemEvent | null;
|
const event = asRecord(parsed) as CodexNativeProjectedSystemEvent | null;
|
||||||
if (!event || event.type !== 'system' || typeof event.subtype !== 'string') {
|
if (event?.type !== 'system' || typeof event.subtype !== 'string') {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10398,7 +10398,7 @@ describe('Team agent launch matrix safe e2e', () => {
|
||||||
const launchAdapter = new FakeOpenCodeRuntimeAdapter();
|
const launchAdapter = new FakeOpenCodeRuntimeAdapter();
|
||||||
const firstService = new TeamProvisioningService();
|
const firstService = new TeamProvisioningService();
|
||||||
firstService.setRuntimeAdapterRegistry(new TeamRuntimeAdapterRegistry([launchAdapter]));
|
firstService.setRuntimeAdapterRegistry(new TeamRuntimeAdapterRegistry([launchAdapter]));
|
||||||
await firstService.createTeam(
|
const launch = await firstService.createTeam(
|
||||||
{
|
{
|
||||||
teamName,
|
teamName,
|
||||||
cwd: projectPath,
|
cwd: projectPath,
|
||||||
|
|
@ -10426,6 +10426,7 @@ describe('Team agent launch matrix safe e2e', () => {
|
||||||
});
|
});
|
||||||
expect(messageAdapter.messageInputs).toHaveLength(1);
|
expect(messageAdapter.messageInputs).toHaveLength(1);
|
||||||
expect(messageAdapter.messageInputs[0]).toMatchObject({
|
expect(messageAdapter.messageInputs[0]).toMatchObject({
|
||||||
|
runId: launch.runId,
|
||||||
teamName,
|
teamName,
|
||||||
laneId: 'primary',
|
laneId: 'primary',
|
||||||
memberName: 'alice',
|
memberName: 'alice',
|
||||||
|
|
@ -10433,7 +10434,6 @@ describe('Team agent launch matrix safe e2e', () => {
|
||||||
text: 'message recovered pure opencode lane',
|
text: 'message recovered pure opencode lane',
|
||||||
messageId: 'msg-recovered-pure-opencode',
|
messageId: 'msg-recovered-pure-opencode',
|
||||||
});
|
});
|
||||||
expect(messageAdapter.messageInputs[0]?.runId).toBeUndefined();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('delivers direct OpenCode member messages to recovered pure OpenCode lanes despite stale terminal provisioning state', async () => {
|
it('delivers direct OpenCode member messages to recovered pure OpenCode lanes despite stale terminal provisioning state', async () => {
|
||||||
|
|
|
||||||
|
|
@ -7752,7 +7752,7 @@ describe('TeamProvisioningService', () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
await (svc as any).launchMixedSecondaryLaneIfNeeded(run);
|
await (svc as any).launchMixedSecondaryLaneIfNeeded(run);
|
||||||
await vi.waitFor(() => expect(adapterLaunch).toHaveBeenCalledTimes(2));
|
await vi.waitFor(() => expect(adapterLaunch).toHaveBeenCalledTimes(2), { timeout: 5_000 });
|
||||||
expect(adapterLaunch).toHaveBeenCalledWith(
|
expect(adapterLaunch).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
laneId: 'secondary:opencode:bob',
|
laneId: 'secondary:opencode:bob',
|
||||||
|
|
@ -7783,20 +7783,23 @@ describe('TeamProvisioningService', () => {
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
await vi.waitFor(() => {
|
await vi.waitFor(
|
||||||
expect(run.mixedSecondaryLanes).toEqual([
|
() => {
|
||||||
expect.objectContaining({
|
expect(run.mixedSecondaryLanes).toEqual([
|
||||||
laneId: 'secondary:opencode:bob',
|
expect.objectContaining({
|
||||||
state: 'finished',
|
laneId: 'secondary:opencode:bob',
|
||||||
result: expect.objectContaining({ teamLaunchState: 'clean_success' }),
|
state: 'finished',
|
||||||
}),
|
result: expect.objectContaining({ teamLaunchState: 'clean_success' }),
|
||||||
expect.objectContaining({
|
}),
|
||||||
laneId: 'secondary:opencode:tom',
|
expect.objectContaining({
|
||||||
state: 'finished',
|
laneId: 'secondary:opencode:tom',
|
||||||
result: expect.objectContaining({ teamLaunchState: 'clean_success' }),
|
state: 'finished',
|
||||||
}),
|
result: expect.objectContaining({ teamLaunchState: 'clean_success' }),
|
||||||
]);
|
}),
|
||||||
});
|
]);
|
||||||
|
},
|
||||||
|
{ timeout: 5_000 }
|
||||||
|
);
|
||||||
const publicStatuses = await svc.getMemberSpawnStatuses('safe-mixed-codex-opencode-launch');
|
const publicStatuses = await svc.getMemberSpawnStatuses('safe-mixed-codex-opencode-launch');
|
||||||
expect(publicStatuses.statuses.bob).toMatchObject({
|
expect(publicStatuses.statuses.bob).toMatchObject({
|
||||||
status: 'online',
|
status: 'online',
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue