This commit is contained in:
iliya 2026-03-30 18:59:42 +03:00
commit 53dd857e0f
20 changed files with 53 additions and 41 deletions

View file

@ -95,11 +95,11 @@ import {
} from './utils/safeWebContentsSend';
import { syncTelemetryFlag } from './sentry';
import {
BranchStatusService,
CliInstallerService,
configManager,
LocalFileSystemProvider,
MemberStatsComputer,
BranchStatusService,
NotificationManager,
PtyTerminalService,
ServiceContext,
@ -108,8 +108,8 @@ import {
TaskBoundaryParser,
TeamDataService,
TeamLogSourceTracker,
TeamMemberLogsFinder,
TeammateToolTracker,
TeamMemberLogsFinder,
TeamProvisioningService,
UpdaterService,
} from './services';

View file

@ -88,8 +88,8 @@ import { registerValidationHandlers, removeValidationHandlers } from './validati
import { registerWindowHandlers, removeWindowHandlers } from './window';
import type {
ChangeExtractorService,
BranchStatusService,
ChangeExtractorService,
CliInstallerService,
FileContentResolver,
GitDiffFallback,
@ -100,8 +100,8 @@ import type {
ServiceContextRegistry,
SshConnectionManager,
TeamDataService,
TeamMemberLogsFinder,
TeammateToolTracker,
TeamMemberLogsFinder,
TeamProvisioningService,
UpdaterService,
} from '../services';

View file

@ -49,8 +49,8 @@ import {
TEAM_SEND_MESSAGE,
TEAM_SET_CHANGE_PRESENCE_TRACKING,
TEAM_SET_PROJECT_BRANCH_TRACKING,
TEAM_SET_TOOL_ACTIVITY_TRACKING,
TEAM_SET_TASK_CLARIFICATION,
TEAM_SET_TOOL_ACTIVITY_TRACKING,
TEAM_SHOW_MESSAGE_NOTIFICATION,
TEAM_SOFT_DELETE_TASK,
TEAM_START_TASK,
@ -113,8 +113,8 @@ import {
import type {
BranchStatusService,
MemberStatsComputer,
TeammateToolTracker,
TeamDataService,
TeammateToolTracker,
TeamMemberLogsFinder,
TeamProvisioningService,
} from '../services';
@ -2978,7 +2978,7 @@ async function handleToolApprovalSettings(
try {
getTeamProvisioningService().updateToolApprovalSettings(
teamName as string,
teamName,
s as unknown as ToolApprovalSettings
);
} catch (err) {

View file

@ -1,6 +1,5 @@
import * as path from 'path';
import { createLogger } from '@shared/utils/logger';
import * as path from 'path';
import { gitIdentityResolver } from '../parsing/GitIdentityResolver';

View file

@ -337,7 +337,7 @@ export class TeammateToolTracker {
for (const block of content) {
if (!block || typeof block !== 'object') continue;
const typedBlock = block as Record<string, unknown>;
const typedBlock = block;
if (typedBlock.type === 'tool_use') {
const rawId = typeof typedBlock.id === 'string' ? typedBlock.id.trim() : '';
if (!rawId) continue;

View file

@ -1,5 +1,5 @@
export { CascadeGuard } from './CascadeGuard';
export { BranchStatusService } from './BranchStatusService';
export { CascadeGuard } from './CascadeGuard';
export { ChangeExtractorService } from './ChangeExtractorService';
export { ClaudeBinaryResolver } from './ClaudeBinaryResolver';
export { CrossTeamOutbox } from './CrossTeamOutbox';
@ -18,10 +18,10 @@ export { TeamInboxReader } from './TeamInboxReader';
export { TeamInboxWriter } from './TeamInboxWriter';
export { TeamKanbanManager } from './TeamKanbanManager';
export { TeamLogSourceTracker } from './TeamLogSourceTracker';
export { TeammateToolTracker } from './TeammateToolTracker';
export { TeamMemberLogsFinder } from './TeamMemberLogsFinder';
export { TeamMemberResolver } from './TeamMemberResolver';
export { TeamMembersMetaStore } from './TeamMembersMetaStore';
export { TeammateToolTracker } from './TeammateToolTracker';
export { TeamProvisioningService } from './TeamProvisioningService';
export { TeamSentMessagesStore } from './TeamSentMessagesStore';
export { TeamTaskReader } from './TeamTaskReader';

View file

@ -1,10 +1,9 @@
import { isParsedSystemChunkMessage, isParsedUserChunkMessage, isTextContent } from '@main/types';
import { parseJsonlLine } from '@main/utils/jsonl';
import { createHash } from 'crypto';
import * as fs from 'fs';
import { extractCommandOutputInfo, extractSlashInfo } from '@shared/utils/contentSanitizer';
import { buildSlashCommandMeta } from '@shared/utils/slashCommands';
import { createHash } from 'crypto';
import * as fs from 'fs';
import type { ParsedMessage } from '@main/types';
import type { CommandOutputMeta, InboxMessage, SlashCommandMeta } from '@shared/types';

View file

@ -126,7 +126,6 @@ import {
TEAM_GET_MEMBER_LOGS,
TEAM_GET_MEMBER_STATS,
TEAM_GET_PROJECT_BRANCH,
TEAM_PROJECT_BRANCH_CHANGE,
TEAM_GET_SAVED_REQUEST,
TEAM_GET_TASK_ATTACHMENT,
TEAM_GET_TASK_CHANGE_PRESENCE,
@ -140,6 +139,7 @@ import {
TEAM_PREPARE_PROVISIONING,
TEAM_PROCESS_ALIVE,
TEAM_PROCESS_SEND,
TEAM_PROJECT_BRANCH_CHANGE,
TEAM_PROVISIONING_PROGRESS,
TEAM_PROVISIONING_STATUS,
TEAM_REMOVE_MEMBER,
@ -152,8 +152,8 @@ import {
TEAM_SEND_MESSAGE,
TEAM_SET_CHANGE_PRESENCE_TRACKING,
TEAM_SET_PROJECT_BRANCH_TRACKING,
TEAM_SET_TOOL_ACTIVITY_TRACKING,
TEAM_SET_TASK_CLARIFICATION,
TEAM_SET_TOOL_ACTIVITY_TRACKING,
TEAM_SHOW_MESSAGE_NOTIFICATION,
TEAM_SOFT_DELETE_TASK,
TEAM_START_TASK,
@ -250,6 +250,7 @@ import type {
MemberLogSummary,
MemberSpawnStatusesSnapshot,
NotificationTrigger,
ProjectBranchChangeEvent,
RejectResult,
ReplaceMembersRequest,
Schedule,
@ -268,7 +269,6 @@ import type {
TaskChangePresenceState,
TaskChangeSetV2,
TaskComment,
ProjectBranchChangeEvent,
TeamChangeEvent,
TeamClaudeLogsQuery,
TeamClaudeLogsResponse,

View file

@ -81,12 +81,12 @@ import { MemberList } from './members/MemberList';
import { MessagesPanel } from './messages/MessagesPanel';
import { ChangeReviewDialog } from './review/ChangeReviewDialog';
import { ScheduleSection } from './schedule/ScheduleSection';
import { ClaudeLogsSection } from './ClaudeLogsSection';
import { CollapsibleTeamSection } from './CollapsibleTeamSection';
import { ProcessesSection } from './ProcessesSection';
import { TeamSidebarHost } from './sidebar/TeamSidebarHost';
import { TeamSidebarPortalSource } from './sidebar/TeamSidebarPortalSource';
import { TeamSidebarRail } from './sidebar/TeamSidebarRail';
import { ClaudeLogsSection } from './ClaudeLogsSection';
import { CollapsibleTeamSection } from './CollapsibleTeamSection';
import { ProcessesSection } from './ProcessesSection';
import { TeamProvisioningBanner } from './TeamProvisioningBanner';
import { TeamSessionsSection } from './TeamSessionsSection';

View file

@ -7,13 +7,12 @@ import { shortenDisplayPath } from '@renderer/utils/pathDisplay';
import { highlightLines } from '@renderer/utils/syntaxHighlighter';
import { AlertTriangle, FileText, MessageCircleQuestion, Search, Terminal } from 'lucide-react';
import { MemberBadge } from './MemberBadge';
import {
ToolApprovalSettingsContent,
ToolApprovalSettingsToggle,
} from './dialogs/ToolApprovalSettingsPanel';
import { FileIcon } from './editor/FileIcon';
import { MemberBadge } from './MemberBadge';
import { ToolApprovalDiffPreview } from './ToolApprovalDiffPreview';
import type { ToolApprovalRequest } from '@shared/types';

View file

@ -3,9 +3,9 @@ import { useMemo } from 'react';
import { Button } from '@renderer/components/ui/button';
import { Checkbox } from '@renderer/components/ui/checkbox';
import { Popover, PopoverContent, PopoverTrigger } from '@renderer/components/ui/popover';
import { formatSessionLabel } from '@renderer/utils/sessionTitleParser';
import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip';
import { displayMemberName } from '@renderer/utils/memberHelpers';
import { formatSessionLabel } from '@renderer/utils/sessionTitleParser';
import { Crown, Filter } from 'lucide-react';
import type { Session } from '@renderer/types/data';

View file

@ -191,10 +191,10 @@ export const FileSectionDiff = ({
);
};
function OversizedDiffNotice({ message }: { message: string }): React.ReactElement {
const OversizedDiffNotice = ({ message }: { message: string }): React.ReactElement => {
return (
<div className="border-b border-border bg-amber-500/10 px-4 py-3 text-xs text-amber-300">
{message}
</div>
);
}
};

View file

@ -3,13 +3,13 @@ import { createPortal } from 'react-dom';
import { useStore } from '@renderer/store';
import { useTeamSidebarHostId } from './TeamSidebarHost';
import {
getTeamSidebarHostElement,
removeTeamSidebarSource,
upsertTeamSidebarSource,
useTeamSidebarPortalSnapshot,
} from './TeamSidebarPortalManager';
import { useTeamSidebarHostId } from './TeamSidebarHost';
interface TeamSidebarPortalSourceProps {
teamName: string;

View file

@ -13,12 +13,12 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { api } from '@renderer/api';
import { useStore } from '@renderer/store';
import { DEFAULT_CLAUDE_LOGS_FILTER } from './ClaudeLogsFilterPopover';
import {
createDefaultClaudeLogsSidebarUiState,
getTeamClaudeLogsSidebarUiState,
setTeamClaudeLogsSidebarUiState,
} from './sidebar/teamSidebarUiState';
import { DEFAULT_CLAUDE_LOGS_FILTER } from './ClaudeLogsFilterPopover';
import type { ClaudeLogsFilterState } from './ClaudeLogsFilterPopover';
import type { ClaudeLogsViewerState } from './CliLogsRichView';

View file

@ -7,8 +7,8 @@
* Class-based with ES #private fields, caching, and DI-ready constructor.
*/
import { isLeadMember } from '@shared/utils/leadDetection';
import { agentAvatarUrl } from '@renderer/utils/memberHelpers';
import { isLeadMember } from '@shared/utils/leadDetection';
import type {
GraphDataPort,

View file

@ -7,7 +7,7 @@
import { Badge } from '@renderer/components/ui/badge';
import { Button } from '@renderer/components/ui/button';
import { agentAvatarUrl } from '@renderer/utils/memberHelpers';
import { Loader2, MessageSquare, ExternalLink, User, Plus } from 'lucide-react';
import { ExternalLink, Loader2, MessageSquare, Plus, User } from 'lucide-react';
import type { GraphNode } from '@claude-teams/agent-graph';
@ -51,14 +51,14 @@ interface GraphNodePopoverProps {
onCreateTask?: (owner: string) => void;
}
export function GraphNodePopover({
export const GraphNodePopover = ({
node,
onClose,
onSendMessage,
onOpenTaskDetail,
onOpenMemberProfile,
onCreateTask,
}: GraphNodePopoverProps): React.JSX.Element {
}: GraphNodePopoverProps): React.JSX.Element => {
if (node.kind === 'member' || node.kind === 'lead') {
return (
<MemberPopoverContent
@ -92,11 +92,11 @@ export function GraphNodePopover({
)}
</div>
);
}
};
// ─── Member Popover ─────────────────────────────────────────────────────────
function MemberPopoverContent({
const MemberPopoverContent = ({
node,
onClose,
onSendMessage,
@ -110,7 +110,7 @@ function MemberPopoverContent({
onOpenProfile?: (name: string) => void;
onCreateTask?: (owner: string) => void;
onOpenTask?: (taskId: string) => void;
}): React.JSX.Element {
}): React.JSX.Element => {
const memberName =
node.domainRef.kind === 'member' || node.domainRef.kind === 'lead'
? node.domainRef.memberName
@ -317,11 +317,11 @@ function MemberPopoverContent({
</div>
</div>
);
}
};
// ─── Task Popover ───────────────────────────────────────────────────────────
function TaskPopoverContent({
const TaskPopoverContent = ({
node,
onClose,
onOpenDetail,
@ -329,7 +329,7 @@ function TaskPopoverContent({
node: GraphNode;
onClose: () => void;
onOpenDetail?: (taskId: string) => void;
}): React.JSX.Element {
}): React.JSX.Element => {
const taskId = node.domainRef.kind === 'task' ? node.domainRef.taskId : '';
const statusColor =
@ -393,4 +393,4 @@ function TaskPopoverContent({
</div>
</div>
);
}
};

View file

@ -9,6 +9,7 @@ import { GraphView } from '@claude-teams/agent-graph';
import { TeamSidebarHost } from '@renderer/components/team/sidebar/TeamSidebarHost';
import { useTeamGraphAdapter } from '../adapters/useTeamGraphAdapter';
import { GraphNodePopover } from './GraphNodePopover';
import type { GraphDomainRef, GraphEventPort } from '@claude-teams/agent-graph';

View file

@ -3,12 +3,13 @@
* Provides Fullscreen button that opens the overlay.
*/
import { useCallback, useState, lazy, Suspense } from 'react';
import { lazy, Suspense, useCallback, useState } from 'react';
import { GraphView } from '@claude-teams/agent-graph';
import { TeamSidebarHost } from '@renderer/components/team/sidebar/TeamSidebarHost';
import { useTeamGraphAdapter } from '../adapters/useTeamGraphAdapter';
import { GraphNodePopover } from './GraphNodePopover';
import type { GraphDomainRef, GraphEventPort, GraphNode } from '@claude-teams/agent-graph';

View file

@ -6,12 +6,12 @@ import { api } from '@renderer/api';
import { syncRendererTelemetry } from '@renderer/sentry';
import { cleanupStale as cleanupCommentReadState } from '@renderer/services/commentReadStorage';
import { normalizePath } from '@renderer/utils/pathNormalize';
import { isVersionOlder, normalizeVersion } from '@shared/utils/version';
import {
buildTaskChangePresenceKey,
buildTaskChangeRequestOptions,
canDisplayTaskChangesForOptions,
} from '@renderer/utils/taskChangeRequest';
import { isVersionOlder, normalizeVersion } from '@shared/utils/version';
import { create } from 'zustand';
import { createChangeReviewSlice } from './slices/changeReviewSlice';

View file

@ -12,6 +12,15 @@ vi.mock('@main/utils/shellEnv', () => ({
resolveInteractiveShellEnv: vi.fn(),
}));
const addTeamNotificationMock = vi.fn().mockResolvedValue(null);
vi.mock('@main/services/infrastructure/NotificationManager', () => ({
NotificationManager: {
getInstance: () => ({
addTeamNotification: addTeamNotificationMock,
}),
},
}));
import { TeamProvisioningService } from '@main/services/team/TeamProvisioningService';
import { ClaudeBinaryResolver } from '@main/services/team/ClaudeBinaryResolver';
import { resolveInteractiveShellEnv } from '@main/utils/shellEnv';
@ -21,6 +30,7 @@ describe('TeamProvisioningService prepare/auth behavior', () => {
beforeEach(() => {
vi.clearAllMocks();
addTeamNotificationMock.mockResolvedValue(null);
tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'claude-team-prepare-'));
vi.mocked(ClaudeBinaryResolver.resolve).mockResolvedValue('/fake/claude');
vi.mocked(resolveInteractiveShellEnv).mockResolvedValue({
@ -228,6 +238,9 @@ describe('TeamProvisioningService prepare/auth behavior', () => {
const svc = new TeamProvisioningService();
const emitter = vi.fn();
svc.setTeamChangeEmitter(emitter);
vi.spyOn(svc as any, 'updateConfigPostLaunch').mockResolvedValue(undefined);
vi.spyOn(svc as any, 'cleanupPrelaunchBackup').mockResolvedValue(undefined);
vi.spyOn(svc as any, 'relayLeadInboxMessages').mockResolvedValue(undefined);
const run = {
runId: 'run-3',