@yancyyu/openhermit 1.6.28 → 1.6.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-renderer/assets/ProjectEditorOverlay-CQm6jUR1.js +52 -0
- package/dist-renderer/assets/{TeamGraphOverlay-Ba5njic5.js → TeamGraphOverlay-h0WDfifv.js} +1 -1
- package/dist-renderer/assets/{_basePickBy-BvnK-OC1.js → _basePickBy-CgG_tjgX.js} +1 -1
- package/dist-renderer/assets/{_baseUniq-DmFYXx9G.js → _baseUniq-DwPTU9lP.js} +1 -1
- package/dist-renderer/assets/{arc-DX4ZQFY4.js → arc-7nIrGRzY.js} +1 -1
- package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-DfYr3vEN.js → architectureDiagram-VXUJARFQ-BYhA6Ev2.js} +1 -1
- package/dist-renderer/assets/{blockDiagram-VD42YOAC-DuXdVeWn.js → blockDiagram-VD42YOAC-BVpZUGDg.js} +1 -1
- package/dist-renderer/assets/{c4Diagram-YG6GDRKO-Bw2nixXe.js → c4Diagram-YG6GDRKO-DsdreMQ9.js} +1 -1
- package/dist-renderer/assets/channel-C0SqeFU7.js +1 -0
- package/dist-renderer/assets/{chunk-4BX2VUAB-DLiNGQoE.js → chunk-4BX2VUAB-CcoAs7Jd.js} +1 -1
- package/dist-renderer/assets/{chunk-55IACEB6-B1L_8VIF.js → chunk-55IACEB6-CGGAOoXd.js} +1 -1
- package/dist-renderer/assets/{chunk-B4BG7PRW-DaZMWKGk.js → chunk-B4BG7PRW-FhpTEPvD.js} +1 -1
- package/dist-renderer/assets/{chunk-DI55MBZ5-ku-dflJG.js → chunk-DI55MBZ5-DoYySbm1.js} +1 -1
- package/dist-renderer/assets/{chunk-FMBD7UC4-DV-mF1dP.js → chunk-FMBD7UC4-e9l2tGHG.js} +1 -1
- package/dist-renderer/assets/{chunk-QN33PNHL-ByGcDFQ0.js → chunk-QN33PNHL-DeiXVTCy.js} +1 -1
- package/dist-renderer/assets/{chunk-QZHKN3VN-7dv-Min8.js → chunk-QZHKN3VN-DC2UJLJM.js} +1 -1
- package/dist-renderer/assets/{chunk-TZMSLE5B-WdXL5fTu.js → chunk-TZMSLE5B-BHFD9eZI.js} +1 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-DWew1HpM.js +1 -0
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-DWew1HpM.js +1 -0
- package/dist-renderer/assets/clone-Dm-k63Yr.js +1 -0
- package/dist-renderer/assets/{cose-bilkent-S5V4N54A-CNcsvqPl.js → cose-bilkent-S5V4N54A-BdybQraU.js} +1 -1
- package/dist-renderer/assets/{dagre-6UL2VRFP-DBNx4qqx.js → dagre-6UL2VRFP-DdF3pwM3.js} +1 -1
- package/dist-renderer/assets/{diagram-PSM6KHXK-BfVlT6sT.js → diagram-PSM6KHXK-B9Ldd3nh.js} +1 -1
- package/dist-renderer/assets/{diagram-QEK2KX5R-HvVjs0K6.js → diagram-QEK2KX5R-XEqkrbpu.js} +1 -1
- package/dist-renderer/assets/{diagram-S2PKOQOG-DYb_KnWS.js → diagram-S2PKOQOG-CipwtY59.js} +1 -1
- package/dist-renderer/assets/{erDiagram-Q2GNP2WA-Ba-IgI5G.js → erDiagram-Q2GNP2WA-BB-2ISGo.js} +1 -1
- package/dist-renderer/assets/{flowDiagram-NV44I4VS-2iDN8Kpj.js → flowDiagram-NV44I4VS-B8XmJ0u2.js} +1 -1
- package/dist-renderer/assets/{ganttDiagram-JELNMOA3-Byjf8Fa3.js → ganttDiagram-JELNMOA3-D-8XglBb.js} +1 -1
- package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-DbKvfZ_j.js → gitGraphDiagram-V2S2FVAM-DL4ChakD.js} +1 -1
- package/dist-renderer/assets/{graph-Enirf-f8.js → graph-BiFNoBjP.js} +1 -1
- package/dist-renderer/assets/{index-AjxP_rE_.js → index-6m1ZAymG.js} +1 -1
- package/dist-renderer/assets/index-BhellmRb.css +1 -0
- package/dist-renderer/assets/{index-DY1zqsb6.js → index-BowUl0Jb.js} +540 -536
- package/dist-renderer/assets/{index-CtlzGepK.js → index-Dp3kJTEe.js} +1 -1
- package/dist-renderer/assets/{index-COZPUWJW.js → index-TOpt_T7A.js} +1 -1
- package/dist-renderer/assets/{index-DdhqolqE.js → index-qNBNjW4K.js} +1 -1
- package/dist-renderer/assets/{index-ChR1D6ZF.js → index-vAykq1H1.js} +1 -1
- package/dist-renderer/assets/{infoDiagram-HS3SLOUP-D6uicwz1.js → infoDiagram-HS3SLOUP-DRIBfHDi.js} +1 -1
- package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-DqwZsXlQ.js → journeyDiagram-XKPGCS4Q-BOMiigU4.js} +1 -1
- package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-fCDVhVUm.js → kanban-definition-3W4ZIXB7-DDxeyjod.js} +1 -1
- package/dist-renderer/assets/{layout-CPFgj98r.js → layout-DNANbrI4.js} +1 -1
- package/dist-renderer/assets/{linear-CYiQ7Y3M.js → linear-DxEJi1yT.js} +1 -1
- package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-D31dS2KE.js → mindmap-definition-VGOIOE7T-nBfGriW8.js} +1 -1
- package/dist-renderer/assets/{pieDiagram-ADFJNKIX-BOsCJfds.js → pieDiagram-ADFJNKIX-Din5j6sV.js} +1 -1
- package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-CYTVQCfr.js → quadrantDiagram-AYHSOK5B-DMVK2BEQ.js} +1 -1
- package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-CODCFpkt.js → requirementDiagram-UZGBJVZJ-6SC94Gg_.js} +1 -1
- package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-Z4ce9ZtZ.js → sankeyDiagram-TZEHDZUN-CD2gghhu.js} +1 -1
- package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-CmS9TxhW.js → sequenceDiagram-WL72ISMW-BnhkN7nZ.js} +1 -1
- package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-o9k-ns3q.js → stateDiagram-FKZM4ZOC-Bn8XdYX-.js} +1 -1
- package/dist-renderer/assets/{stateDiagram-v2-4FDKWEC3-CxHMyEt1.js → stateDiagram-v2-4FDKWEC3-1b6sI1_g.js} +1 -1
- package/dist-renderer/assets/{timeline-definition-IT6M3QCI-B6T3zrde.js → timeline-definition-IT6M3QCI-CNs3RPoa.js} +1 -1
- package/dist-renderer/assets/treemap-GDKQZRPO-DU_yr827.js +162 -0
- package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-CleBrdqc.js → xychartDiagram-PRI3JC2R-B8o5J2f3.js} +1 -1
- package/dist-renderer/index.html +2 -2
- package/package.json +1 -1
- package/src/main/server.ts +699 -179
- package/src/main/services/session-intelligence/UsageTelemetryService.ts +33 -18
- package/src/main/services/teams-mvp/CollaborationBoardService.ts +310 -0
- package/src/main/services/teams-mvp/TaskDispatchService.ts +880 -95
- package/src/main/services/teams-mvp/TeamProvisioningService.ts +58 -19
- package/src/main/services/teams-mvp/TeamWorkspaceService.ts +25 -2
- package/src/main/services/teams-mvp/index.ts +3 -0
- package/src/renderer/App.tsx +5 -0
- package/src/renderer/api/httpClient.ts +67 -0
- package/src/renderer/components/layout/PaneContent.tsx +2 -0
- package/src/renderer/components/layout/SortableTab.tsx +1 -0
- package/src/renderer/components/layout/TabBarActions.tsx +12 -12
- package/src/renderer/components/schedules/SchedulesView.tsx +54 -22
- package/src/renderer/components/settings/sections/AdvancedSection.tsx +1 -1
- package/src/renderer/components/settings/sections/TaskBusSection.tsx +129 -79
- package/src/renderer/components/tasks/TasksView.tsx +343 -0
- package/src/renderer/components/team/TeamDetailView.tsx +20 -98
- package/src/renderer/components/team/dialogs/LaunchTeamDialog.tsx +1 -1
- package/src/renderer/components/team/editor/EditorContextMenu.tsx +8 -23
- package/src/renderer/components/team/editor/EditorFileTree.tsx +0 -4
- package/src/renderer/components/team/editor/EditorSelectionMenu.tsx +1 -8
- package/src/renderer/components/team/editor/ProjectEditorOverlay.tsx +0 -10
- package/src/renderer/components/team/kanban/KanbanBoard.tsx +5 -1
- package/src/renderer/components/team/members/MemberDetailDialog.tsx +8 -33
- package/src/renderer/components/team/messages/MessageComposer.tsx +39 -3
- package/src/renderer/components/team/messages/MessagesPanel.tsx +72 -2
- package/src/renderer/components/team/messages/StatusBlock.tsx +2 -24
- package/src/renderer/components/team/schedule/ScheduleEmptyState.tsx +1 -1
- package/src/renderer/components/ui/MentionableTextarea.tsx +0 -1
- package/src/renderer/store/slices/scheduleSlice.ts +21 -0
- package/src/renderer/store/slices/teamSlice.ts +59 -23
- package/src/renderer/types/tabs.ts +1 -0
- package/src/shared/types/api.ts +29 -0
- package/src/shared/types/team.ts +104 -1
- package/dist-renderer/assets/ProjectEditorOverlay-A4DZTvSy.js +0 -57
- package/dist-renderer/assets/channel-Pre42N5O.js +0 -1
- package/dist-renderer/assets/classDiagram-2ON5EDUG-CdJsTJsj.js +0 -1
- package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-CdJsTJsj.js +0 -1
- package/dist-renderer/assets/clone-BjQBiNfj.js +0 -1
- package/dist-renderer/assets/index-BIOJremZ.css +0 -1
- package/dist-renderer/assets/treemap-GDKQZRPO-CVd5GNDw.js +0 -162
|
@@ -68,6 +68,7 @@ import {
|
|
|
68
68
|
Terminal,
|
|
69
69
|
Trash2,
|
|
70
70
|
Loader2,
|
|
71
|
+
MessageSquare,
|
|
71
72
|
Users,
|
|
72
73
|
} from 'lucide-react';
|
|
73
74
|
import { useShallow } from 'zustand/react/shallow';
|
|
@@ -1591,6 +1592,24 @@ export const TeamDetailView = ({
|
|
|
1591
1592
|
openLaunchDialog('relaunch');
|
|
1592
1593
|
}, [openLaunchDialog]);
|
|
1593
1594
|
|
|
1595
|
+
const handleStartCcConnectTeam = useCallback(() => {
|
|
1596
|
+
void (async () => {
|
|
1597
|
+
if (!data?.config.projectPath) {
|
|
1598
|
+
openLaunchDialog('launch');
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
await api.ccSettings.restart();
|
|
1602
|
+
await api.teams.launchTeam({
|
|
1603
|
+
teamName,
|
|
1604
|
+
cwd: data.config.projectPath,
|
|
1605
|
+
});
|
|
1606
|
+
window.setTimeout(() => {
|
|
1607
|
+
void fetchTeams();
|
|
1608
|
+
void selectTeam(teamName);
|
|
1609
|
+
}, 1500);
|
|
1610
|
+
})();
|
|
1611
|
+
}, [data?.config.projectPath, fetchTeams, openLaunchDialog, selectTeam, teamName]);
|
|
1612
|
+
|
|
1594
1613
|
const handleLaunchDialogSubmit = useCallback(
|
|
1595
1614
|
async (request: TeamLaunchRequest): Promise<void> => {
|
|
1596
1615
|
await launchTeam(request);
|
|
@@ -1904,11 +1923,8 @@ export const TeamDetailView = ({
|
|
|
1904
1923
|
pendingRepliesByMember,
|
|
1905
1924
|
onPendingReplyChange: setPendingRepliesByMember,
|
|
1906
1925
|
onMemberClick: handleSelectMember,
|
|
1907
|
-
onTaskClick: handleOpenTask,
|
|
1908
|
-
onCreateTaskFromMessage: handleCreateTaskFromMessage,
|
|
1909
1926
|
onReplyToMessage: handleReplyToMessage,
|
|
1910
1927
|
onRestartTeam: handleRestartTeam,
|
|
1911
|
-
onTaskIdClick: handleTaskIdClick,
|
|
1912
1928
|
inlineScrollContainerRef: contentRef,
|
|
1913
1929
|
showPositionControls: false,
|
|
1914
1930
|
}),
|
|
@@ -1917,12 +1933,9 @@ export const TeamDetailView = ({
|
|
|
1917
1933
|
data?.config.leadSessionId,
|
|
1918
1934
|
data?.isAlive,
|
|
1919
1935
|
data?.tasks,
|
|
1920
|
-
handleCreateTaskFromMessage,
|
|
1921
|
-
handleOpenTask,
|
|
1922
1936
|
handleReplyToMessage,
|
|
1923
1937
|
handleRestartTeam,
|
|
1924
1938
|
handleSelectMember,
|
|
1925
|
-
handleTaskIdClick,
|
|
1926
1939
|
pendingRepliesByMember,
|
|
1927
1940
|
teamName,
|
|
1928
1941
|
teamSessionIds,
|
|
@@ -2245,10 +2258,7 @@ export const TeamDetailView = ({
|
|
|
2245
2258
|
</div>
|
|
2246
2259
|
|
|
2247
2260
|
{!data.isAlive && !isTeamProvisioning ? (
|
|
2248
|
-
<TeamOfflineStatusBanner
|
|
2249
|
-
teamName={teamName}
|
|
2250
|
-
onLaunch={() => openLaunchDialog('launch')}
|
|
2251
|
-
/>
|
|
2261
|
+
<TeamOfflineStatusBanner teamName={teamName} onLaunch={handleStartCcConnectTeam} />
|
|
2252
2262
|
) : null}
|
|
2253
2263
|
|
|
2254
2264
|
<div ref={provisioningBannerRef}>
|
|
@@ -2276,16 +2286,12 @@ export const TeamDetailView = ({
|
|
|
2276
2286
|
<TeamMemberListBridge
|
|
2277
2287
|
teamName={teamName}
|
|
2278
2288
|
members={membersWithLiveBranches}
|
|
2279
|
-
memberTaskCounts={memberTaskCounts}
|
|
2280
|
-
taskMap={taskMap}
|
|
2281
2289
|
pendingRepliesByMember={pendingRepliesByMember}
|
|
2282
2290
|
isTeamAlive={data.isAlive}
|
|
2283
2291
|
isTeamProvisioning={isTeamProvisioning}
|
|
2284
2292
|
launchParams={launchParams}
|
|
2285
2293
|
onMemberClick={handleSelectMember}
|
|
2286
2294
|
onSendMessage={handleSendMessageToMember}
|
|
2287
|
-
onAssignTask={handleAssignTaskToMember}
|
|
2288
|
-
onOpenTask={handleOpenTaskById}
|
|
2289
2295
|
onRestartMember={handleRestartMember}
|
|
2290
2296
|
onSkipMemberForLaunch={handleSkipMemberForLaunch}
|
|
2291
2297
|
/>
|
|
@@ -2412,7 +2418,6 @@ export const TeamDetailView = ({
|
|
|
2412
2418
|
const task = data?.tasks.find((t) => t.id === taskId);
|
|
2413
2419
|
await updateTaskStatus(teamName, taskId, 'pending');
|
|
2414
2420
|
|
|
2415
|
-
// Notify assignee directly via inbox — they'll see it immediately
|
|
2416
2421
|
if (task?.owner) {
|
|
2417
2422
|
try {
|
|
2418
2423
|
await api.teams.sendMessage(teamName, {
|
|
@@ -2425,7 +2430,6 @@ export const TeamDetailView = ({
|
|
|
2425
2430
|
}
|
|
2426
2431
|
}
|
|
2427
2432
|
|
|
2428
|
-
// Also notify team lead so they can reassign/coordinate
|
|
2429
2433
|
if (data?.isAlive) {
|
|
2430
2434
|
try {
|
|
2431
2435
|
const ownerSuffix = task?.owner
|
|
@@ -2556,16 +2560,7 @@ export const TeamDetailView = ({
|
|
|
2556
2560
|
setReplyQuote(undefined);
|
|
2557
2561
|
setSendDialogOpen(true);
|
|
2558
2562
|
}}
|
|
2559
|
-
onAssignTask={() => {
|
|
2560
|
-
const name = selectedMember?.name ?? '';
|
|
2561
|
-
closeSelectedMemberDialog();
|
|
2562
|
-
openCreateTaskDialog('', '', name);
|
|
2563
|
-
}}
|
|
2564
2563
|
onRestartMember={handleRestartMember}
|
|
2565
|
-
onTaskClick={(task) => {
|
|
2566
|
-
closeSelectedMemberDialog();
|
|
2567
|
-
setSelectedTask(task);
|
|
2568
|
-
}}
|
|
2569
2564
|
onUpdateRole={async (memberName, role) => {
|
|
2570
2565
|
setUpdatingRoleLoading(true);
|
|
2571
2566
|
try {
|
|
@@ -2598,22 +2593,6 @@ export const TeamDetailView = ({
|
|
|
2598
2593
|
}}
|
|
2599
2594
|
/>
|
|
2600
2595
|
|
|
2601
|
-
<CreateTaskDialog
|
|
2602
|
-
open={createTaskDialog.open}
|
|
2603
|
-
teamName={teamName}
|
|
2604
|
-
members={activeMembers}
|
|
2605
|
-
tasks={data.tasks}
|
|
2606
|
-
isTeamAlive={data.isAlive && !isTeamProvisioning}
|
|
2607
|
-
defaultSubject={createTaskDialog.defaultSubject}
|
|
2608
|
-
defaultDescription={createTaskDialog.defaultDescription}
|
|
2609
|
-
defaultOwner={createTaskDialog.defaultOwner}
|
|
2610
|
-
defaultStartImmediately={createTaskDialog.defaultStartImmediately}
|
|
2611
|
-
defaultChip={createTaskDialog.defaultChip}
|
|
2612
|
-
onClose={closeCreateTaskDialog}
|
|
2613
|
-
onSubmit={handleCreateTask}
|
|
2614
|
-
submitting={creatingTask}
|
|
2615
|
-
/>
|
|
2616
|
-
|
|
2617
2596
|
<EditTeamDialog
|
|
2618
2597
|
open={editDialogOpen}
|
|
2619
2598
|
teamName={teamName}
|
|
@@ -2806,63 +2785,6 @@ export const TeamDetailView = ({
|
|
|
2806
2785
|
}}
|
|
2807
2786
|
/>
|
|
2808
2787
|
|
|
2809
|
-
<TaskDetailDialog
|
|
2810
|
-
open={selectedTask !== null}
|
|
2811
|
-
task={selectedTask}
|
|
2812
|
-
teamName={teamName}
|
|
2813
|
-
kanbanTaskState={
|
|
2814
|
-
selectedTask ? data?.kanbanState.tasks[selectedTask.id] : undefined
|
|
2815
|
-
}
|
|
2816
|
-
taskMap={taskMap}
|
|
2817
|
-
members={activeMembers}
|
|
2818
|
-
onClose={() => setSelectedTask(null)}
|
|
2819
|
-
onScrollToTask={(taskId) => {
|
|
2820
|
-
setSelectedTask(null);
|
|
2821
|
-
const el = document.querySelector(`[data-task-id="${taskId}"]`);
|
|
2822
|
-
if (el) {
|
|
2823
|
-
el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
2824
|
-
el.classList.remove('kanban-card-focus-pulse');
|
|
2825
|
-
void (el as HTMLElement).offsetWidth;
|
|
2826
|
-
el.classList.add('kanban-card-focus-pulse');
|
|
2827
|
-
el.addEventListener(
|
|
2828
|
-
'animationend',
|
|
2829
|
-
() => el.classList.remove('kanban-card-focus-pulse'),
|
|
2830
|
-
{ once: true }
|
|
2831
|
-
);
|
|
2832
|
-
}
|
|
2833
|
-
}}
|
|
2834
|
-
onOwnerChange={(taskId, owner) => {
|
|
2835
|
-
void (async () => {
|
|
2836
|
-
try {
|
|
2837
|
-
await updateTaskOwner(teamName, taskId, owner);
|
|
2838
|
-
} catch {
|
|
2839
|
-
// error via store
|
|
2840
|
-
}
|
|
2841
|
-
})();
|
|
2842
|
-
}}
|
|
2843
|
-
onViewChanges={handleViewChangesForFile}
|
|
2844
|
-
onOpenInEditor={(filePath) => {
|
|
2845
|
-
const { revealFileInEditor } = useStore.getState();
|
|
2846
|
-
revealFileInEditor(filePath);
|
|
2847
|
-
}}
|
|
2848
|
-
onDeleteTask={handleDeleteTask}
|
|
2849
|
-
/>
|
|
2850
|
-
|
|
2851
|
-
<TrashDialog
|
|
2852
|
-
open={trashOpen}
|
|
2853
|
-
tasks={deletedTasks}
|
|
2854
|
-
onClose={() => setTrashOpen(false)}
|
|
2855
|
-
onRestore={(taskId) => {
|
|
2856
|
-
void (async () => {
|
|
2857
|
-
try {
|
|
2858
|
-
await restoreTask(teamName, taskId);
|
|
2859
|
-
} catch {
|
|
2860
|
-
// error via store
|
|
2861
|
-
}
|
|
2862
|
-
})();
|
|
2863
|
-
}}
|
|
2864
|
-
/>
|
|
2865
|
-
|
|
2866
2788
|
<ChangeReviewDialog
|
|
2867
2789
|
open={reviewDialogState.open}
|
|
2868
2790
|
onOpenChange={(open) =>
|
|
@@ -2058,7 +2058,7 @@ export const LaunchTeamDialog = (props: LaunchTeamDialogProps): React.JSX.Elemen
|
|
|
2058
2058
|
) : effectiveTeamName ? (
|
|
2059
2059
|
`为团队“${effectiveTeamName}”创建自动运行计划`
|
|
2060
2060
|
) : (
|
|
2061
|
-
'
|
|
2061
|
+
'创建团队自动运行计划'
|
|
2062
2062
|
);
|
|
2063
2063
|
|
|
2064
2064
|
const submitLabel = isLaunchMode
|
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
FilePlus,
|
|
17
17
|
FolderOpen,
|
|
18
18
|
FolderPlus,
|
|
19
|
-
ListTodo,
|
|
20
19
|
MessageSquare,
|
|
21
20
|
Pencil,
|
|
22
21
|
Trash2,
|
|
@@ -39,8 +38,6 @@ interface EditorContextMenuProps {
|
|
|
39
38
|
onNewFolder: (parentDir: string) => void;
|
|
40
39
|
onDelete: (path: string) => void;
|
|
41
40
|
onRename: (path: string) => void;
|
|
42
|
-
/** Trigger "Create Task" with a file mention (files only, not directories) */
|
|
43
|
-
onCreateTask?: (filePath: string) => void;
|
|
44
41
|
/** Trigger "Write Teammate" with a file mention (files only, not directories) */
|
|
45
42
|
onSendMessage?: (filePath: string) => void;
|
|
46
43
|
}
|
|
@@ -56,7 +53,6 @@ export const EditorContextMenu = ({
|
|
|
56
53
|
onNewFolder,
|
|
57
54
|
onDelete,
|
|
58
55
|
onRename,
|
|
59
|
-
onCreateTask,
|
|
60
56
|
onSendMessage,
|
|
61
57
|
}: EditorContextMenuProps): React.ReactElement => {
|
|
62
58
|
const [target, setTarget] = useState<TargetEntry | null>(null);
|
|
@@ -183,27 +179,16 @@ export const EditorContextMenu = ({
|
|
|
183
179
|
)}
|
|
184
180
|
|
|
185
181
|
{/* Team actions — file only */}
|
|
186
|
-
{target && !target.isDir &&
|
|
182
|
+
{target && !target.isDir && onSendMessage && (
|
|
187
183
|
<>
|
|
188
184
|
<ContextMenu.Separator className="my-1 h-px bg-border" />
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
</ContextMenu.Item>
|
|
197
|
-
)}
|
|
198
|
-
{onCreateTask && (
|
|
199
|
-
<ContextMenu.Item
|
|
200
|
-
className="flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-xs text-text outline-none hover:bg-surface-raised focus:bg-surface-raised"
|
|
201
|
-
onSelect={() => onCreateTask(target.path)}
|
|
202
|
-
>
|
|
203
|
-
<ListTodo className="size-3.5 text-text-muted" />
|
|
204
|
-
Create Task
|
|
205
|
-
</ContextMenu.Item>
|
|
206
|
-
)}
|
|
185
|
+
<ContextMenu.Item
|
|
186
|
+
className="flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 text-xs text-text outline-none hover:bg-surface-raised focus:bg-surface-raised"
|
|
187
|
+
onSelect={() => onSendMessage(target.path)}
|
|
188
|
+
>
|
|
189
|
+
<MessageSquare className="size-3.5 text-text-muted" />
|
|
190
|
+
Write Teammate
|
|
191
|
+
</ContextMenu.Item>
|
|
207
192
|
</>
|
|
208
193
|
)}
|
|
209
194
|
</ContextMenu.Content>
|
|
@@ -54,8 +54,6 @@ import type { FileTreeEntry, GitFileStatusType } from '@shared/types/editor';
|
|
|
54
54
|
interface EditorFileTreeProps {
|
|
55
55
|
selectedFilePath: string | null;
|
|
56
56
|
onFileSelect: (filePath: string) => void;
|
|
57
|
-
/** Trigger "Create Task" with a file mention from context menu */
|
|
58
|
-
onCreateTask?: (filePath: string) => void;
|
|
59
57
|
/** Trigger "Write Teammate" with a file mention from context menu */
|
|
60
58
|
onSendMessage?: (filePath: string) => void;
|
|
61
59
|
}
|
|
@@ -91,7 +89,6 @@ let fileTreeRenderCount = 0;
|
|
|
91
89
|
export const EditorFileTree = ({
|
|
92
90
|
selectedFilePath,
|
|
93
91
|
onFileSelect,
|
|
94
|
-
onCreateTask,
|
|
95
92
|
onSendMessage,
|
|
96
93
|
}: EditorFileTreeProps): React.ReactElement => {
|
|
97
94
|
fileTreeRenderCount++;
|
|
@@ -452,7 +449,6 @@ export const EditorFileTree = ({
|
|
|
452
449
|
onNewFolder={handleNewFolder}
|
|
453
450
|
onDelete={handleDelete}
|
|
454
451
|
onRename={handleRename}
|
|
455
|
-
onCreateTask={onCreateTask}
|
|
456
452
|
onSendMessage={onSendMessage}
|
|
457
453
|
>
|
|
458
454
|
<DndContext
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { Button } from '@renderer/components/ui/button';
|
|
9
9
|
import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip';
|
|
10
|
-
import {
|
|
10
|
+
import { MessageSquare } from 'lucide-react';
|
|
11
11
|
|
|
12
12
|
import type { EditorSelectionInfo } from '@shared/types/editor';
|
|
13
13
|
|
|
@@ -20,7 +20,6 @@ interface EditorSelectionMenuProps {
|
|
|
20
20
|
/** Bounding rect of the editor content container (for viewport → container conversion) */
|
|
21
21
|
containerRect: DOMRect;
|
|
22
22
|
onSendMessage: () => void;
|
|
23
|
-
onCreateTask: () => void;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
// =============================================================================
|
|
@@ -39,7 +38,6 @@ export const EditorSelectionMenu = ({
|
|
|
39
38
|
info,
|
|
40
39
|
containerRect,
|
|
41
40
|
onSendMessage,
|
|
42
|
-
onCreateTask,
|
|
43
41
|
}: EditorSelectionMenuProps): React.ReactElement | null => {
|
|
44
42
|
if (!info.text.trim()) return null;
|
|
45
43
|
|
|
@@ -71,11 +69,6 @@ export const EditorSelectionMenu = ({
|
|
|
71
69
|
label="Write Teammate"
|
|
72
70
|
onClick={onSendMessage}
|
|
73
71
|
/>
|
|
74
|
-
<MenuButton
|
|
75
|
-
icon={<ListTodo className="size-3.5" />}
|
|
76
|
-
label="Create Task"
|
|
77
|
-
onClick={onCreateTask}
|
|
78
|
-
/>
|
|
79
72
|
</div>
|
|
80
73
|
);
|
|
81
74
|
};
|
|
@@ -628,12 +628,6 @@ export const ProjectEditorOverlay = ({
|
|
|
628
628
|
<EditorFileTree
|
|
629
629
|
selectedFilePath={activeTabId}
|
|
630
630
|
onFileSelect={handleFileSelect}
|
|
631
|
-
onCreateTask={
|
|
632
|
-
onEditorAction
|
|
633
|
-
? (filePath: string) =>
|
|
634
|
-
onEditorAction(buildFileAction('createTask', filePath, projectPath))
|
|
635
|
-
: undefined
|
|
636
|
-
}
|
|
637
631
|
onSendMessage={
|
|
638
632
|
onEditorAction
|
|
639
633
|
? (filePath: string) =>
|
|
@@ -829,10 +823,6 @@ export const ProjectEditorOverlay = ({
|
|
|
829
823
|
onEditorAction(buildSelectionAction('sendMessage', selectionInfo));
|
|
830
824
|
setSelectionInfo(null);
|
|
831
825
|
}}
|
|
832
|
-
onCreateTask={() => {
|
|
833
|
-
onEditorAction(buildSelectionAction('createTask', selectionInfo));
|
|
834
|
-
setSelectionInfo(null);
|
|
835
|
-
}}
|
|
836
826
|
/>
|
|
837
827
|
)}
|
|
838
828
|
</div>
|
|
@@ -274,7 +274,11 @@ export const KanbanBoard = ({
|
|
|
274
274
|
}: KanbanBoardProps): React.JSX.Element => {
|
|
275
275
|
const boardRef = useRef<HTMLDivElement>(null);
|
|
276
276
|
const scrollRestoreTimeoutsRef = useRef<number[]>([]);
|
|
277
|
-
const [viewMode, setViewMode] = useState<KanbanViewMode>('
|
|
277
|
+
const [viewMode, setViewMode] = useState<KanbanViewMode>('columns');
|
|
278
|
+
|
|
279
|
+
useEffect(() => {
|
|
280
|
+
setViewMode('columns');
|
|
281
|
+
}, []);
|
|
278
282
|
const enableTaskSorting =
|
|
279
283
|
viewMode === 'columns' && !!onColumnOrderChange && sort.field === 'manual';
|
|
280
284
|
|
|
@@ -26,7 +26,6 @@ import { type MemberActivityFilter, type MemberDetailTab } from './memberDetailT
|
|
|
26
26
|
import { MemberLaunchDiagnosticsButton } from './MemberLaunchDiagnosticsButton';
|
|
27
27
|
import { MemberMessagesTab } from './MemberMessagesTab';
|
|
28
28
|
import { MemberStatsTab } from './MemberStatsTab';
|
|
29
|
-
import { MemberTasksTab } from './MemberTasksTab';
|
|
30
29
|
import { MemberWorkspaceTab } from './MemberWorkspaceTab';
|
|
31
30
|
|
|
32
31
|
import type { TeamLaunchParams } from '@renderer/store/slices/teamSlice';
|
|
@@ -56,8 +55,10 @@ interface MemberDetailDialogProps {
|
|
|
56
55
|
launchParams?: TeamLaunchParams;
|
|
57
56
|
onClose: () => void;
|
|
58
57
|
onSendMessage: () => void;
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
/** Deprecated: team tasks UI has been removed, kept for compatibility with older callers/tests. */
|
|
59
|
+
onAssignTask?: () => void;
|
|
60
|
+
/** Deprecated: team tasks UI has been removed, kept for compatibility with older callers/tests. */
|
|
61
|
+
onTaskClick?: (task: TeamTaskWithKanban) => void;
|
|
61
62
|
onRemoveMember?: () => void;
|
|
62
63
|
onRestartMember?: (memberName: string) => Promise<void> | void;
|
|
63
64
|
onUpdateRole?: (memberName: string, role: string | undefined) => Promise<void> | void;
|
|
@@ -83,18 +84,12 @@ export const MemberDetailDialog = ({
|
|
|
83
84
|
launchParams,
|
|
84
85
|
onClose,
|
|
85
86
|
onSendMessage,
|
|
86
|
-
onAssignTask,
|
|
87
|
-
onTaskClick,
|
|
88
87
|
onRemoveMember,
|
|
89
88
|
onRestartMember,
|
|
90
89
|
onUpdateRole,
|
|
91
90
|
updatingRole,
|
|
92
91
|
onViewMemberChanges,
|
|
93
92
|
}: MemberDetailDialogProps): React.JSX.Element | null => {
|
|
94
|
-
const memberTasks = useMemo(
|
|
95
|
-
() => (member ? tasks.filter((t) => t.owner === member.name) : []),
|
|
96
|
-
[tasks, member]
|
|
97
|
-
);
|
|
98
93
|
const memberMessages = useStore((state) =>
|
|
99
94
|
selectMemberMessagesForTeamMember(state, teamName, member?.name ?? null)
|
|
100
95
|
);
|
|
@@ -111,17 +106,9 @@ export const MemberDetailDialog = ({
|
|
|
111
106
|
}).length;
|
|
112
107
|
}, [member, memberMessages, members, tasks, teamName]);
|
|
113
108
|
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
[memberTasks]
|
|
117
|
-
);
|
|
118
|
-
|
|
119
|
-
const completedTasks = useMemo(
|
|
120
|
-
() => memberTasks.filter((t) => t.status === 'completed').length,
|
|
121
|
-
[memberTasks]
|
|
109
|
+
const [activeTab, setActiveTab] = useState<MemberDetailTab>(
|
|
110
|
+
initialTab === 'tasks' ? 'workspace' : initialTab
|
|
122
111
|
);
|
|
123
|
-
|
|
124
|
-
const [activeTab, setActiveTab] = useState<MemberDetailTab>(initialTab);
|
|
125
112
|
const [restarting, setRestarting] = useState(false);
|
|
126
113
|
const [restartError, setRestartError] = useState<string | null>(null);
|
|
127
114
|
|
|
@@ -202,8 +189,8 @@ export const MemberDetailDialog = ({
|
|
|
202
189
|
</DialogHeader>
|
|
203
190
|
|
|
204
191
|
<MemberDetailStats
|
|
205
|
-
totalTasks={
|
|
206
|
-
inProgressTasks={
|
|
192
|
+
totalTasks={0}
|
|
193
|
+
inProgressTasks={0}
|
|
207
194
|
totalTokens={totalTokens}
|
|
208
195
|
statsLoading={statsLoading}
|
|
209
196
|
statsComputedAt={memberStats?.computedAt}
|
|
@@ -217,14 +204,6 @@ export const MemberDetailDialog = ({
|
|
|
217
204
|
className="min-w-0 overflow-hidden"
|
|
218
205
|
>
|
|
219
206
|
<TabsList className="w-full">
|
|
220
|
-
<TabsTrigger value="tasks" className="flex-1 gap-1.5">
|
|
221
|
-
Tasks
|
|
222
|
-
{memberTasks.length > 0 && (
|
|
223
|
-
<span className="rounded-full bg-[var(--color-surface)] px-1.5 text-[10px]">
|
|
224
|
-
{memberTasks.length}
|
|
225
|
-
</span>
|
|
226
|
-
)}
|
|
227
|
-
</TabsTrigger>
|
|
228
207
|
<TabsTrigger value="workspace" className="flex-1 gap-1.5">
|
|
229
208
|
<FolderOpen size={12} />
|
|
230
209
|
Workspace
|
|
@@ -242,9 +221,6 @@ export const MemberDetailDialog = ({
|
|
|
242
221
|
Stats
|
|
243
222
|
</TabsTrigger>
|
|
244
223
|
</TabsList>
|
|
245
|
-
<TabsContent value="tasks">
|
|
246
|
-
<MemberTasksTab tasks={memberTasks} onTaskClick={onTaskClick} />
|
|
247
|
-
</TabsContent>
|
|
248
224
|
<TabsContent value="workspace">
|
|
249
225
|
<MemberWorkspaceTab
|
|
250
226
|
teamName={teamName}
|
|
@@ -260,7 +236,6 @@ export const MemberDetailDialog = ({
|
|
|
260
236
|
members={members}
|
|
261
237
|
tasks={tasks}
|
|
262
238
|
initialFilter={initialActivityFilter}
|
|
263
|
-
onTaskClick={onTaskClick}
|
|
264
239
|
/>
|
|
265
240
|
</TabsContent>
|
|
266
241
|
<TabsContent value="stats">
|
|
@@ -69,6 +69,11 @@ interface MessageComposerProps {
|
|
|
69
69
|
actionMode?: AgentActionMode,
|
|
70
70
|
taskRefs?: TaskRef[]
|
|
71
71
|
) => void;
|
|
72
|
+
onDispatchTask?: (
|
|
73
|
+
toTeam: string,
|
|
74
|
+
subject: string,
|
|
75
|
+
description: string
|
|
76
|
+
) => Promise<boolean | void> | boolean | void;
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
export const MessageComposer = ({
|
|
@@ -86,6 +91,7 @@ export const MessageComposer = ({
|
|
|
86
91
|
onSessionChange,
|
|
87
92
|
textareaRef: externalTextareaRef,
|
|
88
93
|
onSend,
|
|
94
|
+
onDispatchTask,
|
|
89
95
|
}: MessageComposerProps): React.JSX.Element => {
|
|
90
96
|
const internalTextareaRef = useRef<HTMLTextAreaElement>(null);
|
|
91
97
|
const textareaRef = useMemo(() => {
|
|
@@ -223,7 +229,26 @@ export const MessageComposer = ({
|
|
|
223
229
|
? '斜杠命令需要团队负责人在线'
|
|
224
230
|
: null
|
|
225
231
|
: null;
|
|
226
|
-
const
|
|
232
|
+
const teamDispatch = useMemo(() => {
|
|
233
|
+
const match = trimmed.match(/^@([^\s]+)\s+([\s\S]+)$/);
|
|
234
|
+
if (!match || !onDispatchTask) return null;
|
|
235
|
+
const mentioned = match[1];
|
|
236
|
+
const subject = match[2]?.trim();
|
|
237
|
+
if (!mentioned || !subject) return null;
|
|
238
|
+
const targetTeam = teamMentionSuggestions.find((team) => {
|
|
239
|
+
const slug = team.id.startsWith('team:') ? team.id.slice('team:'.length) : team.id;
|
|
240
|
+
return slug === mentioned || team.name === mentioned;
|
|
241
|
+
});
|
|
242
|
+
const slug = targetTeam
|
|
243
|
+
? targetTeam.id.startsWith('team:')
|
|
244
|
+
? targetTeam.id.slice('team:'.length)
|
|
245
|
+
: targetTeam.id
|
|
246
|
+
: mentioned;
|
|
247
|
+
return { slug, subject };
|
|
248
|
+
}, [onDispatchTask, teamMentionSuggestions, trimmed]);
|
|
249
|
+
const canDispatchToTeam =
|
|
250
|
+
teamDispatch !== null && trimmed.length > 0 && trimmed.length <= MAX_TEXT_LENGTH && !sending;
|
|
251
|
+
const canSendRegularMessage =
|
|
227
252
|
recipient.length > 0 &&
|
|
228
253
|
trimmed.length > 0 &&
|
|
229
254
|
trimmed.length <= MAX_TEXT_LENGTH &&
|
|
@@ -231,6 +256,7 @@ export const MessageComposer = ({
|
|
|
231
256
|
!isProvisioning &&
|
|
232
257
|
!attachmentsBlocked &&
|
|
233
258
|
!slashCommandRestrictionReason;
|
|
259
|
+
const canSend = canDispatchToTeam || canSendRegularMessage;
|
|
234
260
|
|
|
235
261
|
// Track whether we initiated a send — clear draft only on confirmed success
|
|
236
262
|
const pendingSendRef = useRef(false);
|
|
@@ -238,9 +264,19 @@ export const MessageComposer = ({
|
|
|
238
264
|
const handleSend = useCallback(() => {
|
|
239
265
|
if (!canSend) return;
|
|
240
266
|
dismissMentionsRef.current?.();
|
|
241
|
-
pendingSendRef.current = true;
|
|
242
267
|
const taskRefs = extractTaskRefsFromText(draft.text, taskSuggestions);
|
|
243
268
|
const serialized = serializeChipsWithText(trimmed, draft.chips);
|
|
269
|
+
|
|
270
|
+
if (teamDispatch && onDispatchTask) {
|
|
271
|
+
void Promise.resolve(
|
|
272
|
+
onDispatchTask(teamDispatch.slug, teamDispatch.subject, serialized)
|
|
273
|
+
).then((dispatched) => {
|
|
274
|
+
if (dispatched !== false) draft.clearDraft();
|
|
275
|
+
});
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
pendingSendRef.current = true;
|
|
244
280
|
onSend(
|
|
245
281
|
recipient,
|
|
246
282
|
serialized,
|
|
@@ -249,7 +285,7 @@ export const MessageComposer = ({
|
|
|
249
285
|
undefined,
|
|
250
286
|
taskRefs
|
|
251
287
|
);
|
|
252
|
-
}, [canSend, recipient, trimmed, onSend, draft
|
|
288
|
+
}, [canSend, recipient, trimmed, onSend, draft, taskSuggestions, teamDispatch, onDispatchTask]);
|
|
253
289
|
|
|
254
290
|
// Clear draft only after send completes successfully (sending: true → false, no error)
|
|
255
291
|
useEffect(() => {
|