@yancyyu/openhermit 1.5.8 → 1.5.9

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.
Files changed (105) hide show
  1. package/README.md +10 -1
  2. package/dist-renderer/assets/{ProjectEditorOverlay-BNoDw9T1.js → ProjectEditorOverlay-C5D83Zxv.js} +1 -1
  3. package/dist-renderer/assets/{TeamGraphOverlay-CfGRKQIu.js → TeamGraphOverlay-ajzuM1-u.js} +1 -1
  4. package/dist-renderer/assets/{_basePickBy-Ct8Hm5_h.js → _basePickBy-C9H2zmVj.js} +1 -1
  5. package/dist-renderer/assets/{_baseUniq-BofrAFBx.js → _baseUniq-CpGZGemc.js} +1 -1
  6. package/dist-renderer/assets/{arc-AbJgatzR.js → arc-CbGBDw-m.js} +1 -1
  7. package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-gpniCJVk.js → architectureDiagram-VXUJARFQ-nuKXUIpb.js} +1 -1
  8. package/dist-renderer/assets/{blockDiagram-VD42YOAC-aBbbmONC.js → blockDiagram-VD42YOAC-DHUUE7Jc.js} +1 -1
  9. package/dist-renderer/assets/{c4Diagram-YG6GDRKO-DJio1IsU.js → c4Diagram-YG6GDRKO-OILHhqLM.js} +1 -1
  10. package/dist-renderer/assets/channel-DpUKLLrj.js +1 -0
  11. package/dist-renderer/assets/{chunk-4BX2VUAB-D1_HKao2.js → chunk-4BX2VUAB-dqNpZaQ8.js} +1 -1
  12. package/dist-renderer/assets/{chunk-55IACEB6-NAmVxF4k.js → chunk-55IACEB6-BCoSJQM-.js} +1 -1
  13. package/dist-renderer/assets/{chunk-B4BG7PRW-Ce829laz.js → chunk-B4BG7PRW-BLbg8yVR.js} +1 -1
  14. package/dist-renderer/assets/{chunk-DI55MBZ5-Ct2Le12y.js → chunk-DI55MBZ5-CUUWOs1Q.js} +1 -1
  15. package/dist-renderer/assets/{chunk-FMBD7UC4-Cie3DzKk.js → chunk-FMBD7UC4-D9geTN5P.js} +1 -1
  16. package/dist-renderer/assets/{chunk-QN33PNHL-4f5Yb50e.js → chunk-QN33PNHL-BGT8-BRX.js} +1 -1
  17. package/dist-renderer/assets/{chunk-QZHKN3VN-D9ranl9c.js → chunk-QZHKN3VN-CC8ebGaM.js} +1 -1
  18. package/dist-renderer/assets/{chunk-TZMSLE5B-bdGZWlEy.js → chunk-TZMSLE5B-CajekcT6.js} +1 -1
  19. package/dist-renderer/assets/classDiagram-2ON5EDUG-LL85aSlz.js +1 -0
  20. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-LL85aSlz.js +1 -0
  21. package/dist-renderer/assets/clone-BHWsFzFA.js +1 -0
  22. package/dist-renderer/assets/{cose-bilkent-S5V4N54A-C6tvfcVi.js → cose-bilkent-S5V4N54A-C_x7hSy3.js} +1 -1
  23. package/dist-renderer/assets/{dagre-6UL2VRFP-B-4qcZam.js → dagre-6UL2VRFP-C4Y1k4DZ.js} +1 -1
  24. package/dist-renderer/assets/{diagram-PSM6KHXK-CwT3TLjx.js → diagram-PSM6KHXK-oRIeULoh.js} +1 -1
  25. package/dist-renderer/assets/{diagram-QEK2KX5R-BWH6-ZFd.js → diagram-QEK2KX5R-DwSqw5HF.js} +1 -1
  26. package/dist-renderer/assets/{diagram-S2PKOQOG-DfpPnfi1.js → diagram-S2PKOQOG-DqjGYje2.js} +1 -1
  27. package/dist-renderer/assets/{erDiagram-Q2GNP2WA-BFbEFR4x.js → erDiagram-Q2GNP2WA-CEV5bBgg.js} +1 -1
  28. package/dist-renderer/assets/{flowDiagram-NV44I4VS-Dg3cf5hW.js → flowDiagram-NV44I4VS-BQQkrRyu.js} +1 -1
  29. package/dist-renderer/assets/{ganttDiagram-JELNMOA3-B21y55W5.js → ganttDiagram-JELNMOA3-CLy4WR1G.js} +1 -1
  30. package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-BDV3BJzn.js → gitGraphDiagram-V2S2FVAM-6W3ioQu_.js} +1 -1
  31. package/dist-renderer/assets/{graph-BfaZ4hZt.js → graph-BnLKQvhH.js} +1 -1
  32. package/dist-renderer/assets/{index-CCqtDawH.js → index-B4aiRxoU.js} +1 -1
  33. package/dist-renderer/assets/{index-pMg_LlsS.js → index-B8lKqPVq.js} +1 -1
  34. package/dist-renderer/assets/{index-CZltVMDP.js → index-BRuhNKyU.js} +12 -12
  35. package/dist-renderer/assets/{index-BMXHMpkG.js → index-BufvLVIl.js} +1 -1
  36. package/dist-renderer/assets/{index-Ct0-y9TF.js → index-C1xShqKH.js} +1 -1
  37. package/dist-renderer/assets/{index-CVMSpK8C.js → index-zIOLLI7O.js} +1 -1
  38. package/dist-renderer/assets/{infoDiagram-HS3SLOUP-DvMlS0CL.js → infoDiagram-HS3SLOUP-BoBweEEY.js} +1 -1
  39. package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-DIyMluRv.js → journeyDiagram-XKPGCS4Q-DLL0V5oP.js} +1 -1
  40. package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-CVOx8f-7.js → kanban-definition-3W4ZIXB7-HsFtEDG3.js} +1 -1
  41. package/dist-renderer/assets/{layout-BPKIXUf4.js → layout-ClIooAAq.js} +1 -1
  42. package/dist-renderer/assets/{linear-CScZGLr2.js → linear-r3RJcj8y.js} +1 -1
  43. package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-CmDQ7Wo6.js → mindmap-definition-VGOIOE7T-BA_P1U4V.js} +1 -1
  44. package/dist-renderer/assets/{pieDiagram-ADFJNKIX-DbVClin-.js → pieDiagram-ADFJNKIX-CzPAfkTB.js} +1 -1
  45. package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-CAB0MYcW.js → quadrantDiagram-AYHSOK5B-PvdPWzFJ.js} +1 -1
  46. package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-w2Lfpg3T.js → requirementDiagram-UZGBJVZJ-CHqIL_Od.js} +1 -1
  47. package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-kvG1QoKY.js → sankeyDiagram-TZEHDZUN-ConzpACM.js} +1 -1
  48. package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-DCVBQ23J.js → sequenceDiagram-WL72ISMW-Zryq4oxP.js} +1 -1
  49. package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-ItZ0JBvq.js → stateDiagram-FKZM4ZOC-BA9V7NHF.js} +1 -1
  50. package/dist-renderer/assets/{stateDiagram-v2-4FDKWEC3-Hpmw4dMm.js → stateDiagram-v2-4FDKWEC3-CGnaujD-.js} +1 -1
  51. package/dist-renderer/assets/{timeline-definition-IT6M3QCI-BzSFaAjV.js → timeline-definition-IT6M3QCI-DPs2ZjMm.js} +1 -1
  52. package/dist-renderer/assets/{treemap-GDKQZRPO-fSz4hQn0.js → treemap-GDKQZRPO-B0lzrLxb.js} +1 -1
  53. package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-CT1kaGlv.js → xychartDiagram-PRI3JC2R-CINGmMxX.js} +1 -1
  54. package/dist-renderer/index.html +1 -1
  55. package/package.json +2 -1
  56. package/src/main/server.ts +993 -764
  57. package/src/main/services/UpdateService.ts +4 -1
  58. package/src/main/services/ccConnect/CcConnectBridge.ts +1 -8
  59. package/src/main/services/ccConnect/CcConnectClient.ts +7 -2
  60. package/src/main/services/teams-mvp/TeamProvisioningService.ts +14 -4
  61. package/src/main/services/teams-mvp/TeamWorkspaceService.ts +11 -6
  62. package/src/renderer/App.tsx +18 -7
  63. package/src/renderer/api/httpClient.ts +136 -42
  64. package/src/renderer/components/chat/ChatHistory.tsx +11 -8
  65. package/src/renderer/components/dashboard/DashboardView.tsx +4 -2
  66. package/src/renderer/components/extensions/ExtensionStoreView.tsx +2 -7
  67. package/src/renderer/components/layout/Sidebar.tsx +3 -1
  68. package/src/renderer/components/schedules/SchedulesView.tsx +15 -13
  69. package/src/renderer/components/settings/SettingsTabs.tsx +2 -1
  70. package/src/renderer/components/settings/hooks/useSettingsHandlers.ts +4 -5
  71. package/src/renderer/components/settings/sections/AdvancedSection.tsx +19 -4
  72. package/src/renderer/components/settings/sections/CliStatusSection.tsx +63 -59
  73. package/src/renderer/components/settings/sections/GeneralSection.tsx +5 -11
  74. package/src/renderer/components/settings/sections/HarnessSection.tsx +30 -15
  75. package/src/renderer/components/settings/sections/PlatformsSection.tsx +110 -51
  76. package/src/renderer/components/sidebar/SidebarSessions.tsx +100 -67
  77. package/src/renderer/components/sidebar/WorkspaceBrowser.tsx +26 -43
  78. package/src/renderer/components/team/CcSessionsSection.tsx +34 -14
  79. package/src/renderer/components/team/TeamDetailView.tsx +150 -148
  80. package/src/renderer/components/team/TeamEmptyState.tsx +27 -16
  81. package/src/renderer/components/team/TeamListView.tsx +4 -2
  82. package/src/renderer/components/team/activity/ActivityItem.tsx +6 -1
  83. package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +282 -75
  84. package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +2 -1
  85. package/src/renderer/components/team/dialogs/PlatformManualForm.tsx +64 -21
  86. package/src/renderer/components/team/dialogs/PlatformSetupQR.tsx +68 -19
  87. package/src/renderer/components/team/dialogs/ProjectPathSelector.tsx +20 -16
  88. package/src/renderer/components/team/dialogs/platformMeta.ts +66 -11
  89. package/src/renderer/components/team/editor/EditorFileTree.tsx +9 -7
  90. package/src/renderer/components/team/kanban/KanbanBoard.tsx +7 -10
  91. package/src/renderer/components/team/kanban/KanbanTaskCard.tsx +1 -3
  92. package/src/renderer/components/team/members/MemberDetailDialog.tsx +1 -5
  93. package/src/renderer/components/team/messages/MessageComposer.tsx +3 -1
  94. package/src/renderer/components/team/messages/MessagesPanel.tsx +34 -26
  95. package/src/renderer/components/team/schedule/CcCronScheduleDialog.tsx +1 -3
  96. package/src/renderer/components/team/schedule/ScheduleSection.tsx +9 -10
  97. package/src/renderer/store/slices/scheduleSlice.ts +4 -1
  98. package/src/renderer/store/slices/teamSlice.ts +3 -1
  99. package/src/shared/types/api.ts +70 -21
  100. package/src/shared/utils/leadDetection.ts +5 -1
  101. package/tsconfig.json +26 -0
  102. package/dist-renderer/assets/channel-CZ8sd5Xf.js +0 -1
  103. package/dist-renderer/assets/classDiagram-2ON5EDUG-CMcfSKj5.js +0 -1
  104. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-CMcfSKj5.js +0 -1
  105. package/dist-renderer/assets/clone-CMuwA8RV.js +0 -1
