Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions app/shared/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@
"./ui/*": "./src/ui/*.tsx",
"./ui/*.css": "./src/ui/*.module.css",
"./lib/utils": "./src/lib/utils.ts",
"./shadcn/ui/*": "./src/shadcn/ui/*.tsx",
"./shadcn/ai-elements/*": "./src/shadcn/ai-elements/*.tsx"
"./shadcn/ui/*": "./src/shadcn/ui/*.tsx"
},
"scripts": {
"test": "vitest run",
Expand Down
17 changes: 17 additions & 0 deletions app/workbench/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@ docs/projects/tasks/settings 页面、mainchain 状态条、terminal host、floa
`workbench` 是端级 shell 层;`shared` 是跨端原语层,
workbench 是端级巨石,两者拆包后依赖方向固定为 **workbench → shared 单向**。

## 目录

根目录只放 shell 与跨域件:`AgentHubWorkbench*`、`WorkbenchFrame*`、
`WorkspaceHeader`、`GlobalRail`、`WorkbenchRoutes`、`index.ts` 入口、图标
registry、preferences/layout、以及 `pages/`、`auxPanel/`、`terminal/`、
`team/`、`floating/`、`mainchain/`、`sessionImport/`、`__tests__/`。

| 目录 | 内容 |
|---|---|
| `composer/` | UnifiedComposer 与其 picker / 附件 / mention / 审批 / dispatch queue 子件、纯 helper |
| `transcript/` | 会话转录与工程列:ConversationHost/Sidebar、ChatViewBridge、transcript chrome、goal banner、mainchain 状态条 |
| `routes/` | 每个 route 的 view + hook + helpers/planners/model(agents、tasks、docs、projects、settings、usage) |
| `inspector/` | 右侧 Inspector 面板、resizer、模式面板、自动展开 hook |

模块与测试同目录;移动文件时改相对导入即可,包外消费者只认
`package.json` 的 exports,不认内部路径。

## 边界

- 依赖方向:`workbench` 可以 import `shared`(深导入走 `@shared/*` 别名,
Expand Down
12 changes: 6 additions & 6 deletions app/workbench/src/AgentHubWorkbench.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@ import type { GlobalRailPage } from './GlobalRail';
import styles from './AgentHubWorkbench.module.css';
import { useWorkbenchPanelLayout } from './useWorkbenchPanelLayout';
import { useWorkbenchProfileChrome } from './useWorkbenchProfileChrome';
import { useWorkbenchSessionChrome } from './useWorkbenchSessionChrome';
import { useWorkbenchTranscriptChrome } from './useWorkbenchTranscriptChrome';
import { useWorkbenchSessionChrome } from './transcript/useWorkbenchSessionChrome';
import { useWorkbenchTranscriptChrome } from './transcript/useWorkbenchTranscriptChrome';
import { useWorkbenchGlobalShortcuts } from './useWorkbenchGlobalShortcuts';
import { useWorkbenchTaskDeepLinks } from './useWorkbenchTaskDeepLinks';
import { WorkbenchTaskDeepLinkProvider } from './workbenchTaskDeepLinks';
import { WorkbenchTaskDeepLinkProvider } from './routes/workbenchTaskDeepLinks';
import { GlobalSearchDialog } from './GlobalSearchDialog';
import { WORKBENCH_INSPECTOR_QUICK_OPEN_EVENT } from './desktopChromeEvents';
import { isEditableKeyboardTarget } from './workbenchSessionChromeHelpers';
import { isEditableKeyboardTarget } from './transcript/workbenchSessionChromeHelpers';
import { WorkbenchFrame } from './WorkbenchFrame';
import {
engineeringColumnActivitySignal,
useEngineeringColumnAutoOpen,
} from './useEngineeringColumnAutoOpen';
} from './inspector/useEngineeringColumnAutoOpen';
import { WorkbenchProfileOverlays } from './WorkbenchProfileOverlays';
import { WorkbenchTranscriptOverlays } from './WorkbenchTranscriptOverlays';
import { WorkbenchTranscriptOverlays } from './transcript/WorkbenchTranscriptOverlays';
import {
buildProfileChromeOptions,
buildProfileOverlaysProps,
Expand Down
4 changes: 2 additions & 2 deletions app/workbench/src/AgentHubWorkbenchHelpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { describe, expect, it, vi } from 'vitest';
import type { AgentHubPlatform, WorkbenchConversation } from '@shared/platform';
import type { TranscriptBlock } from '@shared/transcript';
import type { GlobalRailPage } from './GlobalRail';
import type { WorkbenchSessionChrome } from './workbenchSessionChromeHelpers';
import type { WorkbenchTranscriptChrome } from './useWorkbenchTranscriptChrome';
import type { WorkbenchSessionChrome } from './transcript/workbenchSessionChromeHelpers';
import type { WorkbenchTranscriptChrome } from './transcript/useWorkbenchTranscriptChrome';
import type { WorkbenchProfileChrome } from './useWorkbenchProfileChrome';
import type { WorkbenchPanelLayout } from './useWorkbenchPanelLayout';
import type { AgentHubWorkbenchProps } from './AgentHubWorkbenchTypes';
Expand Down
6 changes: 3 additions & 3 deletions app/workbench/src/AgentHubWorkbenchHelpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import type { Dispatch, SetStateAction } from 'react';
import type { WorkbenchConversation } from '@shared/platform';
import type { GlobalRailPage } from './GlobalRail';
import type { WorkbenchFrameProps } from './workbenchFrameTypes';
import type { UseWorkbenchSessionChromeOptions, WorkbenchSessionChrome } from './workbenchSessionChromeHelpers';
import type { UseWorkbenchSessionChromeOptions, WorkbenchSessionChrome } from './transcript/workbenchSessionChromeHelpers';
import type {
UseWorkbenchTranscriptChromeOptions,
WorkbenchTranscriptChrome,
} from './useWorkbenchTranscriptChrome';
} from './transcript/useWorkbenchTranscriptChrome';
import type {
UseWorkbenchProfileChromeOptions,
WorkbenchProfileChrome,
} from './useWorkbenchProfileChrome';
import type { WorkbenchPanelLayout } from './useWorkbenchPanelLayout';
import type { WorkbenchTranscriptOverlaysProps } from './WorkbenchTranscriptOverlays';
import type { WorkbenchTranscriptOverlaysProps } from './transcript/WorkbenchTranscriptOverlays';
import type { WorkbenchProfileOverlaysProps } from './WorkbenchProfileOverlays';
import type { AgentHubWorkbenchProps } from './AgentHubWorkbenchTypes';

Expand Down
4 changes: 2 additions & 2 deletions app/workbench/src/AgentHubWorkbenchTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import type {
} from '@shared/platform';
import type { TranscriptBlock, ApprovalDecisionAction } from '@shared/transcript';
import type { ConnectionStatusKind } from './GlobalRail';
import type { RuntimeEvidenceSnapshot } from './RightInspector';
import type { RuntimeEvidenceSnapshot } from './inspector/RightInspector';
import type {
WorkbenchAgentProfilesStatus,
WorkbenchContactsData,
WorkbenchContactsActions,
WorkbenchDocumentsActions,
} from './WorkbenchRoutes';
import type { AgentConfig, ProjectDraft, DocRow } from './pages';
import type { AgentConfig, ProjectDraft, DocRow } from './pages/index';
import type { SkillMarketItem, MCPMarketItem } from './pages/AgentsPage';
import type { ProjectInfo } from './pages/ProjectsPage';
import type { WorkbenchAttentionInput } from './workbenchAttentionModel';
Expand Down
2 changes: 1 addition & 1 deletion app/workbench/src/GlobalRail.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { ProfilePopover, DemoToast } from './floating';
import { ProfilePopover, DemoToast } from './floating/index';
import { DesignNavIcon, type DesignNavIconName } from './designIcons';
import { CHATVIEW_I18N_NAMESPACE } from '@shared/chatview/i18n/resources';
import { Tooltip } from '@shared/ui/Tooltip';
Expand Down
2 changes: 1 addition & 1 deletion app/workbench/src/SplitConversationPane.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ beforeAll(async () => {
await useTestI18nLanguage('en');
});

vi.mock('./ChatViewBridge', () => ({
vi.mock('./transcript/ChatViewBridge', () => ({
ChatViewBridge: (props: { displayTranscript: TranscriptBlock[] }) => (
<div data-testid="read-only-transcript" data-block-count={props.displayTranscript.length} />
),
Expand Down
2 changes: 1 addition & 1 deletion app/workbench/src/SplitConversationPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { useTranslation } from 'react-i18next';
import type { WorkbenchConversation } from '@shared/platform';
import type { TranscriptBlock } from '@shared/transcript';
import { CHATVIEW_I18N_NAMESPACE } from '@shared/chatview/i18n/resources';
import { ChatViewBridge } from './ChatViewBridge';
import { ChatViewBridge } from './transcript/ChatViewBridge';
import { DesignNavIcon } from './designIcons';
import { ContextMenu, type ContextMenuItem } from './floating/ContextMenu';
import type { ConversationLiveStatus } from './workbenchAttentionModel';
Expand Down
28 changes: 0 additions & 28 deletions app/workbench/src/UnifiedComposerParts.tsx

This file was deleted.

4 changes: 2 additions & 2 deletions app/workbench/src/WorkbenchFrame.attention.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ vi.mock('./WorkbenchFrameParts', () => ({
WorkspaceLoadingState: () => <div data-testid="loading" />,
}));

vi.mock('./terminal', () => ({
vi.mock('./terminal/index', () => ({
TerminalPanel: () => <div data-testid="terminal-panel-stub" />,
}));

// The real strip would need i18n; the wiring contract is what this file pins.
vi.mock('./MainchainStatusStrip', () => ({
vi.mock('./transcript/MainchainStatusStrip', () => ({
MainchainStatusStrip: (props: {
attention?: WorkbenchAttentionCounts;
onOpenRunningQueue?: () => void;
Expand Down
4 changes: 2 additions & 2 deletions app/workbench/src/WorkbenchFrame.split.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ vi.mock('./GlobalRail', () => ({
GlobalRail: () => <div data-testid="global-rail" />,
}));

vi.mock('./MainchainStatusStrip', () => ({
vi.mock('./transcript/MainchainStatusStrip', () => ({
MainchainStatusStrip: () => <div data-testid="status-bar" />,
}));

vi.mock('./terminal', () => ({
vi.mock('./terminal/index', () => ({
TerminalPanel: () => <div data-testid="terminal-panel-stub" />,
}));

Expand Down
2 changes: 1 addition & 1 deletion app/workbench/src/WorkbenchFrame.terminalDock.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ vi.mock('./WorkbenchFrameParts', () => ({
WorkspaceLoadingState: () => <div data-testid="loading" />,
}));

vi.mock('./terminal', () => ({
vi.mock('./terminal/index', () => ({
TerminalPanel: (props: { localTerminal?: boolean; terminal?: unknown }) => (
<div
data-testid="terminal-panel-stub"
Expand Down
8 changes: 4 additions & 4 deletions app/workbench/src/WorkbenchFrame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
shouldRenderTerminalDock,
} from './workbenchFrameHelpers';
import type { WorkbenchFrameProps } from './workbenchFrameTypes';
import { sumUsageTeamTokens } from './workbenchUsageSummary';
import { sumUsageTeamTokens } from './routes/workbenchUsageSummary';
import {
buildActiveConversationAttention,
findFirstAwaitingConversationId,
Expand All @@ -27,12 +27,12 @@ import {
import { WorkbenchSplitHost } from './WorkbenchSplitHost';
import { SplitConversationPane } from './SplitConversationPane';
import { useSplitTranscriptCache } from './workbenchSplitTranscriptCache';
import { findConversationById } from './workbenchSessionChromeHelpers';
import { findConversationById } from './transcript/workbenchSessionChromeHelpers';
import type { WorkbenchSplitControls } from './workbenchFrameTypes';
import type { GroupLeaf } from './workbenchSplitLayout';
import styles from './AgentHubWorkbench.module.css';
import { TerminalPanel } from './terminal';
import { MainchainStatusStrip } from './MainchainStatusStrip';
import { TerminalPanel } from './terminal/index';
import { MainchainStatusStrip } from './transcript/MainchainStatusStrip';
import { WORKBENCH_APPROVAL_JUMP_EVENT } from './workbenchApprovalEvents';
import { firstPendingApprovalBlockId } from './workbenchApprovalSummary';
import { useExiting } from '@shared/ui/useExiting';
Expand Down
8 changes: 4 additions & 4 deletions app/workbench/src/WorkbenchFrameParts.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
/** Last ConversationHost props seen by the mock (referential-stability gate). */
const hostPropsLog = vi.hoisted(() => ({ last: null as Record<string, unknown> | null }));

vi.mock('./ConversationSidebar', () => ({
vi.mock('./transcript/ConversationSidebar', () => ({
ConversationSidebar: (props: Record<string, unknown>) => (
<div
data-active-id={props.activeConversationId as string}
Expand All @@ -34,7 +34,7 @@ vi.mock('./ConversationSidebar', () => ({
),
}));

vi.mock('./ConversationHost', () => ({
vi.mock('./transcript/ConversationHost', () => ({
ConversationHost: (props: Record<string, unknown>) => {
hostPropsLog.last = props;
return (
Expand All @@ -47,7 +47,7 @@ vi.mock('./ConversationHost', () => ({
},
}));

vi.mock('./RightInspector', () => ({
vi.mock('./inspector/RightInspector', () => ({
RightInspector: (props: Record<string, unknown>) => (
<div
data-testid="right-inspector"
Expand All @@ -59,7 +59,7 @@ vi.mock('./RightInspector', () => ({
),
}));

vi.mock('./ChatEngineeringColumn', () => ({
vi.mock('./transcript/ChatEngineeringColumn', () => ({
ChatEngineeringColumn: (props: Record<string, unknown>) => (
<div
data-testid="chat-engineering-column"
Expand Down
8 changes: 4 additions & 4 deletions app/workbench/src/WorkbenchFrameParts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import type {
ChatSidebarFrameProps,
WorkbenchRoutesFrameProps,
} from './workbenchFrameTypes';
import { ConversationHost } from './ConversationHost';
import { ConversationSidebar } from './ConversationSidebar';
import { RightInspector } from './RightInspector';
import { ChatEngineeringColumn } from './ChatEngineeringColumn';
import { ConversationHost } from './transcript/ConversationHost';
import { ConversationSidebar } from './transcript/ConversationSidebar';
import { RightInspector } from './inspector/RightInspector';
import { ChatEngineeringColumn } from './transcript/ChatEngineeringColumn';
import { WorkbenchRoutes } from './WorkbenchRoutes';
import {
SidebarResizer,
Expand Down
2 changes: 1 addition & 1 deletion app/workbench/src/WorkbenchProfileOverlays.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { ProfilePopover } from './floating';
import { ProfilePopover } from './floating/index';
import { workbenchAgentColor, workbenchProfileInitials } from './profileRegistry';
import {
agentStateLabel,
Expand Down
40 changes: 20 additions & 20 deletions app/workbench/src/WorkbenchRoutes.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import React, { useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { CHATVIEW_I18N_NAMESPACE } from '@shared/chatview/i18n/resources';
import { WorkbenchAgentsRouteView } from './WorkbenchAgentsRouteView';
import { WorkbenchContactsRouteView } from './WorkbenchContactsRouteView';
import { WorkbenchDevicesRouteView } from './WorkbenchDevicesRouteView';
import { WorkbenchDocsRouteView } from './WorkbenchDocsRouteView';
import { WorkbenchProjectsRouteView } from './WorkbenchProjectsRouteView';
import { WorkbenchSettingsRouteView } from './WorkbenchSettingsRouteView';
import { WorkbenchTasksRouteView } from './WorkbenchTasksRouteView';
import { WorkbenchUsageRouteView } from './WorkbenchUsageRouteView';
import { WorkbenchAgentsRouteView } from './routes/WorkbenchAgentsRouteView';
import { WorkbenchContactsRouteView } from './routes/WorkbenchContactsRouteView';
import { WorkbenchDevicesRouteView } from './routes/WorkbenchDevicesRouteView';
import { WorkbenchDocsRouteView } from './routes/WorkbenchDocsRouteView';
import { WorkbenchProjectsRouteView } from './routes/WorkbenchProjectsRouteView';
import { WorkbenchSettingsRouteView } from './routes/WorkbenchSettingsRouteView';
import { WorkbenchTasksRouteView } from './routes/WorkbenchTasksRouteView';
import { WorkbenchUsageRouteView } from './routes/WorkbenchUsageRouteView';
import { PageErrorBoundary } from './PageErrorBoundary';
import { useWorkbenchAgentsRoute } from './useWorkbenchAgentsRoute';
import { useWorkbenchContactsRoute } from './useWorkbenchContactsRoute';
import { useWorkbenchDocsRoute } from './useWorkbenchDocsRoute';
import { useWorkbenchProjectsRoute } from './useWorkbenchProjectsRoute';
import { useWorkbenchSettingsRoute } from './useWorkbenchSettingsRoute';
import { useWorkbenchTasksRoute } from './useWorkbenchTasksRoute';
import { useWorkbenchAgentsRoute } from './routes/useWorkbenchAgentsRoute';
import { useWorkbenchContactsRoute } from './routes/useWorkbenchContactsRoute';
import { useWorkbenchDocsRoute } from './routes/useWorkbenchDocsRoute';
import { useWorkbenchProjectsRoute } from './routes/useWorkbenchProjectsRoute';
import { useWorkbenchSettingsRoute } from './routes/useWorkbenchSettingsRoute';
import { useWorkbenchTasksRoute } from './routes/useWorkbenchTasksRoute';
import { resolveTaskQueueDemoSource } from './useWorkbenchTaskDeepLinks';
import type { WorkbenchTaskQueueSource } from './workbenchTaskDeepLinks';
import type { WorkbenchTaskQueueSource } from './routes/workbenchTaskDeepLinks';
import { buildWorkbenchProfileSources } from './workbenchProfileSources';
import type { WorkbenchRoutesProps } from './workbenchRoutesTypes';
import type { WorkbenchRoutesProps } from './routes/workbenchRoutesTypes';
import type { WorkbenchProfileSource } from './profileRegistry';
import styles from './AgentHubWorkbench.module.css';

Expand All @@ -29,10 +29,10 @@ export type {
WorkbenchAgentProfilesStatus,
WorkbenchPage,
WorkbenchRoutesProps,
} from './workbenchRoutesTypes';
export type { WorkbenchContactsActions, WorkbenchContactsData } from './useWorkbenchContactsRoute';
export type { WorkbenchDocumentsActions } from './useWorkbenchDocsRoute';
export type { WorkbenchProjectsStatus } from './useWorkbenchProjectsRoute';
} from './routes/workbenchRoutesTypes';
export type { WorkbenchContactsActions, WorkbenchContactsData } from './routes/useWorkbenchContactsRoute';
export type { WorkbenchDocumentsActions } from './routes/useWorkbenchDocsRoute';
export type { WorkbenchProjectsStatus } from './routes/useWorkbenchProjectsRoute';

/* ═══════════════════════════════════════════════════════════════════════
#21 性能:route hook 条件化(保留状态的最小方案)
Expand Down
2 changes: 1 addition & 1 deletion app/workbench/src/__tests__/inspector.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { describe, expect, it, vi } from 'vitest';
import { createMockPlatform } from '@shared/platform/createMockPlatform';
import type { TranscriptBlock } from '@shared/transcript/types';
import { AgentHubWorkbench } from '../AgentHubWorkbench';
import { RightInspector } from '../RightInspector';
import { RightInspector } from '../inspector/RightInspector';
import { DESIGN_NAV_GLYPH_STROKE_WIDTH } from '../designIcons';
import {
workbenchAgents as agents,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import {
UNAVAILABLE_ACTION_TOAST_KEY,
applyTranscriptChromeSideEffects,
type TranscriptChromeSideEffect,
} from '../workbenchTranscriptChromeActionMappers';
import type { TranscriptChromeTranslate } from '../workbenchTranscriptChromeLabels';
} from '../transcript/workbenchTranscriptChromeActionMappers';
import type { TranscriptChromeTranslate } from '../transcript/workbenchTranscriptChromeLabels';

type BundleLocale = 'zh' | 'en';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,10 @@ import {
buildAttachmentChipViewModel,
resolveAttachmentUploadProgress,
} from './ComposerPartsHelpers';
import { DesignFileIcon, DesignNavIcon } from './designIcons';
import { DesignFileIcon, DesignNavIcon } from '../designIcons';
import { isImageAttachment } from './unifiedComposerHelpers';
import type { AttachmentUploadState } from './unifiedComposerHelpers';

/* ═══════════════════════════════════════════════════════════════════════
Composer attachment bar and chip (#706).

exactOptionalPropertyTypes-safe spreads for uploadProgress.
In-chip previews: image object-URL thumbnail
(30×30, revoked on unmount), registry file icon for media, and a
CodePreviewCard (maxLines=3) for text/code files.
═══════════════════════════════════════════════════════════════════════ */

export function ComposerAttachmentBar({
attachments,
isSubmitting,
Expand Down
Loading
Loading