@@ -13,7 +13,17 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
13
13
  import { api } from '@renderer/api';
14
14
  import { useStore } from '@renderer/store';
15
15
  import { formatDistanceToNowStrict } from 'date-fns';
16
- import { AlertCircle, ChevronDown, ChevronRight, Loader2, MessageSquare, Radio, RefreshCw, Search, X } from 'lucide-react';
16
+ import {
17
+ AlertCircle,
18
+ ChevronDown,
19
+ ChevronRight,
20
+ Loader2,
21
+ MessageSquare,
22
+ Radio,
23
+ RefreshCw,
24
+ Search,
25
+ X,
26
+ } from 'lucide-react';
17
27
 
18
28
  import type { CcSession, CcSessionDetail, TeamSummary } from '@shared/types';
19
29
 
@@ -55,50 +65,53 @@ export const SidebarSessions = (): React.JSX.Element => {
55
65
  // 优先使用当前激活的团队 Tab,避免 selectedTeamName 在多标签下滞后导致串团队。
56
66
  const scopedTeamName = activeTeamTabName ?? selectedTeamName ?? null;
57
67
 
58
- const fetchAll = useCallback(async (opts: { silent?: boolean } = {}) => {
59
- if (refreshInFlightRef.current) return;
60
- const { silent = false } = opts;
61
- refreshInFlightRef.current = true;
62
- if (!silent) {
63
- setLoading(true);
64
- }
65
- setError(null);
66
- try {
67
- const teamList = await api.teams.list();
68
- const scopedTeams: TeamSummary[] = scopedTeamName
69
- ? teamList.filter((team) => team.teamName === scopedTeamName)
70
- : teamList;
71
-
72
- const results = await Promise.allSettled(
73
- scopedTeams.map(async (t) => {
74
- try {
75
- const sessions = await api.teams.getTeamSessions(t.teamName);
76
- return sessions.map((s) => ({
77
- ...s,
78
- teamName: t.teamName,
79
- teamDisplayName: t.displayName || t.teamName,
80
- }));
81
- } catch {
82
- return [] as TaggedSession[];
83
- }
84
- })
85
- );
86
-
87
- const merged: TaggedSession[] = [];
88
- for (const r of results) {
89
- if (r.status === 'fulfilled') merged.push(...r.value);
90
- }
91
- setAllSessions(merged);
92
- setExpandedId((prev) => (prev && merged.some((s) => s.id === prev) ? prev : null));
93
- } catch (err) {
94
- setError(err instanceof Error ? err.message : '加载失败');
95
- } finally {
96
- refreshInFlightRef.current = false;
68
+ const fetchAll = useCallback(
69
+ async (opts: { silent?: boolean } = {}) => {
70
+ if (refreshInFlightRef.current) return;
71
+ const { silent = false } = opts;
72
+ refreshInFlightRef.current = true;
97
73
  if (!silent) {
98
- setLoading(false);
74
+ setLoading(true);
99
75
  }
100
- }
101
- }, [scopedTeamName]);
76
+ setError(null);
77
+ try {
78
+ const teamList = await api.teams.list();
79
+ const scopedTeams: TeamSummary[] = scopedTeamName
80
+ ? teamList.filter((team) => team.teamName === scopedTeamName)
81
+ : teamList;
82
+
83
+ const results = await Promise.allSettled(
84
+ scopedTeams.map(async (t) => {
85
+ try {
86
+ const sessions = await api.teams.getTeamSessions(t.teamName);
87
+ return sessions.map((s) => ({
88
+ ...s,
89
+ teamName: t.teamName,
90
+ teamDisplayName: t.displayName || t.teamName,
91
+ }));
92
+ } catch {
93
+ return [] as TaggedSession[];
94
+ }
95
+ })
96
+ );
97
+
98
+ const merged: TaggedSession[] = [];
99
+ for (const r of results) {
100
+ if (r.status === 'fulfilled') merged.push(...r.value);
101
+ }
102
+ setAllSessions(merged);
103
+ setExpandedId((prev) => (prev && merged.some((s) => s.id === prev) ? prev : null));
104
+ } catch (err) {
105
+ setError(err instanceof Error ? err.message : '加载失败');
106
+ } finally {
107
+ refreshInFlightRef.current = false;
108
+ if (!silent) {
109
+ setLoading(false);
110
+ }
111
+ }
112
+ },
113
+ [scopedTeamName]
114
+ );
102
115
 
103
116
  useEffect(() => {
104
117
  void fetchAll();
@@ -151,12 +164,9 @@ export const SidebarSessions = (): React.JSX.Element => {
151
164
  [expandedId]
152
165
  );
153
166
 
154
- const handleExpand = useCallback(
155
- (teamName: string, sessionId: string) => {
156
- setExpandedId((prev) => (prev === sessionId ? null : sessionId));
157
- },
158
- []
159
- );
167
+ const handleExpand = useCallback((teamName: string, sessionId: string) => {
168
+ setExpandedId((prev) => (prev === sessionId ? null : sessionId));
169
+ }, []);
160
170
 
161
171
  // Filter + sort
162
172
  const filtered = allSessions.filter((s) => {
@@ -360,7 +370,9 @@ const SessionRow = ({
360
370
  }
361
371
  }
362
372
  })();
363
- return () => { cancelled = true; };
373
+ return () => {
374
+ cancelled = true;
375
+ };
364
376
  }, [historyLimit, isExpanded, session.teamName, session.id]);
365
377
 
366
378
  const handleLoadMoreHistory = useCallback(() => {
@@ -390,7 +402,7 @@ const SessionRow = ({
390
402
  {/* Status */}
391
403
  <div className="mt-0.5 shrink-0">
392
404
  {session.live ? (
393
- <Radio size={12} className="text-emerald-400 animate-pulse" />
405
+ <Radio size={12} className="animate-pulse text-emerald-400" />
394
406
  ) : (
395
407
  <MessageSquare size={12} className="text-[var(--color-text-muted)] opacity-50" />
396
408
  )}
@@ -414,7 +426,13 @@ const SessionRow = ({
414
426
 
415
427
  {session.lastMessage?.content && (
416
428
  <p className="mt-1 truncate text-[10px] text-[var(--color-text-muted)]">
417
- <span className={session.lastMessage.role === 'user' ? 'text-blue-400' : 'text-[var(--color-text-muted)]'}>
429
+ <span
430
+ className={
431
+ session.lastMessage.role === 'user'
432
+ ? 'text-blue-400'
433
+ : 'text-[var(--color-text-muted)]'
434
+ }
435
+ >
418
436
  {session.lastMessage.role === 'user' ? '用户' : 'Agent'}:
419
437
  </span>
420
438
  {session.lastMessage.content.slice(0, 80)}
@@ -427,7 +445,7 @@ const SessionRow = ({
427
445
  {session.live && (
428
446
  <button
429
447
  type="button"
430
- className="absolute right-2 top-2 shrink-0 rounded p-1 opacity-0 transition-opacity group-hover:opacity-100 hover:bg-red-500/10 hover:text-red-400 disabled:opacity-50"
448
+ className="absolute right-2 top-2 shrink-0 rounded p-1 opacity-0 transition-opacity hover:bg-red-500/10 hover:text-red-400 disabled:opacity-50 group-hover:opacity-100"
431
449
  onClick={(e) => {
432
450
  e.stopPropagation();
433
451
  onCancel(session.teamName, session.id);
@@ -442,12 +460,15 @@ const SessionRow = ({
442
460
 
443
461
  {/* Inline expanded messages */}
444
462
  {isExpanded && (
445
- <div className="border-l-2 border-[var(--color-border)] ml-5">
463
+ <div className="ml-5 border-l-2 border-[var(--color-border)]">
446
464
  {loadingDetail && !detail && (
447
465
  <div className="px-3 py-3">
448
466
  <div className="space-y-2">
449
467
  {[1, 2, 3].map((i) => (
450
- <div key={i} className="h-3 animate-pulse rounded bg-[var(--color-surface-raised)]" />
468
+ <div
469
+ key={i}
470
+ className="h-3 animate-pulse rounded bg-[var(--color-surface-raised)]"
471
+ />
451
472
  ))}
452
473
  </div>
453
474
  </div>
@@ -458,13 +479,15 @@ const SessionRow = ({
458
479
  <div className="px-3 py-3 text-xs text-[var(--color-text-muted)]">暂无消息</div>
459
480
  ) : (
460
481
  <>
461
- <div className="max-h-64 overflow-y-auto divide-y divide-[var(--color-border)]/50">
462
- {[...detail.history].reverse().map((msg, i) => (
482
+ <div className="divide-[var(--color-border)]/50 max-h-64 divide-y overflow-y-auto">
483
+ {[...detail.history].reverse().map((msg, i) => (
463
484
  <div key={i} className="px-3 py-2 text-[11px]">
464
485
  <div className="flex items-center gap-2">
465
486
  <span
466
487
  className={`shrink-0 text-[10px] font-medium ${
467
- msg.role === 'user' ? 'text-blue-400' : 'text-[var(--color-text-muted)]'
488
+ msg.role === 'user'
489
+ ? 'text-blue-400'
490
+ : 'text-[var(--color-text-muted)]'
468
491
  }`}
469
492
  >
470
493
  {msg.role === 'user' ? '用户' : 'Agent'}
@@ -481,7 +504,7 @@ const SessionRow = ({
481
504
  ))}
482
505
  </div>
483
506
  {hasMoreHistory && (
484
- <div className="border-t border-[var(--color-border)]/50 px-3 py-2">
507
+ <div className="border-[var(--color-border)]/50 border-t px-3 py-2">
485
508
  <button
486
509
  type="button"
487
510
  className="inline-flex items-center gap-1 text-xs text-[var(--color-text-muted)] transition-colors hover:text-[var(--color-text)] disabled:cursor-not-allowed disabled:opacity-50"
@@ -494,7 +517,10 @@ const SessionRow = ({
494
517
  正在加载更早消息...
495
518
  </>
496
519
  ) : (
497
- <>加载更早消息 ({Math.max(detail.historyCount - detail.history.length, 0)} 条)</>
520
+ <>
521
+ 加载更早消息 ({Math.max(detail.historyCount - detail.history.length, 0)}{' '}
522
+ 条)
523
+ </>
498
524
  )}
499
525
  </button>
500
526
  </div>
@@ -513,13 +539,20 @@ function formatShortTime(date: Date): string {
513
539
  try {
514
540
  const distance = formatDistanceToNowStrict(date, { addSuffix: false });
515
541
  return distance
516
- .replace(' seconds', 's').replace(' second', 's')
517
- .replace(' minutes', 'm').replace(' minute', 'm')
518
- .replace(' hours', 'h').replace(' hour', 'h')
519
- .replace(' days', 'd').replace(' day', 'd')
520
- .replace(' weeks', 'w').replace(' week', 'w')
521
- .replace(' months', 'mo').replace(' month', 'mo')
522
- .replace(' years', 'y').replace(' year', 'y');
542
+ .replace(' seconds', 's')
543
+ .replace(' second', 's')
544
+ .replace(' minutes', 'm')
545
+ .replace(' minute', 'm')
546
+ .replace(' hours', 'h')
547
+ .replace(' hour', 'h')
548
+ .replace(' days', 'd')
549
+ .replace(' day', 'd')
550
+ .replace(' weeks', 'w')
551
+ .replace(' week', 'w')
552
+ .replace(' months', 'mo')
553
+ .replace(' month', 'mo')
554
+ .replace(' years', 'y')
555
+ .replace(' year', 'y');
523
556
  } catch {
524
557
  return '';
525
558
  }
@@ -3,14 +3,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react';
3
3
  import { api } from '@renderer/api';
4
4
  import { FileIcon } from '@renderer/components/team/editor/FileIcon';
5
5
  import { useStore } from '@renderer/store';
6
- import {
7
- Folder,
8
- FolderOpen,
9
- ChevronRight,
10
- ChevronDown,
11
- ArrowUp,
12
- HardDrive,
13
- } from 'lucide-react';
6
+ import { Folder, FolderOpen, ChevronRight, ChevronDown, ArrowUp, HardDrive } from 'lucide-react';
14
7
  import { useShallow } from 'zustand/react/shallow';
15
8
 
16
9
  import type { WorkspaceFileEntry, WorkspaceListResponse } from '@shared/types/editor';
@@ -55,9 +48,8 @@ interface TeamWorkspaceProps {
55
48
 
56
49
  function joinWorkspacePath(basePath: string, entryName: string): string {
57
50
  const separator = basePath.includes('\\') && !basePath.includes('/') ? '\\' : '/';
58
- const normalizedBase = basePath.endsWith('/') || basePath.endsWith('\\')
59
- ? basePath.slice(0, -1)
60
- : basePath;
51
+ const normalizedBase =
52
+ basePath.endsWith('/') || basePath.endsWith('\\') ? basePath.slice(0, -1) : basePath;
61
53
  return `${normalizedBase}${separator}${entryName}`;
62
54
  }
63
55
 
@@ -73,28 +65,25 @@ const TeamWorkspace = ({
73
65
  const [loading, setLoading] = useState(false);
74
66
  const [error, setError] = useState<string | null>(null);
75
67
 
76
- const loadDir = useCallback(
77
- async (dirPath: string) => {
78
- setLoading(true);
79
- setError(null);
80
- try {
81
- const res: WorkspaceListResponse = await api.workspace.list(dirPath);
82
- if (res.error) {
83
- setError(res.error);
84
- setEntries([]);
85
- } else {
86
- setEntries(res.files);
87
- setCurrentDir(res.path);
88
- }
89
- } catch (err) {
90
- setError(err instanceof Error ? err.message : '加载失败');
68
+ const loadDir = useCallback(async (dirPath: string) => {
69
+ setLoading(true);
70
+ setError(null);
71
+ try {
72
+ const res: WorkspaceListResponse = await api.workspace.list(dirPath);
73
+ if (res.error) {
74
+ setError(res.error);
91
75
  setEntries([]);
92
- } finally {
93
- setLoading(false);
76
+ } else {
77
+ setEntries(res.files);
78
+ setCurrentDir(res.path);
94
79
  }
95
- },
96
- []
97
- );
80
+ } catch (err) {
81
+ setError(err instanceof Error ? err.message : '加载失败');
82
+ setEntries([]);
83
+ } finally {
84
+ setLoading(false);
85
+ }
86
+ }, []);
98
87
 
99
88
  // Load root when expanded
100
89
  useEffect(() => {
@@ -179,10 +168,7 @@ const TeamWorkspace = ({
179
168
  {breadcrumb.map((crumb, i) => (
180
169
  <span key={crumb.path} className="flex items-center gap-0.5">
181
170
  {i > 0 && (
182
- <ChevronRight
183
- size={10}
184
- className="text-[var(--color-text-muted)] opacity-50"
185
- />
171
+ <ChevronRight size={10} className="text-[var(--color-text-muted)] opacity-50" />
186
172
  )}
187
173
  <button
188
174
  type="button"
@@ -233,24 +219,21 @@ const TeamWorkspace = ({
233
219
  type="button"
234
220
  className={`flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs transition-colors ${
235
221
  entry.isDirectory
236
- ? 'hover:bg-[var(--color-surface-raised)] cursor-pointer'
222
+ ? 'cursor-pointer hover:bg-[var(--color-surface-raised)]'
237
223
  : onFileClick
238
- ? 'hover:bg-[var(--color-surface-raised)] cursor-pointer'
239
- : 'cursor-default hover:bg-[var(--color-surface-raised)]/50'
224
+ ? 'cursor-pointer hover:bg-[var(--color-surface-raised)]'
225
+ : 'hover:bg-[var(--color-surface-raised)]/50 cursor-default'
240
226
  }`}
241
227
  onClick={() => handleEntryClick(entry)}
242
228
  >
243
229
  {entry.isDirectory ? (
244
- <FolderOpen
245
- size={14}
246
- className="shrink-0 text-[var(--color-text-muted)]"
247
- />
230
+ <FolderOpen size={14} className="shrink-0 text-[var(--color-text-muted)]" />
248
231
  ) : (
249
232
  <FileIcon fileName={entry.name} className="size-3.5 shrink-0" />
250
233
  )}
251
234
  <span className="min-w-0 flex-1 truncate">{entry.name}</span>
252
235
  {!entry.isDirectory && entry.size > 0 && (
253
- <span className="shrink-0 text-[10px] text-[var(--color-text-muted)] tabular-nums">
236
+ <span className="shrink-0 text-[10px] tabular-nums text-[var(--color-text-muted)]">
254
237
  {formatSize(entry.size)}
255
238
  </span>
256
239
  )}
@@ -11,7 +11,16 @@
11
11
 
12
12
  import { useState } from 'react';
13
13
  import { formatDistanceToNowStrict } from 'date-fns';
14
- import { AlertCircle, Loader2, MessageSquare, Monitor, Radio, Wifi, WifiOff, X } from 'lucide-react';
14
+ import {
15
+ AlertCircle,
16
+ Loader2,
17
+ MessageSquare,
18
+ Monitor,
19
+ Radio,
20
+ Wifi,
21
+ WifiOff,
22
+ X,
23
+ } from 'lucide-react';
15
24
 
16
25
  import type { CcSession } from '@shared/types';
17
26
 
@@ -129,7 +138,7 @@ function CcSessionRow({
129
138
  {/* 状态指示 */}
130
139
  <div className="mt-0.5 shrink-0">
131
140
  {session.live ? (
132
- <Radio size={12} className="text-emerald-400 animate-pulse" />
141
+ <Radio size={12} className="animate-pulse text-emerald-400" />
133
142
  ) : session.active ? (
134
143
  <Wifi size={12} className="text-blue-400" />
135
144
  ) : (
@@ -154,14 +163,18 @@ function CcSessionRow({
154
163
  {session.historyCount}
155
164
  </span>
156
165
  <span className="tabular-nums">{timeAgo}</span>
157
- {session.live && (
158
- <span className="text-emerald-500 dark:text-emerald-400">进行中</span>
159
- )}
166
+ {session.live && <span className="text-emerald-500 dark:text-emerald-400">进行中</span>}
160
167
  </div>
161
168
 
162
169
  {session.lastMessage && (
163
170
  <p className="mt-1 truncate text-[10px] text-[var(--color-text-muted)]">
164
- <span className={session.lastMessage.role === 'user' ? 'text-blue-400' : 'text-[var(--color-text-muted)]'}>
171
+ <span
172
+ className={
173
+ session.lastMessage.role === 'user'
174
+ ? 'text-blue-400'
175
+ : 'text-[var(--color-text-muted)]'
176
+ }
177
+ >
165
178
  {session.lastMessage.role === 'user' ? '用户' : 'Agent'}:
166
179
  </span>
167
180
  {session.lastMessage.content.slice(0, 80)}
@@ -174,7 +187,7 @@ function CcSessionRow({
174
187
  {session.live && onCancel && (
175
188
  <button
176
189
  type="button"
177
- className="absolute right-2 top-2 shrink-0 rounded p-1 opacity-0 transition-opacity group-hover:opacity-100 hover:bg-red-500/10 hover:text-red-400"
190
+ className="absolute right-2 top-2 shrink-0 rounded p-1 opacity-0 transition-opacity hover:bg-red-500/10 hover:text-red-400 group-hover:opacity-100"
178
191
  onClick={() => onCancel(session.id)}
179
192
  title="终止会话"
180
193
  >
@@ -189,13 +202,20 @@ function formatShortTime(date: Date): string {
189
202
  try {
190
203
  const distance = formatDistanceToNowStrict(date, { addSuffix: false });
191
204
  return distance
192
- .replace(' seconds', 's').replace(' second', 's')
193
- .replace(' minutes', 'm').replace(' minute', 'm')
194
- .replace(' hours', 'h').replace(' hour', 'h')
195
- .replace(' days', 'd').replace(' day', 'd')
196
- .replace(' weeks', 'w').replace(' week', 'w')
197
- .replace(' months', 'mo').replace(' month', 'mo')
198
- .replace(' years', 'y').replace(' year', 'y');
205
+ .replace(' seconds', 's')
206
+ .replace(' second', 's')
207
+ .replace(' minutes', 'm')
208
+ .replace(' minute', 'm')
209
+ .replace(' hours', 'h')
210
+ .replace(' hour', 'h')
211
+ .replace(' days', 'd')
212
+ .replace(' day', 'd')
213
+ .replace(' weeks', 'w')
214
+ .replace(' week', 'w')
215
+ .replace(' months', 'mo')
216
+ .replace(' month', 'mo')
217
+ .replace(' years', 'y')
218
+ .replace(' year', 'y');
199
219
  } catch {
200
220
  return '';
201
221
  }